nxt_http_parse.c (59:773604145544) nxt_http_parse.c (60:b80bfbd9bddc)
1
2/*
3 * Copyright (C) NGINX, Inc.
4 * Copyright (C) Valentin V. Bartenev
5 */
6
7#include <nxt_main.h>
8
9
10typedef struct {
1
2/*
3 * Copyright (C) NGINX, Inc.
4 * Copyright (C) Valentin V. Bartenev
5 */
6
7#include <nxt_main.h>
8
9
10typedef struct {
11 nxt_http_field_handler_t handler;
12 uintptr_t data;
11 nxt_http_fields_hash_entry_t *entry;
12
13 union {
13 union {
14 uint8_t str[8];
15 uint64_t ui64;
14 uint8_t str[8];
15 uint64_t ui64;
16 } key[];
16 } key[];
17} nxt_http_fields_hash_entry_t;
17} nxt_http_fields_hash_elt_t;
18
19
18
19
20#define nxt_http_fields_hash_next_entry(entry, n) \
21 ((nxt_http_fields_hash_entry_t *) ((u_char *) (entry) \
22 + sizeof(nxt_http_fields_hash_entry_t) \
23 + n * 8))
24
25
26struct nxt_http_fields_hash_s {
27 size_t min_length;
28 size_t max_length;
29 void *long_fields;
20struct nxt_http_fields_hash_s {
21 size_t min_length;
22 size_t max_length;
23 void *long_fields;
30 nxt_http_fields_hash_entry_t *entries[];
24 nxt_http_fields_hash_elt_t *elts[];
31};
32
33
25};
26
27
28#define nxt_http_fields_hash_next_elt(elt, n) \
29 ((nxt_http_fields_hash_elt_t *) ((u_char *) (elt) \
30 + sizeof(nxt_http_fields_hash_elt_t) \
31 + n * 8))
32
33
34static nxt_int_t nxt_http_parse_unusual_target(nxt_http_request_parse_t *rp,
35 u_char **pos, u_char *end);
36static nxt_int_t nxt_http_parse_request_line(nxt_http_request_parse_t *rp,
37 u_char **pos, u_char *end);
38static nxt_int_t nxt_http_parse_field_name(nxt_http_request_parse_t *rp,
39 u_char **pos, u_char *end);
40static nxt_int_t nxt_http_parse_field_value(nxt_http_request_parse_t *rp,
41 u_char **pos, u_char *end);
42static u_char *nxt_http_lookup_field_end(u_char *p, u_char *end);
43static nxt_int_t nxt_http_parse_field_end(nxt_http_request_parse_t *rp,
44 u_char **pos, u_char *end);
45
34static nxt_int_t nxt_http_parse_unusual_target(nxt_http_request_parse_t *rp,
35 u_char **pos, u_char *end);
36static nxt_int_t nxt_http_parse_request_line(nxt_http_request_parse_t *rp,
37 u_char **pos, u_char *end);
38static nxt_int_t nxt_http_parse_field_name(nxt_http_request_parse_t *rp,
39 u_char **pos, u_char *end);
40static nxt_int_t nxt_http_parse_field_value(nxt_http_request_parse_t *rp,
41 u_char **pos, u_char *end);
42static u_char *nxt_http_lookup_field_end(u_char *p, u_char *end);
43static nxt_int_t nxt_http_parse_field_end(nxt_http_request_parse_t *rp,
44 u_char **pos, u_char *end);
45
46static nxt_http_fields_hash_entry_t *nxt_http_fields_hash_lookup(
47 nxt_http_fields_hash_t *hash, uint64_t *key, nxt_str_t *value);
48static nxt_http_fields_hash_entry_t *nxt_http_header_fields_hash_lookup_long(
49 nxt_http_fields_hash_t *hash, nxt_str_t *value);
50
46
47static nxt_http_fields_hash_entry_t *nxt_http_fields_hash_lookup_long(
48 nxt_http_fields_hash_t *hash, nxt_http_field_t *field);
51
49
50
52typedef enum {
53 NXT_HTTP_TARGET_SPACE = 1, /* \s */
54 NXT_HTTP_TARGET_HASH, /* # */
55 NXT_HTTP_TARGET_AGAIN,
56 NXT_HTTP_TARGET_BAD, /* \0\r\n */
57
58 /* traps below are used for extended check only */
59

--- 362 unchanged lines hidden (view full) ---

422 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
423 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
424 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
425 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
426
427 p = *pos;
428
429 size = end - p;
51typedef enum {
52 NXT_HTTP_TARGET_SPACE = 1, /* \s */
53 NXT_HTTP_TARGET_HASH, /* # */
54 NXT_HTTP_TARGET_AGAIN,
55 NXT_HTTP_TARGET_BAD, /* \0\r\n */
56
57 /* traps below are used for extended check only */
58

--- 362 unchanged lines hidden (view full) ---

421 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
422 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
423 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
424 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
425
426 p = *pos;
427
428 size = end - p;
430 i = rp->offset;
429 i = rp->field.name.length;
431
432#define nxt_http_parse_field_name_step \
433 { \
434 ch = p[i]; \
435 c = normal[ch]; \
436 \
437 if (nxt_slow_path(c == '\0')) { \
438 goto name_end; \
439 } \
440 \
430
431#define nxt_http_parse_field_name_step \
432 { \
433 ch = p[i]; \
434 c = normal[ch]; \
435 \
436 if (nxt_slow_path(c == '\0')) { \
437 goto name_end; \
438 } \
439 \
441 rp->field_name_key.str[i % 32] = c; \
440 rp->field.key.str[i % 32] = c; \
442 i++; \
443 }
444
445 while (nxt_fast_path(size - i >= 8)) {
446 nxt_http_parse_field_name_step
447 nxt_http_parse_field_name_step
448 nxt_http_parse_field_name_step
449 nxt_http_parse_field_name_step

--- 5 unchanged lines hidden (view full) ---

455 }
456
457 while (nxt_fast_path(i != size)) {
458 nxt_http_parse_field_name_step
459 }
460
461#undef nxt_http_parse_field_name_step
462
441 i++; \
442 }
443
444 while (nxt_fast_path(size - i >= 8)) {
445 nxt_http_parse_field_name_step
446 nxt_http_parse_field_name_step
447 nxt_http_parse_field_name_step
448 nxt_http_parse_field_name_step

--- 5 unchanged lines hidden (view full) ---

454 }
455
456 while (nxt_fast_path(i != size)) {
457 nxt_http_parse_field_name_step
458 }
459
460#undef nxt_http_parse_field_name_step
461
463 rp->offset = i;
462 rp->field.name.length = i;
464 rp->handler = &nxt_http_parse_field_name;
465
466 return NXT_AGAIN;
467
468name_end:
469
470 if (nxt_fast_path(ch == ':')) {
471 if (nxt_slow_path(i == 0)) {
472 return NXT_ERROR;
473 }
474
475 *pos = &p[i] + 1;
476
463 rp->handler = &nxt_http_parse_field_name;
464
465 return NXT_AGAIN;
466
467name_end:
468
469 if (nxt_fast_path(ch == ':')) {
470 if (nxt_slow_path(i == 0)) {
471 return NXT_ERROR;
472 }
473
474 *pos = &p[i] + 1;
475
477 rp->field_name.start = p;
478 rp->field_name.length = i;
476 rp->field.name.length = i;
477 rp->field.name.start = p;
479
478
480 rp->offset = 0;
481
482 return nxt_http_parse_field_value(rp, pos, end);
483 }
484
485 if (nxt_slow_path(i != 0)) {
486 return NXT_ERROR;
487 }
488
479 return nxt_http_parse_field_value(rp, pos, end);
480 }
481
482 if (nxt_slow_path(i != 0)) {
483 return NXT_ERROR;
484 }
485
489 rp->field_name.length = 0;
490
491 return nxt_http_parse_field_end(rp, pos, end);
492}
493
494
495static nxt_int_t
496nxt_http_parse_field_value(nxt_http_request_parse_t *rp, u_char **pos,
497 u_char *end)
498{

--- 12 unchanged lines hidden (view full) ---

511 break;
512 }
513
514 p++;
515 }
516
517 *pos = p;
518
486 return nxt_http_parse_field_end(rp, pos, end);
487}
488
489
490static nxt_int_t
491nxt_http_parse_field_value(nxt_http_request_parse_t *rp, u_char **pos,
492 u_char *end)
493{

--- 12 unchanged lines hidden (view full) ---

506 break;
507 }
508
509 p++;
510 }
511
512 *pos = p;
513
519 p += rp->offset;
514 p += rp->field.value.length;
520
521 for ( ;; ) {
522 p = nxt_http_lookup_field_end(p, end);
523
524 if (nxt_slow_path(p == end)) {
515
516 for ( ;; ) {
517 p = nxt_http_lookup_field_end(p, end);
518
519 if (nxt_slow_path(p == end)) {
525 rp->offset = p - *pos;
520 rp->field.value.length = p - *pos;
526 rp->handler = &nxt_http_parse_field_value;
527 return NXT_AGAIN;
528 }
529
530 ch = *p;
531
532 if (nxt_fast_path(ch == '\r' || ch == '\n')) {
533 break;

--- 5 unchanged lines hidden (view full) ---

539 }
540
541 if (nxt_fast_path(p != *pos)) {
542 while (p[-1] == ' ') {
543 p--;
544 }
545 }
546
521 rp->handler = &nxt_http_parse_field_value;
522 return NXT_AGAIN;
523 }
524
525 ch = *p;
526
527 if (nxt_fast_path(ch == '\r' || ch == '\n')) {
528 break;

--- 5 unchanged lines hidden (view full) ---

534 }
535
536 if (nxt_fast_path(p != *pos)) {
537 while (p[-1] == ' ') {
538 p--;
539 }
540 }
541
547 rp->offset = 0;
542 rp->field.value.length = p - *pos;
543 rp->field.value.start = *pos;
548
544
549 rp->field_value.start = *pos;
550 rp->field_value.length = p - *pos;
551
552 *pos = p;
553
554 return nxt_http_parse_field_end(rp, pos, end);
555}
556
557
558static u_char *
559nxt_http_lookup_field_end(u_char *p, u_char *end)

--- 59 unchanged lines hidden (view full) ---

619 return p;
620}
621
622
623static nxt_int_t
624nxt_http_parse_field_end(nxt_http_request_parse_t *rp, u_char **pos,
625 u_char *end)
626{
545 *pos = p;
546
547 return nxt_http_parse_field_end(rp, pos, end);
548}
549
550
551static u_char *
552nxt_http_lookup_field_end(u_char *p, u_char *end)

--- 59 unchanged lines hidden (view full) ---

612 return p;
613}
614
615
616static nxt_int_t
617nxt_http_parse_field_end(nxt_http_request_parse_t *rp, u_char **pos,
618 u_char *end)
619{
627 u_char *p;
628 nxt_int_t rc;
629 nxt_http_fields_hash_entry_t *entry;
620 u_char *p;
621 nxt_http_field_t *field;
630
631 p = *pos;
632
633 if (nxt_fast_path(*p == '\r')) {
634 p++;
635
636 if (nxt_slow_path(p == end)) {
637 rp->handler = &nxt_http_parse_field_end;
638 return NXT_AGAIN;
639 }
640 }
641
642 if (nxt_fast_path(*p == '\n')) {
643 *pos = p + 1;
644
622
623 p = *pos;
624
625 if (nxt_fast_path(*p == '\r')) {
626 p++;
627
628 if (nxt_slow_path(p == end)) {
629 rp->handler = &nxt_http_parse_field_end;
630 return NXT_AGAIN;
631 }
632 }
633
634 if (nxt_fast_path(*p == '\n')) {
635 *pos = p + 1;
636
645 if (rp->field_name.length != 0) {
646 entry = nxt_http_fields_hash_lookup(rp->hash,
647 rp->field_name_key.ui64,
648 &rp->field_name);
637 if (rp->field.name.length != 0) {
638 field = nxt_list_add(rp->fields);
649
639
650 if (entry != NULL) {
651 rc = entry->handler(rp->ctx, &rp->field_name, &rp->field_value,
652 entry->data);
653
654 if (nxt_slow_path(rc != NXT_OK)) {
655 return NXT_ERROR;
656 }
640 if (nxt_slow_path(field == NULL)) {
641 return NXT_ERROR;
657 }
658
642 }
643
659 nxt_memzero(rp->field_name_key.str, 32);
644 *field = rp->field;
660
645
646 nxt_memzero(&rp->field, sizeof(nxt_http_field_t));
647
661 rp->handler = &nxt_http_parse_field_name;
662 return NXT_OK;
663 }
664
665 return NXT_DONE;
666 }
667
668 return NXT_ERROR;
669}
670
671
648 rp->handler = &nxt_http_parse_field_name;
649 return NXT_OK;
650 }
651
652 return NXT_DONE;
653 }
654
655 return NXT_ERROR;
656}
657
658
672static nxt_http_fields_hash_entry_t *
673nxt_http_fields_hash_lookup(nxt_http_fields_hash_t *hash, uint64_t *key,
674 nxt_str_t *value)
659nxt_http_fields_hash_t *
660nxt_http_fields_hash_create(nxt_http_fields_hash_entry_t *entries,
661 nxt_mem_pool_t *mp)
675{
662{
676 nxt_http_fields_hash_entry_t *entry;
663 size_t min_length, max_length, length, size;
664 nxt_uint_t i, j, n;
665 nxt_http_fields_hash_t *hash;
666 nxt_http_fields_hash_elt_t *elt;
677
667
678 if (hash == NULL || value->length < hash->min_length) {
668 min_length = 32 + 1;
669 max_length = 0;
670
671 for (i = 0; entries[i].handler != NULL; i++) {
672 length = entries[i].name.length;
673
674 if (length > 32) {
675 /* TODO */
676 return NULL;
677 }
678
679 min_length = nxt_min(length, min_length);
680 max_length = nxt_max(length, max_length);
681 }
682
683 size = sizeof(nxt_http_fields_hash_t);
684
685 if (min_length <= 32) {
686 size += (max_length - min_length + 1)
687 * sizeof(nxt_http_fields_hash_elt_t *);
688 }
689
690 hash = nxt_mem_zalloc(mp, size);
691 if (nxt_slow_path(hash == NULL)) {
679 return NULL;
680 }
681
692 return NULL;
693 }
694
682 if (value->length > hash->max_length) {
683 if (value->length > 32 && hash->long_fields != NULL) {
684 return nxt_http_header_fields_hash_lookup_long(hash, value);
695 hash->min_length = min_length;
696 hash->max_length = max_length;
697
698 for (i = 0; entries[i].handler != NULL; i++) {
699 length = entries[i].name.length;
700 elt = hash->elts[length - min_length];
701
702 if (elt != NULL) {
703 continue;
685 }
686
704 }
705
706 n = 1;
707
708 for (j = i + 1; entries[j].handler != NULL; j++) {
709 if (length == entries[j].name.length) {
710 n++;
711 }
712 }
713
714 size = sizeof(nxt_http_fields_hash_elt_t) + nxt_align_size(length, 8);
715
716 elt = nxt_mem_zalloc(mp, n * size
717 + sizeof(nxt_http_fields_hash_elt_t));
718
719 if (nxt_slow_path(elt == NULL)) {
720 return NULL;
721 }
722
723 hash->elts[length - min_length] = elt;
724
725 for (j = i; entries[j].handler != NULL; j++) {
726 if (length != entries[j].name.length) {
727 continue;
728 }
729
730 elt->entry = &entries[j];
731
732 nxt_memcpy_lowcase(elt->key->str, entries[j].name.start, length);
733
734 n--;
735
736 if (n == 0) {
737 break;
738 }
739
740 elt = (nxt_http_fields_hash_elt_t *) ((u_char *) elt + size);
741 }
742 }
743
744 return hash;
745}
746
747
748nxt_http_fields_hash_entry_t *
749nxt_http_fields_hash_lookup(nxt_http_fields_hash_t *hash,
750 nxt_http_field_t *field)
751{
752 nxt_http_fields_hash_elt_t *elt;
753
754 if (field->name.length < hash->min_length) {
687 return NULL;
688 }
689
755 return NULL;
756 }
757
690 entry = hash->entries[value->length - hash->min_length];
758 if (field->name.length > hash->max_length) {
691
759
692 if (entry == NULL) {
760 if (field->name.length > 32 && hash->long_fields != NULL) {
761 return nxt_http_fields_hash_lookup_long(hash, field);
762 }
763
693 return NULL;
694 }
695
764 return NULL;
765 }
766
696 switch ((value->length + 7) / 8) {
767 elt = hash->elts[field->name.length - hash->min_length];
768
769 if (elt == NULL) {
770 return NULL;
771 }
772
773 switch ((field->name.length + 7) / 8) {
697 case 1:
698 do {
774 case 1:
775 do {
699 if (entry->key[0].ui64 == key[0]) {
700 return entry;
776 if (elt->key[0].ui64 == field->key.ui64[0]) {
777 return elt->entry;
701 }
702
778 }
779
703 entry = nxt_http_fields_hash_next_entry(entry, 1);
780 elt = nxt_http_fields_hash_next_elt(elt, 1);
704
781
705 } while (entry->handler != NULL);
782 } while (elt->entry != NULL);
706
707 break;
708
709 case 2:
710 do {
783
784 break;
785
786 case 2:
787 do {
711 if (entry->key[0].ui64 == key[0]
712 && entry->key[1].ui64 == key[1])
788 if (elt->key[0].ui64 == field->key.ui64[0]
789 && elt->key[1].ui64 == field->key.ui64[1])
713 {
790 {
714 return entry;
791 return elt->entry;
715 }
716
792 }
793
717 entry = nxt_http_fields_hash_next_entry(entry, 2);
794 elt = nxt_http_fields_hash_next_elt(elt, 2);
718
795
719 } while (entry->handler != NULL);
796 } while (elt->entry != NULL);
720
721 break;
722
723 case 3:
724 do {
797
798 break;
799
800 case 3:
801 do {
725 if (entry->key[0].ui64 == key[0]
726 && entry->key[1].ui64 == key[1]
727 && entry->key[2].ui64 == key[2])
802 if (elt->key[0].ui64 == field->key.ui64[0]
803 && elt->key[1].ui64 == field->key.ui64[1]
804 && elt->key[2].ui64 == field->key.ui64[2])
728 {
805 {
729 return entry;
806 return elt->entry;
730 }
731
807 }
808
732 entry = nxt_http_fields_hash_next_entry(entry, 3);
809 elt = nxt_http_fields_hash_next_elt(elt, 3);
733
810
734 } while (entry->handler != NULL);
811 } while (elt->entry != NULL);
735
736 break;
737
738 case 4:
739 do {
812
813 break;
814
815 case 4:
816 do {
740 if (entry->key[0].ui64 == key[0]
741 && entry->key[1].ui64 == key[1]
742 && entry->key[2].ui64 == key[2]
743 && entry->key[3].ui64 == key[3])
817 if (elt->key[0].ui64 == field->key.ui64[0]
818 && elt->key[1].ui64 == field->key.ui64[1]
819 && elt->key[2].ui64 == field->key.ui64[2]
820 && elt->key[3].ui64 == field->key.ui64[3])
744 {
821 {
745 return entry;
822 return elt->entry;
746 }
747
823 }
824
748 entry = nxt_http_fields_hash_next_entry(entry, 4);
825 elt = nxt_http_fields_hash_next_elt(elt, 4);
749
826
750 } while (entry->handler != NULL);
827 } while (elt->entry != NULL);
751
752 break;
753
754 default:
755 nxt_unreachable();
756 }
757
758 return NULL;
759}
760
761
762static nxt_http_fields_hash_entry_t *
828
829 break;
830
831 default:
832 nxt_unreachable();
833 }
834
835 return NULL;
836}
837
838
839static nxt_http_fields_hash_entry_t *
763nxt_http_header_fields_hash_lookup_long(nxt_http_fields_hash_t *hash,
764 nxt_str_t *value)
840nxt_http_fields_hash_lookup_long(nxt_http_fields_hash_t *hash,
841 nxt_http_field_t *field)
765{
766 /* TODO */
767 return NULL;
768}
769
770
842{
843 /* TODO */
844 return NULL;
845}
846
847
771nxt_http_fields_hash_t *
772nxt_http_fields_hash(nxt_http_fields_t *fields, nxt_mem_pool_t *mp)
848nxt_int_t
849nxt_http_fields_process(nxt_list_t *fields, nxt_http_fields_hash_t *hash,
850 void *ctx, nxt_log_t *log)
773{
851{
774 size_t min_length, max_length, length, size;
775 nxt_uint_t i, j, n;
776 nxt_http_fields_hash_t *hash;
852 nxt_int_t rc;
853 nxt_http_field_t *field;
777 nxt_http_fields_hash_entry_t *entry;
778
854 nxt_http_fields_hash_entry_t *entry;
855
779 min_length = 32 + 1;
780 max_length = 0;
856 nxt_list_each(field, fields) {
857 entry = nxt_http_fields_hash_lookup(hash, field);
781
858
782 for (i = 0; fields[i].handler != NULL; i++) {
783 length = fields[i].name.length;
784
785 if (length > 32) {
786 /* TODO */
787 return NULL;
788 }
789
790 min_length = nxt_min(length, min_length);
791 max_length = nxt_max(length, max_length);
792 }
793
794 size = sizeof(nxt_http_fields_hash_t);
795
796 if (min_length <= 32) {
797 size += (max_length - min_length + 1)
798 * sizeof(nxt_http_fields_hash_entry_t *);
799 }
800
801 hash = nxt_mem_zalloc(mp, size);
802 if (nxt_slow_path(hash == NULL)) {
803 return NULL;
804 }
805
806 hash->min_length = min_length;
807 hash->max_length = max_length;
808
809 for (i = 0; fields[i].handler != NULL; i++) {
810 length = fields[i].name.length;
811 entry = hash->entries[length - min_length];
812
813 if (entry != NULL) {
859 if (entry != NULL) {
814 continue;
815 }
860 rc = entry->handler(ctx, field, entry->data, log);
816
861
817 n = 1;
818
819 for (j = i + 1; fields[j].handler != NULL; j++) {
820 if (length == fields[j].name.length) {
821 n++;
862 if (rc != NXT_OK) {
863 return rc;
822 }
823 }
824
864 }
865 }
866
825 size = sizeof(nxt_http_fields_hash_entry_t) + nxt_align_size(length, 8);
867 } nxt_list_loop;
826
868
827 entry = nxt_mem_zalloc(mp, n * size
828 + sizeof(nxt_http_fields_hash_entry_t));
829
830 if (nxt_slow_path(entry == NULL)) {
831 return NULL;
832 }
833
834 hash->entries[length - min_length] = entry;
835
836 for (j = i; fields[j].handler != NULL; j++) {
837 if (length != fields[j].name.length) {
838 continue;
839 }
840
841 entry->handler = fields[j].handler;
842 entry->data = fields[j].data;
843
844 nxt_memcpy_lowcase(entry->key->str, fields[j].name.start, length);
845
846 n--;
847
848 if (n == 0) {
849 break;
850 }
851
852 entry = (nxt_http_fields_hash_entry_t *) ((u_char *) entry + size);
853 }
854 }
855
856 return hash;
869 return NXT_OK;
857}
870}