http_parser.rb 0.5.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/linux.yml +23 -0
  3. data/.github/workflows/windows.yml +23 -0
  4. data/.gitignore +5 -4
  5. data/.gitmodules +4 -4
  6. data/Gemfile +1 -1
  7. data/README.md +52 -47
  8. data/Rakefile +1 -0
  9. data/bench/standalone.rb +23 -0
  10. data/bench/thin.rb +1 -0
  11. data/ext/ruby_http_parser/extconf.rb +1 -1
  12. data/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java +139 -83
  13. data/ext/ruby_http_parser/ruby_http_parser.c +40 -41
  14. data/ext/ruby_http_parser/vendor/http-parser-java/AUTHORS +32 -0
  15. data/ext/ruby_http_parser/vendor/http-parser-java/LICENSE-MIT +5 -1
  16. data/ext/ruby_http_parser/vendor/http-parser-java/README.md +133 -1
  17. data/ext/ruby_http_parser/vendor/http-parser-java/TODO +6 -0
  18. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.c +1202 -671
  19. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.gyp +79 -0
  20. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.h +172 -51
  21. data/ext/ruby_http_parser/vendor/http-parser-java/src/Http-parser.java.iml +22 -0
  22. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/FieldData.java +41 -0
  23. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPMethod.java +8 -3
  24. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParserUrl.java +76 -0
  25. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserSettings.java +35 -102
  26. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/Util.java +6 -6
  27. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java +775 -682
  28. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java +8 -4
  29. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Message.java +70 -20
  30. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/ParseUrl.java +51 -0
  31. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Requests.java +1 -1
  32. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Responses.java +1 -0
  33. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Test.java +2 -1
  34. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestHeaderOverflowError.java +1 -0
  35. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestLoaderNG.java +6 -17
  36. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestNoOverflowLongBody.java +1 -0
  37. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/UnitTest.java +1 -0
  38. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Upgrade.java +1 -0
  39. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Url.java +127 -0
  40. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Util.java +80 -9
  41. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/WrongContentLength.java +2 -1
  42. data/ext/ruby_http_parser/vendor/http-parser-java/test.c +1637 -280
  43. data/ext/ruby_http_parser/vendor/http-parser-java/tests.dumped +230 -71
  44. data/ext/ruby_http_parser/vendor/http-parser/AUTHORS +68 -0
  45. data/ext/ruby_http_parser/vendor/http-parser/LICENSE-MIT +1 -1
  46. data/ext/ruby_http_parser/vendor/http-parser/README.md +113 -38
  47. data/ext/ruby_http_parser/vendor/http-parser/bench.c +128 -0
  48. data/ext/ruby_http_parser/vendor/http-parser/contrib/parsertrace.c +157 -0
  49. data/ext/ruby_http_parser/vendor/http-parser/contrib/url_parser.c +47 -0
  50. data/ext/ruby_http_parser/vendor/http-parser/http_parser.c +1576 -780
  51. data/ext/ruby_http_parser/vendor/http-parser/http_parser.gyp +111 -0
  52. data/ext/ruby_http_parser/vendor/http-parser/http_parser.h +308 -58
  53. data/ext/ruby_http_parser/vendor/http-parser/test.c +2964 -460
  54. data/http_parser.rb.gemspec +14 -7
  55. data/spec/parser_spec.rb +196 -102
  56. data/spec/support/requests.json +236 -24
  57. data/spec/support/responses.json +202 -36
  58. data/tasks/compile.rake +2 -2
  59. data/tasks/fixtures.rake +8 -2
  60. data/tasks/spec.rake +1 -1
  61. metadata +141 -134
  62. data/Gemfile.lock +0 -32
  63. data/ext/ruby_http_parser/vendor/http-parser-java/compile +0 -1
  64. data/ext/ruby_http_parser/vendor/http-parser-java/test_permutations +0 -1
  65. data/ext/ruby_http_parser/vendor/http-parser-java/test_unit +0 -1
  66. data/ext/ruby_http_parser/vendor/http-parser-java/test_utf8 +0 -1
  67. data/ext/ruby_http_parser/vendor/http-parser/CONTRIBUTIONS +0 -4
@@ -0,0 +1,111 @@
1
+ # This file is used with the GYP meta build system.
2
+ # http://code.google.com/p/gyp/
3
+ # To build try this:
4
+ # svn co http://gyp.googlecode.com/svn/trunk gyp
5
+ # ./gyp/gyp -f make --depth=`pwd` http_parser.gyp
6
+ # ./out/Debug/test
7
+ {
8
+ 'target_defaults': {
9
+ 'default_configuration': 'Debug',
10
+ 'configurations': {
11
+ # TODO: hoist these out and put them somewhere common, because
12
+ # RuntimeLibrary MUST MATCH across the entire project
13
+ 'Debug': {
14
+ 'defines': [ 'DEBUG', '_DEBUG' ],
15
+ 'cflags': [ '-Wall', '-Wextra', '-O0', '-g', '-ftrapv' ],
16
+ 'msvs_settings': {
17
+ 'VCCLCompilerTool': {
18
+ 'RuntimeLibrary': 1, # static debug
19
+ },
20
+ },
21
+ },
22
+ 'Release': {
23
+ 'defines': [ 'NDEBUG' ],
24
+ 'cflags': [ '-Wall', '-Wextra', '-O3' ],
25
+ 'msvs_settings': {
26
+ 'VCCLCompilerTool': {
27
+ 'RuntimeLibrary': 0, # static release
28
+ },
29
+ },
30
+ }
31
+ },
32
+ 'msvs_settings': {
33
+ 'VCCLCompilerTool': {
34
+ },
35
+ 'VCLibrarianTool': {
36
+ },
37
+ 'VCLinkerTool': {
38
+ 'GenerateDebugInformation': 'true',
39
+ },
40
+ },
41
+ 'conditions': [
42
+ ['OS == "win"', {
43
+ 'defines': [
44
+ 'WIN32'
45
+ ],
46
+ }]
47
+ ],
48
+ },
49
+
50
+ 'targets': [
51
+ {
52
+ 'target_name': 'http_parser',
53
+ 'type': 'static_library',
54
+ 'include_dirs': [ '.' ],
55
+ 'direct_dependent_settings': {
56
+ 'defines': [ 'HTTP_PARSER_STRICT=0' ],
57
+ 'include_dirs': [ '.' ],
58
+ },
59
+ 'defines': [ 'HTTP_PARSER_STRICT=0' ],
60
+ 'sources': [ './http_parser.c', ],
61
+ 'conditions': [
62
+ ['OS=="win"', {
63
+ 'msvs_settings': {
64
+ 'VCCLCompilerTool': {
65
+ # Compile as C++. http_parser.c is actually C99, but C++ is
66
+ # close enough in this case.
67
+ 'CompileAs': 2,
68
+ },
69
+ },
70
+ }]
71
+ ],
72
+ },
73
+
74
+ {
75
+ 'target_name': 'http_parser_strict',
76
+ 'type': 'static_library',
77
+ 'include_dirs': [ '.' ],
78
+ 'direct_dependent_settings': {
79
+ 'defines': [ 'HTTP_PARSER_STRICT=1' ],
80
+ 'include_dirs': [ '.' ],
81
+ },
82
+ 'defines': [ 'HTTP_PARSER_STRICT=1' ],
83
+ 'sources': [ './http_parser.c', ],
84
+ 'conditions': [
85
+ ['OS=="win"', {
86
+ 'msvs_settings': {
87
+ 'VCCLCompilerTool': {
88
+ # Compile as C++. http_parser.c is actually C99, but C++ is
89
+ # close enough in this case.
90
+ 'CompileAs': 2,
91
+ },
92
+ },
93
+ }]
94
+ ],
95
+ },
96
+
97
+ {
98
+ 'target_name': 'test-nonstrict',
99
+ 'type': 'executable',
100
+ 'dependencies': [ 'http_parser' ],
101
+ 'sources': [ 'test.c' ]
102
+ },
103
+
104
+ {
105
+ 'target_name': 'test-strict',
106
+ 'type': 'executable',
107
+ 'dependencies': [ 'http_parser_strict' ],
108
+ 'sources': [ 'test.c' ]
109
+ }
110
+ ]
111
+ }
@@ -24,11 +24,15 @@
24
24
  extern "C" {
25
25
  #endif
26
26
 
27
- #define HTTP_PARSER_VERSION_MAJOR 1
28
- #define HTTP_PARSER_VERSION_MINOR 0
27
+ /* Also update SONAME in the Makefile whenever you change these. */
28
+ #define HTTP_PARSER_VERSION_MAJOR 2
29
+ #define HTTP_PARSER_VERSION_MINOR 8
30
+ #define HTTP_PARSER_VERSION_PATCH 1
29
31
 
30
- #include <sys/types.h>
31
- #if defined(_WIN32) && !defined(__MINGW32__)
32
+ #include <stddef.h>
33
+ #if defined(_WIN32) && !defined(__MINGW32__) && \
34
+ (!defined(_MSC_VER) || _MSC_VER<1600) && !defined(__WINE__)
35
+ #include <BaseTsd.h>
32
36
  typedef __int8 int8_t;
33
37
  typedef unsigned __int8 uint8_t;
34
38
  typedef __int16 int16_t;
@@ -37,9 +41,6 @@ typedef __int32 int32_t;
37
41
  typedef unsigned __int32 uint32_t;
38
42
  typedef __int64 int64_t;
39
43
  typedef unsigned __int64 uint64_t;
40
-
41
- typedef unsigned int size_t;
42
- typedef int ssize_t;
43
44
  #else
44
45
  #include <stdint.h>
45
46
  #endif
@@ -49,14 +50,18 @@ typedef int ssize_t;
49
50
  */
50
51
  #ifndef HTTP_PARSER_STRICT
51
52
  # define HTTP_PARSER_STRICT 1
52
- #else
53
- # define HTTP_PARSER_STRICT 0
54
53
  #endif
55
54
 
56
-
57
- /* Maximium header size allowed */
58
- #define HTTP_MAX_HEADER_SIZE (80*1024)
59
-
55
+ /* Maximium header size allowed. If the macro is not defined
56
+ * before including this header then the default is used. To
57
+ * change the maximum header size, define the macro in the build
58
+ * environment (e.g. -DHTTP_MAX_HEADER_SIZE=<value>). To remove
59
+ * the effective limit on the size of the header, define the macro
60
+ * to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff)
61
+ */
62
+ #ifndef HTTP_MAX_HEADER_SIZE
63
+ # define HTTP_MAX_HEADER_SIZE (80*1024)
64
+ #endif
60
65
 
61
66
  typedef struct http_parser http_parser;
62
67
  typedef struct http_parser_settings http_parser_settings;
@@ -71,72 +76,245 @@ typedef struct http_parser_settings http_parser_settings;
71
76
  * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding:
72
77
  * chunked' headers that indicate the presence of a body.
73
78
  *
74
- * http_data_cb does not return data chunks. It will be call arbitrarally
75
- * many times for each string. E.G. you might get 10 callbacks for "on_path"
79
+ * Returning `2` from on_headers_complete will tell parser that it should not
80
+ * expect neither a body nor any futher responses on this connection. This is
81
+ * useful for handling responses to a CONNECT request which may not contain
82
+ * `Upgrade` or `Connection: upgrade` headers.
83
+ *
84
+ * http_data_cb does not return data chunks. It will be called arbitrarily
85
+ * many times for each string. E.G. you might get 10 callbacks for "on_url"
76
86
  * each providing just a few characters more data.
77
87
  */
78
88
  typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
79
89
  typedef int (*http_cb) (http_parser*);
80
90
 
81
91
 
92
+ /* Status Codes */
93
+ #define HTTP_STATUS_MAP(XX) \
94
+ XX(100, CONTINUE, Continue) \
95
+ XX(101, SWITCHING_PROTOCOLS, Switching Protocols) \
96
+ XX(102, PROCESSING, Processing) \
97
+ XX(200, OK, OK) \
98
+ XX(201, CREATED, Created) \
99
+ XX(202, ACCEPTED, Accepted) \
100
+ XX(203, NON_AUTHORITATIVE_INFORMATION, Non-Authoritative Information) \
101
+ XX(204, NO_CONTENT, No Content) \
102
+ XX(205, RESET_CONTENT, Reset Content) \
103
+ XX(206, PARTIAL_CONTENT, Partial Content) \
104
+ XX(207, MULTI_STATUS, Multi-Status) \
105
+ XX(208, ALREADY_REPORTED, Already Reported) \
106
+ XX(226, IM_USED, IM Used) \
107
+ XX(300, MULTIPLE_CHOICES, Multiple Choices) \
108
+ XX(301, MOVED_PERMANENTLY, Moved Permanently) \
109
+ XX(302, FOUND, Found) \
110
+ XX(303, SEE_OTHER, See Other) \
111
+ XX(304, NOT_MODIFIED, Not Modified) \
112
+ XX(305, USE_PROXY, Use Proxy) \
113
+ XX(307, TEMPORARY_REDIRECT, Temporary Redirect) \
114
+ XX(308, PERMANENT_REDIRECT, Permanent Redirect) \
115
+ XX(400, BAD_REQUEST, Bad Request) \
116
+ XX(401, UNAUTHORIZED, Unauthorized) \
117
+ XX(402, PAYMENT_REQUIRED, Payment Required) \
118
+ XX(403, FORBIDDEN, Forbidden) \
119
+ XX(404, NOT_FOUND, Not Found) \
120
+ XX(405, METHOD_NOT_ALLOWED, Method Not Allowed) \
121
+ XX(406, NOT_ACCEPTABLE, Not Acceptable) \
122
+ XX(407, PROXY_AUTHENTICATION_REQUIRED, Proxy Authentication Required) \
123
+ XX(408, REQUEST_TIMEOUT, Request Timeout) \
124
+ XX(409, CONFLICT, Conflict) \
125
+ XX(410, GONE, Gone) \
126
+ XX(411, LENGTH_REQUIRED, Length Required) \
127
+ XX(412, PRECONDITION_FAILED, Precondition Failed) \
128
+ XX(413, PAYLOAD_TOO_LARGE, Payload Too Large) \
129
+ XX(414, URI_TOO_LONG, URI Too Long) \
130
+ XX(415, UNSUPPORTED_MEDIA_TYPE, Unsupported Media Type) \
131
+ XX(416, RANGE_NOT_SATISFIABLE, Range Not Satisfiable) \
132
+ XX(417, EXPECTATION_FAILED, Expectation Failed) \
133
+ XX(421, MISDIRECTED_REQUEST, Misdirected Request) \
134
+ XX(422, UNPROCESSABLE_ENTITY, Unprocessable Entity) \
135
+ XX(423, LOCKED, Locked) \
136
+ XX(424, FAILED_DEPENDENCY, Failed Dependency) \
137
+ XX(426, UPGRADE_REQUIRED, Upgrade Required) \
138
+ XX(428, PRECONDITION_REQUIRED, Precondition Required) \
139
+ XX(429, TOO_MANY_REQUESTS, Too Many Requests) \
140
+ XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, Request Header Fields Too Large) \
141
+ XX(451, UNAVAILABLE_FOR_LEGAL_REASONS, Unavailable For Legal Reasons) \
142
+ XX(500, INTERNAL_SERVER_ERROR, Internal Server Error) \
143
+ XX(501, NOT_IMPLEMENTED, Not Implemented) \
144
+ XX(502, BAD_GATEWAY, Bad Gateway) \
145
+ XX(503, SERVICE_UNAVAILABLE, Service Unavailable) \
146
+ XX(504, GATEWAY_TIMEOUT, Gateway Timeout) \
147
+ XX(505, HTTP_VERSION_NOT_SUPPORTED, HTTP Version Not Supported) \
148
+ XX(506, VARIANT_ALSO_NEGOTIATES, Variant Also Negotiates) \
149
+ XX(507, INSUFFICIENT_STORAGE, Insufficient Storage) \
150
+ XX(508, LOOP_DETECTED, Loop Detected) \
151
+ XX(510, NOT_EXTENDED, Not Extended) \
152
+ XX(511, NETWORK_AUTHENTICATION_REQUIRED, Network Authentication Required) \
153
+
154
+ enum http_status
155
+ {
156
+ #define XX(num, name, string) HTTP_STATUS_##name = num,
157
+ HTTP_STATUS_MAP(XX)
158
+ #undef XX
159
+ };
160
+
161
+
82
162
  /* Request Methods */
163
+ #define HTTP_METHOD_MAP(XX) \
164
+ XX(0, DELETE, DELETE) \
165
+ XX(1, GET, GET) \
166
+ XX(2, HEAD, HEAD) \
167
+ XX(3, POST, POST) \
168
+ XX(4, PUT, PUT) \
169
+ /* pathological */ \
170
+ XX(5, CONNECT, CONNECT) \
171
+ XX(6, OPTIONS, OPTIONS) \
172
+ XX(7, TRACE, TRACE) \
173
+ /* WebDAV */ \
174
+ XX(8, COPY, COPY) \
175
+ XX(9, LOCK, LOCK) \
176
+ XX(10, MKCOL, MKCOL) \
177
+ XX(11, MOVE, MOVE) \
178
+ XX(12, PROPFIND, PROPFIND) \
179
+ XX(13, PROPPATCH, PROPPATCH) \
180
+ XX(14, SEARCH, SEARCH) \
181
+ XX(15, UNLOCK, UNLOCK) \
182
+ XX(16, BIND, BIND) \
183
+ XX(17, REBIND, REBIND) \
184
+ XX(18, UNBIND, UNBIND) \
185
+ XX(19, ACL, ACL) \
186
+ /* subversion */ \
187
+ XX(20, REPORT, REPORT) \
188
+ XX(21, MKACTIVITY, MKACTIVITY) \
189
+ XX(22, CHECKOUT, CHECKOUT) \
190
+ XX(23, MERGE, MERGE) \
191
+ /* upnp */ \
192
+ XX(24, MSEARCH, M-SEARCH) \
193
+ XX(25, NOTIFY, NOTIFY) \
194
+ XX(26, SUBSCRIBE, SUBSCRIBE) \
195
+ XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \
196
+ /* RFC-5789 */ \
197
+ XX(28, PATCH, PATCH) \
198
+ XX(29, PURGE, PURGE) \
199
+ /* CalDAV */ \
200
+ XX(30, MKCALENDAR, MKCALENDAR) \
201
+ /* RFC-2068, section 19.6.1.2 */ \
202
+ XX(31, LINK, LINK) \
203
+ XX(32, UNLINK, UNLINK) \
204
+ /* icecast */ \
205
+ XX(33, SOURCE, SOURCE) \
206
+
83
207
  enum http_method
84
- { HTTP_DELETE = 0
85
- , HTTP_GET
86
- , HTTP_HEAD
87
- , HTTP_POST
88
- , HTTP_PUT
89
- /* pathological */
90
- , HTTP_CONNECT
91
- , HTTP_OPTIONS
92
- , HTTP_TRACE
93
- /* webdav */
94
- , HTTP_COPY
95
- , HTTP_LOCK
96
- , HTTP_MKCOL
97
- , HTTP_MOVE
98
- , HTTP_PROPFIND
99
- , HTTP_PROPPATCH
100
- , HTTP_UNLOCK
101
- /* subversion */
102
- , HTTP_REPORT
103
- , HTTP_MKACTIVITY
104
- , HTTP_CHECKOUT
105
- , HTTP_MERGE
106
- /* upnp */
107
- , HTTP_MSEARCH
108
- , HTTP_NOTIFY
109
- , HTTP_SUBSCRIBE
110
- , HTTP_UNSUBSCRIBE
208
+ {
209
+ #define XX(num, name, string) HTTP_##name = num,
210
+ HTTP_METHOD_MAP(XX)
211
+ #undef XX
111
212
  };
112
213
 
113
214
 
114
215
  enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH };
115
216
 
116
217
 
218
+ /* Flag values for http_parser.flags field */
219
+ enum flags
220
+ { F_CHUNKED = 1 << 0
221
+ , F_CONNECTION_KEEP_ALIVE = 1 << 1
222
+ , F_CONNECTION_CLOSE = 1 << 2
223
+ , F_CONNECTION_UPGRADE = 1 << 3
224
+ , F_TRAILING = 1 << 4
225
+ , F_UPGRADE = 1 << 5
226
+ , F_SKIPBODY = 1 << 6
227
+ , F_CONTENTLENGTH = 1 << 7
228
+ };
229
+
230
+
231
+ /* Map for errno-related constants
232
+ *
233
+ * The provided argument should be a macro that takes 2 arguments.
234
+ */
235
+ #define HTTP_ERRNO_MAP(XX) \
236
+ /* No error */ \
237
+ XX(OK, "success") \
238
+ \
239
+ /* Callback-related errors */ \
240
+ XX(CB_message_begin, "the on_message_begin callback failed") \
241
+ XX(CB_url, "the on_url callback failed") \
242
+ XX(CB_header_field, "the on_header_field callback failed") \
243
+ XX(CB_header_value, "the on_header_value callback failed") \
244
+ XX(CB_headers_complete, "the on_headers_complete callback failed") \
245
+ XX(CB_body, "the on_body callback failed") \
246
+ XX(CB_message_complete, "the on_message_complete callback failed") \
247
+ XX(CB_status, "the on_status callback failed") \
248
+ XX(CB_chunk_header, "the on_chunk_header callback failed") \
249
+ XX(CB_chunk_complete, "the on_chunk_complete callback failed") \
250
+ \
251
+ /* Parsing-related errors */ \
252
+ XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
253
+ XX(HEADER_OVERFLOW, \
254
+ "too many header bytes seen; overflow detected") \
255
+ XX(CLOSED_CONNECTION, \
256
+ "data received after completed connection: close message") \
257
+ XX(INVALID_VERSION, "invalid HTTP version") \
258
+ XX(INVALID_STATUS, "invalid HTTP status code") \
259
+ XX(INVALID_METHOD, "invalid HTTP method") \
260
+ XX(INVALID_URL, "invalid URL") \
261
+ XX(INVALID_HOST, "invalid host") \
262
+ XX(INVALID_PORT, "invalid port") \
263
+ XX(INVALID_PATH, "invalid path") \
264
+ XX(INVALID_QUERY_STRING, "invalid query string") \
265
+ XX(INVALID_FRAGMENT, "invalid fragment") \
266
+ XX(LF_EXPECTED, "LF character expected") \
267
+ XX(INVALID_HEADER_TOKEN, "invalid character in header") \
268
+ XX(INVALID_CONTENT_LENGTH, \
269
+ "invalid character in content-length header") \
270
+ XX(UNEXPECTED_CONTENT_LENGTH, \
271
+ "unexpected content-length header") \
272
+ XX(INVALID_CHUNK_SIZE, \
273
+ "invalid character in chunk size header") \
274
+ XX(INVALID_CONSTANT, "invalid constant string") \
275
+ XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
276
+ XX(STRICT, "strict mode assertion failed") \
277
+ XX(PAUSED, "parser is paused") \
278
+ XX(UNKNOWN, "an unknown error occurred")
279
+
280
+
281
+ /* Define HPE_* values for each errno value above */
282
+ #define HTTP_ERRNO_GEN(n, s) HPE_##n,
283
+ enum http_errno {
284
+ HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)
285
+ };
286
+ #undef HTTP_ERRNO_GEN
287
+
288
+
289
+ /* Get an http_errno value from an http_parser */
290
+ #define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno)
291
+
292
+
117
293
  struct http_parser {
118
294
  /** PRIVATE **/
119
- unsigned char type : 2;
120
- unsigned char flags : 6;
121
- unsigned char state;
122
- unsigned char header_state;
123
- unsigned char index;
295
+ unsigned int type : 2; /* enum http_parser_type */
296
+ unsigned int flags : 8; /* F_* values from 'flags' enum; semi-public */
297
+ unsigned int state : 7; /* enum state from http_parser.c */
298
+ unsigned int header_state : 7; /* enum header_state from http_parser.c */
299
+ unsigned int index : 7; /* index into current matcher */
300
+ unsigned int lenient_http_headers : 1;
124
301
 
125
- uint32_t nread;
126
- int64_t content_length;
302
+ uint32_t nread; /* # bytes read in various scenarios */
303
+ uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */
127
304
 
128
305
  /** READ-ONLY **/
129
306
  unsigned short http_major;
130
307
  unsigned short http_minor;
131
- unsigned short status_code; /* responses only */
132
- unsigned char method; /* requests only */
308
+ unsigned int status_code : 16; /* responses only */
309
+ unsigned int method : 8; /* requests only */
310
+ unsigned int http_errno : 7;
133
311
 
134
312
  /* 1 = Upgrade header was present and the parser has exited because of that.
135
313
  * 0 = No upgrade header present.
136
314
  * Should be checked when http_parser_execute() returns in addition to
137
315
  * error checking.
138
316
  */
139
- char upgrade;
317
+ unsigned int upgrade : 1;
140
318
 
141
319
  /** PUBLIC **/
142
320
  void *data; /* A pointer to get hook to the "connection" or "socket" object */
@@ -145,21 +323,73 @@ struct http_parser {
145
323
 
146
324
  struct http_parser_settings {
147
325
  http_cb on_message_begin;
148
- http_data_cb on_path;
149
- http_data_cb on_query_string;
150
326
  http_data_cb on_url;
151
- http_data_cb on_fragment;
327
+ http_data_cb on_status;
152
328
  http_data_cb on_header_field;
153
329
  http_data_cb on_header_value;
154
330
  http_cb on_headers_complete;
155
331
  http_data_cb on_body;
156
332
  http_cb on_message_complete;
333
+ /* When on_chunk_header is called, the current chunk length is stored
334
+ * in parser->content_length.
335
+ */
336
+ http_cb on_chunk_header;
337
+ http_cb on_chunk_complete;
338
+ };
339
+
340
+
341
+ enum http_parser_url_fields
342
+ { UF_SCHEMA = 0
343
+ , UF_HOST = 1
344
+ , UF_PORT = 2
345
+ , UF_PATH = 3
346
+ , UF_QUERY = 4
347
+ , UF_FRAGMENT = 5
348
+ , UF_USERINFO = 6
349
+ , UF_MAX = 7
350
+ };
351
+
352
+
353
+ /* Result structure for http_parser_parse_url().
354
+ *
355
+ * Callers should index into field_data[] with UF_* values iff field_set
356
+ * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and
357
+ * because we probably have padding left over), we convert any port to
358
+ * a uint16_t.
359
+ */
360
+ struct http_parser_url {
361
+ uint16_t field_set; /* Bitmask of (1 << UF_*) values */
362
+ uint16_t port; /* Converted UF_PORT string */
363
+
364
+ struct {
365
+ uint16_t off; /* Offset into buffer in which field starts */
366
+ uint16_t len; /* Length of run in buffer */
367
+ } field_data[UF_MAX];
157
368
  };
158
369
 
159
370
 
371
+ /* Returns the library version. Bits 16-23 contain the major version number,
372
+ * bits 8-15 the minor version number and bits 0-7 the patch level.
373
+ * Usage example:
374
+ *
375
+ * unsigned long version = http_parser_version();
376
+ * unsigned major = (version >> 16) & 255;
377
+ * unsigned minor = (version >> 8) & 255;
378
+ * unsigned patch = version & 255;
379
+ * printf("http_parser v%u.%u.%u\n", major, minor, patch);
380
+ */
381
+ unsigned long http_parser_version(void);
382
+
160
383
  void http_parser_init(http_parser *parser, enum http_parser_type type);
161
384
 
162
385
 
386
+ /* Initialize http_parser_settings members to 0
387
+ */
388
+ void http_parser_settings_init(http_parser_settings *settings);
389
+
390
+
391
+ /* Executes the parser. Returns number of parsed bytes. Sets
392
+ * `parser->http_errno` on error. */
163
393
  size_t http_parser_execute(http_parser *parser,
164
394
  const http_parser_settings *settings,
165
395
  const char *data,
@@ -167,15 +397,35 @@ size_t http_parser_execute(http_parser *parser,
167
397
 
168
398
 
169
399
  /* If http_should_keep_alive() in the on_headers_complete or
170
- * on_message_complete callback returns true, then this will be should be
400
+ * on_message_complete callback returns 0, then this should be
171
401
  * the last message on the connection.
172
402
  * If you are the server, respond with the "Connection: close" header.
173
403
  * If you are the client, close the connection.
174
404
  */
175
- int http_should_keep_alive(http_parser *parser);
405
+ int http_should_keep_alive(const http_parser *parser);
176
406
 
177
407
  /* Returns a string version of the HTTP method. */
178
- const char *http_method_str(enum http_method);
408
+ const char *http_method_str(enum http_method m);
409
+
410
+ /* Return a string name of the given error */
411
+ const char *http_errno_name(enum http_errno err);
412
+
413
+ /* Return a string description of the given error */
414
+ const char *http_errno_description(enum http_errno err);
415
+
416
+ /* Initialize all http_parser_url members to 0 */
417
+ void http_parser_url_init(struct http_parser_url *u);
418
+
419
+ /* Parse a URL; return nonzero on failure */
420
+ int http_parser_parse_url(const char *buf, size_t buflen,
421
+ int is_connect,
422
+ struct http_parser_url *u);
423
+
424
+ /* Pause or un-pause the parser; a nonzero value pauses */
425
+ void http_parser_pause(http_parser *parser, int paused);
426
+
427
+ /* Checks if this is the final chunk of the body. */
428
+ int http_body_is_final(const http_parser *parser);
179
429
 
180
430
  #ifdef __cplusplus
181
431
  }