http_parser.rb 0.5.1 → 0.6.0.beta.1

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.
Files changed (70) hide show
  1. data/.gitmodules +4 -4
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +11 -4
  4. data/LICENSE-MIT +20 -0
  5. data/README.md +51 -46
  6. data/bench/standalone.rb +23 -0
  7. data/bench/thin.rb +1 -0
  8. data/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java +121 -56
  9. data/ext/ruby_http_parser/ruby_http_parser.c +89 -48
  10. data/ext/ruby_http_parser/vendor/http-parser/AUTHORS +32 -0
  11. data/ext/ruby_http_parser/vendor/http-parser/LICENSE-MIT +5 -1
  12. data/ext/ruby_http_parser/vendor/http-parser/Makefile +34 -17
  13. data/ext/ruby_http_parser/vendor/http-parser/README.md +9 -2
  14. data/ext/ruby_http_parser/vendor/http-parser/http_parser.c +1045 -589
  15. data/ext/ruby_http_parser/vendor/http-parser/http_parser.gyp +79 -0
  16. data/ext/ruby_http_parser/vendor/http-parser/http_parser.h +148 -17
  17. data/ext/ruby_http_parser/vendor/http-parser/test.c +1138 -128
  18. data/ext/ruby_http_parser/vendor/http-parser-java/AUTHORS +32 -0
  19. data/ext/ruby_http_parser/vendor/http-parser-java/LICENSE-MIT +30 -1
  20. data/ext/ruby_http_parser/vendor/http-parser-java/Makefile +34 -17
  21. data/ext/ruby_http_parser/vendor/http-parser-java/README.md +30 -18
  22. data/ext/ruby_http_parser/vendor/http-parser-java/TODO +9 -0
  23. data/ext/ruby_http_parser/vendor/http-parser-java/build.xml +74 -0
  24. data/ext/ruby_http_parser/vendor/http-parser-java/ext/primitives.jar +0 -0
  25. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.c +1075 -607
  26. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.gyp +79 -0
  27. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.h +190 -40
  28. data/ext/ruby_http_parser/vendor/http-parser-java/src/Http-parser.java.iml +22 -0
  29. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/FieldData.java +41 -0
  30. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPCallback.java +8 -0
  31. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPDataCallback.java +34 -0
  32. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPErrorCallback.java +12 -0
  33. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPException.java +4 -2
  34. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPHeadersCompleteCallback.java +13 -0
  35. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPMethod.java +67 -52
  36. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParser.java +5 -0
  37. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParserUrl.java +76 -0
  38. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserSettings.java +323 -0
  39. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/{lolevel/Util.java → Util.java} +34 -35
  40. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPHeadersCompleteCallback.java +12 -0
  41. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java +839 -587
  42. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java +2 -1
  43. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Message.java +374 -0
  44. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/ParseUrl.java +51 -0
  45. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Requests.java +69 -0
  46. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Responses.java +52 -0
  47. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Test.java +16 -0
  48. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestHeaderOverflowError.java +48 -0
  49. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestLoaderNG.java +171 -446
  50. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestNoOverflowLongBody.java +62 -0
  51. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/UnitTest.java +3 -1
  52. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Upgrade.java +27 -0
  53. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Url.java +127 -0
  54. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Util.java +236 -0
  55. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/WrongContentLength.java +59 -0
  56. data/ext/ruby_http_parser/vendor/http-parser-java/test.c +1318 -184
  57. data/ext/ruby_http_parser/vendor/http-parser-java/tests.dumped +355 -49
  58. data/ext/ruby_http_parser/vendor/http-parser-java/tests.utf8 +17 -0
  59. data/http_parser.rb.gemspec +10 -2
  60. data/lib/http_parser.rb +17 -0
  61. data/spec/parser_spec.rb +157 -23
  62. data/spec/support/requests.json +236 -24
  63. data/spec/support/responses.json +182 -36
  64. data/tasks/compile.rake +5 -3
  65. data/tasks/fixtures.rake +8 -2
  66. metadata +209 -127
  67. data/ext/ruby_http_parser/vendor/http-parser-java/CONTRIBUTIONS +0 -4
  68. data/ext/ruby_http_parser/vendor/http-parser-java/compile +0 -1
  69. data/ext/ruby_http_parser/vendor/http-parser-java/test_permutations +0 -1
  70. data/ext/ruby_http_parser/vendor/http-parser-java/test_unit +0 -1
@@ -1,4 +1,7 @@
1
- /* Copyright 2009,2010 Ryan Dahl <ry@tinyclouds.org>
1
+ /* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev
2
+ *
3
+ * Additional changes are licensed under the same terms as NGINX and
4
+ * copyright Joyent, Inc. and other Node contributors. All rights reserved.
2
5
  *
3
6
  * Permission is hereby granted, free of charge, to any person obtaining a copy
4
7
  * of this software and associated documentation files (the "Software"), to
@@ -18,48 +21,94 @@
18
21
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19
22
  * IN THE SOFTWARE.
20
23
  */
21
- #include <http_parser.h>
24
+ #include "http_parser.h"
22
25
  #include <assert.h>
23
26
  #include <stddef.h>
27
+ #include <ctype.h>
28
+ #include <stdlib.h>
29
+ #include <string.h>
30
+ #include <limits.h>
24
31
 
32
+ #ifndef ULLONG_MAX
33
+ # define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */
34
+ #endif
25
35
 
26
36
  #ifndef MIN
27
37
  # define MIN(a,b) ((a) < (b) ? (a) : (b))
28
38
  #endif
29
39
 
30
40
 
31
- #define CALLBACK2(FOR) \
41
+ #if HTTP_PARSER_DEBUG
42
+ #define SET_ERRNO(e) \
32
43
  do { \
33
- if (settings->on_##FOR) { \
34
- if (0 != settings->on_##FOR(parser)) return (p - data); \
35
- } \
44
+ parser->http_errno = (e); \
45
+ parser->error_lineno = __LINE__; \
36
46
  } while (0)
47
+ #else
48
+ #define SET_ERRNO(e) \
49
+ do { \
50
+ parser->http_errno = (e); \
51
+ } while(0)
52
+ #endif
37
53
 
38
54
 
39
- #define MARK(FOR) \
55
+ /* Run the notify callback FOR, returning ER if it fails */
56
+ #define CALLBACK_NOTIFY_(FOR, ER) \
40
57
  do { \
41
- FOR##_mark = p; \
58
+ assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \
59
+ \
60
+ if (settings->on_##FOR) { \
61
+ if (0 != settings->on_##FOR(parser)) { \
62
+ SET_ERRNO(HPE_CB_##FOR); \
63
+ } \
64
+ \
65
+ /* We either errored above or got paused; get out */ \
66
+ if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \
67
+ return (ER); \
68
+ } \
69
+ } \
42
70
  } while (0)
43
71
 
44
- #define CALLBACK_NOCLEAR(FOR) \
72
+ /* Run the notify callback FOR and consume the current byte */
73
+ #define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1)
74
+
75
+ /* Run the notify callback FOR and don't consume the current byte */
76
+ #define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data)
77
+
78
+ /* Run data callback FOR with LEN bytes, returning ER if it fails */
79
+ #define CALLBACK_DATA_(FOR, LEN, ER) \
45
80
  do { \
81
+ assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \
82
+ \
46
83
  if (FOR##_mark) { \
47
84
  if (settings->on_##FOR) { \
48
- if (0 != settings->on_##FOR(parser, \
49
- FOR##_mark, \
50
- p - FOR##_mark)) \
51
- { \
52
- return (p - data); \
85
+ if (0 != settings->on_##FOR(parser, FOR##_mark, (LEN))) { \
86
+ SET_ERRNO(HPE_CB_##FOR); \
87
+ } \
88
+ \
89
+ /* We either errored above or got paused; get out */ \
90
+ if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \
91
+ return (ER); \
53
92
  } \
54
93
  } \
94
+ FOR##_mark = NULL; \
55
95
  } \
56
96
  } while (0)
97
+
98
+ /* Run the data callback FOR and consume the current byte */
99
+ #define CALLBACK_DATA(FOR) \
100
+ CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1)
57
101
 
102
+ /* Run the data callback FOR and don't consume the current byte */
103
+ #define CALLBACK_DATA_NOADVANCE(FOR) \
104
+ CALLBACK_DATA_(FOR, p - FOR##_mark, p - data)
58
105
 
59
- #define CALLBACK(FOR) \
106
+ /* Set the mark FOR; non-destructive if mark is already set */
107
+ #define MARK(FOR) \
60
108
  do { \
61
- CALLBACK_NOCLEAR(FOR); \
62
- FOR##_mark = NULL; \
109
+ if (!FOR##_mark) { \
110
+ FOR##_mark = p; \
111
+ } \
63
112
  } while (0)
64
113
 
65
114
 
@@ -97,6 +146,8 @@ static const char *method_strings[] =
97
146
  , "NOTIFY"
98
147
  , "SUBSCRIBE"
99
148
  , "UNSUBSCRIBE"
149
+ , "PATCH"
150
+ , "PURGE"
100
151
  };
101
152
 
102
153
 
@@ -117,9 +168,9 @@ static const char tokens[256] = {
117
168
  /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
118
169
  0, 0, 0, 0, 0, 0, 0, 0,
119
170
  /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
120
- ' ', '!', '"', '#', '$', '%', '&', '\'',
171
+ 0, '!', 0, '#', '$', '%', '&', '\'',
121
172
  /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
122
- 0, 0, '*', '+', 0, '-', '.', '/',
173
+ 0, 0, '*', '+', 0, '-', '.', 0,
123
174
  /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
124
175
  '0', '1', '2', '3', '4', '5', '6', '7',
125
176
  /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
@@ -139,7 +190,7 @@ static const char tokens[256] = {
139
190
  /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
140
191
  'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
141
192
  /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
142
- 'x', 'y', 'z', 0, '|', '}', '~', 0 };
193
+ 'x', 'y', 'z', 0, '|', 0, '~', 0 };
143
194
 
144
195
 
145
196
  static const int8_t unhex[256] =
@@ -186,7 +237,7 @@ static const uint8_t normal_url_char[256] = {
186
237
  /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
187
238
  1, 1, 1, 1, 1, 1, 1, 1,
188
239
  /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
189
- 1, 1, 1, 1, 1, 1, 1, 0 };
240
+ 1, 1, 1, 1, 1, 1, 1, 0, };
190
241
 
191
242
 
192
243
  enum state
@@ -215,7 +266,12 @@ enum state
215
266
  , s_req_schema
216
267
  , s_req_schema_slash
217
268
  , s_req_schema_slash_slash
269
+ , s_req_host_start
270
+ , s_req_host_v6_start
271
+ , s_req_host_v6
272
+ , s_req_host_v6_end
218
273
  , s_req_host
274
+ , s_req_port_start
219
275
  , s_req_port
220
276
  , s_req_path
221
277
  , s_req_query_string_start
@@ -237,28 +293,35 @@ enum state
237
293
  , s_header_field
238
294
  , s_header_value_start
239
295
  , s_header_value
296
+ , s_header_value_lws
240
297
 
241
298
  , s_header_almost_done
242
299
 
300
+ , s_chunk_size_start
301
+ , s_chunk_size
302
+ , s_chunk_parameters
303
+ , s_chunk_size_almost_done
304
+
243
305
  , s_headers_almost_done
244
- /* Important: 's_headers_almost_done' must be the last 'header' state. All
306
+ , s_headers_done
307
+
308
+ /* Important: 's_headers_done' must be the last 'header' state. All
245
309
  * states beyond this must be 'body' states. It is used for overflow
246
310
  * checking. See the PARSING_HEADER() macro.
247
311
  */
248
- , s_chunk_size_start
249
- , s_chunk_size
250
- , s_chunk_size_almost_done
251
- , s_chunk_parameters
312
+
252
313
  , s_chunk_data
253
314
  , s_chunk_data_almost_done
254
315
  , s_chunk_data_done
255
316
 
256
317
  , s_body_identity
257
318
  , s_body_identity_eof
319
+
320
+ , s_message_done
258
321
  };
259
322
 
260
323
 
261
- #define PARSING_HEADER(state) (state <= s_headers_almost_done && 0 == (parser->flags & F_TRAILING))
324
+ #define PARSING_HEADER(state) (state <= s_headers_done)
262
325
 
263
326
 
264
327
  enum header_states
@@ -288,27 +351,39 @@ enum header_states
288
351
  };
289
352
 
290
353
 
291
- enum flags
292
- { F_CHUNKED = 1 << 0
293
- , F_CONNECTION_KEEP_ALIVE = 1 << 1
294
- , F_CONNECTION_CLOSE = 1 << 2
295
- , F_TRAILING = 1 << 3
296
- , F_UPGRADE = 1 << 4
297
- , F_SKIPBODY = 1 << 5
298
- };
299
-
354
+ /* Macros for character classes; depends on strict-mode */
355
+ #define CR '\r'
356
+ #define LF '\n'
357
+ #define LOWER(c) (unsigned char)(c | 0x20)
358
+ #define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z')
359
+ #define IS_NUM(c) ((c) >= '0' && (c) <= '9')
360
+ #define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c))
361
+ #define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f'))
300
362
 
301
- #define CR '\r'
302
- #define LF '\n'
303
- #define LOWER(c) (unsigned char)(c | 0x20)
304
- #define TOKEN(c) tokens[(unsigned char)c]
363
+ #if HTTP_PARSER_STRICT
364
+ #define TOKEN(c) (tokens[(unsigned char)c])
365
+ #define IS_URL_CHAR(c) (normal_url_char[(unsigned char) (c)])
366
+ #define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
367
+ #else
368
+ #define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c])
369
+ #define IS_URL_CHAR(c) \
370
+ (normal_url_char[(unsigned char) (c)] || ((c) & 0x80))
371
+ #define IS_HOST_CHAR(c) \
372
+ (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')
373
+ #endif
305
374
 
306
375
 
307
376
  #define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res)
308
377
 
309
378
 
310
379
  #if HTTP_PARSER_STRICT
311
- # define STRICT_CHECK(cond) if (cond) goto error
380
+ # define STRICT_CHECK(cond) \
381
+ do { \
382
+ if (cond) { \
383
+ SET_ERRNO(HPE_STRICT); \
384
+ goto error; \
385
+ } \
386
+ } while (0)
312
387
  # define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead)
313
388
  #else
314
389
  # define STRICT_CHECK(cond)
@@ -316,69 +391,290 @@ enum flags
316
391
  #endif
317
392
 
318
393
 
394
+ /* Map errno values to strings for human-readable output */
395
+ #define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s },
396
+ static struct {
397
+ const char *name;
398
+ const char *description;
399
+ } http_strerror_tab[] = {
400
+ HTTP_ERRNO_MAP(HTTP_STRERROR_GEN)
401
+ };
402
+ #undef HTTP_STRERROR_GEN
403
+
404
+ int http_message_needs_eof(http_parser *parser);
405
+
406
+ /* Our URL parser.
407
+ *
408
+ * This is designed to be shared by http_parser_execute() for URL validation,
409
+ * hence it has a state transition + byte-for-byte interface. In addition, it
410
+ * is meant to be embedded in http_parser_parse_url(), which does the dirty
411
+ * work of turning state transitions URL components for its API.
412
+ *
413
+ * This function should only be invoked with non-space characters. It is
414
+ * assumed that the caller cares about (and can detect) the transition between
415
+ * URL and non-URL states by looking for these.
416
+ */
417
+ static enum state
418
+ parse_url_char(enum state s, const char ch)
419
+ {
420
+ assert(!isspace(ch));
421
+
422
+ switch (s) {
423
+ case s_req_spaces_before_url:
424
+ /* Proxied requests are followed by scheme of an absolute URI (alpha).
425
+ * All methods except CONNECT are followed by '/' or '*'.
426
+ */
427
+
428
+ if (ch == '/' || ch == '*') {
429
+ return s_req_path;
430
+ }
431
+
432
+ if (IS_ALPHA(ch)) {
433
+ return s_req_schema;
434
+ }
435
+
436
+ break;
437
+
438
+ case s_req_schema:
439
+ if (IS_ALPHA(ch)) {
440
+ return s;
441
+ }
442
+
443
+ if (ch == ':') {
444
+ return s_req_schema_slash;
445
+ }
446
+
447
+ break;
448
+
449
+ case s_req_schema_slash:
450
+ if (ch == '/') {
451
+ return s_req_schema_slash_slash;
452
+ }
453
+
454
+ break;
455
+
456
+ case s_req_schema_slash_slash:
457
+ if (ch == '/') {
458
+ return s_req_host_start;
459
+ }
460
+
461
+ break;
462
+
463
+ case s_req_host_start:
464
+ if (ch == '[') {
465
+ return s_req_host_v6_start;
466
+ }
467
+
468
+ if (IS_HOST_CHAR(ch)) {
469
+ return s_req_host;
470
+ }
471
+
472
+ break;
473
+
474
+ case s_req_host:
475
+ if (IS_HOST_CHAR(ch)) {
476
+ return s_req_host;
477
+ }
478
+
479
+ /* FALLTHROUGH */
480
+ case s_req_host_v6_end:
481
+ switch (ch) {
482
+ case ':':
483
+ return s_req_port_start;
484
+
485
+ case '/':
486
+ return s_req_path;
487
+
488
+ case '?':
489
+ return s_req_query_string_start;
490
+ }
491
+
492
+ break;
493
+
494
+ case s_req_host_v6:
495
+ if (ch == ']') {
496
+ return s_req_host_v6_end;
497
+ }
498
+
499
+ /* FALLTHROUGH */
500
+ case s_req_host_v6_start:
501
+ if (IS_HEX(ch) || ch == ':') {
502
+ return s_req_host_v6;
503
+ }
504
+ break;
505
+
506
+ case s_req_port:
507
+ switch (ch) {
508
+ case '/':
509
+ return s_req_path;
510
+
511
+ case '?':
512
+ return s_req_query_string_start;
513
+ }
514
+
515
+ /* FALLTHROUGH */
516
+ case s_req_port_start:
517
+ if (IS_NUM(ch)) {
518
+ return s_req_port;
519
+ }
520
+
521
+ break;
522
+
523
+ case s_req_path:
524
+ if (IS_URL_CHAR(ch)) {
525
+ return s;
526
+ }
527
+
528
+ switch (ch) {
529
+ case '?':
530
+ return s_req_query_string_start;
531
+
532
+ case '#':
533
+ return s_req_fragment_start;
534
+ }
535
+
536
+ break;
537
+
538
+ case s_req_query_string_start:
539
+ case s_req_query_string:
540
+ if (IS_URL_CHAR(ch)) {
541
+ return s_req_query_string;
542
+ }
543
+
544
+ switch (ch) {
545
+ case '?':
546
+ /* allow extra '?' in query string */
547
+ return s_req_query_string;
548
+
549
+ case '#':
550
+ return s_req_fragment_start;
551
+ }
552
+
553
+ break;
554
+
555
+ case s_req_fragment_start:
556
+ if (IS_URL_CHAR(ch)) {
557
+ return s_req_fragment;
558
+ }
559
+
560
+ switch (ch) {
561
+ case '?':
562
+ return s_req_fragment;
563
+
564
+ case '#':
565
+ return s;
566
+ }
567
+
568
+ break;
569
+
570
+ case s_req_fragment:
571
+ if (IS_URL_CHAR(ch)) {
572
+ return s;
573
+ }
574
+
575
+ switch (ch) {
576
+ case '?':
577
+ case '#':
578
+ return s;
579
+ }
580
+
581
+ break;
582
+
583
+ default:
584
+ break;
585
+ }
586
+
587
+ /* We should never fall out of the switch above unless there's an error */
588
+ return s_dead;
589
+ }
590
+
319
591
  size_t http_parser_execute (http_parser *parser,
320
592
  const http_parser_settings *settings,
321
593
  const char *data,
322
594
  size_t len)
323
595
  {
324
596
  char c, ch;
325
- const char *p = data, *pe;
326
- int64_t to_read;
597
+ int8_t unhex_val;
598
+ const char *p = data;
599
+ const char *header_field_mark = 0;
600
+ const char *header_value_mark = 0;
601
+ const char *url_mark = 0;
602
+ const char *body_mark = 0;
327
603
 
328
- enum state state = (enum state) parser->state;
329
- enum header_states header_state = (enum header_states) parser->header_state;
330
- uint64_t index = parser->index;
331
- uint64_t nread = parser->nread;
604
+ /* We're in an error state. Don't bother doing anything. */
605
+ if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
606
+ return 0;
607
+ }
332
608
 
333
609
  if (len == 0) {
334
- if (state == s_body_identity_eof) {
335
- CALLBACK2(message_complete);
610
+ switch (parser->state) {
611
+ case s_body_identity_eof:
612
+ /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if
613
+ * we got paused.
614
+ */
615
+ CALLBACK_NOTIFY_NOADVANCE(message_complete);
616
+ return 0;
617
+
618
+ case s_dead:
619
+ case s_start_req_or_res:
620
+ case s_start_res:
621
+ case s_start_req:
622
+ return 0;
623
+
624
+ default:
625
+ SET_ERRNO(HPE_INVALID_EOF_STATE);
626
+ return 1;
336
627
  }
337
- return 0;
338
628
  }
339
629
 
340
- /* technically we could combine all of these (except for url_mark) into one
341
- variable, saving stack space, but it seems more clear to have them
342
- separated. */
343
- const char *header_field_mark = 0;
344
- const char *header_value_mark = 0;
345
- const char *fragment_mark = 0;
346
- const char *query_string_mark = 0;
347
- const char *path_mark = 0;
348
- const char *url_mark = 0;
349
630
 
350
- if (state == s_header_field)
631
+ if (parser->state == s_header_field)
351
632
  header_field_mark = data;
352
- if (state == s_header_value)
633
+ if (parser->state == s_header_value)
353
634
  header_value_mark = data;
354
- if (state == s_req_fragment)
355
- fragment_mark = data;
356
- if (state == s_req_query_string)
357
- query_string_mark = data;
358
- if (state == s_req_path)
359
- path_mark = data;
360
- if (state == s_req_path || state == s_req_schema || state == s_req_schema_slash
361
- || state == s_req_schema_slash_slash || state == s_req_port
362
- || state == s_req_query_string_start || state == s_req_query_string
363
- || state == s_req_host
364
- || state == s_req_fragment_start || state == s_req_fragment)
635
+ switch (parser->state) {
636
+ case s_req_path:
637
+ case s_req_schema:
638
+ case s_req_schema_slash:
639
+ case s_req_schema_slash_slash:
640
+ case s_req_host_start:
641
+ case s_req_host_v6_start:
642
+ case s_req_host_v6:
643
+ case s_req_host_v6_end:
644
+ case s_req_host:
645
+ case s_req_port_start:
646
+ case s_req_port:
647
+ case s_req_query_string_start:
648
+ case s_req_query_string:
649
+ case s_req_fragment_start:
650
+ case s_req_fragment:
365
651
  url_mark = data;
652
+ break;
653
+ }
366
654
 
367
- for (p=data, pe=data+len; p != pe; p++) {
655
+ for (p=data; p != data + len; p++) {
368
656
  ch = *p;
369
657
 
370
- if (PARSING_HEADER(state)) {
371
- ++nread;
658
+ if (PARSING_HEADER(parser->state)) {
659
+ ++parser->nread;
372
660
  /* Buffer overflow attack */
373
- if (nread > HTTP_MAX_HEADER_SIZE) goto error;
661
+ if (parser->nread > HTTP_MAX_HEADER_SIZE) {
662
+ SET_ERRNO(HPE_HEADER_OVERFLOW);
663
+ goto error;
664
+ }
374
665
  }
375
666
 
376
- switch (state) {
667
+ reexecute_byte:
668
+ switch (parser->state) {
377
669
 
378
670
  case s_dead:
379
671
  /* this state is used after a 'Connection: close' message
380
672
  * the parser will error out if it reads another message
381
673
  */
674
+ if (ch == CR || ch == LF)
675
+ break;
676
+
677
+ SET_ERRNO(HPE_CLOSED_CONNECTION);
382
678
  goto error;
383
679
 
384
680
  case s_start_req_or_res:
@@ -386,42 +682,46 @@ size_t http_parser_execute (http_parser *parser,
386
682
  if (ch == CR || ch == LF)
387
683
  break;
388
684
  parser->flags = 0;
389
- parser->content_length = -1;
685
+ parser->content_length = ULLONG_MAX;
390
686
 
391
- CALLBACK2(message_begin);
687
+ if (ch == 'H') {
688
+ parser->state = s_res_or_resp_H;
392
689
 
393
- if (ch == 'H')
394
- state = s_res_or_resp_H;
395
- else {
690
+ CALLBACK_NOTIFY(message_begin);
691
+ } else {
396
692
  parser->type = HTTP_REQUEST;
397
- goto start_req_method_assign;
693
+ parser->state = s_start_req;
694
+ goto reexecute_byte;
398
695
  }
696
+
399
697
  break;
400
698
  }
401
699
 
402
700
  case s_res_or_resp_H:
403
701
  if (ch == 'T') {
404
702
  parser->type = HTTP_RESPONSE;
405
- state = s_res_HT;
703
+ parser->state = s_res_HT;
406
704
  } else {
407
- if (ch != 'E') goto error;
705
+ if (ch != 'E') {
706
+ SET_ERRNO(HPE_INVALID_CONSTANT);
707
+ goto error;
708
+ }
709
+
408
710
  parser->type = HTTP_REQUEST;
409
711
  parser->method = HTTP_HEAD;
410
- index = 2;
411
- state = s_req_method;
712
+ parser->index = 2;
713
+ parser->state = s_req_method;
412
714
  }
413
715
  break;
414
716
 
415
717
  case s_start_res:
416
718
  {
417
719
  parser->flags = 0;
418
- parser->content_length = -1;
419
-
420
- CALLBACK2(message_begin);
720
+ parser->content_length = ULLONG_MAX;
421
721
 
422
722
  switch (ch) {
423
723
  case 'H':
424
- state = s_res_H;
724
+ parser->state = s_res_H;
425
725
  break;
426
726
 
427
727
  case CR:
@@ -429,105 +729,133 @@ size_t http_parser_execute (http_parser *parser,
429
729
  break;
430
730
 
431
731
  default:
732
+ SET_ERRNO(HPE_INVALID_CONSTANT);
432
733
  goto error;
433
734
  }
735
+
736
+ CALLBACK_NOTIFY(message_begin);
434
737
  break;
435
738
  }
436
739
 
437
740
  case s_res_H:
438
741
  STRICT_CHECK(ch != 'T');
439
- state = s_res_HT;
742
+ parser->state = s_res_HT;
440
743
  break;
441
744
 
442
745
  case s_res_HT:
443
746
  STRICT_CHECK(ch != 'T');
444
- state = s_res_HTT;
747
+ parser->state = s_res_HTT;
445
748
  break;
446
749
 
447
750
  case s_res_HTT:
448
751
  STRICT_CHECK(ch != 'P');
449
- state = s_res_HTTP;
752
+ parser->state = s_res_HTTP;
450
753
  break;
451
754
 
452
755
  case s_res_HTTP:
453
756
  STRICT_CHECK(ch != '/');
454
- state = s_res_first_http_major;
757
+ parser->state = s_res_first_http_major;
455
758
  break;
456
759
 
457
760
  case s_res_first_http_major:
458
- if (ch < '1' || ch > '9') goto error;
761
+ if (ch < '0' || ch > '9') {
762
+ SET_ERRNO(HPE_INVALID_VERSION);
763
+ goto error;
764
+ }
765
+
459
766
  parser->http_major = ch - '0';
460
- state = s_res_http_major;
767
+ parser->state = s_res_http_major;
461
768
  break;
462
769
 
463
770
  /* major HTTP version or dot */
464
771
  case s_res_http_major:
465
772
  {
466
773
  if (ch == '.') {
467
- state = s_res_first_http_minor;
774
+ parser->state = s_res_first_http_minor;
468
775
  break;
469
776
  }
470
777
 
471
- if (ch < '0' || ch > '9') goto error;
778
+ if (!IS_NUM(ch)) {
779
+ SET_ERRNO(HPE_INVALID_VERSION);
780
+ goto error;
781
+ }
472
782
 
473
783
  parser->http_major *= 10;
474
784
  parser->http_major += ch - '0';
475
785
 
476
- if (parser->http_major > 999) goto error;
786
+ if (parser->http_major > 999) {
787
+ SET_ERRNO(HPE_INVALID_VERSION);
788
+ goto error;
789
+ }
790
+
477
791
  break;
478
792
  }
479
793
 
480
794
  /* first digit of minor HTTP version */
481
795
  case s_res_first_http_minor:
482
- if (ch < '0' || ch > '9') goto error;
796
+ if (!IS_NUM(ch)) {
797
+ SET_ERRNO(HPE_INVALID_VERSION);
798
+ goto error;
799
+ }
800
+
483
801
  parser->http_minor = ch - '0';
484
- state = s_res_http_minor;
802
+ parser->state = s_res_http_minor;
485
803
  break;
486
804
 
487
805
  /* minor HTTP version or end of request line */
488
806
  case s_res_http_minor:
489
807
  {
490
808
  if (ch == ' ') {
491
- state = s_res_first_status_code;
809
+ parser->state = s_res_first_status_code;
492
810
  break;
493
811
  }
494
812
 
495
- if (ch < '0' || ch > '9') goto error;
813
+ if (!IS_NUM(ch)) {
814
+ SET_ERRNO(HPE_INVALID_VERSION);
815
+ goto error;
816
+ }
496
817
 
497
818
  parser->http_minor *= 10;
498
819
  parser->http_minor += ch - '0';
499
820
 
500
- if (parser->http_minor > 999) goto error;
821
+ if (parser->http_minor > 999) {
822
+ SET_ERRNO(HPE_INVALID_VERSION);
823
+ goto error;
824
+ }
825
+
501
826
  break;
502
827
  }
503
828
 
504
829
  case s_res_first_status_code:
505
830
  {
506
- if (ch < '0' || ch > '9') {
831
+ if (!IS_NUM(ch)) {
507
832
  if (ch == ' ') {
508
833
  break;
509
834
  }
835
+
836
+ SET_ERRNO(HPE_INVALID_STATUS);
510
837
  goto error;
511
838
  }
512
839
  parser->status_code = ch - '0';
513
- state = s_res_status_code;
840
+ parser->state = s_res_status_code;
514
841
  break;
515
842
  }
516
843
 
517
844
  case s_res_status_code:
518
845
  {
519
- if (ch < '0' || ch > '9') {
846
+ if (!IS_NUM(ch)) {
520
847
  switch (ch) {
521
848
  case ' ':
522
- state = s_res_status;
849
+ parser->state = s_res_status;
523
850
  break;
524
851
  case CR:
525
- state = s_res_line_almost_done;
852
+ parser->state = s_res_line_almost_done;
526
853
  break;
527
854
  case LF:
528
- state = s_header_field_start;
855
+ parser->state = s_header_field_start;
529
856
  break;
530
857
  default:
858
+ SET_ERRNO(HPE_INVALID_STATUS);
531
859
  goto error;
532
860
  }
533
861
  break;
@@ -536,7 +864,11 @@ size_t http_parser_execute (http_parser *parser,
536
864
  parser->status_code *= 10;
537
865
  parser->status_code += ch - '0';
538
866
 
539
- if (parser->status_code > 999) goto error;
867
+ if (parser->status_code > 999) {
868
+ SET_ERRNO(HPE_INVALID_STATUS);
869
+ goto error;
870
+ }
871
+
540
872
  break;
541
873
  }
542
874
 
@@ -544,19 +876,19 @@ size_t http_parser_execute (http_parser *parser,
544
876
  /* the human readable status. e.g. "NOT FOUND"
545
877
  * we are not humans so just ignore this */
546
878
  if (ch == CR) {
547
- state = s_res_line_almost_done;
879
+ parser->state = s_res_line_almost_done;
548
880
  break;
549
881
  }
550
882
 
551
883
  if (ch == LF) {
552
- state = s_header_field_start;
884
+ parser->state = s_header_field_start;
553
885
  break;
554
886
  }
555
887
  break;
556
888
 
557
889
  case s_res_line_almost_done:
558
890
  STRICT_CHECK(ch != LF);
559
- state = s_header_field_start;
891
+ parser->state = s_header_field_start;
560
892
  break;
561
893
 
562
894
  case s_start_req:
@@ -564,15 +896,15 @@ size_t http_parser_execute (http_parser *parser,
564
896
  if (ch == CR || ch == LF)
565
897
  break;
566
898
  parser->flags = 0;
567
- parser->content_length = -1;
899
+ parser->content_length = ULLONG_MAX;
568
900
 
569
- CALLBACK2(message_begin);
570
-
571
- if (ch < 'A' || 'Z' < ch) goto error;
901
+ if (!IS_ALPHA(ch)) {
902
+ SET_ERRNO(HPE_INVALID_METHOD);
903
+ goto error;
904
+ }
572
905
 
573
- start_req_method_assign:
574
906
  parser->method = (enum http_method) 0;
575
- index = 1;
907
+ parser->index = 1;
576
908
  switch (ch) {
577
909
  case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break;
578
910
  case 'D': parser->method = HTTP_DELETE; break;
@@ -582,336 +914,157 @@ size_t http_parser_execute (http_parser *parser,
582
914
  case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH */ break;
583
915
  case 'N': parser->method = HTTP_NOTIFY; break;
584
916
  case 'O': parser->method = HTTP_OPTIONS; break;
585
- case 'P': parser->method = HTTP_POST; /* or PROPFIND or PROPPATCH or PUT */ break;
917
+ case 'P': parser->method = HTTP_POST;
918
+ /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */
919
+ break;
586
920
  case 'R': parser->method = HTTP_REPORT; break;
587
921
  case 'S': parser->method = HTTP_SUBSCRIBE; break;
588
922
  case 'T': parser->method = HTTP_TRACE; break;
589
923
  case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break;
590
- default: goto error;
924
+ default:
925
+ SET_ERRNO(HPE_INVALID_METHOD);
926
+ goto error;
591
927
  }
592
- state = s_req_method;
928
+ parser->state = s_req_method;
929
+
930
+ CALLBACK_NOTIFY(message_begin);
931
+
593
932
  break;
594
933
  }
595
934
 
596
935
  case s_req_method:
597
936
  {
598
- if (ch == '\0')
937
+ const char *matcher;
938
+ if (ch == '\0') {
939
+ SET_ERRNO(HPE_INVALID_METHOD);
599
940
  goto error;
941
+ }
600
942
 
601
- const char *matcher = method_strings[parser->method];
602
- if (ch == ' ' && matcher[index] == '\0') {
603
- state = s_req_spaces_before_url;
604
- } else if (ch == matcher[index]) {
943
+ matcher = method_strings[parser->method];
944
+ if (ch == ' ' && matcher[parser->index] == '\0') {
945
+ parser->state = s_req_spaces_before_url;
946
+ } else if (ch == matcher[parser->index]) {
605
947
  ; /* nada */
606
948
  } else if (parser->method == HTTP_CONNECT) {
607
- if (index == 1 && ch == 'H') {
949
+ if (parser->index == 1 && ch == 'H') {
608
950
  parser->method = HTTP_CHECKOUT;
609
- } else if (index == 2 && ch == 'P') {
951
+ } else if (parser->index == 2 && ch == 'P') {
610
952
  parser->method = HTTP_COPY;
953
+ } else {
954
+ goto error;
611
955
  }
612
956
  } else if (parser->method == HTTP_MKCOL) {
613
- if (index == 1 && ch == 'O') {
957
+ if (parser->index == 1 && ch == 'O') {
614
958
  parser->method = HTTP_MOVE;
615
- } else if (index == 1 && ch == 'E') {
959
+ } else if (parser->index == 1 && ch == 'E') {
616
960
  parser->method = HTTP_MERGE;
617
- } else if (index == 1 && ch == '-') {
961
+ } else if (parser->index == 1 && ch == '-') {
618
962
  parser->method = HTTP_MSEARCH;
619
- } else if (index == 2 && ch == 'A') {
963
+ } else if (parser->index == 2 && ch == 'A') {
620
964
  parser->method = HTTP_MKACTIVITY;
965
+ } else {
966
+ goto error;
967
+ }
968
+ } else if (parser->index == 1 && parser->method == HTTP_POST) {
969
+ if (ch == 'R') {
970
+ parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */
971
+ } else if (ch == 'U') {
972
+ parser->method = HTTP_PUT; /* or HTTP_PURGE */
973
+ } else if (ch == 'A') {
974
+ parser->method = HTTP_PATCH;
975
+ } else {
976
+ goto error;
621
977
  }
622
- } else if (index == 1 && parser->method == HTTP_POST && ch == 'R') {
623
- parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */
624
- } else if (index == 1 && parser->method == HTTP_POST && ch == 'U') {
625
- parser->method = HTTP_PUT;
626
- } else if (index == 2 && parser->method == HTTP_UNLOCK && ch == 'S') {
627
- parser->method = HTTP_UNSUBSCRIBE;
628
- } else if (index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') {
978
+ } else if (parser->index == 2) {
979
+ if (parser->method == HTTP_PUT) {
980
+ if (ch == 'R') parser->method = HTTP_PURGE;
981
+ } else if (parser->method == HTTP_UNLOCK) {
982
+ if (ch == 'S') parser->method = HTTP_UNSUBSCRIBE;
983
+ }
984
+ } else if (parser->index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') {
629
985
  parser->method = HTTP_PROPPATCH;
630
986
  } else {
987
+ SET_ERRNO(HPE_INVALID_METHOD);
631
988
  goto error;
632
989
  }
633
990
 
634
- ++index;
991
+ ++parser->index;
635
992
  break;
636
993
  }
994
+
637
995
  case s_req_spaces_before_url:
638
996
  {
639
997
  if (ch == ' ') break;
640
998
 
641
- if (ch == '/' || ch == '*') {
642
- MARK(url);
643
- MARK(path);
644
- state = s_req_path;
645
- break;
999
+ MARK(url);
1000
+ if (parser->method == HTTP_CONNECT) {
1001
+ parser->state = s_req_host_start;
646
1002
  }
647
1003
 
648
- c = LOWER(ch);
649
-
650
- if (c >= 'a' && c <= 'z') {
651
- MARK(url);
652
- state = s_req_schema;
653
- break;
1004
+ parser->state = parse_url_char((enum state)parser->state, ch);
1005
+ if (parser->state == s_dead) {
1006
+ SET_ERRNO(HPE_INVALID_URL);
1007
+ goto error;
654
1008
  }
655
1009
 
656
- goto error;
1010
+ break;
657
1011
  }
658
1012
 
659
1013
  case s_req_schema:
660
- {
661
- c = LOWER(ch);
662
-
663
- if (c >= 'a' && c <= 'z') break;
664
-
665
- if (ch == ':') {
666
- state = s_req_schema_slash;
667
- break;
668
- } else if (ch == '.') {
669
- state = s_req_host;
670
- break;
671
- } else if ('0' <= ch && ch <= '9') {
672
- state = s_req_host;
673
- break;
674
- }
675
-
676
- goto error;
677
- }
678
-
679
1014
  case s_req_schema_slash:
680
- STRICT_CHECK(ch != '/');
681
- state = s_req_schema_slash_slash;
682
- break;
683
-
684
1015
  case s_req_schema_slash_slash:
685
- STRICT_CHECK(ch != '/');
686
- state = s_req_host;
687
- break;
688
-
689
- case s_req_host:
690
- {
691
- c = LOWER(ch);
692
- if (c >= 'a' && c <= 'z') break;
693
- if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '-') break;
694
- switch (ch) {
695
- case ':':
696
- state = s_req_port;
697
- break;
698
- case '/':
699
- MARK(path);
700
- state = s_req_path;
701
- break;
702
- case ' ':
703
- /* The request line looks like:
704
- * "GET http://foo.bar.com HTTP/1.1"
705
- * That is, there is no path.
706
- */
707
- CALLBACK(url);
708
- state = s_req_http_start;
709
- break;
710
- default:
711
- goto error;
712
- }
713
- break;
714
- }
715
-
716
- case s_req_port:
1016
+ case s_req_host_start:
1017
+ case s_req_host_v6_start:
1018
+ case s_req_host_v6:
1019
+ case s_req_port_start:
717
1020
  {
718
- if (ch >= '0' && ch <= '9') break;
719
1021
  switch (ch) {
720
- case '/':
721
- MARK(path);
722
- state = s_req_path;
723
- break;
1022
+ /* No whitespace allowed here */
724
1023
  case ' ':
725
- /* The request line looks like:
726
- * "GET http://foo.bar.com:1234 HTTP/1.1"
727
- * That is, there is no path.
728
- */
729
- CALLBACK(url);
730
- state = s_req_http_start;
731
- break;
732
- default:
733
- goto error;
734
- }
735
- break;
736
- }
737
-
738
- case s_req_path:
739
- {
740
- if (normal_url_char[(unsigned char)ch]) break;
741
-
742
- switch (ch) {
743
- case ' ':
744
- CALLBACK(url);
745
- CALLBACK(path);
746
- state = s_req_http_start;
747
- break;
748
1024
  case CR:
749
- CALLBACK(url);
750
- CALLBACK(path);
751
- parser->http_major = 0;
752
- parser->http_minor = 9;
753
- state = s_req_line_almost_done;
754
- break;
755
1025
  case LF:
756
- CALLBACK(url);
757
- CALLBACK(path);
758
- parser->http_major = 0;
759
- parser->http_minor = 9;
760
- state = s_header_field_start;
761
- break;
762
- case '?':
763
- CALLBACK(path);
764
- state = s_req_query_string_start;
765
- break;
766
- case '#':
767
- CALLBACK(path);
768
- state = s_req_fragment_start;
769
- break;
770
- default:
1026
+ SET_ERRNO(HPE_INVALID_URL);
771
1027
  goto error;
772
- }
773
- break;
774
- }
775
-
776
- case s_req_query_string_start:
777
- {
778
- if (normal_url_char[(unsigned char)ch]) {
779
- MARK(query_string);
780
- state = s_req_query_string;
781
- break;
782
- }
783
-
784
- switch (ch) {
785
- case '?':
786
- break; /* XXX ignore extra '?' ... is this right? */
787
- case ' ':
788
- CALLBACK(url);
789
- state = s_req_http_start;
790
- break;
791
- case CR:
792
- CALLBACK(url);
793
- parser->http_major = 0;
794
- parser->http_minor = 9;
795
- state = s_req_line_almost_done;
796
- break;
797
- case LF:
798
- CALLBACK(url);
799
- parser->http_major = 0;
800
- parser->http_minor = 9;
801
- state = s_header_field_start;
802
- break;
803
- case '#':
804
- state = s_req_fragment_start;
805
- break;
806
1028
  default:
807
- goto error;
1029
+ parser->state = parse_url_char((enum state)parser->state, ch);
1030
+ if (parser->state == s_dead) {
1031
+ SET_ERRNO(HPE_INVALID_URL);
1032
+ goto error;
1033
+ }
808
1034
  }
809
- break;
810
- }
811
1035
 
812
- case s_req_query_string:
813
- {
814
- if (normal_url_char[(unsigned char)ch]) break;
815
-
816
- switch (ch) {
817
- case '?':
818
- /* allow extra '?' in query string */
819
- break;
820
- case ' ':
821
- CALLBACK(url);
822
- CALLBACK(query_string);
823
- state = s_req_http_start;
824
- break;
825
- case CR:
826
- CALLBACK(url);
827
- CALLBACK(query_string);
828
- parser->http_major = 0;
829
- parser->http_minor = 9;
830
- state = s_req_line_almost_done;
831
- break;
832
- case LF:
833
- CALLBACK(url);
834
- CALLBACK(query_string);
835
- parser->http_major = 0;
836
- parser->http_minor = 9;
837
- state = s_header_field_start;
838
- break;
839
- case '#':
840
- CALLBACK(query_string);
841
- state = s_req_fragment_start;
842
- break;
843
- default:
844
- goto error;
845
- }
846
1036
  break;
847
1037
  }
848
1038
 
1039
+ case s_req_host:
1040
+ case s_req_host_v6_end:
1041
+ case s_req_port:
1042
+ case s_req_path:
1043
+ case s_req_query_string_start:
1044
+ case s_req_query_string:
849
1045
  case s_req_fragment_start:
850
- {
851
- if (normal_url_char[(unsigned char)ch]) {
852
- MARK(fragment);
853
- state = s_req_fragment;
854
- break;
855
- }
856
-
857
- switch (ch) {
858
- case ' ':
859
- CALLBACK(url);
860
- state = s_req_http_start;
861
- break;
862
- case CR:
863
- CALLBACK(url);
864
- parser->http_major = 0;
865
- parser->http_minor = 9;
866
- state = s_req_line_almost_done;
867
- break;
868
- case LF:
869
- CALLBACK(url);
870
- parser->http_major = 0;
871
- parser->http_minor = 9;
872
- state = s_header_field_start;
873
- break;
874
- case '?':
875
- MARK(fragment);
876
- state = s_req_fragment;
877
- break;
878
- case '#':
879
- break;
880
- default:
881
- goto error;
882
- }
883
- break;
884
- }
885
-
886
1046
  case s_req_fragment:
887
1047
  {
888
- if (normal_url_char[(unsigned char)ch]) break;
889
-
890
1048
  switch (ch) {
891
1049
  case ' ':
892
- CALLBACK(url);
893
- CALLBACK(fragment);
894
- state = s_req_http_start;
1050
+ parser->state = s_req_http_start;
1051
+ CALLBACK_DATA(url);
895
1052
  break;
896
1053
  case CR:
897
- CALLBACK(url);
898
- CALLBACK(fragment);
899
- parser->http_major = 0;
900
- parser->http_minor = 9;
901
- state = s_req_line_almost_done;
902
- break;
903
1054
  case LF:
904
- CALLBACK(url);
905
- CALLBACK(fragment);
906
1055
  parser->http_major = 0;
907
1056
  parser->http_minor = 9;
908
- state = s_header_field_start;
909
- break;
910
- case '?':
911
- case '#':
1057
+ parser->state = (ch == CR) ?
1058
+ s_req_line_almost_done :
1059
+ s_header_field_start;
1060
+ CALLBACK_DATA(url);
912
1061
  break;
913
1062
  default:
914
- goto error;
1063
+ parser->state = parse_url_char((enum state)parser->state, ch);
1064
+ if (parser->state == s_dead) {
1065
+ SET_ERRNO(HPE_INVALID_URL);
1066
+ goto error;
1067
+ }
915
1068
  }
916
1069
  break;
917
1070
  }
@@ -919,140 +1072,170 @@ size_t http_parser_execute (http_parser *parser,
919
1072
  case s_req_http_start:
920
1073
  switch (ch) {
921
1074
  case 'H':
922
- state = s_req_http_H;
1075
+ parser->state = s_req_http_H;
923
1076
  break;
924
1077
  case ' ':
925
1078
  break;
926
1079
  default:
1080
+ SET_ERRNO(HPE_INVALID_CONSTANT);
927
1081
  goto error;
928
1082
  }
929
1083
  break;
930
1084
 
931
1085
  case s_req_http_H:
932
1086
  STRICT_CHECK(ch != 'T');
933
- state = s_req_http_HT;
1087
+ parser->state = s_req_http_HT;
934
1088
  break;
935
1089
 
936
1090
  case s_req_http_HT:
937
1091
  STRICT_CHECK(ch != 'T');
938
- state = s_req_http_HTT;
1092
+ parser->state = s_req_http_HTT;
939
1093
  break;
940
1094
 
941
1095
  case s_req_http_HTT:
942
1096
  STRICT_CHECK(ch != 'P');
943
- state = s_req_http_HTTP;
1097
+ parser->state = s_req_http_HTTP;
944
1098
  break;
945
1099
 
946
1100
  case s_req_http_HTTP:
947
1101
  STRICT_CHECK(ch != '/');
948
- state = s_req_first_http_major;
1102
+ parser->state = s_req_first_http_major;
949
1103
  break;
950
1104
 
951
1105
  /* first digit of major HTTP version */
952
1106
  case s_req_first_http_major:
953
- if (ch < '1' || ch > '9') goto error;
1107
+ if (ch < '1' || ch > '9') {
1108
+ SET_ERRNO(HPE_INVALID_VERSION);
1109
+ goto error;
1110
+ }
1111
+
954
1112
  parser->http_major = ch - '0';
955
- state = s_req_http_major;
1113
+ parser->state = s_req_http_major;
956
1114
  break;
957
1115
 
958
1116
  /* major HTTP version or dot */
959
1117
  case s_req_http_major:
960
1118
  {
961
1119
  if (ch == '.') {
962
- state = s_req_first_http_minor;
1120
+ parser->state = s_req_first_http_minor;
963
1121
  break;
964
1122
  }
965
1123
 
966
- if (ch < '0' || ch > '9') goto error;
1124
+ if (!IS_NUM(ch)) {
1125
+ SET_ERRNO(HPE_INVALID_VERSION);
1126
+ goto error;
1127
+ }
967
1128
 
968
1129
  parser->http_major *= 10;
969
1130
  parser->http_major += ch - '0';
970
1131
 
971
- if (parser->http_major > 999) goto error;
1132
+ if (parser->http_major > 999) {
1133
+ SET_ERRNO(HPE_INVALID_VERSION);
1134
+ goto error;
1135
+ }
1136
+
972
1137
  break;
973
1138
  }
974
1139
 
975
1140
  /* first digit of minor HTTP version */
976
1141
  case s_req_first_http_minor:
977
- if (ch < '0' || ch > '9') goto error;
1142
+ if (!IS_NUM(ch)) {
1143
+ SET_ERRNO(HPE_INVALID_VERSION);
1144
+ goto error;
1145
+ }
1146
+
978
1147
  parser->http_minor = ch - '0';
979
- state = s_req_http_minor;
1148
+ parser->state = s_req_http_minor;
980
1149
  break;
981
1150
 
982
1151
  /* minor HTTP version or end of request line */
983
1152
  case s_req_http_minor:
984
1153
  {
985
1154
  if (ch == CR) {
986
- state = s_req_line_almost_done;
1155
+ parser->state = s_req_line_almost_done;
987
1156
  break;
988
1157
  }
989
1158
 
990
1159
  if (ch == LF) {
991
- state = s_header_field_start;
1160
+ parser->state = s_header_field_start;
992
1161
  break;
993
1162
  }
994
1163
 
995
1164
  /* XXX allow spaces after digit? */
996
1165
 
997
- if (ch < '0' || ch > '9') goto error;
1166
+ if (!IS_NUM(ch)) {
1167
+ SET_ERRNO(HPE_INVALID_VERSION);
1168
+ goto error;
1169
+ }
998
1170
 
999
1171
  parser->http_minor *= 10;
1000
1172
  parser->http_minor += ch - '0';
1001
1173
 
1002
- if (parser->http_minor > 999) goto error;
1174
+ if (parser->http_minor > 999) {
1175
+ SET_ERRNO(HPE_INVALID_VERSION);
1176
+ goto error;
1177
+ }
1178
+
1003
1179
  break;
1004
1180
  }
1005
1181
 
1006
1182
  /* end of request line */
1007
1183
  case s_req_line_almost_done:
1008
1184
  {
1009
- if (ch != LF) goto error;
1010
- state = s_header_field_start;
1185
+ if (ch != LF) {
1186
+ SET_ERRNO(HPE_LF_EXPECTED);
1187
+ goto error;
1188
+ }
1189
+
1190
+ parser->state = s_header_field_start;
1011
1191
  break;
1012
1192
  }
1013
1193
 
1014
1194
  case s_header_field_start:
1015
1195
  {
1016
1196
  if (ch == CR) {
1017
- state = s_headers_almost_done;
1197
+ parser->state = s_headers_almost_done;
1018
1198
  break;
1019
1199
  }
1020
1200
 
1021
1201
  if (ch == LF) {
1022
1202
  /* they might be just sending \n instead of \r\n so this would be
1023
1203
  * the second \n to denote the end of headers*/
1024
- state = s_headers_almost_done;
1025
- goto headers_almost_done;
1204
+ parser->state = s_headers_almost_done;
1205
+ goto reexecute_byte;
1026
1206
  }
1027
1207
 
1028
1208
  c = TOKEN(ch);
1029
1209
 
1030
- if (!c) goto error;
1210
+ if (!c) {
1211
+ SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
1212
+ goto error;
1213
+ }
1031
1214
 
1032
1215
  MARK(header_field);
1033
1216
 
1034
- index = 0;
1035
- state = s_header_field;
1217
+ parser->index = 0;
1218
+ parser->state = s_header_field;
1036
1219
 
1037
1220
  switch (c) {
1038
1221
  case 'c':
1039
- header_state = h_C;
1222
+ parser->header_state = h_C;
1040
1223
  break;
1041
1224
 
1042
1225
  case 'p':
1043
- header_state = h_matching_proxy_connection;
1226
+ parser->header_state = h_matching_proxy_connection;
1044
1227
  break;
1045
1228
 
1046
1229
  case 't':
1047
- header_state = h_matching_transfer_encoding;
1230
+ parser->header_state = h_matching_transfer_encoding;
1048
1231
  break;
1049
1232
 
1050
1233
  case 'u':
1051
- header_state = h_matching_upgrade;
1234
+ parser->header_state = h_matching_upgrade;
1052
1235
  break;
1053
1236
 
1054
1237
  default:
1055
- header_state = h_general;
1238
+ parser->header_state = h_general;
1056
1239
  break;
1057
1240
  }
1058
1241
  break;
@@ -1063,31 +1246,31 @@ size_t http_parser_execute (http_parser *parser,
1063
1246
  c = TOKEN(ch);
1064
1247
 
1065
1248
  if (c) {
1066
- switch (header_state) {
1249
+ switch (parser->header_state) {
1067
1250
  case h_general:
1068
1251
  break;
1069
1252
 
1070
1253
  case h_C:
1071
- index++;
1072
- header_state = (c == 'o' ? h_CO : h_general);
1254
+ parser->index++;
1255
+ parser->header_state = (c == 'o' ? h_CO : h_general);
1073
1256
  break;
1074
1257
 
1075
1258
  case h_CO:
1076
- index++;
1077
- header_state = (c == 'n' ? h_CON : h_general);
1259
+ parser->index++;
1260
+ parser->header_state = (c == 'n' ? h_CON : h_general);
1078
1261
  break;
1079
1262
 
1080
1263
  case h_CON:
1081
- index++;
1264
+ parser->index++;
1082
1265
  switch (c) {
1083
1266
  case 'n':
1084
- header_state = h_matching_connection;
1267
+ parser->header_state = h_matching_connection;
1085
1268
  break;
1086
1269
  case 't':
1087
- header_state = h_matching_content_length;
1270
+ parser->header_state = h_matching_content_length;
1088
1271
  break;
1089
1272
  default:
1090
- header_state = h_general;
1273
+ parser->header_state = h_general;
1091
1274
  break;
1092
1275
  }
1093
1276
  break;
@@ -1095,60 +1278,60 @@ size_t http_parser_execute (http_parser *parser,
1095
1278
  /* connection */
1096
1279
 
1097
1280
  case h_matching_connection:
1098
- index++;
1099
- if (index > sizeof(CONNECTION)-1
1100
- || c != CONNECTION[index]) {
1101
- header_state = h_general;
1102
- } else if (index == sizeof(CONNECTION)-2) {
1103
- header_state = h_connection;
1281
+ parser->index++;
1282
+ if (parser->index > sizeof(CONNECTION)-1
1283
+ || c != CONNECTION[parser->index]) {
1284
+ parser->header_state = h_general;
1285
+ } else if (parser->index == sizeof(CONNECTION)-2) {
1286
+ parser->header_state = h_connection;
1104
1287
  }
1105
1288
  break;
1106
1289
 
1107
1290
  /* proxy-connection */
1108
1291
 
1109
1292
  case h_matching_proxy_connection:
1110
- index++;
1111
- if (index > sizeof(PROXY_CONNECTION)-1
1112
- || c != PROXY_CONNECTION[index]) {
1113
- header_state = h_general;
1114
- } else if (index == sizeof(PROXY_CONNECTION)-2) {
1115
- header_state = h_connection;
1293
+ parser->index++;
1294
+ if (parser->index > sizeof(PROXY_CONNECTION)-1
1295
+ || c != PROXY_CONNECTION[parser->index]) {
1296
+ parser->header_state = h_general;
1297
+ } else if (parser->index == sizeof(PROXY_CONNECTION)-2) {
1298
+ parser->header_state = h_connection;
1116
1299
  }
1117
1300
  break;
1118
1301
 
1119
1302
  /* content-length */
1120
1303
 
1121
1304
  case h_matching_content_length:
1122
- index++;
1123
- if (index > sizeof(CONTENT_LENGTH)-1
1124
- || c != CONTENT_LENGTH[index]) {
1125
- header_state = h_general;
1126
- } else if (index == sizeof(CONTENT_LENGTH)-2) {
1127
- header_state = h_content_length;
1305
+ parser->index++;
1306
+ if (parser->index > sizeof(CONTENT_LENGTH)-1
1307
+ || c != CONTENT_LENGTH[parser->index]) {
1308
+ parser->header_state = h_general;
1309
+ } else if (parser->index == sizeof(CONTENT_LENGTH)-2) {
1310
+ parser->header_state = h_content_length;
1128
1311
  }
1129
1312
  break;
1130
1313
 
1131
1314
  /* transfer-encoding */
1132
1315
 
1133
1316
  case h_matching_transfer_encoding:
1134
- index++;
1135
- if (index > sizeof(TRANSFER_ENCODING)-1
1136
- || c != TRANSFER_ENCODING[index]) {
1137
- header_state = h_general;
1138
- } else if (index == sizeof(TRANSFER_ENCODING)-2) {
1139
- header_state = h_transfer_encoding;
1317
+ parser->index++;
1318
+ if (parser->index > sizeof(TRANSFER_ENCODING)-1
1319
+ || c != TRANSFER_ENCODING[parser->index]) {
1320
+ parser->header_state = h_general;
1321
+ } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) {
1322
+ parser->header_state = h_transfer_encoding;
1140
1323
  }
1141
1324
  break;
1142
1325
 
1143
1326
  /* upgrade */
1144
1327
 
1145
1328
  case h_matching_upgrade:
1146
- index++;
1147
- if (index > sizeof(UPGRADE)-1
1148
- || c != UPGRADE[index]) {
1149
- header_state = h_general;
1150
- } else if (index == sizeof(UPGRADE)-2) {
1151
- header_state = h_upgrade;
1329
+ parser->index++;
1330
+ if (parser->index > sizeof(UPGRADE)-1
1331
+ || c != UPGRADE[parser->index]) {
1332
+ parser->header_state = h_general;
1333
+ } else if (parser->index == sizeof(UPGRADE)-2) {
1334
+ parser->header_state = h_upgrade;
1152
1335
  }
1153
1336
  break;
1154
1337
 
@@ -1156,7 +1339,7 @@ size_t http_parser_execute (http_parser *parser,
1156
1339
  case h_content_length:
1157
1340
  case h_transfer_encoding:
1158
1341
  case h_upgrade:
1159
- if (ch != ' ') header_state = h_general;
1342
+ if (ch != ' ') parser->header_state = h_general;
1160
1343
  break;
1161
1344
 
1162
1345
  default:
@@ -1167,84 +1350,89 @@ size_t http_parser_execute (http_parser *parser,
1167
1350
  }
1168
1351
 
1169
1352
  if (ch == ':') {
1170
- CALLBACK(header_field);
1171
- state = s_header_value_start;
1353
+ parser->state = s_header_value_start;
1354
+ CALLBACK_DATA(header_field);
1172
1355
  break;
1173
1356
  }
1174
1357
 
1175
1358
  if (ch == CR) {
1176
- state = s_header_almost_done;
1177
- CALLBACK(header_field);
1359
+ parser->state = s_header_almost_done;
1360
+ CALLBACK_DATA(header_field);
1178
1361
  break;
1179
1362
  }
1180
1363
 
1181
1364
  if (ch == LF) {
1182
- CALLBACK(header_field);
1183
- state = s_header_field_start;
1365
+ parser->state = s_header_field_start;
1366
+ CALLBACK_DATA(header_field);
1184
1367
  break;
1185
1368
  }
1186
1369
 
1370
+ SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
1187
1371
  goto error;
1188
1372
  }
1189
1373
 
1190
1374
  case s_header_value_start:
1191
1375
  {
1192
- if (ch == ' ') break;
1376
+ if (ch == ' ' || ch == '\t') break;
1193
1377
 
1194
1378
  MARK(header_value);
1195
1379
 
1196
- state = s_header_value;
1197
- index = 0;
1198
-
1199
- c = LOWER(ch);
1380
+ parser->state = s_header_value;
1381
+ parser->index = 0;
1200
1382
 
1201
1383
  if (ch == CR) {
1202
- CALLBACK(header_value);
1203
- header_state = h_general;
1204
- state = s_header_almost_done;
1384
+ parser->header_state = h_general;
1385
+ parser->state = s_header_almost_done;
1386
+ CALLBACK_DATA(header_value);
1205
1387
  break;
1206
1388
  }
1207
1389
 
1208
1390
  if (ch == LF) {
1209
- CALLBACK(header_value);
1210
- state = s_header_field_start;
1391
+ parser->state = s_header_field_start;
1392
+ CALLBACK_DATA(header_value);
1211
1393
  break;
1212
1394
  }
1213
1395
 
1214
- switch (header_state) {
1396
+ c = LOWER(ch);
1397
+
1398
+ switch (parser->header_state) {
1215
1399
  case h_upgrade:
1216
1400
  parser->flags |= F_UPGRADE;
1217
- header_state = h_general;
1401
+ parser->header_state = h_general;
1218
1402
  break;
1219
1403
 
1220
1404
  case h_transfer_encoding:
1221
1405
  /* looking for 'Transfer-Encoding: chunked' */
1222
1406
  if ('c' == c) {
1223
- header_state = h_matching_transfer_encoding_chunked;
1407
+ parser->header_state = h_matching_transfer_encoding_chunked;
1224
1408
  } else {
1225
- header_state = h_general;
1409
+ parser->header_state = h_general;
1226
1410
  }
1227
1411
  break;
1228
1412
 
1229
1413
  case h_content_length:
1230
- if (ch < '0' || ch > '9') goto error;
1414
+ if (!IS_NUM(ch)) {
1415
+ SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1416
+ goto error;
1417
+ }
1418
+
1231
1419
  parser->content_length = ch - '0';
1232
1420
  break;
1233
1421
 
1234
1422
  case h_connection:
1235
1423
  /* looking for 'Connection: keep-alive' */
1236
1424
  if (c == 'k') {
1237
- header_state = h_matching_connection_keep_alive;
1425
+ parser->header_state = h_matching_connection_keep_alive;
1238
1426
  /* looking for 'Connection: close' */
1239
1427
  } else if (c == 'c') {
1240
- header_state = h_matching_connection_close;
1428
+ parser->header_state = h_matching_connection_close;
1241
1429
  } else {
1242
- header_state = h_general;
1430
+ parser->header_state = h_general;
1243
1431
  }
1244
1432
  break;
1245
1433
 
1246
1434
  default:
1247
- header_state = h_general;
1435
+ parser->header_state = h_general;
1248
1436
  break;
1249
1437
  }
1250
1438
  break;
@@ -1252,20 +1440,22 @@ size_t http_parser_execute (http_parser *parser,
1252
1440
 
1253
1441
  case s_header_value:
1254
1442
  {
1255
- c = LOWER(ch);
1256
1443
 
1257
1444
  if (ch == CR) {
1258
- CALLBACK(header_value);
1259
- state = s_header_almost_done;
1445
+ parser->state = s_header_almost_done;
1446
+ CALLBACK_DATA(header_value);
1260
1447
  break;
1261
1448
  }
1262
1449
 
1263
1450
  if (ch == LF) {
1264
- CALLBACK(header_value);
1265
- goto header_almost_done;
1451
+ parser->state = s_header_almost_done;
1452
+ CALLBACK_DATA_NOADVANCE(header_value);
1453
+ goto reexecute_byte;
1266
1454
  }
1267
1455
 
1268
- switch (header_state) {
1456
+ c = LOWER(ch);
1457
+
1458
+ switch (parser->header_state) {
1269
1459
  case h_general:
1270
1460
  break;
1271
1461
 
@@ -1275,66 +1465,83 @@ size_t http_parser_execute (http_parser *parser,
1275
1465
  break;
1276
1466
 
1277
1467
  case h_content_length:
1468
+ {
1469
+ uint64_t t;
1470
+
1278
1471
  if (ch == ' ') break;
1279
- if (ch < '0' || ch > '9') goto error;
1280
- parser->content_length *= 10;
1281
- parser->content_length += ch - '0';
1472
+
1473
+ if (!IS_NUM(ch)) {
1474
+ SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1475
+ goto error;
1476
+ }
1477
+
1478
+ t = parser->content_length;
1479
+ t *= 10;
1480
+ t += ch - '0';
1481
+
1482
+ /* Overflow? */
1483
+ if (t < parser->content_length || t == ULLONG_MAX) {
1484
+ SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1485
+ goto error;
1486
+ }
1487
+
1488
+ parser->content_length = t;
1282
1489
  break;
1490
+ }
1283
1491
 
1284
1492
  /* Transfer-Encoding: chunked */
1285
1493
  case h_matching_transfer_encoding_chunked:
1286
- index++;
1287
- if (index > sizeof(CHUNKED)-1
1288
- || c != CHUNKED[index]) {
1289
- header_state = h_general;
1290
- } else if (index == sizeof(CHUNKED)-2) {
1291
- header_state = h_transfer_encoding_chunked;
1494
+ parser->index++;
1495
+ if (parser->index > sizeof(CHUNKED)-1
1496
+ || c != CHUNKED[parser->index]) {
1497
+ parser->header_state = h_general;
1498
+ } else if (parser->index == sizeof(CHUNKED)-2) {
1499
+ parser->header_state = h_transfer_encoding_chunked;
1292
1500
  }
1293
1501
  break;
1294
1502
 
1295
1503
  /* looking for 'Connection: keep-alive' */
1296
1504
  case h_matching_connection_keep_alive:
1297
- index++;
1298
- if (index > sizeof(KEEP_ALIVE)-1
1299
- || c != KEEP_ALIVE[index]) {
1300
- header_state = h_general;
1301
- } else if (index == sizeof(KEEP_ALIVE)-2) {
1302
- header_state = h_connection_keep_alive;
1505
+ parser->index++;
1506
+ if (parser->index > sizeof(KEEP_ALIVE)-1
1507
+ || c != KEEP_ALIVE[parser->index]) {
1508
+ parser->header_state = h_general;
1509
+ } else if (parser->index == sizeof(KEEP_ALIVE)-2) {
1510
+ parser->header_state = h_connection_keep_alive;
1303
1511
  }
1304
1512
  break;
1305
1513
 
1306
1514
  /* looking for 'Connection: close' */
1307
1515
  case h_matching_connection_close:
1308
- index++;
1309
- if (index > sizeof(CLOSE)-1 || c != CLOSE[index]) {
1310
- header_state = h_general;
1311
- } else if (index == sizeof(CLOSE)-2) {
1312
- header_state = h_connection_close;
1516
+ parser->index++;
1517
+ if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) {
1518
+ parser->header_state = h_general;
1519
+ } else if (parser->index == sizeof(CLOSE)-2) {
1520
+ parser->header_state = h_connection_close;
1313
1521
  }
1314
1522
  break;
1315
1523
 
1316
1524
  case h_transfer_encoding_chunked:
1317
1525
  case h_connection_keep_alive:
1318
1526
  case h_connection_close:
1319
- if (ch != ' ') header_state = h_general;
1527
+ if (ch != ' ') parser->header_state = h_general;
1320
1528
  break;
1321
1529
 
1322
1530
  default:
1323
- state = s_header_value;
1324
- header_state = h_general;
1531
+ parser->state = s_header_value;
1532
+ parser->header_state = h_general;
1325
1533
  break;
1326
1534
  }
1327
1535
  break;
1328
1536
  }
1329
1537
 
1330
1538
  case s_header_almost_done:
1331
- header_almost_done:
1332
1539
  {
1333
1540
  STRICT_CHECK(ch != LF);
1334
1541
 
1335
- state = s_header_field_start;
1542
+ parser->state = s_header_value_lws;
1336
1543
 
1337
- switch (header_state) {
1544
+ switch (parser->header_state) {
1338
1545
  case h_connection_keep_alive:
1339
1546
  parser->flags |= F_CONNECTION_KEEP_ALIVE;
1340
1547
  break;
@@ -1347,32 +1554,47 @@ size_t http_parser_execute (http_parser *parser,
1347
1554
  default:
1348
1555
  break;
1349
1556
  }
1557
+
1558
+ break;
1559
+ }
1560
+
1561
+ case s_header_value_lws:
1562
+ {
1563
+ if (ch == ' ' || ch == '\t')
1564
+ parser->state = s_header_value_start;
1565
+ else
1566
+ {
1567
+ parser->state = s_header_field_start;
1568
+ goto reexecute_byte;
1569
+ }
1350
1570
  break;
1351
1571
  }
1352
1572
 
1353
1573
  case s_headers_almost_done:
1354
- headers_almost_done:
1355
1574
  {
1356
1575
  STRICT_CHECK(ch != LF);
1357
1576
 
1358
1577
  if (parser->flags & F_TRAILING) {
1359
1578
  /* End of a chunked request */
1360
- CALLBACK2(message_complete);
1361
- state = NEW_MESSAGE();
1579
+ parser->state = NEW_MESSAGE();
1580
+ CALLBACK_NOTIFY(message_complete);
1362
1581
  break;
1363
1582
  }
1364
1583
 
1365
- nread = 0;
1584
+ parser->state = s_headers_done;
1366
1585
 
1367
- if (parser->flags & F_UPGRADE || parser->method == HTTP_CONNECT) {
1368
- parser->upgrade = 1;
1369
- }
1586
+ /* Set this here so that on_headers_complete() callbacks can see it */
1587
+ parser->upgrade =
1588
+ (parser->flags & F_UPGRADE || parser->method == HTTP_CONNECT);
1370
1589
 
1371
1590
  /* Here we call the headers_complete callback. This is somewhat
1372
1591
  * different than other callbacks because if the user returns 1, we
1373
1592
  * will interpret that as saying that this message has no body. This
1374
1593
  * is needed for the annoying case of recieving a response to a HEAD
1375
1594
  * request.
1595
+ *
1596
+ * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so
1597
+ * we have to simulate it by handling a change in errno below.
1376
1598
  */
1377
1599
  if (settings->on_headers_complete) {
1378
1600
  switch (settings->on_headers_complete(parser)) {
@@ -1384,39 +1606,54 @@ size_t http_parser_execute (http_parser *parser,
1384
1606
  break;
1385
1607
 
1386
1608
  default:
1387
- parser->state = state;
1609
+ SET_ERRNO(HPE_CB_headers_complete);
1388
1610
  return p - data; /* Error */
1389
1611
  }
1390
1612
  }
1391
1613
 
1614
+ if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
1615
+ return p - data;
1616
+ }
1617
+
1618
+ goto reexecute_byte;
1619
+ }
1620
+
1621
+ case s_headers_done:
1622
+ {
1623
+ STRICT_CHECK(ch != LF);
1624
+
1625
+ parser->nread = 0;
1626
+
1392
1627
  /* Exit, the rest of the connect is in a different protocol. */
1393
1628
  if (parser->upgrade) {
1394
- CALLBACK2(message_complete);
1395
- return (p - data);
1629
+ parser->state = NEW_MESSAGE();
1630
+ CALLBACK_NOTIFY(message_complete);
1631
+ return (p - data) + 1;
1396
1632
  }
1397
1633
 
1398
1634
  if (parser->flags & F_SKIPBODY) {
1399
- CALLBACK2(message_complete);
1400
- state = NEW_MESSAGE();
1635
+ parser->state = NEW_MESSAGE();
1636
+ CALLBACK_NOTIFY(message_complete);
1401
1637
  } else if (parser->flags & F_CHUNKED) {
1402
1638
  /* chunked encoding - ignore Content-Length header */
1403
- state = s_chunk_size_start;
1639
+ parser->state = s_chunk_size_start;
1404
1640
  } else {
1405
1641
  if (parser->content_length == 0) {
1406
1642
  /* Content-Length header given but zero: Content-Length: 0\r\n */
1407
- CALLBACK2(message_complete);
1408
- state = NEW_MESSAGE();
1409
- } else if (parser->content_length > 0) {
1643
+ parser->state = NEW_MESSAGE();
1644
+ CALLBACK_NOTIFY(message_complete);
1645
+ } else if (parser->content_length != ULLONG_MAX) {
1410
1646
  /* Content-Length header given and non-zero */
1411
- state = s_body_identity;
1647
+ parser->state = s_body_identity;
1412
1648
  } else {
1413
- if (parser->type == HTTP_REQUEST || http_should_keep_alive(parser)) {
1649
+ if (parser->type == HTTP_REQUEST ||
1650
+ !http_message_needs_eof(parser)) {
1414
1651
  /* Assume content-length 0 - read the next */
1415
- CALLBACK2(message_complete);
1416
- state = NEW_MESSAGE();
1652
+ parser->state = NEW_MESSAGE();
1653
+ CALLBACK_NOTIFY(message_complete);
1417
1654
  } else {
1418
1655
  /* Read body until EOF */
1419
- state = s_body_identity_eof;
1656
+ parser->state = s_body_identity_eof;
1420
1657
  }
1421
1658
  }
1422
1659
  }
@@ -1425,59 +1662,103 @@ size_t http_parser_execute (http_parser *parser,
1425
1662
  }
1426
1663
 
1427
1664
  case s_body_identity:
1428
- to_read = MIN(pe - p, (int64_t)parser->content_length);
1429
- if (to_read > 0) {
1430
- if (settings->on_body) settings->on_body(parser, p, to_read);
1431
- p += to_read - 1;
1432
- parser->content_length -= to_read;
1433
- if (parser->content_length == 0) {
1434
- CALLBACK2(message_complete);
1435
- state = NEW_MESSAGE();
1436
- }
1665
+ {
1666
+ uint64_t to_read = MIN(parser->content_length,
1667
+ (uint64_t) ((data + len) - p));
1668
+
1669
+ assert(parser->content_length != 0
1670
+ && parser->content_length != ULLONG_MAX);
1671
+
1672
+ /* The difference between advancing content_length and p is because
1673
+ * the latter will automaticaly advance on the next loop iteration.
1674
+ * Further, if content_length ends up at 0, we want to see the last
1675
+ * byte again for our message complete callback.
1676
+ */
1677
+ MARK(body);
1678
+ parser->content_length -= to_read;
1679
+ p += to_read - 1;
1680
+
1681
+ if (parser->content_length == 0) {
1682
+ parser->state = s_message_done;
1683
+
1684
+ /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte.
1685
+ *
1686
+ * The alternative to doing this is to wait for the next byte to
1687
+ * trigger the data callback, just as in every other case. The
1688
+ * problem with this is that this makes it difficult for the test
1689
+ * harness to distinguish between complete-on-EOF and
1690
+ * complete-on-length. It's not clear that this distinction is
1691
+ * important for applications, but let's keep it for now.
1692
+ */
1693
+ CALLBACK_DATA_(body, p - body_mark + 1, p - data);
1694
+ goto reexecute_byte;
1437
1695
  }
1696
+
1438
1697
  break;
1698
+ }
1439
1699
 
1440
1700
  /* read until EOF */
1441
1701
  case s_body_identity_eof:
1442
- to_read = pe - p;
1443
- if (to_read > 0) {
1444
- if (settings->on_body) settings->on_body(parser, p, to_read);
1445
- p += to_read - 1;
1446
- }
1702
+ MARK(body);
1703
+ p = data + len - 1;
1704
+
1705
+ break;
1706
+
1707
+ case s_message_done:
1708
+ parser->state = NEW_MESSAGE();
1709
+ CALLBACK_NOTIFY(message_complete);
1447
1710
  break;
1448
1711
 
1449
1712
  case s_chunk_size_start:
1450
1713
  {
1714
+ assert(parser->nread == 1);
1451
1715
  assert(parser->flags & F_CHUNKED);
1452
1716
 
1453
- c = unhex[(unsigned char)ch];
1454
- if (c == -1) goto error;
1455
- parser->content_length = c;
1456
- state = s_chunk_size;
1717
+ unhex_val = unhex[(unsigned char)ch];
1718
+ if (unhex_val == -1) {
1719
+ SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
1720
+ goto error;
1721
+ }
1722
+
1723
+ parser->content_length = unhex_val;
1724
+ parser->state = s_chunk_size;
1457
1725
  break;
1458
1726
  }
1459
1727
 
1460
1728
  case s_chunk_size:
1461
1729
  {
1730
+ uint64_t t;
1731
+
1462
1732
  assert(parser->flags & F_CHUNKED);
1463
1733
 
1464
1734
  if (ch == CR) {
1465
- state = s_chunk_size_almost_done;
1735
+ parser->state = s_chunk_size_almost_done;
1466
1736
  break;
1467
1737
  }
1468
1738
 
1469
- c = unhex[(unsigned char)ch];
1739
+ unhex_val = unhex[(unsigned char)ch];
1470
1740
 
1471
- if (c == -1) {
1741
+ if (unhex_val == -1) {
1472
1742
  if (ch == ';' || ch == ' ') {
1473
- state = s_chunk_parameters;
1743
+ parser->state = s_chunk_parameters;
1474
1744
  break;
1475
1745
  }
1746
+
1747
+ SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
1476
1748
  goto error;
1477
1749
  }
1478
1750
 
1479
- parser->content_length *= 16;
1480
- parser->content_length += c;
1751
+ t = parser->content_length;
1752
+ t *= 16;
1753
+ t += unhex_val;
1754
+
1755
+ /* Overflow? */
1756
+ if (t < parser->content_length || t == ULLONG_MAX) {
1757
+ SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1758
+ goto error;
1759
+ }
1760
+
1761
+ parser->content_length = t;
1481
1762
  break;
1482
1763
  }
1483
1764
 
@@ -1486,7 +1767,7 @@ size_t http_parser_execute (http_parser *parser,
1486
1767
  assert(parser->flags & F_CHUNKED);
1487
1768
  /* just ignore this shit. TODO check for overflow */
1488
1769
  if (ch == CR) {
1489
- state = s_chunk_size_almost_done;
1770
+ parser->state = s_chunk_size_almost_done;
1490
1771
  break;
1491
1772
  }
1492
1773
  break;
@@ -1497,72 +1778,117 @@ size_t http_parser_execute (http_parser *parser,
1497
1778
  assert(parser->flags & F_CHUNKED);
1498
1779
  STRICT_CHECK(ch != LF);
1499
1780
 
1781
+ parser->nread = 0;
1782
+
1500
1783
  if (parser->content_length == 0) {
1501
1784
  parser->flags |= F_TRAILING;
1502
- state = s_header_field_start;
1785
+ parser->state = s_header_field_start;
1503
1786
  } else {
1504
- state = s_chunk_data;
1787
+ parser->state = s_chunk_data;
1505
1788
  }
1506
1789
  break;
1507
1790
  }
1508
1791
 
1509
1792
  case s_chunk_data:
1510
1793
  {
1511
- assert(parser->flags & F_CHUNKED);
1794
+ uint64_t to_read = MIN(parser->content_length,
1795
+ (uint64_t) ((data + len) - p));
1512
1796
 
1513
- to_read = MIN(pe - p, (int64_t)(parser->content_length));
1797
+ assert(parser->flags & F_CHUNKED);
1798
+ assert(parser->content_length != 0
1799
+ && parser->content_length != ULLONG_MAX);
1514
1800
 
1515
- if (to_read > 0) {
1516
- if (settings->on_body) settings->on_body(parser, p, to_read);
1517
- p += to_read - 1;
1518
- }
1801
+ /* See the explanation in s_body_identity for why the content
1802
+ * length and data pointers are managed this way.
1803
+ */
1804
+ MARK(body);
1805
+ parser->content_length -= to_read;
1806
+ p += to_read - 1;
1519
1807
 
1520
- if (to_read == parser->content_length) {
1521
- state = s_chunk_data_almost_done;
1808
+ if (parser->content_length == 0) {
1809
+ parser->state = s_chunk_data_almost_done;
1522
1810
  }
1523
1811
 
1524
- parser->content_length -= to_read;
1525
1812
  break;
1526
1813
  }
1527
1814
 
1528
1815
  case s_chunk_data_almost_done:
1529
1816
  assert(parser->flags & F_CHUNKED);
1817
+ assert(parser->content_length == 0);
1530
1818
  STRICT_CHECK(ch != CR);
1531
- state = s_chunk_data_done;
1819
+ parser->state = s_chunk_data_done;
1820
+ CALLBACK_DATA(body);
1532
1821
  break;
1533
1822
 
1534
1823
  case s_chunk_data_done:
1535
1824
  assert(parser->flags & F_CHUNKED);
1536
1825
  STRICT_CHECK(ch != LF);
1537
- state = s_chunk_size_start;
1826
+ parser->nread = 0;
1827
+ parser->state = s_chunk_size_start;
1538
1828
  break;
1539
1829
 
1540
1830
  default:
1541
1831
  assert(0 && "unhandled state");
1832
+ SET_ERRNO(HPE_INVALID_INTERNAL_STATE);
1542
1833
  goto error;
1543
1834
  }
1544
1835
  }
1545
1836
 
1546
- CALLBACK_NOCLEAR(header_field);
1547
- CALLBACK_NOCLEAR(header_value);
1548
- CALLBACK_NOCLEAR(fragment);
1549
- CALLBACK_NOCLEAR(query_string);
1550
- CALLBACK_NOCLEAR(path);
1551
- CALLBACK_NOCLEAR(url);
1837
+ /* Run callbacks for any marks that we have leftover after we ran our of
1838
+ * bytes. There should be at most one of these set, so it's OK to invoke
1839
+ * them in series (unset marks will not result in callbacks).
1840
+ *
1841
+ * We use the NOADVANCE() variety of callbacks here because 'p' has already
1842
+ * overflowed 'data' and this allows us to correct for the off-by-one that
1843
+ * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p'
1844
+ * value that's in-bounds).
1845
+ */
1846
+
1847
+ assert(((header_field_mark ? 1 : 0) +
1848
+ (header_value_mark ? 1 : 0) +
1849
+ (url_mark ? 1 : 0) +
1850
+ (body_mark ? 1 : 0)) <= 1);
1552
1851
 
1553
- parser->state = state;
1554
- parser->header_state = header_state;
1555
- parser->index = index;
1556
- parser->nread = nread;
1852
+ CALLBACK_DATA_NOADVANCE(header_field);
1853
+ CALLBACK_DATA_NOADVANCE(header_value);
1854
+ CALLBACK_DATA_NOADVANCE(url);
1855
+ CALLBACK_DATA_NOADVANCE(body);
1557
1856
 
1558
1857
  return len;
1559
1858
 
1560
1859
  error:
1561
- parser->state = s_dead;
1860
+ if (HTTP_PARSER_ERRNO(parser) == HPE_OK) {
1861
+ SET_ERRNO(HPE_UNKNOWN);
1862
+ }
1863
+
1562
1864
  return (p - data);
1563
1865
  }
1564
1866
 
1565
1867
 
1868
+ /* Does the parser need to see an EOF to find the end of the message? */
1869
+ int
1870
+ http_message_needs_eof (http_parser *parser)
1871
+ {
1872
+ if (parser->type == HTTP_REQUEST) {
1873
+ return 0;
1874
+ }
1875
+
1876
+ /* See RFC 2616 section 4.4 */
1877
+ if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */
1878
+ parser->status_code == 204 || /* No Content */
1879
+ parser->status_code == 304 || /* Not Modified */
1880
+ parser->flags & F_SKIPBODY) { /* response to a HEAD request */
1881
+ return 0;
1882
+ }
1883
+
1884
+ if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) {
1885
+ return 0;
1886
+ }
1887
+
1888
+ return 1;
1889
+ }
1890
+
1891
+
1566
1892
  int
1567
1893
  http_should_keep_alive (http_parser *parser)
1568
1894
  {
@@ -1570,17 +1896,15 @@ http_should_keep_alive (http_parser *parser)
1570
1896
  /* HTTP/1.1 */
1571
1897
  if (parser->flags & F_CONNECTION_CLOSE) {
1572
1898
  return 0;
1573
- } else {
1574
- return 1;
1575
1899
  }
1576
1900
  } else {
1577
1901
  /* HTTP/1.0 or earlier */
1578
- if (parser->flags & F_CONNECTION_KEEP_ALIVE) {
1579
- return 1;
1580
- } else {
1902
+ if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) {
1581
1903
  return 0;
1582
1904
  }
1583
1905
  }
1906
+
1907
+ return !http_message_needs_eof(parser);
1584
1908
  }
1585
1909
 
1586
1910
 
@@ -1593,10 +1917,142 @@ const char * http_method_str (enum http_method m)
1593
1917
  void
1594
1918
  http_parser_init (http_parser *parser, enum http_parser_type t)
1595
1919
  {
1920
+ void *data = parser->data; /* preserve application data */
1921
+ memset(parser, 0, sizeof(*parser));
1922
+ parser->data = data;
1596
1923
  parser->type = t;
1597
1924
  parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res));
1598
- parser->nread = 0;
1599
- parser->upgrade = 0;
1600
- parser->flags = 0;
1601
- parser->method = 0;
1925
+ parser->http_errno = HPE_OK;
1926
+ }
1927
+
1928
+ const char *
1929
+ http_errno_name(enum http_errno err) {
1930
+ assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0])));
1931
+ return http_strerror_tab[err].name;
1932
+ }
1933
+
1934
+ const char *
1935
+ http_errno_description(enum http_errno err) {
1936
+ assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0])));
1937
+ return http_strerror_tab[err].description;
1938
+ }
1939
+
1940
+ int
1941
+ http_parser_parse_url(const char *buf, size_t buflen, int is_connect,
1942
+ struct http_parser_url *u)
1943
+ {
1944
+ enum state s;
1945
+ const char *p;
1946
+ enum http_parser_url_fields uf, old_uf;
1947
+
1948
+ u->port = u->field_set = 0;
1949
+ s = is_connect ? s_req_host_start : s_req_spaces_before_url;
1950
+ uf = old_uf = UF_MAX;
1951
+
1952
+ for (p = buf; p < buf + buflen; p++) {
1953
+ s = parse_url_char(s, *p);
1954
+
1955
+ /* Figure out the next field that we're operating on */
1956
+ switch (s) {
1957
+ case s_dead:
1958
+ return 1;
1959
+
1960
+ /* Skip delimeters */
1961
+ case s_req_schema_slash:
1962
+ case s_req_schema_slash_slash:
1963
+ case s_req_host_start:
1964
+ case s_req_host_v6_start:
1965
+ case s_req_host_v6_end:
1966
+ case s_req_port_start:
1967
+ case s_req_query_string_start:
1968
+ case s_req_fragment_start:
1969
+ continue;
1970
+
1971
+ case s_req_schema:
1972
+ uf = UF_SCHEMA;
1973
+ break;
1974
+
1975
+ case s_req_host:
1976
+ case s_req_host_v6:
1977
+ uf = UF_HOST;
1978
+ break;
1979
+
1980
+ case s_req_port:
1981
+ uf = UF_PORT;
1982
+ break;
1983
+
1984
+ case s_req_path:
1985
+ uf = UF_PATH;
1986
+ break;
1987
+
1988
+ case s_req_query_string:
1989
+ uf = UF_QUERY;
1990
+ break;
1991
+
1992
+ case s_req_fragment:
1993
+ uf = UF_FRAGMENT;
1994
+ break;
1995
+
1996
+ default:
1997
+ assert(!"Unexpected state");
1998
+ return 1;
1999
+ }
2000
+
2001
+ /* Nothing's changed; soldier on */
2002
+ if (uf == old_uf) {
2003
+ u->field_data[uf].len++;
2004
+ continue;
2005
+ }
2006
+
2007
+ u->field_data[uf].off = p - buf;
2008
+ u->field_data[uf].len = 1;
2009
+
2010
+ u->field_set |= (1 << uf);
2011
+ old_uf = uf;
2012
+ }
2013
+
2014
+ /* CONNECT requests can only contain "hostname:port" */
2015
+ if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) {
2016
+ return 1;
2017
+ }
2018
+
2019
+ /* Make sure we don't end somewhere unexpected */
2020
+ switch (s) {
2021
+ case s_req_host_v6_start:
2022
+ case s_req_host_v6:
2023
+ case s_req_host_v6_end:
2024
+ case s_req_host:
2025
+ case s_req_port_start:
2026
+ return 1;
2027
+ default:
2028
+ break;
2029
+ }
2030
+
2031
+ if (u->field_set & (1 << UF_PORT)) {
2032
+ /* Don't bother with endp; we've already validated the string */
2033
+ unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10);
2034
+
2035
+ /* Ports have a max value of 2^16 */
2036
+ if (v > 0xffff) {
2037
+ return 1;
2038
+ }
2039
+
2040
+ u->port = (uint16_t) v;
2041
+ }
2042
+
2043
+ return 0;
2044
+ }
2045
+
2046
+ void
2047
+ http_parser_pause(http_parser *parser, int paused) {
2048
+ /* Users should only be pausing/unpausing a parser that is not in an error
2049
+ * state. In non-debug builds, there's not much that we can do about this
2050
+ * other than ignore it.
2051
+ */
2052
+ if (HTTP_PARSER_ERRNO(parser) == HPE_OK ||
2053
+ HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) {
2054
+ SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK);
2055
+ } else {
2056
+ assert(0 && "Attempting to pause parser in error state");
2057
+ }
1602
2058
  }