http-parser 1.0.4 → 1.2.3

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 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