http_parser.rb 0.5.1-x86-mingw32 → 0.5.2-x86-mingw32

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 (50) 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/LICENSE-MIT +1 -1
  6. data/ext/ruby_http_parser/vendor/http-parser/http_parser.c +52 -10
  7. data/ext/ruby_http_parser/vendor/http-parser/http_parser.h +3 -1
  8. data/ext/ruby_http_parser/vendor/http-parser/test.c +89 -3
  9. data/ext/ruby_http_parser/vendor/http-parser-java/LICENSE-MIT +26 -1
  10. data/ext/ruby_http_parser/vendor/http-parser-java/README.md +23 -143
  11. data/ext/ruby_http_parser/vendor/http-parser-java/TODO +3 -0
  12. data/ext/ruby_http_parser/vendor/http-parser-java/build.xml +74 -0
  13. data/ext/ruby_http_parser/vendor/http-parser-java/ext/primitives.jar +0 -0
  14. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.c +115 -61
  15. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.h +19 -3
  16. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPCallback.java +8 -0
  17. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPDataCallback.java +34 -0
  18. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPErrorCallback.java +12 -0
  19. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPException.java +4 -2
  20. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPMethod.java +64 -52
  21. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParser.java +5 -0
  22. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserSettings.java +323 -0
  23. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/{lolevel/Util.java → Util.java} +27 -28
  24. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java +259 -85
  25. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java +1 -0
  26. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Message.java +324 -0
  27. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Requests.java +69 -0
  28. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Responses.java +51 -0
  29. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Test.java +15 -0
  30. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestHeaderOverflowError.java +47 -0
  31. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestLoaderNG.java +183 -447
  32. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestNoOverflowLongBody.java +61 -0
  33. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/UnitTest.java +2 -1
  34. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Upgrade.java +26 -0
  35. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Util.java +165 -0
  36. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/WrongContentLength.java +58 -0
  37. data/ext/ruby_http_parser/vendor/http-parser-java/test.c +232 -29
  38. data/ext/ruby_http_parser/vendor/http-parser-java/test_permutations +1 -1
  39. data/ext/ruby_http_parser/vendor/http-parser-java/test_unit +1 -1
  40. data/ext/ruby_http_parser/vendor/http-parser-java/test_utf8 +1 -0
  41. data/ext/ruby_http_parser/vendor/http-parser-java/tests.dumped +154 -7
  42. data/ext/ruby_http_parser/vendor/http-parser-java/tests.utf8 +17 -0
  43. data/http_parser.rb.gemspec +8 -2
  44. data/lib/1.8/ruby_http_parser.so +0 -0
  45. data/lib/1.9/ruby_http_parser.so +0 -0
  46. data/lib/http_parser.rb +17 -0
  47. data/spec/parser_spec.rb +97 -6
  48. data/tasks/compile.rake +3 -1
  49. metadata +83 -20
  50. data/ext/ruby_http_parser/vendor/http-parser-java/CONTRIBUTIONS +0 -4
@@ -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