http_parser.rb 0.5.1-x86-mswin32-60 → 0.5.2-x86-mswin32-60

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/Gemfile.lock +16 -16
  2. data/LICENSE-MIT +20 -0
  3. data/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java +68 -11
  4. data/ext/ruby_http_parser/ruby_http_parser.c +74 -6
  5. data/ext/ruby_http_parser/vendor/http-parser-java/LICENSE-MIT +26 -1
  6. data/ext/ruby_http_parser/vendor/http-parser-java/README.md +23 -143
  7. data/ext/ruby_http_parser/vendor/http-parser-java/TODO +3 -0
  8. data/ext/ruby_http_parser/vendor/http-parser-java/build.xml +74 -0
  9. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.c +115 -61
  10. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.h +19 -3
  11. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPCallback.java +8 -0
  12. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPDataCallback.java +34 -0
  13. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPErrorCallback.java +12 -0
  14. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPException.java +4 -2
  15. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPMethod.java +64 -52
  16. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParser.java +5 -0
  17. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserSettings.java +323 -0
  18. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/{lolevel/Util.java → Util.java} +27 -28
  19. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java +259 -85
  20. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java +1 -0
  21. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Message.java +324 -0
  22. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Requests.java +69 -0
  23. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Responses.java +51 -0
  24. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Test.java +15 -0
  25. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestHeaderOverflowError.java +47 -0
  26. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestLoaderNG.java +183 -447
  27. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestNoOverflowLongBody.java +61 -0
  28. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/UnitTest.java +2 -1
  29. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Upgrade.java +26 -0
  30. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Util.java +165 -0
  31. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/WrongContentLength.java +58 -0
  32. data/ext/ruby_http_parser/vendor/http-parser-java/test.c +232 -29
  33. data/ext/ruby_http_parser/vendor/http-parser-java/test_permutations +1 -1
  34. data/ext/ruby_http_parser/vendor/http-parser-java/test_unit +1 -1
  35. data/ext/ruby_http_parser/vendor/http-parser-java/test_utf8 +1 -0
  36. data/ext/ruby_http_parser/vendor/http-parser-java/tests.dumped +154 -7
  37. data/ext/ruby_http_parser/vendor/http-parser-java/tests.utf8 +17 -0
  38. data/ext/ruby_http_parser/vendor/http-parser/LICENSE-MIT +1 -1
  39. data/ext/ruby_http_parser/vendor/http-parser/http_parser.c +52 -10
  40. data/ext/ruby_http_parser/vendor/http-parser/http_parser.h +3 -1
  41. data/ext/ruby_http_parser/vendor/http-parser/test.c +89 -3
  42. data/http_parser.rb.gemspec +8 -2
  43. data/lib/http_parser.rb +17 -0
  44. data/spec/parser_spec.rb +97 -6
  45. data/tasks/compile.rake +3 -1
  46. metadata +83 -20
  47. data/ext/ruby_http_parser/vendor/http-parser-java/CONTRIBUTIONS +0 -4
@@ -1,35 +1,34 @@
1
- package http_parser.lolevel;
1
+ package http_parser;
2
2
 
3
3
  import java.nio.ByteBuffer;
4
- import http_parser.HTTPException;
5
4
 
6
5
  public class Util {
7
- public static String toString(HTTPParser p) {
8
- StringBuilder builder = new StringBuilder();
9
-
10
- // the stuff up to the break is ephermeral and only meaningful
11
- // while the parser is parsing. In general, this method is
12
- // probably only useful during debugging.
13
-
14
- builder.append("state :"); builder.append(p.state); builder.append("\n");
15
- builder.append("header_state :"); builder.append(p.header_state); builder.append("\n");
16
- builder.append("strict :"); builder.append(p.strict); builder.append("\n");
17
- builder.append("index :"); builder.append(p.index); builder.append("\n");
18
- builder.append("flags :"); builder.append(p.flags); builder.append("\n");
19
- builder.append("nread :"); builder.append(p.nread); builder.append("\n");
20
- builder.append("content_length :"); builder.append(p.content_length); builder.append("\n");
21
-
22
-
23
- builder.append("type :"); builder.append(p.type); builder.append("\n");
24
- builder.append("http_major :"); builder.append(p.http_major); builder.append("\n");
25
- builder.append("http_minor :"); builder.append(p.http_minor); builder.append("\n");
26
- builder.append("status_code :"); builder.append(p.status_code); builder.append("\n");
27
- builder.append("method :"); builder.append(p.method); builder.append("\n");
28
- builder.append("upgrade :"); builder.append(p.upgrade); builder.append("\n");
29
-
30
- return builder.toString();
31
-
32
- }
6
+ // public static String toString(http_parser.lolevel.HTTPParser p) {
7
+ // StringBuilder builder = new StringBuilder();
8
+ //
9
+ // // the stuff up to the break is ephermeral and only meaningful
10
+ // // while the parser is parsing. In general, this method is
11
+ // // probably only useful during debugging.
12
+ //
13
+ // builder.append("state :"); builder.append(p.state); builder.append("\n");
14
+ // builder.append("header_state :"); builder.append(p.header_state); builder.append("\n");
15
+ // builder.append("strict :"); builder.append(p.strict); builder.append("\n");
16
+ // builder.append("index :"); builder.append(p.index); builder.append("\n");
17
+ // builder.append("flags :"); builder.append(p.flags); builder.append("\n");
18
+ // builder.append("nread :"); builder.append(p.nread); builder.append("\n");
19
+ // builder.append("content_length :"); builder.append(p.content_length); builder.append("\n");
20
+ //
21
+ //
22
+ // builder.append("type :"); builder.append(p.type); builder.append("\n");
23
+ // builder.append("http_major :"); builder.append(p.http_major); builder.append("\n");
24
+ // builder.append("http_minor :"); builder.append(p.http_minor); builder.append("\n");
25
+ // builder.append("status_code :"); builder.append(p.status_code); builder.append("\n");
26
+ // builder.append("method :"); builder.append(p.method); builder.append("\n");
27
+ // builder.append("upgrade :"); builder.append(p.upgrade); builder.append("\n");
28
+ //
29
+ // return builder.toString();
30
+ //
31
+ // }
33
32
 
34
33
  public static String error (String mes, ByteBuffer b, int begining) {
35
34
  // the error message should look like this:
@@ -22,19 +22,21 @@ public class HTTPParser {
22
22
  int nread;
23
23
  int content_length;
24
24
 
25
-
25
+ int start_position;
26
+ ByteBuffer data;
27
+
26
28
  /** READ-ONLY **/
27
- protected int http_major;
28
- protected int http_minor;
29
- protected int status_code; /* responses only */
30
- protected HTTPMethod method; /* requests only */
29
+ public int http_major;
30
+ public int http_minor;
31
+ public int status_code; /* responses only */
32
+ public HTTPMethod method; /* requests only */
31
33
 
32
34
  /* true = Upgrade header was present and the parser has exited because of that.
33
35
  * false = No upgrade header present.
34
36
  * Should be checked when http_parser_execute() returns in addition to
35
37
  * error checking.
36
38
  */
37
- protected boolean upgrade;
39
+ public boolean upgrade;
38
40
 
39
41
  /** PUBLIC **/
40
42
  // TODO : this is used in c to maintain application state.
@@ -95,21 +97,39 @@ public class HTTPParser {
95
97
  * correctly (obviously) and a will be updated approriately when the
96
98
  * method returns to reflect the consumed data.
97
99
  */
98
- public void execute(ParserSettings settings, ByteBuffer data) {
100
+ public int execute(ParserSettings settings, ByteBuffer data) {
99
101
 
100
102
  int p = data.position();
101
103
  int p_err = p; // this is used for pretty printing errors.
104
+
105
+ this.start_position = p;
106
+ this.data = data;
102
107
 
103
108
  // In case the headers don't provide information about the content
104
109
  // length, `execute` needs to be called with an empty buffer to
105
110
  // indicate that all the data has been send be the client/server,
106
111
  // else there is no way of knowing the message is complete.
107
112
  int len = (data.limit() - data.position());
108
- if (0 == len) {
109
- if (State.body_identity_eof == state) {
110
- settings.call_on_message_complete(this);
111
- }
112
- }
113
+ if (0 == len) {
114
+ // if (State.body_identity_eof == state) {
115
+ // settings.call_on_message_complete(this);
116
+ // }
117
+ switch (state) {
118
+ case body_identity_eof:
119
+ settings.call_on_message_complete(this);
120
+ return data.position() - start_position;
121
+
122
+ case dead:
123
+ case start_res_or_res:
124
+ case start_res:
125
+ case start_req:
126
+ return data.position() - start_position;
127
+
128
+ default:
129
+ // should we really consider this an error!?
130
+ throw new HTTPException("empty bytes! "+state); // error
131
+ }
132
+ }
113
133
 
114
134
 
115
135
  // in case the _previous_ call to the parser only has data to get to
@@ -151,6 +171,7 @@ public class HTTPParser {
151
171
  int pe = data.limit();
152
172
 
153
173
  byte ch = data.get(); // the current character to process.
174
+ int chi = ch & 0xff; // utility, ch without signedness for table lookups.
154
175
  byte c = -1; // utility variably used for up- and downcasing etc.
155
176
  int to_read = 0; // used to keep track of how much of body, etc. is left to read
156
177
 
@@ -158,9 +179,10 @@ public class HTTPParser {
158
179
  ++nread;
159
180
  if (nread > HTTP_MAX_HEADER_SIZE) {
160
181
  settings.call_on_error(this, "possible buffer overflow", data, p_err);
182
+ return error();
161
183
  }
162
184
  }
163
-
185
+ //p(state + ":" + ch +":"+p);
164
186
  switch (state) {
165
187
  /*
166
188
  * this state is used after a 'Connection: close' message
@@ -168,6 +190,7 @@ public class HTTPParser {
168
190
  */
169
191
  case dead:
170
192
  settings.call_on_error(this, "Connection already closed", data, p_err);
193
+ return error();
171
194
 
172
195
 
173
196
 
@@ -187,6 +210,7 @@ public class HTTPParser {
187
210
  method = start_req_method_assign(ch);
188
211
  if (null == method) {
189
212
  settings.call_on_error(this, "invalid method", data, p_err);
213
+ return error();
190
214
  }
191
215
  index = 1;
192
216
  state = State.req_method;
@@ -202,6 +226,7 @@ public class HTTPParser {
202
226
  } else {
203
227
  if (E != ch) {
204
228
  settings.call_on_error(this, "not E", data, p_err);
229
+ return error();
205
230
  }
206
231
  type = ParserType.HTTP_REQUEST;
207
232
  method = HTTPMethod.HTTP_HEAD;
@@ -227,6 +252,7 @@ public class HTTPParser {
227
252
  break;
228
253
  default:
229
254
  settings.call_on_error(this, "Not H or CR/LF", data, p_err);
255
+ return error();
230
256
  }
231
257
  break;
232
258
 
@@ -235,24 +261,28 @@ public class HTTPParser {
235
261
  case res_H:
236
262
  if (strict && T != ch) {
237
263
  settings.call_on_error(this, "Not T", data, p_err);
264
+ return error();
238
265
  }
239
266
  state = State.res_HT;
240
267
  break;
241
268
  case res_HT:
242
269
  if (strict && T != ch) {
243
270
  settings.call_on_error(this, "Not T2", data, p_err);
271
+ return error();
244
272
  }
245
273
  state = State.res_HTT;
246
274
  break;
247
275
  case res_HTT:
248
276
  if (strict && P != ch) {
249
277
  settings.call_on_error(this, "Not P", data, p_err);
278
+ return error();
250
279
  }
251
280
  state = State.res_HTTP;
252
281
  break;
253
282
  case res_HTTP:
254
283
  if (strict && SLASH != ch) {
255
284
  settings.call_on_error(this, "Not '/'", data, p_err);
285
+ return error();
256
286
  }
257
287
  state = State.res_first_http_major;
258
288
  break;
@@ -262,6 +292,7 @@ public class HTTPParser {
262
292
  case res_first_http_major:
263
293
  if (!isDigit(ch)) {
264
294
  settings.call_on_error(this, "Not a digit", data, p_err);
295
+ return error();
265
296
  }
266
297
  http_major = (int) ch - 0x30;
267
298
  state = State.res_http_major;
@@ -270,17 +301,19 @@ public class HTTPParser {
270
301
  /* major HTTP version or dot */
271
302
  case res_http_major:
272
303
  if (DOT == ch) {
273
- state = State.res_http_minor;
304
+ state = State.res_first_http_minor;
274
305
  break;
275
306
  }
276
307
  if (!isDigit(ch)) {
277
308
  settings.call_on_error(this, "Not a digit", data, p_err);
309
+ return error();
278
310
  }
279
311
  http_major *= 10;
280
312
  http_major += (ch - 0x30);
281
313
 
282
314
  if (http_major > 999) {
283
315
  settings.call_on_error(this, "invalid http major version: "+http_major, data, p_err);
316
+ return error();
284
317
  }
285
318
  break;
286
319
 
@@ -288,6 +321,7 @@ public class HTTPParser {
288
321
  case res_first_http_minor:
289
322
  if (!isDigit(ch)) {
290
323
  settings.call_on_error(this, "Not a digit", data, p_err);
324
+ return error();
291
325
  }
292
326
  http_minor = (int)ch - 0x30;
293
327
  state = State.res_http_minor;
@@ -301,12 +335,13 @@ public class HTTPParser {
301
335
  }
302
336
  if (!isDigit(ch)) {
303
337
  settings.call_on_error(this, "Not a digit", data, p_err);
338
+ return error();
304
339
  }
305
340
  http_minor *= 10;
306
341
  http_minor += (ch - 0x30);
307
-
308
342
  if (http_minor > 999) {
309
343
  settings.call_on_error(this, "invalid http minor version: "+http_minor, data, p_err);
344
+ return error();
310
345
  }
311
346
  break;
312
347
 
@@ -318,6 +353,7 @@ public class HTTPParser {
318
353
  break;
319
354
  }
320
355
  settings.call_on_error(this, "Not a digit (status code)", data, p_err);
356
+ return error();
321
357
  }
322
358
  status_code = (int)ch - 0x30;
323
359
  state = State.res_status_code;
@@ -337,6 +373,7 @@ public class HTTPParser {
337
373
  break;
338
374
  default:
339
375
  settings.call_on_error(this, "not a valid status code", data, p_err);
376
+ return error();
340
377
  }
341
378
  break;
342
379
  }
@@ -344,6 +381,7 @@ public class HTTPParser {
344
381
  status_code += (int)ch - 0x30;
345
382
  if (status_code > 999) {
346
383
  settings.call_on_error(this, "ridiculous status code:"+status_code, data, p_err);
384
+ return error();
347
385
  }
348
386
  break;
349
387
 
@@ -365,6 +403,7 @@ public class HTTPParser {
365
403
  case res_line_almost_done:
366
404
  if (strict && LF != ch) {
367
405
  settings.call_on_error(this, "not LF", data, p_err);
406
+ return error();
368
407
  }
369
408
  state = State.header_field_start;
370
409
  break;
@@ -372,7 +411,7 @@ public class HTTPParser {
372
411
 
373
412
 
374
413
  case start_req:
375
- if (CR==ch || LF == LF) {
414
+ if (CR==ch || LF == ch) {
376
415
  break;
377
416
  }
378
417
  flags = 0;
@@ -381,6 +420,7 @@ public class HTTPParser {
381
420
  method = start_req_method_assign(ch);
382
421
  if (null == method) {
383
422
  settings.call_on_error(this, "invalid method", data, p_err);
423
+ return error();
384
424
  }
385
425
  index = 1;
386
426
  state = State.req_method;
@@ -391,6 +431,7 @@ public class HTTPParser {
391
431
  case req_method:
392
432
  if (0 == ch) {
393
433
  settings.call_on_error(this, "NULL in method", data, p_err);
434
+ return error();
394
435
  }
395
436
 
396
437
  byte [] arr = method.bytes;
@@ -410,6 +451,8 @@ public class HTTPParser {
410
451
  method = HTTPMethod.HTTP_MOVE;
411
452
  } else if (1 == index && E == ch) {
412
453
  method = HTTPMethod.HTTP_MERGE;
454
+ } else if (1 == index && DASH == ch) { /* M-SEARCH */
455
+ method = HTTPMethod.HTTP_MSEARCH;
413
456
  } else if (2 == index && A == ch) {
414
457
  method = HTTPMethod.HTTP_MKACTIVITY;
415
458
  }
@@ -417,10 +460,13 @@ public class HTTPParser {
417
460
  method = HTTPMethod.HTTP_PROPFIND;
418
461
  } else if (1 == index && HTTPMethod.HTTP_POST == method && U == ch) {
419
462
  method = HTTPMethod.HTTP_PUT;
463
+ } else if (2 == index && HTTPMethod.HTTP_UNLOCK == method && S == ch) {
464
+ method = HTTPMethod.HTTP_UNSUBSCRIBE;
420
465
  } else if (4 == index && HTTPMethod.HTTP_PROPFIND == method && P == ch) {
421
466
  method = HTTPMethod.HTTP_PROPPATCH;
422
467
  } else {
423
468
  settings.call_on_error(this, "Invalid HTTP method", data, p_err);
469
+ return error();
424
470
  }
425
471
 
426
472
  ++index;
@@ -433,7 +479,7 @@ public class HTTPParser {
433
479
  if (SPACE == ch) {
434
480
  break;
435
481
  }
436
- if (SLASH == ch) {
482
+ if (SLASH == ch || STAR == ch) {
437
483
  url_mark = p;
438
484
  path_mark = p;
439
485
  state = State.req_path;
@@ -445,6 +491,7 @@ public class HTTPParser {
445
491
  break;
446
492
  }
447
493
  settings.call_on_error(this, "Invalid something", data, p_err);
494
+ return error();
448
495
 
449
496
  case req_schema:
450
497
  if (isAtoZ(ch)){
@@ -453,15 +500,17 @@ public class HTTPParser {
453
500
  if (COLON == ch) {
454
501
  state = State.req_schema_slash;
455
502
  break;
456
- } else if (DOT == ch) {
503
+ } else if (DOT == ch || isDigit(ch)) {
457
504
  state = State.req_host;
458
505
  break;
459
506
  }
460
507
  settings.call_on_error(this, "invalid char in schema: "+ch, data, p_err);
508
+ return error();
461
509
 
462
510
  case req_schema_slash:
463
511
  if (strict && SLASH != ch) {
464
512
  settings.call_on_error(this, "invalid char in schema, not /", data, p_err);
513
+ return error();
465
514
  }
466
515
  state = State.req_schema_slash_slash;
467
516
  break;
@@ -469,6 +518,7 @@ public class HTTPParser {
469
518
  case req_schema_slash_slash:
470
519
  if (strict && SLASH != ch) {
471
520
  settings.call_on_error(this, "invalid char in schema, not /", data, p_err);
521
+ return error();
472
522
  }
473
523
  state = State.req_host;
474
524
  break;
@@ -494,8 +544,12 @@ public class HTTPParser {
494
544
  url_mark = -1;
495
545
  state = State.req_http_start;
496
546
  break;
547
+ case QMARK:
548
+ state = State.req_query_string_start;
549
+ break;
497
550
  default:
498
551
  settings.call_on_error(this, "host error in method line", data, p_err);
552
+ return error();
499
553
  }
500
554
  break;
501
555
 
@@ -515,13 +569,17 @@ public class HTTPParser {
515
569
  url_mark = -1;
516
570
  state = State.req_http_start;
517
571
  break;
572
+ case QMARK:
573
+ state = State.req_query_string_start;
574
+ break;
518
575
  default:
519
576
  settings.call_on_error(this, "invalid port", data, p_err);
577
+ return error();
520
578
  }
521
579
  break;
522
580
 
523
581
  case req_path:
524
- if (normal_url_char[ch]) break;
582
+ if (normal_url_char[chi]) break;
525
583
  switch (ch) {
526
584
  case SPACE:
527
585
  settings.call_on_url(this,data,url_mark, p-url_mark);
@@ -571,11 +629,12 @@ public class HTTPParser {
571
629
 
572
630
  default:
573
631
  settings.call_on_error(this, "unexpected char in path", data, p_err);
632
+ return error();
574
633
  }
575
634
  break;
576
635
 
577
636
  case req_query_string_start:
578
- if (normal_url_char[ch]) {
637
+ if (normal_url_char[chi]) {
579
638
  query_string_mark = p;
580
639
  state = State.req_query_string;
581
640
  break;
@@ -605,11 +664,12 @@ public class HTTPParser {
605
664
  break;
606
665
  default:
607
666
  settings.call_on_error(this, "unexpected char in path", data, p_err);
667
+ return error();
608
668
  }
609
669
  break;
610
670
 
611
671
  case req_query_string:
612
- if (normal_url_char[ch]) {
672
+ if (normal_url_char[chi]) {
613
673
  break;
614
674
  }
615
675
 
@@ -652,11 +712,12 @@ public class HTTPParser {
652
712
  break;
653
713
  default:
654
714
  settings.call_on_error(this, "unexpected char in path", data, p_err);
715
+ return error();
655
716
  }
656
717
  break;
657
718
 
658
719
  case req_fragment_start:
659
- if (normal_url_char[ch]) {
720
+ if (normal_url_char[chi]) {
660
721
  fragment_mark = p;
661
722
  state = State.req_fragment;
662
723
  break;
@@ -691,11 +752,12 @@ public class HTTPParser {
691
752
  break;
692
753
  default:
693
754
  settings.call_on_error(this, "unexpected char in path", data, p_err);
755
+ return error();
694
756
  }
695
757
  break;
696
758
 
697
759
  case req_fragment:
698
- if (normal_url_char[ch]) {
760
+ if (normal_url_char[chi]) {
699
761
  break;
700
762
  }
701
763
 
@@ -734,6 +796,7 @@ public class HTTPParser {
734
796
  break;
735
797
  default:
736
798
  settings.call_on_error(this, "unexpected char in path", data, p_err);
799
+ return error();
737
800
  }
738
801
  break;
739
802
  /******************* URL *******************/
@@ -750,12 +813,14 @@ public class HTTPParser {
750
813
  break;
751
814
  default:
752
815
  settings.call_on_error(this, "error in req_http_H", data, p_err);
816
+ return error();
753
817
  }
754
818
  break;
755
819
 
756
820
  case req_http_H:
757
821
  if (strict && T != ch) {
758
822
  settings.call_on_error(this, "unexpected char", data, p_err);
823
+ return error();
759
824
  }
760
825
  state = State.req_http_HT;
761
826
  break;
@@ -763,6 +828,7 @@ public class HTTPParser {
763
828
  case req_http_HT:
764
829
  if (strict && T != ch) {
765
830
  settings.call_on_error(this, "unexpected char", data, p_err);
831
+ return error();
766
832
  }
767
833
  state = State.req_http_HTT;
768
834
  break;
@@ -770,6 +836,7 @@ public class HTTPParser {
770
836
  case req_http_HTT:
771
837
  if (strict && P != ch) {
772
838
  settings.call_on_error(this, "unexpected char", data, p_err);
839
+ return error();
773
840
  }
774
841
  state = State.req_http_HTTP;
775
842
  break;
@@ -777,6 +844,7 @@ public class HTTPParser {
777
844
  case req_http_HTTP:
778
845
  if (strict && SLASH != ch) {
779
846
  settings.call_on_error(this, "unexpected char", data, p_err);
847
+ return error();
780
848
  }
781
849
  state = req_first_http_major;
782
850
  break;
@@ -785,6 +853,7 @@ public class HTTPParser {
785
853
  case req_first_http_major:
786
854
  if (!isDigit(ch)) {
787
855
  settings.call_on_error(this, "non digit in http major", data, p_err);
856
+ return error();
788
857
  }
789
858
  http_major = (int)ch - 0x30;
790
859
  state = State.req_http_major;
@@ -799,6 +868,7 @@ public class HTTPParser {
799
868
 
800
869
  if (!isDigit(ch)) {
801
870
  settings.call_on_error(this, "non digit in http major", data, p_err);
871
+ return error();
802
872
  }
803
873
 
804
874
  http_major *= 10;
@@ -806,6 +876,7 @@ public class HTTPParser {
806
876
 
807
877
  if (http_major > 999) {
808
878
  settings.call_on_error(this, "ridiculous http major", data, p_err);
879
+ return error();
809
880
  };
810
881
  break;
811
882
 
@@ -813,6 +884,7 @@ public class HTTPParser {
813
884
  case req_first_http_minor:
814
885
  if (!isDigit(ch)) {
815
886
  settings.call_on_error(this, "non digit in http minor", data, p_err);
887
+ return error();
816
888
  }
817
889
  http_minor = (int)ch - 0x30;
818
890
  state = State.req_http_minor;
@@ -833,6 +905,7 @@ public class HTTPParser {
833
905
 
834
906
  if (!isDigit(ch)) {
835
907
  settings.call_on_error(this, "non digit in http minor", data, p_err);
908
+ return error();
836
909
  }
837
910
 
838
911
  http_minor *= 10;
@@ -841,6 +914,7 @@ public class HTTPParser {
841
914
 
842
915
  if (http_minor > 999) {
843
916
  settings.call_on_error(this, "ridiculous http minor", data, p_err);
917
+ return error();
844
918
  };
845
919
 
846
920
  break;
@@ -850,6 +924,7 @@ public class HTTPParser {
850
924
  {
851
925
  if (ch != LF) {
852
926
  settings.call_on_error(this, "missing LF after request line", data, p_err);
927
+ return error();
853
928
  }
854
929
  state = State.header_field_start;
855
930
  break;
@@ -873,14 +948,19 @@ public class HTTPParser {
873
948
  state = State.headers_almost_done;
874
949
  if (!headers_almost_done(ch, settings)) {
875
950
  settings.call_on_error(this, "header not properly completed", data, p_err);
951
+ return error();
952
+ }
953
+ if (upgrade) {
954
+ return data.position() - start_position;
876
955
  }
877
956
  break;
878
957
  }
879
958
 
880
- c = upper(ch);
959
+ c = token(ch);
881
960
 
882
- if (c < A || Z < c) {
883
- settings.call_on_error(this, "invalid char in header", data, p_err);
961
+ if (0 == c) {
962
+ settings.call_on_error(this, "invalid char in header:"+c, data, p_err);
963
+ return error();
884
964
  };
885
965
 
886
966
  header_field_mark = p;
@@ -916,7 +996,7 @@ public class HTTPParser {
916
996
 
917
997
  case header_field:
918
998
  {
919
- c = (byte) acceptable_header[ch];
999
+ c = token(ch);
920
1000
  if (0 != c) {
921
1001
  switch (header_state) {
922
1002
  case general:
@@ -1011,6 +1091,7 @@ public class HTTPParser {
1011
1091
 
1012
1092
  default:
1013
1093
  settings.call_on_error(this, "Unknown Header State", data, p_err);
1094
+ return error();
1014
1095
  } // switch: header_state
1015
1096
  break;
1016
1097
  } // 0 != c
@@ -1040,6 +1121,7 @@ public class HTTPParser {
1040
1121
  }
1041
1122
 
1042
1123
  settings.call_on_error(this, "invalid header field", data, p_err);
1124
+ return error();
1043
1125
  }
1044
1126
 
1045
1127
 
@@ -1053,30 +1135,27 @@ public class HTTPParser {
1053
1135
  state = State.header_value;
1054
1136
  index = 0;
1055
1137
 
1056
- c = (byte)acceptable_header[ch];
1057
-
1058
- if (c == 0) {
1059
- if (CR == ch) {
1060
- settings.call_on_header_value(this, data, header_value_mark, p-header_value_mark);
1061
- header_value_mark = -1;
1062
1138
 
1063
- header_state = HState.general;
1064
- state = State.header_almost_done;
1065
- break;
1066
- }
1067
-
1068
- if (LF == ch) {
1069
- settings.call_on_header_value(this, data, header_value_mark, p-header_value_mark);
1070
- header_value_mark = -1;
1071
-
1072
- state = State.header_field_start;
1073
- break;
1074
- }
1139
+ if (CR == ch) {
1140
+ settings.call_on_header_value(this, data, header_value_mark, p-header_value_mark);
1141
+ header_value_mark = -1;
1075
1142
 
1076
1143
  header_state = HState.general;
1144
+ state = State.header_almost_done;
1145
+ break;
1146
+ }
1147
+
1148
+ if (LF == ch) {
1149
+ settings.call_on_header_value(this, data, header_value_mark, p-header_value_mark);
1150
+ header_value_mark = -1;
1151
+
1152
+ state = State.header_field_start;
1077
1153
  break;
1078
1154
  }
1079
1155
 
1156
+
1157
+ c = upper(ch);
1158
+
1080
1159
  switch (header_state) {
1081
1160
  case upgrade:
1082
1161
  flags |= F_UPGRADE;
@@ -1095,6 +1174,7 @@ public class HTTPParser {
1095
1174
  case content_length:
1096
1175
  if (!isDigit(ch)) {
1097
1176
  settings.call_on_error(this, "Content-Length not numeric", data, p_err);
1177
+ return error();
1098
1178
  }
1099
1179
  content_length = (int)ch - 0x30;
1100
1180
  break;
@@ -1122,29 +1202,27 @@ public class HTTPParser {
1122
1202
 
1123
1203
  case header_value:
1124
1204
  {
1125
- c = (byte)acceptable_header[ch];
1126
1205
 
1127
- if (c == 0) {
1128
- if (CR == ch) {
1129
- settings.call_on_header_value(this, data, header_value_mark, p-header_value_mark);
1130
- header_value_mark = -1;
1206
+ if (CR == ch) {
1207
+ settings.call_on_header_value(this, data, header_value_mark, p-header_value_mark);
1208
+ header_value_mark = -1;
1131
1209
 
1132
- state = State.header_almost_done;
1133
- break;
1134
- }
1210
+ state = State.header_almost_done;
1211
+ break;
1212
+ }
1135
1213
 
1136
- if (LF == ch) {
1137
- settings.call_on_header_value(this, data, header_value_mark, p-header_value_mark);
1138
- header_value_mark = -1;
1139
-
1140
- if (!header_almost_done(ch)) {
1141
- settings.call_on_error(this,"incorrect header ending, expection LF", data, p_err);
1142
- }
1143
- break;
1214
+ if (LF == ch) {
1215
+ settings.call_on_header_value(this, data, header_value_mark, p-header_value_mark);
1216
+ header_value_mark = -1;
1217
+
1218
+ if (!header_almost_done(ch)) {
1219
+ settings.call_on_error(this,"incorrect header ending, expection LF", data, p_err);
1220
+ return error();
1144
1221
  }
1145
1222
  break;
1146
1223
  }
1147
1224
 
1225
+ c = upper(ch);
1148
1226
  switch (header_state) {
1149
1227
  case general:
1150
1228
  break;
@@ -1152,6 +1230,7 @@ public class HTTPParser {
1152
1230
  case connection:
1153
1231
  case transfer_encoding:
1154
1232
  settings.call_on_error(this, "Shouldn't be here", data, p_err);
1233
+ return error();
1155
1234
 
1156
1235
  case content_length:
1157
1236
  if (SPACE == ch) {
@@ -1159,6 +1238,7 @@ public class HTTPParser {
1159
1238
  }
1160
1239
  if (!isDigit(ch)) {
1161
1240
  settings.call_on_error(this, "Content-Length not numeric", data, p_err);
1241
+ return error();
1162
1242
  }
1163
1243
 
1164
1244
  content_length *= 10;
@@ -1214,12 +1294,17 @@ public class HTTPParser {
1214
1294
  case header_almost_done:
1215
1295
  if (!header_almost_done(ch)) {
1216
1296
  settings.call_on_error(this,"incorrect header ending, expection LF", data, p_err);
1297
+ return error();
1217
1298
  }
1218
1299
  break;
1219
1300
 
1220
1301
  case headers_almost_done:
1221
1302
  if (!headers_almost_done(ch, settings)) {
1222
1303
  settings.call_on_error(this, "header not properly completed", data, p_err);
1304
+ return error();
1305
+ }
1306
+ if (upgrade) {
1307
+ return data.position()-start_position ;
1223
1308
  }
1224
1309
  break;
1225
1310
 
@@ -1258,13 +1343,20 @@ public class HTTPParser {
1258
1343
 
1259
1344
  /******************* Chunk *******************/
1260
1345
  case chunk_size_start:
1346
+ if (1 != this.nread) {
1347
+ settings.call_on_error(this, "nread != 1 (chunking)", data, p_err);
1348
+ return error();
1349
+
1350
+ }
1261
1351
  if (0 == (flags & F_CHUNKED)) {
1262
1352
  settings.call_on_error(this, "not chunked", data, p_err);
1353
+ return error();
1263
1354
  }
1264
1355
 
1265
- c = UNHEX[ch];
1356
+ c = UNHEX[chi];
1266
1357
  if (c == -1) {
1267
1358
  settings.call_on_error(this, "invalid hex char in chunk content length", data, p_err);
1359
+ return error();
1268
1360
  }
1269
1361
  content_length = c;
1270
1362
  state = State.chunk_size;
@@ -1275,6 +1367,7 @@ public class HTTPParser {
1275
1367
  case chunk_size:
1276
1368
  if (0 == (flags & F_CHUNKED)) {
1277
1369
  settings.call_on_error(this, "not chunked", data, p_err);
1370
+ return error();
1278
1371
  }
1279
1372
 
1280
1373
  if (CR == ch) {
@@ -1282,7 +1375,7 @@ public class HTTPParser {
1282
1375
  break;
1283
1376
  }
1284
1377
 
1285
- c = UNHEX[ch];
1378
+ c = UNHEX[chi];
1286
1379
 
1287
1380
  if (c == -1) {
1288
1381
  if (SEMI == ch || SPACE == ch) {
@@ -1290,6 +1383,7 @@ public class HTTPParser {
1290
1383
  break;
1291
1384
  }
1292
1385
  settings.call_on_error(this, "invalid hex char in chunk content length", data, p_err);
1386
+ return error();
1293
1387
  }
1294
1388
 
1295
1389
  content_length *= 16;
@@ -1301,6 +1395,7 @@ public class HTTPParser {
1301
1395
  case chunk_parameters:
1302
1396
  if (0 == (flags & F_CHUNKED)) {
1303
1397
  settings.call_on_error(this, "not chunked", data, p_err);
1398
+ return error();
1304
1399
  }
1305
1400
  /* just ignore this shit. TODO check for overflow */
1306
1401
  if (CR == ch) {
@@ -1314,11 +1409,15 @@ public class HTTPParser {
1314
1409
  case chunk_size_almost_done:
1315
1410
  if (0 == (flags & F_CHUNKED)) {
1316
1411
  settings.call_on_error(this, "not chunked", data, p_err);
1412
+ return error();
1317
1413
  }
1318
1414
  if (strict && LF != ch) {
1319
1415
  settings.call_on_error(this, "expected LF at end of chunk size", data, p_err);
1416
+ return error();
1320
1417
  }
1321
1418
 
1419
+ this.nread = 0;
1420
+
1322
1421
  if (0 == content_length) {
1323
1422
  flags |= F_TRAILING;
1324
1423
  state = State.header_field_start;
@@ -1333,6 +1432,7 @@ public class HTTPParser {
1333
1432
  {
1334
1433
  if (0 == (flags & F_CHUNKED)) {
1335
1434
  settings.call_on_error(this, "not chunked", data, p_err);
1435
+ return error();
1336
1436
  }
1337
1437
 
1338
1438
  to_read = min(pe-p, content_length);
@@ -1354,9 +1454,11 @@ public class HTTPParser {
1354
1454
  case chunk_data_almost_done:
1355
1455
  if (0 == (flags & F_CHUNKED)) {
1356
1456
  settings.call_on_error(this, "not chunked", data, p_err);
1457
+ return error();
1357
1458
  }
1358
1459
  if (strict && CR != ch) {
1359
1460
  settings.call_on_error(this, "chunk data terminated incorrectly, expected CR", data, p_err);
1461
+ return error();
1360
1462
  }
1361
1463
  state = State.chunk_data_done;
1362
1464
  break;
@@ -1366,9 +1468,11 @@ public class HTTPParser {
1366
1468
  case chunk_data_done:
1367
1469
  if (0 == (flags & F_CHUNKED)) {
1368
1470
  settings.call_on_error(this, "not chunked", data, p_err);
1471
+ return error();
1369
1472
  }
1370
1473
  if (strict && LF != ch) {
1371
1474
  settings.call_on_error(this, "chunk data terminated incorrectly, expected LF", data, p_err);
1475
+ return error();
1372
1476
  }
1373
1477
  state = State.chunk_size_start;
1374
1478
  break;
@@ -1378,6 +1482,7 @@ public class HTTPParser {
1378
1482
 
1379
1483
  default:
1380
1484
  settings.call_on_error(this, "unhandled state", data, p_err);
1485
+ return error();
1381
1486
 
1382
1487
  } // switch
1383
1488
  } // while
@@ -1394,9 +1499,15 @@ public class HTTPParser {
1394
1499
  settings.call_on_query_string(this, data, query_string_mark, p-query_string_mark);
1395
1500
  settings.call_on_path (this, data, path_mark, p-path_mark);
1396
1501
  settings.call_on_url (this, data, url_mark, p-url_mark);
1397
-
1502
+
1503
+ return data.position()-start_position;
1398
1504
  } // execute
1399
1505
 
1506
+ int error () {
1507
+ this.state = State.dead;
1508
+ return this.data.position()-start_position;
1509
+ }
1510
+
1400
1511
  /* If http_should_keep_alive() in the on_headers_complete or
1401
1512
  * on_message_complete callback returns true, then this will be should be
1402
1513
  * the last message on the connection.
@@ -1442,6 +1553,10 @@ public class HTTPParser {
1442
1553
  char c = (char)(b);
1443
1554
  return (byte)Character.toUpperCase(c);
1444
1555
  }
1556
+
1557
+ byte token(byte b) {
1558
+ return (byte)tokens[b];
1559
+ }
1445
1560
 
1446
1561
 
1447
1562
  HTTPMethod start_req_method_assign(byte c){
@@ -1451,12 +1566,14 @@ public class HTTPParser {
1451
1566
  case G: return HTTPMethod.HTTP_GET;
1452
1567
  case H: return HTTPMethod.HTTP_HEAD;
1453
1568
  case L: return HTTPMethod.HTTP_LOCK;
1454
- case M: return HTTPMethod.HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE */
1569
+ case M: return HTTPMethod.HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH */
1570
+ case N: return HTTPMethod.HTTP_NOTIFY;
1455
1571
  case O: return HTTPMethod.HTTP_OPTIONS;
1456
1572
  case P: return HTTPMethod.HTTP_POST; /* or PROPFIND, PROPPATH, PUT */
1457
1573
  case R: return HTTPMethod.HTTP_REPORT;
1574
+ case S: return HTTPMethod.HTTP_SUBSCRIBE;
1458
1575
  case T: return HTTPMethod.HTTP_TRACE;
1459
- case U: return HTTPMethod.HTTP_UNLOCK;
1576
+ case U: return HTTPMethod.HTTP_UNLOCK; /* or UNSUBSCRIBE */
1460
1577
  }
1461
1578
  return null; // ugh.
1462
1579
  }
@@ -1489,7 +1606,6 @@ public class HTTPParser {
1489
1606
  if (LF != ch) {
1490
1607
  return false;
1491
1608
  }
1492
-
1493
1609
  if (0 != (flags & F_TRAILING)) {
1494
1610
  /* End of a chunked request */
1495
1611
 
@@ -1553,6 +1669,7 @@ public class HTTPParser {
1553
1669
  // Exit, the rest of the connect is in a different protocol.
1554
1670
  if (upgrade) {
1555
1671
  settings.call_on_message_complete(this);
1672
+ state = State.body_identity_eof;
1556
1673
  return true;
1557
1674
  }
1558
1675
 
@@ -1608,10 +1725,6 @@ public class HTTPParser {
1608
1725
  boolean parsing_header(State state) {
1609
1726
 
1610
1727
  switch (state) {
1611
- case chunk_size_start :
1612
- case chunk_size :
1613
- case chunk_size_almost_done :
1614
- case chunk_parameters :
1615
1728
  case chunk_data :
1616
1729
  case chunk_data_almost_done :
1617
1730
  case chunk_data_done :
@@ -1620,7 +1733,7 @@ public class HTTPParser {
1620
1733
  return false;
1621
1734
 
1622
1735
  }
1623
- return (0==(flags & F_TRAILING));
1736
+ return true;
1624
1737
  }
1625
1738
 
1626
1739
  /* "Dial C for Constants" */
@@ -1676,12 +1789,16 @@ public class HTTPParser {
1676
1789
  static final byte [] CLOSE = {
1677
1790
  0x43, 0x4c, 0x4f, 0x53, 0x45,
1678
1791
  };
1679
- /*
1680
- * ' ', '_', '-' and all alpha-numeric ascii characters are accepted by acceptable_header.
1681
- * The 'A'-'Z' are upper-cased.
1682
- */
1683
-
1684
- static final char [] acceptable_header = {
1792
+
1793
+ /* Tokens as defined by rfc 2616. Also lowercases them.
1794
+ * token = 1*<any CHAR except CTLs or separators>
1795
+ * separators = "(" | ")" | "<" | ">" | "@"
1796
+ * | "," | ";" | ":" | "\" | <">
1797
+ * | "/" | "[" | "]" | "?" | "="
1798
+ * | "{" | "}" | SP | HT
1799
+ */
1800
+
1801
+ static final char [] tokens = {
1685
1802
  /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
1686
1803
  0, 0, 0, 0, 0, 0, 0, 0,
1687
1804
  /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
@@ -1691,9 +1808,9 @@ public class HTTPParser {
1691
1808
  /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
1692
1809
  0, 0, 0, 0, 0, 0, 0, 0,
1693
1810
  /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
1694
- ' ', 0, 0, 0, 0, 0, 0, 0,
1811
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
1695
1812
  /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
1696
- 0, 0, 0, 0, 0, '-', 0, 0,
1813
+ 0, 0, '*', '+', 0, '-', '.', '/' ,
1697
1814
  /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
1698
1815
  '0', '1', '2', '3', '4', '5', '6', '7',
1699
1816
  /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
@@ -1713,7 +1830,24 @@ public class HTTPParser {
1713
1830
  /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
1714
1831
  'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
1715
1832
  /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
1716
- 'X', 'Y', 'Z', 0, 0, 0, 0, 0 };
1833
+ 'X', 'Y', 'Z', 0, '|', '}', 0, 0,
1834
+ /* hi bit set, not ascii */
1835
+ 0, 0, 0, 0, 0, 0, 0, 0,
1836
+ 0, 0, 0, 0, 0, 0, 0, 0,
1837
+ 0, 0, 0, 0, 0, 0, 0, 0,
1838
+ 0, 0, 0, 0, 0, 0, 0, 0,
1839
+ 0, 0, 0, 0, 0, 0, 0, 0,
1840
+ 0, 0, 0, 0, 0, 0, 0, 0,
1841
+ 0, 0, 0, 0, 0, 0, 0, 0,
1842
+ 0, 0, 0, 0, 0, 0, 0, 0,
1843
+ 0, 0, 0, 0, 0, 0, 0, 0,
1844
+ 0, 0, 0, 0, 0, 0, 0, 0,
1845
+ 0, 0, 0, 0, 0, 0, 0, 0,
1846
+ 0, 0, 0, 0, 0, 0, 0, 0,
1847
+ 0, 0, 0, 0, 0, 0, 0, 0,
1848
+ 0, 0, 0, 0, 0, 0, 0, 0,
1849
+ 0, 0, 0, 0, 0, 0, 0, 0,
1850
+ 0, 0, 0, 0, 0, 0, 0, 0, };
1717
1851
 
1718
1852
  static final byte [] UNHEX =
1719
1853
  { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
@@ -1724,6 +1858,14 @@ public class HTTPParser {
1724
1858
  ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
1725
1859
  ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
1726
1860
  ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
1861
+ ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
1862
+ ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
1863
+ ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
1864
+ ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
1865
+ ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
1866
+ ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
1867
+ ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
1868
+ ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
1727
1869
  };
1728
1870
 
1729
1871
  static final boolean [] normal_url_char = {
@@ -1758,7 +1900,31 @@ public class HTTPParser {
1758
1900
  /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
1759
1901
  true, true, true, true, true, true, true, true,
1760
1902
  /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
1761
- true, true, true, true, true, true, true, false };
1903
+ true, true, true, true, true, true, true, false,
1904
+
1905
+ /* hi bit set, not ascii */
1906
+ /* Remainder of non-ASCII range are accepted as-is to support implicitly UTF-8
1907
+ * encoded paths. This is out of spec, but clients generate this and most other
1908
+ * HTTP servers support it. We should, too. */
1909
+
1910
+ true, true, true, true, true, true, true, true,
1911
+ true, true, true, true, true, true, true, true,
1912
+ true, true, true, true, true, true, true, true,
1913
+ true, true, true, true, true, true, true, true,
1914
+ true, true, true, true, true, true, true, true,
1915
+ true, true, true, true, true, true, true, true,
1916
+ true, true, true, true, true, true, true, true,
1917
+ true, true, true, true, true, true, true, true,
1918
+ true, true, true, true, true, true, true, true,
1919
+ true, true, true, true, true, true, true, true,
1920
+ true, true, true, true, true, true, true, true,
1921
+ true, true, true, true, true, true, true, true,
1922
+ true, true, true, true, true, true, true, true,
1923
+ true, true, true, true, true, true, true, true,
1924
+ true, true, true, true, true, true, true, true,
1925
+ true, true, true, true, true, true, true, true,
1926
+
1927
+ };
1762
1928
 
1763
1929
  public static final byte A = 0x41;
1764
1930
  public static final byte B = 0x42;
@@ -1796,6 +1962,7 @@ public class HTTPParser {
1796
1962
  public static final byte QMARK = 0x3f;
1797
1963
  public static final byte SLASH = 0x2f;
1798
1964
  public static final byte DASH = 0x2d;
1965
+ public static final byte STAR = 0x2a;
1799
1966
  public static final byte NULL = 0x00;
1800
1967
  }
1801
1968
 
@@ -1851,12 +2018,19 @@ public class HTTPParser {
1851
2018
 
1852
2019
  , header_almost_done
1853
2020
 
1854
- , headers_almost_done
1855
-
1856
2021
  , chunk_size_start
1857
2022
  , chunk_size
1858
- , chunk_size_almost_done
1859
2023
  , chunk_parameters
2024
+ , chunk_size_almost_done
2025
+
2026
+ , headers_almost_done
2027
+ // This space intentionally not left blank, comment from c, for orientation...
2028
+ // the c version uses <= s_header_almost_done in java, we list the states explicitly
2029
+ // in `parsing_header()`
2030
+ /* Important: 's_headers_almost_done' must be the last 'header' state. All
2031
+ * states beyond this must be 'body' states. It is used for overflow
2032
+ * checking. See the PARSING_HEADER() macro.
2033
+ */
1860
2034
  , chunk_data
1861
2035
  , chunk_data_almost_done
1862
2036
  , chunk_data_done