noderb-http 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,10 +31,27 @@
31
31
  #endif
32
32
 
33
33
 
34
+ #if HTTP_PARSER_DEBUG
35
+ #define SET_ERRNO(e) \
36
+ do { \
37
+ parser->http_errno = (e); \
38
+ parser->error_lineno = __LINE__; \
39
+ } while (0)
40
+ #else
41
+ #define SET_ERRNO(e) \
42
+ do { \
43
+ parser->http_errno = (e); \
44
+ } while(0)
45
+ #endif
46
+
47
+
34
48
  #define CALLBACK2(FOR) \
35
49
  do { \
36
50
  if (settings->on_##FOR) { \
37
- if (0 != settings->on_##FOR(parser)) return (p - data); \
51
+ if (0 != settings->on_##FOR(parser)) { \
52
+ SET_ERRNO(HPE_CB_##FOR); \
53
+ return (p - data); \
54
+ } \
38
55
  } \
39
56
  } while (0)
40
57
 
@@ -44,7 +61,7 @@ do { \
44
61
  FOR##_mark = p; \
45
62
  } while (0)
46
63
 
47
- #define CALLBACK_NOCLEAR(FOR) \
64
+ #define CALLBACK(FOR) \
48
65
  do { \
49
66
  if (FOR##_mark) { \
50
67
  if (settings->on_##FOR) { \
@@ -52,20 +69,15 @@ do { \
52
69
  FOR##_mark, \
53
70
  p - FOR##_mark)) \
54
71
  { \
72
+ SET_ERRNO(HPE_CB_##FOR); \
55
73
  return (p - data); \
56
74
  } \
57
75
  } \
76
+ FOR##_mark = NULL; \
58
77
  } \
59
78
  } while (0)
60
79
 
61
80
 
62
- #define CALLBACK(FOR) \
63
- do { \
64
- CALLBACK_NOCLEAR(FOR); \
65
- FOR##_mark = NULL; \
66
- } while (0)
67
-
68
-
69
81
  #define PROXY_CONNECTION "proxy-connection"
70
82
  #define CONNECTION "connection"
71
83
  #define CONTENT_LENGTH "content-length"
@@ -241,6 +253,7 @@ enum state
241
253
  , s_header_field
242
254
  , s_header_value_start
243
255
  , s_header_value
256
+ , s_header_value_lws
244
257
 
245
258
  , s_header_almost_done
246
259
 
@@ -299,7 +312,7 @@ enum header_states
299
312
  #define LF '\n'
300
313
  #define LOWER(c) (unsigned char)(c | 0x20)
301
314
  #define TOKEN(c) (tokens[(unsigned char)c])
302
- #define IS_ALPHA(c) ((c) >= 'a' && (c) <= 'z')
315
+ #define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z')
303
316
  #define IS_NUM(c) ((c) >= '0' && (c) <= '9')
304
317
  #define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c))
305
318
 
@@ -318,7 +331,13 @@ enum header_states
318
331
 
319
332
 
320
333
  #if HTTP_PARSER_STRICT
321
- # define STRICT_CHECK(cond) if (cond) goto error
334
+ # define STRICT_CHECK(cond) \
335
+ do { \
336
+ if (cond) { \
337
+ SET_ERRNO(HPE_STRICT); \
338
+ goto error; \
339
+ } \
340
+ } while (0)
322
341
  # define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead)
323
342
  #else
324
343
  # define STRICT_CHECK(cond)
@@ -326,20 +345,39 @@ enum header_states
326
345
  #endif
327
346
 
328
347
 
348
+ /* Map errno values to strings for human-readable output */
349
+ #define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s },
350
+ static struct {
351
+ const char *name;
352
+ const char *description;
353
+ } http_strerror_tab[] = {
354
+ HTTP_ERRNO_MAP(HTTP_STRERROR_GEN)
355
+ };
356
+ #undef HTTP_STRERROR_GEN
357
+
358
+
329
359
  size_t http_parser_execute (http_parser *parser,
330
360
  const http_parser_settings *settings,
331
361
  const char *data,
332
362
  size_t len)
333
363
  {
334
364
  char c, ch;
365
+ int8_t unhex_val;
335
366
  const char *p = data, *pe;
336
367
  int64_t to_read;
337
-
338
- enum state state = (enum state) parser->state;
339
- enum header_states header_state = (enum header_states) parser->header_state;
368
+ enum state state;
369
+ enum header_states header_state;
340
370
  uint64_t index = parser->index;
341
371
  uint64_t nread = parser->nread;
342
372
 
373
+ /* We're in an error state. Don't bother doing anything. */
374
+ if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
375
+ return 0;
376
+ }
377
+
378
+ state = (enum state) parser->state;
379
+ header_state = (enum header_states) parser->header_state;
380
+
343
381
  if (len == 0) {
344
382
  switch (state) {
345
383
  case s_body_identity_eof:
@@ -353,7 +391,8 @@ size_t http_parser_execute (http_parser *parser,
353
391
  return 0;
354
392
 
355
393
  default:
356
- return 1; // error
394
+ SET_ERRNO(HPE_INVALID_EOF_STATE);
395
+ return 1;
357
396
  }
358
397
  }
359
398
 
@@ -362,21 +401,12 @@ size_t http_parser_execute (http_parser *parser,
362
401
  separated. */
363
402
  const char *header_field_mark = 0;
364
403
  const char *header_value_mark = 0;
365
- const char *fragment_mark = 0;
366
- const char *query_string_mark = 0;
367
- const char *path_mark = 0;
368
404
  const char *url_mark = 0;
369
405
 
370
406
  if (state == s_header_field)
371
407
  header_field_mark = data;
372
408
  if (state == s_header_value)
373
409
  header_value_mark = data;
374
- if (state == s_req_fragment)
375
- fragment_mark = data;
376
- if (state == s_req_query_string)
377
- query_string_mark = data;
378
- if (state == s_req_path)
379
- path_mark = data;
380
410
  if (state == s_req_path || state == s_req_schema || state == s_req_schema_slash
381
411
  || state == s_req_schema_slash_slash || state == s_req_port
382
412
  || state == s_req_query_string_start || state == s_req_query_string
@@ -390,7 +420,10 @@ size_t http_parser_execute (http_parser *parser,
390
420
  if (PARSING_HEADER(state)) {
391
421
  ++nread;
392
422
  /* Buffer overflow attack */
393
- if (nread > HTTP_MAX_HEADER_SIZE) goto error;
423
+ if (nread > HTTP_MAX_HEADER_SIZE) {
424
+ SET_ERRNO(HPE_HEADER_OVERFLOW);
425
+ goto error;
426
+ }
394
427
  }
395
428
 
396
429
  switch (state) {
@@ -399,6 +432,7 @@ size_t http_parser_execute (http_parser *parser,
399
432
  /* this state is used after a 'Connection: close' message
400
433
  * the parser will error out if it reads another message
401
434
  */
435
+ SET_ERRNO(HPE_CLOSED_CONNECTION);
402
436
  goto error;
403
437
 
404
438
  case s_start_req_or_res:
@@ -424,7 +458,11 @@ size_t http_parser_execute (http_parser *parser,
424
458
  parser->type = HTTP_RESPONSE;
425
459
  state = s_res_HT;
426
460
  } else {
427
- if (ch != 'E') goto error;
461
+ if (ch != 'E') {
462
+ SET_ERRNO(HPE_INVALID_CONSTANT);
463
+ goto error;
464
+ }
465
+
428
466
  parser->type = HTTP_REQUEST;
429
467
  parser->method = HTTP_HEAD;
430
468
  index = 2;
@@ -449,6 +487,7 @@ size_t http_parser_execute (http_parser *parser,
449
487
  break;
450
488
 
451
489
  default:
490
+ SET_ERRNO(HPE_INVALID_CONSTANT);
452
491
  goto error;
453
492
  }
454
493
  break;
@@ -475,7 +514,11 @@ size_t http_parser_execute (http_parser *parser,
475
514
  break;
476
515
 
477
516
  case s_res_first_http_major:
478
- if (ch < '1' || ch > '9') goto error;
517
+ if (ch < '1' || ch > '9') {
518
+ SET_ERRNO(HPE_INVALID_VERSION);
519
+ goto error;
520
+ }
521
+
479
522
  parser->http_major = ch - '0';
480
523
  state = s_res_http_major;
481
524
  break;
@@ -488,18 +531,29 @@ size_t http_parser_execute (http_parser *parser,
488
531
  break;
489
532
  }
490
533
 
491
- if (!IS_NUM(ch)) goto error;
534
+ if (!IS_NUM(ch)) {
535
+ SET_ERRNO(HPE_INVALID_VERSION);
536
+ goto error;
537
+ }
492
538
 
493
539
  parser->http_major *= 10;
494
540
  parser->http_major += ch - '0';
495
541
 
496
- if (parser->http_major > 999) goto error;
542
+ if (parser->http_major > 999) {
543
+ SET_ERRNO(HPE_INVALID_VERSION);
544
+ goto error;
545
+ }
546
+
497
547
  break;
498
548
  }
499
549
 
500
550
  /* first digit of minor HTTP version */
501
551
  case s_res_first_http_minor:
502
- if (!IS_NUM(ch)) goto error;
552
+ if (!IS_NUM(ch)) {
553
+ SET_ERRNO(HPE_INVALID_VERSION);
554
+ goto error;
555
+ }
556
+
503
557
  parser->http_minor = ch - '0';
504
558
  state = s_res_http_minor;
505
559
  break;
@@ -512,12 +566,19 @@ size_t http_parser_execute (http_parser *parser,
512
566
  break;
513
567
  }
514
568
 
515
- if (!IS_NUM(ch)) goto error;
569
+ if (!IS_NUM(ch)) {
570
+ SET_ERRNO(HPE_INVALID_VERSION);
571
+ goto error;
572
+ }
516
573
 
517
574
  parser->http_minor *= 10;
518
575
  parser->http_minor += ch - '0';
519
576
 
520
- if (parser->http_minor > 999) goto error;
577
+ if (parser->http_minor > 999) {
578
+ SET_ERRNO(HPE_INVALID_VERSION);
579
+ goto error;
580
+ }
581
+
521
582
  break;
522
583
  }
523
584
 
@@ -527,6 +588,8 @@ size_t http_parser_execute (http_parser *parser,
527
588
  if (ch == ' ') {
528
589
  break;
529
590
  }
591
+
592
+ SET_ERRNO(HPE_INVALID_STATUS);
530
593
  goto error;
531
594
  }
532
595
  parser->status_code = ch - '0';
@@ -548,6 +611,7 @@ size_t http_parser_execute (http_parser *parser,
548
611
  state = s_header_field_start;
549
612
  break;
550
613
  default:
614
+ SET_ERRNO(HPE_INVALID_STATUS);
551
615
  goto error;
552
616
  }
553
617
  break;
@@ -556,7 +620,11 @@ size_t http_parser_execute (http_parser *parser,
556
620
  parser->status_code *= 10;
557
621
  parser->status_code += ch - '0';
558
622
 
559
- if (parser->status_code > 999) goto error;
623
+ if (parser->status_code > 999) {
624
+ SET_ERRNO(HPE_INVALID_STATUS);
625
+ goto error;
626
+ }
627
+
560
628
  break;
561
629
  }
562
630
 
@@ -588,7 +656,10 @@ size_t http_parser_execute (http_parser *parser,
588
656
 
589
657
  CALLBACK2(message_begin);
590
658
 
591
- if (!IS_ALPHA(LOWER(ch))) goto error;
659
+ if (!IS_ALPHA(ch)) {
660
+ SET_ERRNO(HPE_INVALID_METHOD);
661
+ goto error;
662
+ }
592
663
 
593
664
  start_req_method_assign:
594
665
  parser->method = (enum http_method) 0;
@@ -609,7 +680,9 @@ size_t http_parser_execute (http_parser *parser,
609
680
  case 'S': parser->method = HTTP_SUBSCRIBE; break;
610
681
  case 'T': parser->method = HTTP_TRACE; break;
611
682
  case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break;
612
- default: goto error;
683
+ default:
684
+ SET_ERRNO(HPE_INVALID_METHOD);
685
+ goto error;
613
686
  }
614
687
  state = s_req_method;
615
688
  break;
@@ -617,8 +690,10 @@ size_t http_parser_execute (http_parser *parser,
617
690
 
618
691
  case s_req_method:
619
692
  {
620
- if (ch == '\0')
693
+ if (ch == '\0') {
694
+ SET_ERRNO(HPE_INVALID_METHOD);
621
695
  goto error;
696
+ }
622
697
 
623
698
  const char *matcher = method_strings[parser->method];
624
699
  if (ch == ' ' && matcher[index] == '\0') {
@@ -630,6 +705,8 @@ size_t http_parser_execute (http_parser *parser,
630
705
  parser->method = HTTP_CHECKOUT;
631
706
  } else if (index == 2 && ch == 'P') {
632
707
  parser->method = HTTP_COPY;
708
+ } else {
709
+ goto error;
633
710
  }
634
711
  } else if (parser->method == HTTP_MKCOL) {
635
712
  if (index == 1 && ch == 'O') {
@@ -640,18 +717,25 @@ size_t http_parser_execute (http_parser *parser,
640
717
  parser->method = HTTP_MSEARCH;
641
718
  } else if (index == 2 && ch == 'A') {
642
719
  parser->method = HTTP_MKACTIVITY;
720
+ } else {
721
+ goto error;
722
+ }
723
+ } else if (index == 1 && parser->method == HTTP_POST) {
724
+ if (ch == 'R') {
725
+ parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */
726
+ } else if (ch == 'U') {
727
+ parser->method = HTTP_PUT;
728
+ } else if (ch == 'A') {
729
+ parser->method = HTTP_PATCH;
730
+ } else {
731
+ goto error;
643
732
  }
644
- } else if (index == 1 && parser->method == HTTP_POST && ch == 'R') {
645
- parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */
646
- } else if (index == 1 && parser->method == HTTP_POST && ch == 'U') {
647
- parser->method = HTTP_PUT;
648
- } else if (index == 1 && parser->method == HTTP_POST && ch == 'A') {
649
- parser->method = HTTP_PATCH;
650
733
  } else if (index == 2 && parser->method == HTTP_UNLOCK && ch == 'S') {
651
734
  parser->method = HTTP_UNSUBSCRIBE;
652
735
  } else if (index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') {
653
736
  parser->method = HTTP_PROPPATCH;
654
737
  } else {
738
+ SET_ERRNO(HPE_INVALID_METHOD);
655
739
  goto error;
656
740
  }
657
741
 
@@ -664,13 +748,10 @@ size_t http_parser_execute (http_parser *parser,
664
748
 
665
749
  if (ch == '/' || ch == '*') {
666
750
  MARK(url);
667
- MARK(path);
668
751
  state = s_req_path;
669
752
  break;
670
753
  }
671
754
 
672
- c = LOWER(ch);
673
-
674
755
  /* Proxied requests are followed by scheme of an absolute URI (alpha).
675
756
  * CONNECT is followed by a hostname, which begins with alphanum.
676
757
  * All other methods are followed by '/' or '*' (handled above).
@@ -681,20 +762,20 @@ size_t http_parser_execute (http_parser *parser,
681
762
  break;
682
763
  }
683
764
 
765
+ SET_ERRNO(HPE_INVALID_URL);
684
766
  goto error;
685
767
  }
686
768
 
687
769
  case s_req_schema:
688
770
  {
689
- c = LOWER(ch);
690
-
691
- if (IS_ALPHA(c)) break;
771
+ if (IS_ALPHA(ch)) break;
692
772
 
693
773
  if (ch == ':') {
694
774
  state = s_req_schema_slash;
695
775
  break;
696
776
  }
697
777
 
778
+ SET_ERRNO(HPE_INVALID_URL);
698
779
  goto error;
699
780
  }
700
781
 
@@ -710,14 +791,12 @@ size_t http_parser_execute (http_parser *parser,
710
791
 
711
792
  case s_req_host:
712
793
  {
713
- c = LOWER(ch);
714
794
  if (IS_HOST_CHAR(ch)) break;
715
795
  switch (ch) {
716
796
  case ':':
717
797
  state = s_req_port;
718
798
  break;
719
799
  case '/':
720
- MARK(path);
721
800
  state = s_req_path;
722
801
  break;
723
802
  case ' ':
@@ -732,6 +811,7 @@ size_t http_parser_execute (http_parser *parser,
732
811
  state = s_req_query_string_start;
733
812
  break;
734
813
  default:
814
+ SET_ERRNO(HPE_INVALID_HOST);
735
815
  goto error;
736
816
  }
737
817
  break;
@@ -742,7 +822,6 @@ size_t http_parser_execute (http_parser *parser,
742
822
  if (IS_NUM(ch)) break;
743
823
  switch (ch) {
744
824
  case '/':
745
- MARK(path);
746
825
  state = s_req_path;
747
826
  break;
748
827
  case ' ':
@@ -757,6 +836,7 @@ size_t http_parser_execute (http_parser *parser,
757
836
  state = s_req_query_string_start;
758
837
  break;
759
838
  default:
839
+ SET_ERRNO(HPE_INVALID_PORT);
760
840
  goto error;
761
841
  }
762
842
  break;
@@ -769,32 +849,28 @@ size_t http_parser_execute (http_parser *parser,
769
849
  switch (ch) {
770
850
  case ' ':
771
851
  CALLBACK(url);
772
- CALLBACK(path);
773
852
  state = s_req_http_start;
774
853
  break;
775
854
  case CR:
776
855
  CALLBACK(url);
777
- CALLBACK(path);
778
856
  parser->http_major = 0;
779
857
  parser->http_minor = 9;
780
858
  state = s_req_line_almost_done;
781
859
  break;
782
860
  case LF:
783
861
  CALLBACK(url);
784
- CALLBACK(path);
785
862
  parser->http_major = 0;
786
863
  parser->http_minor = 9;
787
864
  state = s_header_field_start;
788
865
  break;
789
866
  case '?':
790
- CALLBACK(path);
791
867
  state = s_req_query_string_start;
792
868
  break;
793
869
  case '#':
794
- CALLBACK(path);
795
870
  state = s_req_fragment_start;
796
871
  break;
797
872
  default:
873
+ SET_ERRNO(HPE_INVALID_PATH);
798
874
  goto error;
799
875
  }
800
876
  break;
@@ -803,7 +879,6 @@ size_t http_parser_execute (http_parser *parser,
803
879
  case s_req_query_string_start:
804
880
  {
805
881
  if (IS_URL_CHAR(ch)) {
806
- MARK(query_string);
807
882
  state = s_req_query_string;
808
883
  break;
809
884
  }
@@ -831,6 +906,7 @@ size_t http_parser_execute (http_parser *parser,
831
906
  state = s_req_fragment_start;
832
907
  break;
833
908
  default:
909
+ SET_ERRNO(HPE_INVALID_QUERY_STRING);
834
910
  goto error;
835
911
  }
836
912
  break;
@@ -846,28 +922,25 @@ size_t http_parser_execute (http_parser *parser,
846
922
  break;
847
923
  case ' ':
848
924
  CALLBACK(url);
849
- CALLBACK(query_string);
850
925
  state = s_req_http_start;
851
926
  break;
852
927
  case CR:
853
928
  CALLBACK(url);
854
- CALLBACK(query_string);
855
929
  parser->http_major = 0;
856
930
  parser->http_minor = 9;
857
931
  state = s_req_line_almost_done;
858
932
  break;
859
933
  case LF:
860
934
  CALLBACK(url);
861
- CALLBACK(query_string);
862
935
  parser->http_major = 0;
863
936
  parser->http_minor = 9;
864
937
  state = s_header_field_start;
865
938
  break;
866
939
  case '#':
867
- CALLBACK(query_string);
868
940
  state = s_req_fragment_start;
869
941
  break;
870
942
  default:
943
+ SET_ERRNO(HPE_INVALID_QUERY_STRING);
871
944
  goto error;
872
945
  }
873
946
  break;
@@ -876,7 +949,6 @@ size_t http_parser_execute (http_parser *parser,
876
949
  case s_req_fragment_start:
877
950
  {
878
951
  if (IS_URL_CHAR(ch)) {
879
- MARK(fragment);
880
952
  state = s_req_fragment;
881
953
  break;
882
954
  }
@@ -899,12 +971,12 @@ size_t http_parser_execute (http_parser *parser,
899
971
  state = s_header_field_start;
900
972
  break;
901
973
  case '?':
902
- MARK(fragment);
903
974
  state = s_req_fragment;
904
975
  break;
905
976
  case '#':
906
977
  break;
907
978
  default:
979
+ SET_ERRNO(HPE_INVALID_FRAGMENT);
908
980
  goto error;
909
981
  }
910
982
  break;
@@ -917,19 +989,16 @@ size_t http_parser_execute (http_parser *parser,
917
989
  switch (ch) {
918
990
  case ' ':
919
991
  CALLBACK(url);
920
- CALLBACK(fragment);
921
992
  state = s_req_http_start;
922
993
  break;
923
994
  case CR:
924
995
  CALLBACK(url);
925
- CALLBACK(fragment);
926
996
  parser->http_major = 0;
927
997
  parser->http_minor = 9;
928
998
  state = s_req_line_almost_done;
929
999
  break;
930
1000
  case LF:
931
1001
  CALLBACK(url);
932
- CALLBACK(fragment);
933
1002
  parser->http_major = 0;
934
1003
  parser->http_minor = 9;
935
1004
  state = s_header_field_start;
@@ -938,6 +1007,7 @@ size_t http_parser_execute (http_parser *parser,
938
1007
  case '#':
939
1008
  break;
940
1009
  default:
1010
+ SET_ERRNO(HPE_INVALID_FRAGMENT);
941
1011
  goto error;
942
1012
  }
943
1013
  break;
@@ -951,6 +1021,7 @@ size_t http_parser_execute (http_parser *parser,
951
1021
  case ' ':
952
1022
  break;
953
1023
  default:
1024
+ SET_ERRNO(HPE_INVALID_CONSTANT);
954
1025
  goto error;
955
1026
  }
956
1027
  break;
@@ -977,7 +1048,11 @@ size_t http_parser_execute (http_parser *parser,
977
1048
 
978
1049
  /* first digit of major HTTP version */
979
1050
  case s_req_first_http_major:
980
- if (ch < '1' || ch > '9') goto error;
1051
+ if (ch < '1' || ch > '9') {
1052
+ SET_ERRNO(HPE_INVALID_VERSION);
1053
+ goto error;
1054
+ }
1055
+
981
1056
  parser->http_major = ch - '0';
982
1057
  state = s_req_http_major;
983
1058
  break;
@@ -990,18 +1065,29 @@ size_t http_parser_execute (http_parser *parser,
990
1065
  break;
991
1066
  }
992
1067
 
993
- if (!IS_NUM(ch)) goto error;
1068
+ if (!IS_NUM(ch)) {
1069
+ SET_ERRNO(HPE_INVALID_VERSION);
1070
+ goto error;
1071
+ }
994
1072
 
995
1073
  parser->http_major *= 10;
996
1074
  parser->http_major += ch - '0';
997
1075
 
998
- if (parser->http_major > 999) goto error;
1076
+ if (parser->http_major > 999) {
1077
+ SET_ERRNO(HPE_INVALID_VERSION);
1078
+ goto error;
1079
+ }
1080
+
999
1081
  break;
1000
1082
  }
1001
1083
 
1002
1084
  /* first digit of minor HTTP version */
1003
1085
  case s_req_first_http_minor:
1004
- if (!IS_NUM(ch)) goto error;
1086
+ if (!IS_NUM(ch)) {
1087
+ SET_ERRNO(HPE_INVALID_VERSION);
1088
+ goto error;
1089
+ }
1090
+
1005
1091
  parser->http_minor = ch - '0';
1006
1092
  state = s_req_http_minor;
1007
1093
  break;
@@ -1021,24 +1107,36 @@ size_t http_parser_execute (http_parser *parser,
1021
1107
 
1022
1108
  /* XXX allow spaces after digit? */
1023
1109
 
1024
- if (!IS_NUM(ch)) goto error;
1110
+ if (!IS_NUM(ch)) {
1111
+ SET_ERRNO(HPE_INVALID_VERSION);
1112
+ goto error;
1113
+ }
1025
1114
 
1026
1115
  parser->http_minor *= 10;
1027
1116
  parser->http_minor += ch - '0';
1028
1117
 
1029
- if (parser->http_minor > 999) goto error;
1118
+ if (parser->http_minor > 999) {
1119
+ SET_ERRNO(HPE_INVALID_VERSION);
1120
+ goto error;
1121
+ }
1122
+
1030
1123
  break;
1031
1124
  }
1032
1125
 
1033
1126
  /* end of request line */
1034
1127
  case s_req_line_almost_done:
1035
1128
  {
1036
- if (ch != LF) goto error;
1129
+ if (ch != LF) {
1130
+ SET_ERRNO(HPE_LF_EXPECTED);
1131
+ goto error;
1132
+ }
1133
+
1037
1134
  state = s_header_field_start;
1038
1135
  break;
1039
1136
  }
1040
1137
 
1041
1138
  case s_header_field_start:
1139
+ header_field_start:
1042
1140
  {
1043
1141
  if (ch == CR) {
1044
1142
  state = s_headers_almost_done;
@@ -1054,7 +1152,10 @@ size_t http_parser_execute (http_parser *parser,
1054
1152
 
1055
1153
  c = TOKEN(ch);
1056
1154
 
1057
- if (!c) goto error;
1155
+ if (!c) {
1156
+ SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
1157
+ goto error;
1158
+ }
1058
1159
 
1059
1160
  MARK(header_field);
1060
1161
 
@@ -1211,20 +1312,19 @@ size_t http_parser_execute (http_parser *parser,
1211
1312
  break;
1212
1313
  }
1213
1314
 
1315
+ SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
1214
1316
  goto error;
1215
1317
  }
1216
1318
 
1217
1319
  case s_header_value_start:
1218
1320
  {
1219
- if (ch == ' ') break;
1321
+ if (ch == ' ' || ch == '\t') break;
1220
1322
 
1221
1323
  MARK(header_value);
1222
1324
 
1223
1325
  state = s_header_value;
1224
1326
  index = 0;
1225
1327
 
1226
- c = LOWER(ch);
1227
-
1228
1328
  if (ch == CR) {
1229
1329
  CALLBACK(header_value);
1230
1330
  header_state = h_general;
@@ -1238,6 +1338,8 @@ size_t http_parser_execute (http_parser *parser,
1238
1338
  break;
1239
1339
  }
1240
1340
 
1341
+ c = LOWER(ch);
1342
+
1241
1343
  switch (header_state) {
1242
1344
  case h_upgrade:
1243
1345
  parser->flags |= F_UPGRADE;
@@ -1254,7 +1356,11 @@ size_t http_parser_execute (http_parser *parser,
1254
1356
  break;
1255
1357
 
1256
1358
  case h_content_length:
1257
- if (!IS_NUM(ch)) goto error;
1359
+ if (!IS_NUM(ch)) {
1360
+ SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1361
+ goto error;
1362
+ }
1363
+
1258
1364
  parser->content_length = ch - '0';
1259
1365
  break;
1260
1366
 
@@ -1279,7 +1385,6 @@ size_t http_parser_execute (http_parser *parser,
1279
1385
 
1280
1386
  case s_header_value:
1281
1387
  {
1282
- c = LOWER(ch);
1283
1388
 
1284
1389
  if (ch == CR) {
1285
1390
  CALLBACK(header_value);
@@ -1292,6 +1397,8 @@ size_t http_parser_execute (http_parser *parser,
1292
1397
  goto header_almost_done;
1293
1398
  }
1294
1399
 
1400
+ c = LOWER(ch);
1401
+
1295
1402
  switch (header_state) {
1296
1403
  case h_general:
1297
1404
  break;
@@ -1303,7 +1410,11 @@ size_t http_parser_execute (http_parser *parser,
1303
1410
 
1304
1411
  case h_content_length:
1305
1412
  if (ch == ' ') break;
1306
- if (!IS_NUM(ch)) goto error;
1413
+ if (!IS_NUM(ch)) {
1414
+ SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1415
+ goto error;
1416
+ }
1417
+
1307
1418
  parser->content_length *= 10;
1308
1419
  parser->content_length += ch - '0';
1309
1420
  break;
@@ -1359,7 +1470,7 @@ size_t http_parser_execute (http_parser *parser,
1359
1470
  {
1360
1471
  STRICT_CHECK(ch != LF);
1361
1472
 
1362
- state = s_header_field_start;
1473
+ state = s_header_value_lws;
1363
1474
 
1364
1475
  switch (header_state) {
1365
1476
  case h_connection_keep_alive:
@@ -1377,6 +1488,18 @@ size_t http_parser_execute (http_parser *parser,
1377
1488
  break;
1378
1489
  }
1379
1490
 
1491
+ case s_header_value_lws:
1492
+ {
1493
+ if (ch == ' ' || ch == '\t')
1494
+ state = s_header_value_start;
1495
+ else
1496
+ {
1497
+ state = s_header_field_start;
1498
+ goto header_field_start;
1499
+ }
1500
+ break;
1501
+ }
1502
+
1380
1503
  case s_headers_almost_done:
1381
1504
  headers_almost_done:
1382
1505
  {
@@ -1412,6 +1535,7 @@ size_t http_parser_execute (http_parser *parser,
1412
1535
 
1413
1536
  default:
1414
1537
  parser->state = state;
1538
+ SET_ERRNO(HPE_CB_headers_complete);
1415
1539
  return p - data; /* Error */
1416
1540
  }
1417
1541
  }
@@ -1419,7 +1543,7 @@ size_t http_parser_execute (http_parser *parser,
1419
1543
  /* Exit, the rest of the connect is in a different protocol. */
1420
1544
  if (parser->upgrade) {
1421
1545
  CALLBACK2(message_complete);
1422
- return (p - data);
1546
+ return (p - data) + 1;
1423
1547
  }
1424
1548
 
1425
1549
  if (parser->flags & F_SKIPBODY) {
@@ -1478,9 +1602,13 @@ size_t http_parser_execute (http_parser *parser,
1478
1602
  assert(nread == 1);
1479
1603
  assert(parser->flags & F_CHUNKED);
1480
1604
 
1481
- c = unhex[(unsigned char)ch];
1482
- if (c == -1) goto error;
1483
- parser->content_length = c;
1605
+ unhex_val = unhex[(unsigned char)ch];
1606
+ if (unhex_val == -1) {
1607
+ SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
1608
+ goto error;
1609
+ }
1610
+
1611
+ parser->content_length = unhex_val;
1484
1612
  state = s_chunk_size;
1485
1613
  break;
1486
1614
  }
@@ -1494,18 +1622,20 @@ size_t http_parser_execute (http_parser *parser,
1494
1622
  break;
1495
1623
  }
1496
1624
 
1497
- c = unhex[(unsigned char)ch];
1625
+ unhex_val = unhex[(unsigned char)ch];
1498
1626
 
1499
- if (c == -1) {
1627
+ if (unhex_val == -1) {
1500
1628
  if (ch == ';' || ch == ' ') {
1501
1629
  state = s_chunk_parameters;
1502
1630
  break;
1503
1631
  }
1632
+
1633
+ SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
1504
1634
  goto error;
1505
1635
  }
1506
1636
 
1507
1637
  parser->content_length *= 16;
1508
- parser->content_length += c;
1638
+ parser->content_length += unhex_val;
1509
1639
  break;
1510
1640
  }
1511
1641
 
@@ -1569,16 +1699,14 @@ size_t http_parser_execute (http_parser *parser,
1569
1699
 
1570
1700
  default:
1571
1701
  assert(0 && "unhandled state");
1702
+ SET_ERRNO(HPE_INVALID_INTERNAL_STATE);
1572
1703
  goto error;
1573
1704
  }
1574
1705
  }
1575
1706
 
1576
- CALLBACK_NOCLEAR(header_field);
1577
- CALLBACK_NOCLEAR(header_value);
1578
- CALLBACK_NOCLEAR(fragment);
1579
- CALLBACK_NOCLEAR(query_string);
1580
- CALLBACK_NOCLEAR(path);
1581
- CALLBACK_NOCLEAR(url);
1707
+ CALLBACK(header_field);
1708
+ CALLBACK(header_value);
1709
+ CALLBACK(url);
1582
1710
 
1583
1711
  parser->state = state;
1584
1712
  parser->header_state = header_state;
@@ -1588,7 +1716,10 @@ size_t http_parser_execute (http_parser *parser,
1588
1716
  return len;
1589
1717
 
1590
1718
  error:
1591
- parser->state = s_dead;
1719
+ if (HTTP_PARSER_ERRNO(parser) == HPE_OK) {
1720
+ SET_ERRNO(HPE_UNKNOWN);
1721
+ }
1722
+
1592
1723
  return (p - data);
1593
1724
  }
1594
1725
 
@@ -1629,4 +1760,17 @@ http_parser_init (http_parser *parser, enum http_parser_type t)
1629
1760
  parser->upgrade = 0;
1630
1761
  parser->flags = 0;
1631
1762
  parser->method = 0;
1763
+ parser->http_errno = 0;
1764
+ }
1765
+
1766
+ const char *
1767
+ http_errno_name(enum http_errno err) {
1768
+ assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0])));
1769
+ return http_strerror_tab[err].name;
1770
+ }
1771
+
1772
+ const char *
1773
+ http_errno_description(enum http_errno err) {
1774
+ assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0])));
1775
+ return http_strerror_tab[err].description;
1632
1776
  }