noderb-http 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
  }