http-parser 1.0.3 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -26,13 +26,13 @@ extern "C" {
26
26
 
27
27
  /* Also update SONAME in the Makefile whenever you change these. */
28
28
  #define HTTP_PARSER_VERSION_MAJOR 2
29
- #define HTTP_PARSER_VERSION_MINOR 1
30
- #define HTTP_PARSER_VERSION_PATCH 0
29
+ #define HTTP_PARSER_VERSION_MINOR 9
30
+ #define HTTP_PARSER_VERSION_PATCH 4
31
31
 
32
- #include <sys/types.h>
33
- #if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600)
34
- #include <BaseTsd.h>
35
32
  #include <stddef.h>
33
+ #if defined(_WIN32) && !defined(__MINGW32__) && \
34
+ (!defined(_MSC_VER) || _MSC_VER<1600) && !defined(__WINE__)
35
+ #include <BaseTsd.h>
36
36
  typedef __int8 int8_t;
37
37
  typedef unsigned __int8 uint8_t;
38
38
  typedef __int16 int16_t;
@@ -41,6 +41,8 @@ typedef __int32 int32_t;
41
41
  typedef unsigned __int32 uint32_t;
42
42
  typedef __int64 int64_t;
43
43
  typedef unsigned __int64 uint64_t;
44
+ #elif (defined(__sun) || defined(__sun__)) && defined(__SunOS_5_9)
45
+ #include <sys/inttypes.h>
44
46
  #else
45
47
  #include <stdint.h>
46
48
  #endif
@@ -52,9 +54,16 @@ typedef unsigned __int64 uint64_t;
52
54
  # define HTTP_PARSER_STRICT 1
53
55
  #endif
54
56
 
55
- /* Maximium header size allowed */
56
- #define HTTP_MAX_HEADER_SIZE (80*1024)
57
-
57
+ /* Maximium header size allowed. If the macro is not defined
58
+ * before including this header then the default is used. To
59
+ * change the maximum header size, define the macro in the build
60
+ * environment (e.g. -DHTTP_MAX_HEADER_SIZE=<value>). To remove
61
+ * the effective limit on the size of the header, define the macro
62
+ * to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff)
63
+ */
64
+ #ifndef HTTP_MAX_HEADER_SIZE
65
+ # define HTTP_MAX_HEADER_SIZE (80*1024)
66
+ #endif
58
67
 
59
68
  typedef struct http_parser http_parser;
60
69
  typedef struct http_parser_settings http_parser_settings;
@@ -69,7 +78,12 @@ typedef struct http_parser_settings http_parser_settings;
69
78
  * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding:
70
79
  * chunked' headers that indicate the presence of a body.
71
80
  *
72
- * http_data_cb does not return data chunks. It will be call arbitrarally
81
+ * Returning `2` from on_headers_complete will tell parser that it should not
82
+ * expect neither a body nor any futher responses on this connection. This is
83
+ * useful for handling responses to a CONNECT request which may not contain
84
+ * `Upgrade` or `Connection: upgrade` headers.
85
+ *
86
+ * http_data_cb does not return data chunks. It will be called arbitrarily
73
87
  * many times for each string. E.G. you might get 10 callbacks for "on_url"
74
88
  * each providing just a few characters more data.
75
89
  */
@@ -77,6 +91,76 @@ typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
77
91
  typedef int (*http_cb) (http_parser*);
78
92
 
79
93
 
94
+ /* Status Codes */
95
+ #define HTTP_STATUS_MAP(XX) \
96
+ XX(100, CONTINUE, Continue) \
97
+ XX(101, SWITCHING_PROTOCOLS, Switching Protocols) \
98
+ XX(102, PROCESSING, Processing) \
99
+ XX(200, OK, OK) \
100
+ XX(201, CREATED, Created) \
101
+ XX(202, ACCEPTED, Accepted) \
102
+ XX(203, NON_AUTHORITATIVE_INFORMATION, Non-Authoritative Information) \
103
+ XX(204, NO_CONTENT, No Content) \
104
+ XX(205, RESET_CONTENT, Reset Content) \
105
+ XX(206, PARTIAL_CONTENT, Partial Content) \
106
+ XX(207, MULTI_STATUS, Multi-Status) \
107
+ XX(208, ALREADY_REPORTED, Already Reported) \
108
+ XX(226, IM_USED, IM Used) \
109
+ XX(300, MULTIPLE_CHOICES, Multiple Choices) \
110
+ XX(301, MOVED_PERMANENTLY, Moved Permanently) \
111
+ XX(302, FOUND, Found) \
112
+ XX(303, SEE_OTHER, See Other) \
113
+ XX(304, NOT_MODIFIED, Not Modified) \
114
+ XX(305, USE_PROXY, Use Proxy) \
115
+ XX(307, TEMPORARY_REDIRECT, Temporary Redirect) \
116
+ XX(308, PERMANENT_REDIRECT, Permanent Redirect) \
117
+ XX(400, BAD_REQUEST, Bad Request) \
118
+ XX(401, UNAUTHORIZED, Unauthorized) \
119
+ XX(402, PAYMENT_REQUIRED, Payment Required) \
120
+ XX(403, FORBIDDEN, Forbidden) \
121
+ XX(404, NOT_FOUND, Not Found) \
122
+ XX(405, METHOD_NOT_ALLOWED, Method Not Allowed) \
123
+ XX(406, NOT_ACCEPTABLE, Not Acceptable) \
124
+ XX(407, PROXY_AUTHENTICATION_REQUIRED, Proxy Authentication Required) \
125
+ XX(408, REQUEST_TIMEOUT, Request Timeout) \
126
+ XX(409, CONFLICT, Conflict) \
127
+ XX(410, GONE, Gone) \
128
+ XX(411, LENGTH_REQUIRED, Length Required) \
129
+ XX(412, PRECONDITION_FAILED, Precondition Failed) \
130
+ XX(413, PAYLOAD_TOO_LARGE, Payload Too Large) \
131
+ XX(414, URI_TOO_LONG, URI Too Long) \
132
+ XX(415, UNSUPPORTED_MEDIA_TYPE, Unsupported Media Type) \
133
+ XX(416, RANGE_NOT_SATISFIABLE, Range Not Satisfiable) \
134
+ XX(417, EXPECTATION_FAILED, Expectation Failed) \
135
+ XX(421, MISDIRECTED_REQUEST, Misdirected Request) \
136
+ XX(422, UNPROCESSABLE_ENTITY, Unprocessable Entity) \
137
+ XX(423, LOCKED, Locked) \
138
+ XX(424, FAILED_DEPENDENCY, Failed Dependency) \
139
+ XX(426, UPGRADE_REQUIRED, Upgrade Required) \
140
+ XX(428, PRECONDITION_REQUIRED, Precondition Required) \
141
+ XX(429, TOO_MANY_REQUESTS, Too Many Requests) \
142
+ XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, Request Header Fields Too Large) \
143
+ XX(451, UNAVAILABLE_FOR_LEGAL_REASONS, Unavailable For Legal Reasons) \
144
+ XX(500, INTERNAL_SERVER_ERROR, Internal Server Error) \
145
+ XX(501, NOT_IMPLEMENTED, Not Implemented) \
146
+ XX(502, BAD_GATEWAY, Bad Gateway) \
147
+ XX(503, SERVICE_UNAVAILABLE, Service Unavailable) \
148
+ XX(504, GATEWAY_TIMEOUT, Gateway Timeout) \
149
+ XX(505, HTTP_VERSION_NOT_SUPPORTED, HTTP Version Not Supported) \
150
+ XX(506, VARIANT_ALSO_NEGOTIATES, Variant Also Negotiates) \
151
+ XX(507, INSUFFICIENT_STORAGE, Insufficient Storage) \
152
+ XX(508, LOOP_DETECTED, Loop Detected) \
153
+ XX(510, NOT_EXTENDED, Not Extended) \
154
+ XX(511, NETWORK_AUTHENTICATION_REQUIRED, Network Authentication Required) \
155
+
156
+ enum http_status
157
+ {
158
+ #define XX(num, name, string) HTTP_STATUS_##name = num,
159
+ HTTP_STATUS_MAP(XX)
160
+ #undef XX
161
+ };
162
+
163
+
80
164
  /* Request Methods */
81
165
  #define HTTP_METHOD_MAP(XX) \
82
166
  XX(0, DELETE, DELETE) \
@@ -88,7 +172,7 @@ typedef int (*http_cb) (http_parser*);
88
172
  XX(5, CONNECT, CONNECT) \
89
173
  XX(6, OPTIONS, OPTIONS) \
90
174
  XX(7, TRACE, TRACE) \
91
- /* webdav */ \
175
+ /* WebDAV */ \
92
176
  XX(8, COPY, COPY) \
93
177
  XX(9, LOCK, LOCK) \
94
178
  XX(10, MKCOL, MKCOL) \
@@ -97,19 +181,30 @@ typedef int (*http_cb) (http_parser*);
97
181
  XX(13, PROPPATCH, PROPPATCH) \
98
182
  XX(14, SEARCH, SEARCH) \
99
183
  XX(15, UNLOCK, UNLOCK) \
184
+ XX(16, BIND, BIND) \
185
+ XX(17, REBIND, REBIND) \
186
+ XX(18, UNBIND, UNBIND) \
187
+ XX(19, ACL, ACL) \
100
188
  /* subversion */ \
101
- XX(16, REPORT, REPORT) \
102
- XX(17, MKACTIVITY, MKACTIVITY) \
103
- XX(18, CHECKOUT, CHECKOUT) \
104
- XX(19, MERGE, MERGE) \
189
+ XX(20, REPORT, REPORT) \
190
+ XX(21, MKACTIVITY, MKACTIVITY) \
191
+ XX(22, CHECKOUT, CHECKOUT) \
192
+ XX(23, MERGE, MERGE) \
105
193
  /* upnp */ \
106
- XX(20, MSEARCH, M-SEARCH) \
107
- XX(21, NOTIFY, NOTIFY) \
108
- XX(22, SUBSCRIBE, SUBSCRIBE) \
109
- XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \
194
+ XX(24, MSEARCH, M-SEARCH) \
195
+ XX(25, NOTIFY, NOTIFY) \
196
+ XX(26, SUBSCRIBE, SUBSCRIBE) \
197
+ XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \
110
198
  /* RFC-5789 */ \
111
- XX(24, PATCH, PATCH) \
112
- XX(25, PURGE, PURGE) \
199
+ XX(28, PATCH, PATCH) \
200
+ XX(29, PURGE, PURGE) \
201
+ /* CalDAV */ \
202
+ XX(30, MKCALENDAR, MKCALENDAR) \
203
+ /* RFC-2068, section 19.6.1.2 */ \
204
+ XX(31, LINK, LINK) \
205
+ XX(32, UNLINK, UNLINK) \
206
+ /* icecast */ \
207
+ XX(33, SOURCE, SOURCE) \
113
208
 
114
209
  enum http_method
115
210
  {
@@ -127,14 +222,16 @@ enum flags
127
222
  { F_CHUNKED = 1 << 0
128
223
  , F_CONNECTION_KEEP_ALIVE = 1 << 1
129
224
  , F_CONNECTION_CLOSE = 1 << 2
130
- , F_TRAILING = 1 << 3
131
- , F_UPGRADE = 1 << 4
132
- , F_SKIPBODY = 1 << 5
225
+ , F_CONNECTION_UPGRADE = 1 << 3
226
+ , F_TRAILING = 1 << 4
227
+ , F_UPGRADE = 1 << 5
228
+ , F_SKIPBODY = 1 << 6
229
+ , F_CONTENTLENGTH = 1 << 7
133
230
  };
134
231
 
135
232
 
136
233
  /* Map for errno-related constants
137
- *
234
+ *
138
235
  * The provided argument should be a macro that takes 2 arguments.
139
236
  */
140
237
  #define HTTP_ERRNO_MAP(XX) \
@@ -143,13 +240,15 @@ enum flags
143
240
  \
144
241
  /* Callback-related errors */ \
145
242
  XX(CB_message_begin, "the on_message_begin callback failed") \
146
- XX(CB_status_complete, "the on_status_complete callback failed") \
147
243
  XX(CB_url, "the on_url callback failed") \
148
244
  XX(CB_header_field, "the on_header_field callback failed") \
149
245
  XX(CB_header_value, "the on_header_value callback failed") \
150
246
  XX(CB_headers_complete, "the on_headers_complete callback failed") \
151
247
  XX(CB_body, "the on_body callback failed") \
152
248
  XX(CB_message_complete, "the on_message_complete callback failed") \
249
+ XX(CB_status, "the on_status callback failed") \
250
+ XX(CB_chunk_header, "the on_chunk_header callback failed") \
251
+ XX(CB_chunk_complete, "the on_chunk_complete callback failed") \
153
252
  \
154
253
  /* Parsing-related errors */ \
155
254
  XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
@@ -170,13 +269,17 @@ enum flags
170
269
  XX(INVALID_HEADER_TOKEN, "invalid character in header") \
171
270
  XX(INVALID_CONTENT_LENGTH, \
172
271
  "invalid character in content-length header") \
272
+ XX(UNEXPECTED_CONTENT_LENGTH, \
273
+ "unexpected content-length header") \
173
274
  XX(INVALID_CHUNK_SIZE, \
174
275
  "invalid character in chunk size header") \
175
276
  XX(INVALID_CONSTANT, "invalid constant string") \
176
277
  XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
177
278
  XX(STRICT, "strict mode assertion failed") \
178
279
  XX(PAUSED, "parser is paused") \
179
- XX(UNKNOWN, "an unknown error occurred")
280
+ XX(UNKNOWN, "an unknown error occurred") \
281
+ XX(INVALID_TRANSFER_ENCODING, \
282
+ "request has invalid transfer-encoding") \
180
283
 
181
284
 
182
285
  /* Define HPE_* values for each errno value above */
@@ -194,13 +297,20 @@ enum http_errno {
194
297
  struct http_parser {
195
298
  /** PRIVATE **/
196
299
  unsigned int type : 2; /* enum http_parser_type */
197
- unsigned int flags : 6; /* F_* values from 'flags' enum; semi-public */
198
- unsigned int state : 8; /* enum state from http_parser.c */
199
- unsigned int header_state : 8; /* enum header_state from http_parser.c */
200
- unsigned int index : 8; /* index into current matcher */
300
+ unsigned int flags : 8; /* F_* values from 'flags' enum; semi-public */
301
+ unsigned int state : 7; /* enum state from http_parser.c */
302
+ unsigned int header_state : 7; /* enum header_state from http_parser.c */
303
+ unsigned int index : 5; /* index into current matcher */
304
+ unsigned int uses_transfer_encoding : 1; /* Transfer-Encoding header is present */
305
+ unsigned int allow_chunked_length : 1; /* Allow headers with both
306
+ * `Content-Length` and
307
+ * `Transfer-Encoding: chunked` set */
308
+ unsigned int lenient_http_headers : 1;
201
309
 
202
310
  uint32_t nread; /* # bytes read in various scenarios */
203
- uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */
311
+ uint64_t content_length; /* # bytes in body. `(uint64_t) -1` (all bits one)
312
+ * if no Content-Length header.
313
+ */
204
314
 
205
315
  /** READ-ONLY **/
206
316
  unsigned short http_major;
@@ -224,12 +334,17 @@ struct http_parser {
224
334
  struct http_parser_settings {
225
335
  http_cb on_message_begin;
226
336
  http_data_cb on_url;
227
- http_cb on_status_complete;
337
+ http_data_cb on_status;
228
338
  http_data_cb on_header_field;
229
339
  http_data_cb on_header_value;
230
340
  http_cb on_headers_complete;
231
341
  http_data_cb on_body;
232
342
  http_cb on_message_complete;
343
+ /* When on_chunk_header is called, the current chunk length is stored
344
+ * in parser->content_length.
345
+ */
346
+ http_cb on_chunk_header;
347
+ http_cb on_chunk_complete;
233
348
  };
234
349
 
235
350
 
@@ -271,13 +386,20 @@ struct http_parser_url {
271
386
  * unsigned major = (version >> 16) & 255;
272
387
  * unsigned minor = (version >> 8) & 255;
273
388
  * unsigned patch = version & 255;
274
- * printf("http_parser v%u.%u.%u\n", major, minor, version);
389
+ * printf("http_parser v%u.%u.%u\n", major, minor, patch);
275
390
  */
276
391
  unsigned long http_parser_version(void);
277
392
 
278
393
  void http_parser_init(http_parser *parser, enum http_parser_type type);
279
394
 
280
395
 
396
+ /* Initialize http_parser_settings members to 0
397
+ */
398
+ void http_parser_settings_init(http_parser_settings *settings);
399
+
400
+
401
+ /* Executes the parser. Returns number of parsed bytes. Sets
402
+ * `parser->http_errno` on error. */
281
403
  size_t http_parser_execute(http_parser *parser,
282
404
  const http_parser_settings *settings,
283
405
  const char *data,
@@ -295,12 +417,18 @@ int http_should_keep_alive(const http_parser *parser);
295
417
  /* Returns a string version of the HTTP method. */
296
418
  const char *http_method_str(enum http_method m);
297
419
 
420
+ /* Returns a string version of the HTTP status code. */
421
+ const char *http_status_str(enum http_status s);
422
+
298
423
  /* Return a string name of the given error */
299
424
  const char *http_errno_name(enum http_errno err);
300
425
 
301
426
  /* Return a string description of the given error */
302
427
  const char *http_errno_description(enum http_errno err);
303
428
 
429
+ /* Initialize all http_parser_url members to 0 */
430
+ void http_parser_url_init(struct http_parser_url *u);
431
+
304
432
  /* Parse a URL; return nonzero on failure */
305
433
  int http_parser_parse_url(const char *buf, size_t buflen,
306
434
  int is_connect,
@@ -312,6 +440,9 @@ void http_parser_pause(http_parser *parser, int paused);
312
440
  /* Checks if this is the final chunk of the body. */
313
441
  int http_body_is_final(const http_parser *parser);
314
442
 
443
+ /* Change the maximum header size provided at compile time. */
444
+ void http_parser_set_max_header_size(uint32_t size);
445
+
315
446
  #ifdef __cplusplus
316
447
  }
317
448
  #endif
@@ -1,4 +1,6 @@
1
+ # frozen_string_literal: true
1
2
  # -*- encoding: utf-8 -*-
3
+
2
4
  $:.push File.expand_path("../lib", __FILE__)
3
5
  require "http-parser/version"
4
6
 
@@ -16,12 +18,12 @@ Gem::Specification.new do |s|
16
18
  EOF
17
19
 
18
20
 
19
- s.add_dependency 'ffi-compiler', '>= 0.0.2'
20
- s.add_dependency 'rake'
21
+ s.add_dependency 'ffi-compiler'
22
+
23
+ s.add_development_dependency 'rake', '~> 11.2'
24
+ s.add_development_dependency 'rspec', '~> 3.5'
25
+ s.add_development_dependency 'yard', '~> 0.9'
21
26
 
22
- s.add_development_dependency 'rspec'
23
- s.add_development_dependency 'yard'
24
-
25
27
 
26
28
  s.files = Dir["{lib}/**/*"] + %w(Rakefile http-parser.gemspec README.md LICENSE)
27
29
  s.files += ["ext/http-parser/http_parser.c", "ext/http-parser/http_parser.h"]
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "ffi" # Bindings to C libraries
2
4
 
3
5
  require "http-parser/ext" # Loads http-parser ext
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
 
2
3
  module HttpParser
3
4
  class Error < StandardError
@@ -36,13 +37,15 @@ module HttpParser
36
37
  :OK => Error::OK,
37
38
 
38
39
  :CB_message_begin => Error::CALLBACK,
39
- :CB_status_complete => Error::CALLBACK,
40
40
  :CB_url => Error::CALLBACK,
41
41
  :CB_header_field => Error::CALLBACK,
42
42
  :CB_header_value => Error::CALLBACK,
43
43
  :CB_headers_complete => Error::CALLBACK,
44
44
  :CB_body => Error::CALLBACK,
45
45
  :CB_message_complete => Error::CALLBACK,
46
+ :CB_status => Error::CALLBACK,
47
+ :CB_chunk_header => Error::CALLBACK,
48
+ :CB_chunk_complete => Error::CALLBACK,
46
49
 
47
50
  :INVALID_EOF_STATE => Error::INVALID_EOF_STATE,
48
51
  :HEADER_OVERFLOW => Error::HEADER_OVERFLOW,
@@ -68,7 +71,7 @@ module HttpParser
68
71
  :UNKNOWN => Error::UNKNOWN
69
72
  }
70
73
 
71
- attach_function :err_desc, :http_errno_description, [:int], :string, :blocking => true
72
- attach_function :err_name, :http_errno_name, [:int], :string, :blocking => true
74
+ attach_function :err_desc, :http_errno_description, [:int], :string
75
+ attach_function :err_name, :http_errno_name, [:int], :string
73
76
  end
74
77
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'ffi'
2
4
  require 'ffi-compiler/loader'
3
5
 
@@ -1,13 +1,17 @@
1
+ # frozen_string_literal: true
1
2
 
2
3
  module HttpParser
3
4
  class Parser
4
- CALLBACKS = [:on_message_begin, :on_url, :on_status_complete, :on_header_field, :on_header_value, :on_headers_complete, :on_body, :on_message_complete]
5
+ CALLBACKS = [
6
+ :on_message_begin, :on_url, :on_status, :on_header_field, :on_header_value,
7
+ :on_headers_complete, :on_body, :on_message_complete, :on_chunk_header, :on_chunk_complete
8
+ ]
5
9
 
6
10
  #
7
11
  # Returns a new request/response instance variable
8
12
  #
9
- def self.new_instance &block
10
- ::HttpParser::Instance.new &block
13
+ def self.new_instance(&block)
14
+ ::HttpParser::Instance.new(&block)
11
15
  end
12
16
 
13
17
 
@@ -72,10 +76,10 @@ module HttpParser
72
76
  # @yieldparam [HttpParser::Instance] instance
73
77
  # The state so far of the request / response being processed.
74
78
  #
75
- def on_status_complete(&block)
76
- cb = Callback.new(&block)
77
- @callbacks[:on_status_complete] = cb
78
- @settings[:on_status_complete] = cb
79
+ def on_status(&block)
80
+ cb = DataCallback.new(&block)
81
+ @callbacks[:on_status] = cb
82
+ @settings[:on_status] = cb
79
83
  end
80
84
 
81
85
  #
@@ -172,6 +176,36 @@ module HttpParser
172
176
  @settings[:on_message_complete] = cb
173
177
  end
174
178
 
179
+ #
180
+ # Registers an `on_chunk_header` callback.
181
+ #
182
+ # @yield [instance]
183
+ # The given block will be called when a new chunk header is received.
184
+ #
185
+ # @yieldparam [HttpParser::Instance] instance
186
+ # The state so far of the request / response being processed.
187
+ #
188
+ def on_chunk_header(&block)
189
+ cb = Callback.new(&block)
190
+ @callbacks[:on_message_complete] = cb
191
+ @settings[:on_message_complete] = cb
192
+ end
193
+
194
+ #
195
+ # Registers an `on_chunk_complete` callback.
196
+ #
197
+ # @yield [instance]
198
+ # The given block will be called when the current chunk completes.
199
+ #
200
+ # @yieldparam [HttpParser::Instance] instance
201
+ # The state so far of the request / response being processed.
202
+ #
203
+ def on_chunk_complete(&block)
204
+ cb = Callback.new(&block)
205
+ @callbacks[:on_message_complete] = cb
206
+ @settings[:on_message_complete] = cb
207
+ end
208
+
175
209
  #
176
210
  # Parses data.
177
211
  #