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.
- data/ext/noderb_http_extension/Makefile +187 -0
- data/ext/noderb_http_extension/extconf.rb +1 -1
- data/ext/noderb_http_extension/http_parser.c +239 -95
- data/ext/noderb_http_extension/http_parser.h +88 -6
- data/ext/noderb_http_extension/http_parser.o +0 -0
- data/ext/noderb_http_extension/noderb_http.c +41 -50
- data/ext/noderb_http_extension/noderb_http.o +0 -0
- data/ext/noderb_http_extension/noderb_http_extension.bundle +0 -0
- data/lib/noderb/modules/http/parser.rb +112 -0
- data/lib/noderb/modules/http/version.rb +9 -0
- data/lib/noderb/modules/http.rb +2 -99
- data/lib/noderb-http.rb +2 -2
- data/test/cases/curl_get.rb +25 -0
- data/test/cases/patch_request.rb +29 -0
- data/test/cases/response.rb +38 -0
- data/test/cases/upgrade_request.rb +34 -0
- data/test/init.rb +62 -0
- metadata +13 -5
- data/ext/http_parser.o +0 -0
- data/ext/noderb_http.o +0 -0
@@ -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))
|
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
|
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)
|
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
|
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
|
-
|
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)
|
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')
|
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')
|
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))
|
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)
|
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))
|
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))
|
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)
|
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)
|
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(
|
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:
|
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
|
-
|
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')
|
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))
|
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)
|
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))
|
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))
|
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)
|
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)
|
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)
|
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))
|
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))
|
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 =
|
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
|
-
|
1482
|
-
if (
|
1483
|
-
|
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
|
-
|
1625
|
+
unhex_val = unhex[(unsigned char)ch];
|
1498
1626
|
|
1499
|
-
if (
|
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 +=
|
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
|
-
|
1577
|
-
|
1578
|
-
|
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
|
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
|
}
|