http-parser 1.0.4 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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 2
30
- #define HTTP_PARSER_VERSION_PATCH 0
29
+ #define HTTP_PARSER_VERSION_MINOR 8
30
+ #define HTTP_PARSER_VERSION_PATCH 1
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;
@@ -52,9 +52,16 @@ typedef unsigned __int64 uint64_t;
52
52
  # define HTTP_PARSER_STRICT 1
53
53
  #endif
54
54
 
55
- /* Maximium header size allowed */
56
- #define HTTP_MAX_HEADER_SIZE (80*1024)
57
-
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
58
65
 
59
66
  typedef struct http_parser http_parser;
60
67
  typedef struct http_parser_settings http_parser_settings;
@@ -69,7 +76,12 @@ typedef struct http_parser_settings http_parser_settings;
69
76
  * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding:
70
77
  * chunked' headers that indicate the presence of a body.
71
78
  *
72
- * http_data_cb does not return data chunks. It will be call arbitrarally
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
73
85
  * many times for each string. E.G. you might get 10 callbacks for "on_url"
74
86
  * each providing just a few characters more data.
75
87
  */
@@ -77,6 +89,76 @@ typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
77
89
  typedef int (*http_cb) (http_parser*);
78
90
 
79
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
+
80
162
  /* Request Methods */
81
163
  #define HTTP_METHOD_MAP(XX) \
82
164
  XX(0, DELETE, DELETE) \
@@ -88,7 +170,7 @@ typedef int (*http_cb) (http_parser*);
88
170
  XX(5, CONNECT, CONNECT) \
89
171
  XX(6, OPTIONS, OPTIONS) \
90
172
  XX(7, TRACE, TRACE) \
91
- /* webdav */ \
173
+ /* WebDAV */ \
92
174
  XX(8, COPY, COPY) \
93
175
  XX(9, LOCK, LOCK) \
94
176
  XX(10, MKCOL, MKCOL) \
@@ -97,19 +179,30 @@ typedef int (*http_cb) (http_parser*);
97
179
  XX(13, PROPPATCH, PROPPATCH) \
98
180
  XX(14, SEARCH, SEARCH) \
99
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) \
100
186
  /* subversion */ \
101
- XX(16, REPORT, REPORT) \
102
- XX(17, MKACTIVITY, MKACTIVITY) \
103
- XX(18, CHECKOUT, CHECKOUT) \
104
- XX(19, MERGE, MERGE) \
187
+ XX(20, REPORT, REPORT) \
188
+ XX(21, MKACTIVITY, MKACTIVITY) \
189
+ XX(22, CHECKOUT, CHECKOUT) \
190
+ XX(23, MERGE, MERGE) \
105
191
  /* upnp */ \
106
- XX(20, MSEARCH, M-SEARCH) \
107
- XX(21, NOTIFY, NOTIFY) \
108
- XX(22, SUBSCRIBE, SUBSCRIBE) \
109
- XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \
192
+ XX(24, MSEARCH, M-SEARCH) \
193
+ XX(25, NOTIFY, NOTIFY) \
194
+ XX(26, SUBSCRIBE, SUBSCRIBE) \
195
+ XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \
110
196
  /* RFC-5789 */ \
111
- XX(24, PATCH, PATCH) \
112
- XX(25, PURGE, PURGE) \
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) \
113
206
 
114
207
  enum http_method
115
208
  {
@@ -127,14 +220,16 @@ enum flags
127
220
  { F_CHUNKED = 1 << 0
128
221
  , F_CONNECTION_KEEP_ALIVE = 1 << 1
129
222
  , F_CONNECTION_CLOSE = 1 << 2
130
- , F_TRAILING = 1 << 3
131
- , F_UPGRADE = 1 << 4
132
- , F_SKIPBODY = 1 << 5
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
133
228
  };
134
229
 
135
230
 
136
231
  /* Map for errno-related constants
137
- *
232
+ *
138
233
  * The provided argument should be a macro that takes 2 arguments.
139
234
  */
140
235
  #define HTTP_ERRNO_MAP(XX) \
@@ -150,6 +245,8 @@ enum flags
150
245
  XX(CB_body, "the on_body callback failed") \
151
246
  XX(CB_message_complete, "the on_message_complete callback failed") \
152
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") \
153
250
  \
154
251
  /* Parsing-related errors */ \
155
252
  XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
@@ -170,6 +267,8 @@ enum flags
170
267
  XX(INVALID_HEADER_TOKEN, "invalid character in header") \
171
268
  XX(INVALID_CONTENT_LENGTH, \
172
269
  "invalid character in content-length header") \
270
+ XX(UNEXPECTED_CONTENT_LENGTH, \
271
+ "unexpected content-length header") \
173
272
  XX(INVALID_CHUNK_SIZE, \
174
273
  "invalid character in chunk size header") \
175
274
  XX(INVALID_CONSTANT, "invalid constant string") \
@@ -194,10 +293,11 @@ enum http_errno {
194
293
  struct http_parser {
195
294
  /** PRIVATE **/
196
295
  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 */
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;
201
301
 
202
302
  uint32_t nread; /* # bytes read in various scenarios */
203
303
  uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */
@@ -230,6 +330,11 @@ struct http_parser_settings {
230
330
  http_cb on_headers_complete;
231
331
  http_data_cb on_body;
232
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;
233
338
  };
234
339
 
235
340
 
@@ -271,13 +376,20 @@ struct http_parser_url {
271
376
  * unsigned major = (version >> 16) & 255;
272
377
  * unsigned minor = (version >> 8) & 255;
273
378
  * unsigned patch = version & 255;
274
- * printf("http_parser v%u.%u.%u\n", major, minor, version);
379
+ * printf("http_parser v%u.%u.%u\n", major, minor, patch);
275
380
  */
276
381
  unsigned long http_parser_version(void);
277
382
 
278
383
  void http_parser_init(http_parser *parser, enum http_parser_type type);
279
384
 
280
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. */
281
393
  size_t http_parser_execute(http_parser *parser,
282
394
  const http_parser_settings *settings,
283
395
  const char *data,
@@ -295,12 +407,18 @@ int http_should_keep_alive(const http_parser *parser);
295
407
  /* Returns a string version of the HTTP method. */
296
408
  const char *http_method_str(enum http_method m);
297
409
 
410
+ /* Returns a string version of the HTTP status code. */
411
+ const char *http_status_str(enum http_status s);
412
+
298
413
  /* Return a string name of the given error */
299
414
  const char *http_errno_name(enum http_errno err);
300
415
 
301
416
  /* Return a string description of the given error */
302
417
  const char *http_errno_description(enum http_errno err);
303
418
 
419
+ /* Initialize all http_parser_url members to 0 */
420
+ void http_parser_url_init(struct http_parser_url *u);
421
+
304
422
  /* Parse a URL; return nonzero on failure */
305
423
  int http_parser_parse_url(const char *buf, size_t buflen,
306
424
  int is_connect,
@@ -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,11 +18,11 @@ 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', '>= 1.0', '< 2.0'
21
22
 
22
- s.add_development_dependency 'rspec'
23
- s.add_development_dependency 'yard'
23
+ s.add_development_dependency 'rake', '~> 11.2'
24
+ s.add_development_dependency 'rspec', '~> 3.5'
25
+ s.add_development_dependency 'yard', '~> 0.9'
24
26
 
25
27
 
26
28
  s.files = Dir["{lib}/**/*"] + %w(Rakefile http-parser.gemspec README.md LICENSE)
@@ -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
@@ -43,6 +44,8 @@ module HttpParser
43
44
  :CB_body => Error::CALLBACK,
44
45
  :CB_message_complete => Error::CALLBACK,
45
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, :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
 
@@ -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
  #
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
 
2
3
  module HttpParser
3
4
  HTTP_MAX_HEADER_SIZE = (80 * 1024)
@@ -14,9 +15,10 @@ module HttpParser
14
15
  :CHUNKED => 1 << 2,
15
16
  :CONNECTION_KEEP_ALIVE => 1 << 3,
16
17
  :CONNECTION_CLOSE => 1 << 4,
17
- :TRAILING => 1 << 5,
18
- :UPGRADE => 1 << 6,
19
- :SKIPBODY => 1 << 7
18
+ :CONNECTION_UPGRADE => 1 << 5,
19
+ :TRAILING => 1 << 6,
20
+ :UPGRADE => 1 << 7,
21
+ :SKIPBODY => 1 << 8
20
22
  }
21
23
 
22
24
  #
@@ -41,6 +43,10 @@ module HttpParser
41
43
  :PROPPATCH,
42
44
  :SEARCH,
43
45
  :UNLOCK,
46
+ :BIND,
47
+ :REBIND,
48
+ :UNBIND,
49
+ :ACL,
44
50
  # subversion
45
51
  :REPORT,
46
52
  :MKACTIVITY,
@@ -53,7 +59,12 @@ module HttpParser
53
59
  :UNSUBSCRIBE,
54
60
  # RFC-5789
55
61
  :PATCH,
56
- :PURGE
62
+ :PURGE,
63
+ # CalDAV
64
+ :MKCALENDAR,
65
+ # RFC-2068, section 19.6.1.2
66
+ :LINK,
67
+ :UNLINK
57
68
  ]
58
69
 
59
70
 
@@ -79,7 +90,7 @@ module HttpParser
79
90
  :index, :uchar,
80
91
 
81
92
  :nread, :uint32,
82
- :content_length, :int64,
93
+ :content_length, :uint64,
83
94
 
84
95
  # READ-ONLY
85
96
  :http_major, :ushort,
@@ -260,6 +271,16 @@ module HttpParser
260
271
  ::HttpParser.http_should_keep_alive(self) > 0
261
272
  end
262
273
 
274
+ #
275
+ # Determines if a chunked response has completed
276
+ #
277
+ # @return [Boolean]
278
+ # Specifies whether the chunked response has completed
279
+ #
280
+ def final_chunk?
281
+ ::HttpParser.http_body_is_final(self) > 0
282
+ end
283
+
263
284
  #
264
285
  # Halts the parser if called in a callback
265
286
  #
@@ -299,13 +320,16 @@ module HttpParser
299
320
  :on_header_value, :http_data_cb,
300
321
  :on_headers_complete, :http_cb,
301
322
  :on_body, :http_data_cb,
302
- :on_message_complete, :http_cb
323
+ :on_message_complete, :http_cb,
324
+ :on_chunk_header, :http_cb,
325
+ :on_chunk_complete, :http_cb
303
326
  end
304
327
 
305
328
 
306
- attach_function :http_parser_init, [Instance.by_ref, :http_parser_type], :void, :blocking => true
307
- attach_function :http_parser_execute, [Instance.by_ref, Settings.by_ref, :pointer, :size_t], :size_t, :blocking => true
329
+ attach_function :http_parser_init, [Instance.by_ref, :http_parser_type], :void
330
+ attach_function :http_parser_execute, [Instance.by_ref, Settings.by_ref, :pointer, :size_t], :size_t
331
+ attach_function :http_should_keep_alive, [Instance.by_ref], :int
308
332
 
309
- attach_function :http_should_keep_alive, [Instance.by_ref], :int, :blocking => true
310
- attach_function :http_method_str, [:http_method], :string, :blocking => true
333
+ # Checks if this is the final chunk of the body
334
+ attach_function :http_body_is_final, [Instance.by_ref], :int
311
335
  end