116Svbart@nginx.com 216Svbart@nginx.com /* 316Svbart@nginx.com * Copyright (C) NGINX, Inc. 416Svbart@nginx.com * Copyright (C) Valentin V. Bartenev 516Svbart@nginx.com */ 616Svbart@nginx.com 716Svbart@nginx.com #include <nxt_main.h> 816Svbart@nginx.com 916Svbart@nginx.com 1016Svbart@nginx.com typedef struct { 11*60Svbart@nginx.com nxt_http_fields_hash_entry_t *entry; 12*60Svbart@nginx.com 1316Svbart@nginx.com union { 14*60Svbart@nginx.com uint8_t str[8]; 15*60Svbart@nginx.com uint64_t ui64; 1616Svbart@nginx.com } key[]; 17*60Svbart@nginx.com } nxt_http_fields_hash_elt_t; 1816Svbart@nginx.com 1916Svbart@nginx.com 2016Svbart@nginx.com struct nxt_http_fields_hash_s { 2116Svbart@nginx.com size_t min_length; 2216Svbart@nginx.com size_t max_length; 2316Svbart@nginx.com void *long_fields; 24*60Svbart@nginx.com nxt_http_fields_hash_elt_t *elts[]; 2516Svbart@nginx.com }; 2616Svbart@nginx.com 2716Svbart@nginx.com 28*60Svbart@nginx.com #define nxt_http_fields_hash_next_elt(elt, n) \ 29*60Svbart@nginx.com ((nxt_http_fields_hash_elt_t *) ((u_char *) (elt) \ 30*60Svbart@nginx.com + sizeof(nxt_http_fields_hash_elt_t) \ 31*60Svbart@nginx.com + n * 8)) 32*60Svbart@nginx.com 33*60Svbart@nginx.com 3416Svbart@nginx.com static nxt_int_t nxt_http_parse_unusual_target(nxt_http_request_parse_t *rp, 3516Svbart@nginx.com u_char **pos, u_char *end); 3616Svbart@nginx.com static nxt_int_t nxt_http_parse_request_line(nxt_http_request_parse_t *rp, 3716Svbart@nginx.com u_char **pos, u_char *end); 3816Svbart@nginx.com static nxt_int_t nxt_http_parse_field_name(nxt_http_request_parse_t *rp, 3916Svbart@nginx.com u_char **pos, u_char *end); 4016Svbart@nginx.com static nxt_int_t nxt_http_parse_field_value(nxt_http_request_parse_t *rp, 4116Svbart@nginx.com u_char **pos, u_char *end); 4216Svbart@nginx.com static u_char *nxt_http_lookup_field_end(u_char *p, u_char *end); 4316Svbart@nginx.com static nxt_int_t nxt_http_parse_field_end(nxt_http_request_parse_t *rp, 4416Svbart@nginx.com u_char **pos, u_char *end); 4516Svbart@nginx.com 46*60Svbart@nginx.com 47*60Svbart@nginx.com static nxt_http_fields_hash_entry_t *nxt_http_fields_hash_lookup_long( 48*60Svbart@nginx.com nxt_http_fields_hash_t *hash, nxt_http_field_t *field); 4916Svbart@nginx.com 5016Svbart@nginx.com 5116Svbart@nginx.com typedef enum { 5216Svbart@nginx.com NXT_HTTP_TARGET_SPACE = 1, /* \s */ 5316Svbart@nginx.com NXT_HTTP_TARGET_HASH, /* # */ 5416Svbart@nginx.com NXT_HTTP_TARGET_AGAIN, 5516Svbart@nginx.com NXT_HTTP_TARGET_BAD, /* \0\r\n */ 5616Svbart@nginx.com 5716Svbart@nginx.com /* traps below are used for extended check only */ 5816Svbart@nginx.com 5916Svbart@nginx.com NXT_HTTP_TARGET_SLASH = 5, /* / */ 6016Svbart@nginx.com NXT_HTTP_TARGET_DOT, /* . */ 6116Svbart@nginx.com NXT_HTTP_TARGET_ARGS_MARK, /* ? */ 6216Svbart@nginx.com NXT_HTTP_TARGET_QUOTE_MARK, /* % */ 6316Svbart@nginx.com NXT_HTTP_TARGET_PLUS, /* + */ 6416Svbart@nginx.com } nxt_http_target_traps_e; 6516Svbart@nginx.com 6616Svbart@nginx.com 6716Svbart@nginx.com static const uint8_t nxt_http_target_chars[256] nxt_aligned(64) = { 6816Svbart@nginx.com /* \0 \n \r */ 6916Svbart@nginx.com 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 4, 0, 0, 7016Svbart@nginx.com 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7152Svbart@nginx.com 7252Svbart@nginx.com /* \s ! " # $ % & ' ( ) * + , - . / */ 7316Svbart@nginx.com 1, 0, 0, 2, 0, 8, 0, 0, 0, 0, 0, 9, 0, 0, 6, 5, 7452Svbart@nginx.com 7552Svbart@nginx.com /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 7616Svbart@nginx.com 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7716Svbart@nginx.com }; 7816Svbart@nginx.com 7916Svbart@nginx.com 8016Svbart@nginx.com nxt_inline nxt_http_target_traps_e 8116Svbart@nginx.com nxt_http_parse_target(u_char **pos, u_char *end) 8216Svbart@nginx.com { 8316Svbart@nginx.com u_char *p; 8416Svbart@nginx.com nxt_uint_t trap; 8516Svbart@nginx.com 8616Svbart@nginx.com p = *pos; 8716Svbart@nginx.com 8816Svbart@nginx.com for ( ;; ) { 8916Svbart@nginx.com if (nxt_slow_path(end - p < 10)) { 9016Svbart@nginx.com return NXT_HTTP_TARGET_AGAIN; 9116Svbart@nginx.com } 9216Svbart@nginx.com 9316Svbart@nginx.com #define nxt_http_parse_target_step \ 9416Svbart@nginx.com { \ 9516Svbart@nginx.com trap = nxt_http_target_chars[*p]; \ 9616Svbart@nginx.com \ 9716Svbart@nginx.com if (nxt_slow_path(trap != 0)) { \ 9816Svbart@nginx.com break; \ 9916Svbart@nginx.com } \ 10016Svbart@nginx.com \ 10116Svbart@nginx.com p++; \ 10216Svbart@nginx.com } 10316Svbart@nginx.com 10416Svbart@nginx.com nxt_http_parse_target_step 10516Svbart@nginx.com nxt_http_parse_target_step 10616Svbart@nginx.com nxt_http_parse_target_step 10716Svbart@nginx.com nxt_http_parse_target_step 10816Svbart@nginx.com 10916Svbart@nginx.com nxt_http_parse_target_step 11016Svbart@nginx.com nxt_http_parse_target_step 11116Svbart@nginx.com nxt_http_parse_target_step 11216Svbart@nginx.com nxt_http_parse_target_step 11316Svbart@nginx.com 11416Svbart@nginx.com nxt_http_parse_target_step 11516Svbart@nginx.com nxt_http_parse_target_step 11616Svbart@nginx.com 11716Svbart@nginx.com #undef nxt_http_parse_target_step 11816Svbart@nginx.com } 11916Svbart@nginx.com 12016Svbart@nginx.com *pos = p; 12116Svbart@nginx.com 12216Svbart@nginx.com return trap; 12316Svbart@nginx.com } 12416Svbart@nginx.com 12516Svbart@nginx.com 12616Svbart@nginx.com nxt_int_t 12716Svbart@nginx.com nxt_http_parse_request(nxt_http_request_parse_t *rp, nxt_buf_mem_t *b) 12816Svbart@nginx.com { 12916Svbart@nginx.com nxt_int_t rc; 13016Svbart@nginx.com 13116Svbart@nginx.com if (rp->handler == NULL) { 13216Svbart@nginx.com rp->handler = &nxt_http_parse_request_line; 13316Svbart@nginx.com } 13416Svbart@nginx.com 13516Svbart@nginx.com do { 13616Svbart@nginx.com rc = rp->handler(rp, &b->pos, b->free); 13716Svbart@nginx.com } while (rc == NXT_OK); 13816Svbart@nginx.com 13916Svbart@nginx.com return rc; 14016Svbart@nginx.com } 14116Svbart@nginx.com 14216Svbart@nginx.com 14316Svbart@nginx.com static nxt_int_t 14416Svbart@nginx.com nxt_http_parse_request_line(nxt_http_request_parse_t *rp, u_char **pos, 14516Svbart@nginx.com u_char *end) 14616Svbart@nginx.com { 14716Svbart@nginx.com u_char *p, ch, *after_slash; 14816Svbart@nginx.com nxt_int_t rc; 14916Svbart@nginx.com nxt_http_ver_t version; 15016Svbart@nginx.com nxt_http_target_traps_e trap; 15116Svbart@nginx.com 15216Svbart@nginx.com static const nxt_http_ver_t http11 = { "HTTP/1.1" }; 15316Svbart@nginx.com static const nxt_http_ver_t http10 = { "HTTP/1.0" }; 15416Svbart@nginx.com 15516Svbart@nginx.com p = *pos; 15616Svbart@nginx.com 15716Svbart@nginx.com rp->method.start = p; 15816Svbart@nginx.com 15916Svbart@nginx.com for ( ;; p++) { 16016Svbart@nginx.com 16116Svbart@nginx.com for ( ;; ) { 16216Svbart@nginx.com if (nxt_slow_path(end - p < 12)) { 16316Svbart@nginx.com return NXT_AGAIN; 16416Svbart@nginx.com } 16516Svbart@nginx.com 16616Svbart@nginx.com #define nxt_http_parse_request_line_step \ 16716Svbart@nginx.com { \ 16816Svbart@nginx.com ch = *p; \ 16916Svbart@nginx.com \ 17016Svbart@nginx.com if (nxt_slow_path(ch < 'A' || ch > 'Z')) { \ 17116Svbart@nginx.com break; \ 17216Svbart@nginx.com } \ 17316Svbart@nginx.com \ 17416Svbart@nginx.com p++; \ 17516Svbart@nginx.com } 17616Svbart@nginx.com 17716Svbart@nginx.com nxt_http_parse_request_line_step 17816Svbart@nginx.com nxt_http_parse_request_line_step 17916Svbart@nginx.com nxt_http_parse_request_line_step 18016Svbart@nginx.com nxt_http_parse_request_line_step 18116Svbart@nginx.com 18216Svbart@nginx.com nxt_http_parse_request_line_step 18316Svbart@nginx.com nxt_http_parse_request_line_step 18416Svbart@nginx.com nxt_http_parse_request_line_step 18516Svbart@nginx.com nxt_http_parse_request_line_step 18616Svbart@nginx.com 18716Svbart@nginx.com #undef nxt_http_parse_request_line_step 18816Svbart@nginx.com } 18916Svbart@nginx.com 19016Svbart@nginx.com if (nxt_fast_path(ch == ' ')) { 19116Svbart@nginx.com rp->method.length = p - rp->method.start; 19216Svbart@nginx.com break; 19316Svbart@nginx.com } 19416Svbart@nginx.com 19516Svbart@nginx.com if (ch == '_' || ch == '-') { 19616Svbart@nginx.com continue; 19716Svbart@nginx.com } 19816Svbart@nginx.com 19916Svbart@nginx.com if (rp->method.start == p && (ch == NXT_CR || ch == NXT_LF)) { 20016Svbart@nginx.com rp->method.start++; 20116Svbart@nginx.com continue; 20216Svbart@nginx.com } 20316Svbart@nginx.com 20416Svbart@nginx.com return NXT_ERROR; 20516Svbart@nginx.com } 20616Svbart@nginx.com 20716Svbart@nginx.com p++; 20816Svbart@nginx.com 20916Svbart@nginx.com if (nxt_slow_path(p == end)) { 21016Svbart@nginx.com return NXT_AGAIN; 21116Svbart@nginx.com } 21216Svbart@nginx.com 21316Svbart@nginx.com /* target */ 21416Svbart@nginx.com 21516Svbart@nginx.com ch = *p; 21616Svbart@nginx.com 21716Svbart@nginx.com if (nxt_slow_path(ch != '/')) { 21816Svbart@nginx.com rc = nxt_http_parse_unusual_target(rp, &p, end); 21916Svbart@nginx.com 22016Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 22116Svbart@nginx.com return rc; 22216Svbart@nginx.com } 22316Svbart@nginx.com } 22416Svbart@nginx.com 22516Svbart@nginx.com rp->target_start = p; 22616Svbart@nginx.com 22716Svbart@nginx.com after_slash = p + 1; 22816Svbart@nginx.com 22916Svbart@nginx.com for ( ;; ) { 23016Svbart@nginx.com p++; 23116Svbart@nginx.com 23216Svbart@nginx.com trap = nxt_http_parse_target(&p, end); 23316Svbart@nginx.com 23416Svbart@nginx.com switch (trap) { 23516Svbart@nginx.com case NXT_HTTP_TARGET_SLASH: 23616Svbart@nginx.com if (nxt_slow_path(after_slash == p)) { 23716Svbart@nginx.com rp->complex_target = 1; 23816Svbart@nginx.com goto rest_of_target; 23916Svbart@nginx.com } 24016Svbart@nginx.com 24116Svbart@nginx.com after_slash = p + 1; 24216Svbart@nginx.com 24316Svbart@nginx.com rp->exten_start = NULL; 24416Svbart@nginx.com continue; 24516Svbart@nginx.com 24616Svbart@nginx.com case NXT_HTTP_TARGET_DOT: 24716Svbart@nginx.com if (nxt_slow_path(after_slash == p)) { 24816Svbart@nginx.com rp->complex_target = 1; 24916Svbart@nginx.com goto rest_of_target; 25016Svbart@nginx.com } 25116Svbart@nginx.com 25216Svbart@nginx.com rp->exten_start = p + 1; 25316Svbart@nginx.com continue; 25416Svbart@nginx.com 25516Svbart@nginx.com case NXT_HTTP_TARGET_ARGS_MARK: 25616Svbart@nginx.com rp->args_start = p + 1; 25716Svbart@nginx.com goto rest_of_target; 25816Svbart@nginx.com 25916Svbart@nginx.com case NXT_HTTP_TARGET_SPACE: 26016Svbart@nginx.com rp->target_end = p; 26116Svbart@nginx.com goto space_after_target; 26216Svbart@nginx.com 26316Svbart@nginx.com case NXT_HTTP_TARGET_QUOTE_MARK: 26416Svbart@nginx.com rp->quoted_target = 1; 26516Svbart@nginx.com goto rest_of_target; 26616Svbart@nginx.com 26716Svbart@nginx.com case NXT_HTTP_TARGET_PLUS: 26816Svbart@nginx.com rp->plus_in_target = 1; 26916Svbart@nginx.com continue; 27016Svbart@nginx.com 27116Svbart@nginx.com case NXT_HTTP_TARGET_HASH: 27216Svbart@nginx.com rp->complex_target = 1; 27316Svbart@nginx.com goto rest_of_target; 27416Svbart@nginx.com 27516Svbart@nginx.com case NXT_HTTP_TARGET_AGAIN: 27616Svbart@nginx.com return NXT_AGAIN; 27716Svbart@nginx.com 27816Svbart@nginx.com case NXT_HTTP_TARGET_BAD: 27916Svbart@nginx.com return NXT_ERROR; 28016Svbart@nginx.com } 28116Svbart@nginx.com 28216Svbart@nginx.com nxt_unreachable(); 28316Svbart@nginx.com } 28416Svbart@nginx.com 28516Svbart@nginx.com rest_of_target: 28616Svbart@nginx.com 28716Svbart@nginx.com for ( ;; ) { 28816Svbart@nginx.com p++; 28916Svbart@nginx.com 29019Svbart@nginx.com trap = nxt_http_parse_target(&p, end); 29116Svbart@nginx.com 29216Svbart@nginx.com switch (trap) { 29316Svbart@nginx.com case NXT_HTTP_TARGET_SPACE: 29416Svbart@nginx.com rp->target_end = p; 29516Svbart@nginx.com goto space_after_target; 29616Svbart@nginx.com 29716Svbart@nginx.com case NXT_HTTP_TARGET_HASH: 29816Svbart@nginx.com rp->complex_target = 1; 29916Svbart@nginx.com continue; 30016Svbart@nginx.com 30116Svbart@nginx.com case NXT_HTTP_TARGET_AGAIN: 30216Svbart@nginx.com return NXT_AGAIN; 30316Svbart@nginx.com 30416Svbart@nginx.com case NXT_HTTP_TARGET_BAD: 30516Svbart@nginx.com return NXT_ERROR; 30616Svbart@nginx.com 30716Svbart@nginx.com default: 30816Svbart@nginx.com continue; 30916Svbart@nginx.com } 31016Svbart@nginx.com 31116Svbart@nginx.com nxt_unreachable(); 31216Svbart@nginx.com } 31316Svbart@nginx.com 31416Svbart@nginx.com space_after_target: 31516Svbart@nginx.com 31616Svbart@nginx.com if (nxt_slow_path(end - p < 10)) { 31716Svbart@nginx.com return NXT_AGAIN; 31816Svbart@nginx.com } 31916Svbart@nginx.com 32016Svbart@nginx.com /* " HTTP/1.1\r\n" or " HTTP/1.1\n" */ 32116Svbart@nginx.com 32216Svbart@nginx.com nxt_memcpy(version.str, &p[1], 8); 32316Svbart@nginx.com 32416Svbart@nginx.com if (nxt_fast_path((version.ui64 == http11.ui64 32516Svbart@nginx.com || version.ui64 == http10.ui64 32616Svbart@nginx.com || (p[1] == 'H' 32716Svbart@nginx.com && p[2] == 'T' 32816Svbart@nginx.com && p[3] == 'T' 32916Svbart@nginx.com && p[4] == 'P' 33016Svbart@nginx.com && p[5] == '/' 33116Svbart@nginx.com && p[6] >= '0' && p[6] <= '9' 33216Svbart@nginx.com && p[7] == '.' 33316Svbart@nginx.com && p[8] >= '0' && p[8] <= '9')) 33416Svbart@nginx.com && (p[9] == '\r' || p[9] == '\n'))) 33516Svbart@nginx.com { 33616Svbart@nginx.com rp->version.ui64 = version.ui64; 33716Svbart@nginx.com 33816Svbart@nginx.com if (nxt_fast_path(p[9] == '\r')) { 33916Svbart@nginx.com p += 10; 34016Svbart@nginx.com 34116Svbart@nginx.com if (nxt_slow_path(p == end)) { 34216Svbart@nginx.com return NXT_AGAIN; 34316Svbart@nginx.com } 34416Svbart@nginx.com 34516Svbart@nginx.com if (nxt_slow_path(*p != '\n')) { 34616Svbart@nginx.com return NXT_ERROR; 34716Svbart@nginx.com } 34816Svbart@nginx.com 34916Svbart@nginx.com *pos = p + 1; 35016Svbart@nginx.com return nxt_http_parse_field_name(rp, pos, end); 35116Svbart@nginx.com } 35216Svbart@nginx.com 35316Svbart@nginx.com *pos = p + 10; 35416Svbart@nginx.com return nxt_http_parse_field_name(rp, pos, end); 35516Svbart@nginx.com } 35616Svbart@nginx.com 35716Svbart@nginx.com if (p[1] == ' ') { 35816Svbart@nginx.com /* surplus space after tartet */ 35916Svbart@nginx.com p++; 36016Svbart@nginx.com goto space_after_target; 36116Svbart@nginx.com } 36216Svbart@nginx.com 36316Svbart@nginx.com rp->space_in_target = 1; 36416Svbart@nginx.com goto rest_of_target; 36516Svbart@nginx.com } 36616Svbart@nginx.com 36716Svbart@nginx.com 36816Svbart@nginx.com static nxt_int_t 36916Svbart@nginx.com nxt_http_parse_unusual_target(nxt_http_request_parse_t *rp, u_char **pos, 37016Svbart@nginx.com u_char *end) 37116Svbart@nginx.com { 37216Svbart@nginx.com u_char *p, ch; 37316Svbart@nginx.com 37416Svbart@nginx.com p = *pos; 37516Svbart@nginx.com 37616Svbart@nginx.com ch = *p; 37716Svbart@nginx.com 37816Svbart@nginx.com if (ch == ' ') { 37916Svbart@nginx.com /* skip surplus spaces before target */ 38016Svbart@nginx.com 38116Svbart@nginx.com do { 38216Svbart@nginx.com p++; 38316Svbart@nginx.com 38416Svbart@nginx.com if (nxt_slow_path(p == end)) { 38516Svbart@nginx.com return NXT_AGAIN; 38616Svbart@nginx.com } 38716Svbart@nginx.com 38816Svbart@nginx.com ch = *p; 38916Svbart@nginx.com 39016Svbart@nginx.com } while (ch == ' '); 39116Svbart@nginx.com 39216Svbart@nginx.com if (ch == '/') { 39316Svbart@nginx.com *pos = p; 39416Svbart@nginx.com return NXT_OK; 39516Svbart@nginx.com } 39616Svbart@nginx.com } 39716Svbart@nginx.com 39816Svbart@nginx.com /* absolute path or '*' */ 39916Svbart@nginx.com 40016Svbart@nginx.com /* TODO */ 40116Svbart@nginx.com 40216Svbart@nginx.com return NXT_ERROR; 40316Svbart@nginx.com } 40416Svbart@nginx.com 40516Svbart@nginx.com 40616Svbart@nginx.com static nxt_int_t 40716Svbart@nginx.com nxt_http_parse_field_name(nxt_http_request_parse_t *rp, u_char **pos, 40816Svbart@nginx.com u_char *end) 40916Svbart@nginx.com { 41016Svbart@nginx.com u_char *p, ch, c; 41116Svbart@nginx.com size_t i, size; 41216Svbart@nginx.com 41316Svbart@nginx.com static const u_char normal[256] nxt_aligned(64) = 41416Svbart@nginx.com "\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" 41516Svbart@nginx.com "\0\0\0\0\0\0\0\0\0\0\0\0\0-\0\0" "0123456789\0\0\0\0\0\0" 41616Svbart@nginx.com 41716Svbart@nginx.com /* These 64 bytes should reside in one cache line. */ 41816Svbart@nginx.com "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0" 41916Svbart@nginx.com "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0" 42016Svbart@nginx.com 42116Svbart@nginx.com "\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" 42216Svbart@nginx.com "\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" 42316Svbart@nginx.com "\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" 42416Svbart@nginx.com "\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"; 42516Svbart@nginx.com 42616Svbart@nginx.com p = *pos; 42716Svbart@nginx.com 42816Svbart@nginx.com size = end - p; 429*60Svbart@nginx.com i = rp->field.name.length; 43016Svbart@nginx.com 43119Svbart@nginx.com #define nxt_http_parse_field_name_step \ 43219Svbart@nginx.com { \ 43319Svbart@nginx.com ch = p[i]; \ 43419Svbart@nginx.com c = normal[ch]; \ 43519Svbart@nginx.com \ 43619Svbart@nginx.com if (nxt_slow_path(c == '\0')) { \ 43719Svbart@nginx.com goto name_end; \ 43819Svbart@nginx.com } \ 43919Svbart@nginx.com \ 440*60Svbart@nginx.com rp->field.key.str[i % 32] = c; \ 44119Svbart@nginx.com i++; \ 44219Svbart@nginx.com } 44316Svbart@nginx.com 44419Svbart@nginx.com while (nxt_fast_path(size - i >= 8)) { 44519Svbart@nginx.com nxt_http_parse_field_name_step 44619Svbart@nginx.com nxt_http_parse_field_name_step 44719Svbart@nginx.com nxt_http_parse_field_name_step 44819Svbart@nginx.com nxt_http_parse_field_name_step 44916Svbart@nginx.com 45019Svbart@nginx.com nxt_http_parse_field_name_step 45119Svbart@nginx.com nxt_http_parse_field_name_step 45219Svbart@nginx.com nxt_http_parse_field_name_step 45319Svbart@nginx.com nxt_http_parse_field_name_step 45419Svbart@nginx.com } 45516Svbart@nginx.com 45619Svbart@nginx.com while (nxt_fast_path(i != size)) { 45719Svbart@nginx.com nxt_http_parse_field_name_step 45819Svbart@nginx.com } 45916Svbart@nginx.com 46019Svbart@nginx.com #undef nxt_http_parse_field_name_step 46116Svbart@nginx.com 462*60Svbart@nginx.com rp->field.name.length = i; 46316Svbart@nginx.com rp->handler = &nxt_http_parse_field_name; 46416Svbart@nginx.com 46516Svbart@nginx.com return NXT_AGAIN; 46619Svbart@nginx.com 46719Svbart@nginx.com name_end: 46819Svbart@nginx.com 46919Svbart@nginx.com if (nxt_fast_path(ch == ':')) { 47019Svbart@nginx.com if (nxt_slow_path(i == 0)) { 47119Svbart@nginx.com return NXT_ERROR; 47219Svbart@nginx.com } 47319Svbart@nginx.com 47419Svbart@nginx.com *pos = &p[i] + 1; 47519Svbart@nginx.com 476*60Svbart@nginx.com rp->field.name.length = i; 477*60Svbart@nginx.com rp->field.name.start = p; 47819Svbart@nginx.com 47919Svbart@nginx.com return nxt_http_parse_field_value(rp, pos, end); 48019Svbart@nginx.com } 48119Svbart@nginx.com 48259Svbart@nginx.com if (nxt_slow_path(i != 0)) { 48359Svbart@nginx.com return NXT_ERROR; 48459Svbart@nginx.com } 48519Svbart@nginx.com 48619Svbart@nginx.com return nxt_http_parse_field_end(rp, pos, end); 48716Svbart@nginx.com } 48816Svbart@nginx.com 48916Svbart@nginx.com 49016Svbart@nginx.com static nxt_int_t 49116Svbart@nginx.com nxt_http_parse_field_value(nxt_http_request_parse_t *rp, u_char **pos, 49216Svbart@nginx.com u_char *end) 49316Svbart@nginx.com { 49416Svbart@nginx.com u_char *p, ch; 49516Svbart@nginx.com 49616Svbart@nginx.com p = *pos; 49716Svbart@nginx.com 49816Svbart@nginx.com for ( ;; ) { 49916Svbart@nginx.com if (nxt_slow_path(p == end)) { 50016Svbart@nginx.com *pos = p; 50116Svbart@nginx.com rp->handler = &nxt_http_parse_field_value; 50216Svbart@nginx.com return NXT_AGAIN; 50316Svbart@nginx.com } 50416Svbart@nginx.com 50516Svbart@nginx.com if (*p != ' ') { 50616Svbart@nginx.com break; 50716Svbart@nginx.com } 50816Svbart@nginx.com 50916Svbart@nginx.com p++; 51016Svbart@nginx.com } 51116Svbart@nginx.com 51216Svbart@nginx.com *pos = p; 51316Svbart@nginx.com 514*60Svbart@nginx.com p += rp->field.value.length; 51516Svbart@nginx.com 51616Svbart@nginx.com for ( ;; ) { 51716Svbart@nginx.com p = nxt_http_lookup_field_end(p, end); 51816Svbart@nginx.com 51916Svbart@nginx.com if (nxt_slow_path(p == end)) { 520*60Svbart@nginx.com rp->field.value.length = p - *pos; 52116Svbart@nginx.com rp->handler = &nxt_http_parse_field_value; 52216Svbart@nginx.com return NXT_AGAIN; 52316Svbart@nginx.com } 52416Svbart@nginx.com 52516Svbart@nginx.com ch = *p; 52616Svbart@nginx.com 52716Svbart@nginx.com if (nxt_fast_path(ch == '\r' || ch == '\n')) { 52816Svbart@nginx.com break; 52916Svbart@nginx.com } 53016Svbart@nginx.com 53116Svbart@nginx.com if (ch == '\0') { 53216Svbart@nginx.com return NXT_ERROR; 53316Svbart@nginx.com } 53416Svbart@nginx.com } 53516Svbart@nginx.com 53616Svbart@nginx.com if (nxt_fast_path(p != *pos)) { 53716Svbart@nginx.com while (p[-1] == ' ') { 53816Svbart@nginx.com p--; 53916Svbart@nginx.com } 54016Svbart@nginx.com } 54116Svbart@nginx.com 542*60Svbart@nginx.com rp->field.value.length = p - *pos; 543*60Svbart@nginx.com rp->field.value.start = *pos; 54416Svbart@nginx.com 54516Svbart@nginx.com *pos = p; 54616Svbart@nginx.com 54716Svbart@nginx.com return nxt_http_parse_field_end(rp, pos, end); 54816Svbart@nginx.com } 54916Svbart@nginx.com 55016Svbart@nginx.com 55116Svbart@nginx.com static u_char * 55216Svbart@nginx.com nxt_http_lookup_field_end(u_char *p, u_char *end) 55316Svbart@nginx.com { 55416Svbart@nginx.com nxt_uint_t n; 55516Svbart@nginx.com 55616Svbart@nginx.com #define nxt_http_lookup_field_end_step \ 55716Svbart@nginx.com { \ 55819Svbart@nginx.com if (nxt_slow_path(*p < 0x10)) { \ 55916Svbart@nginx.com return p; \ 56016Svbart@nginx.com } \ 56116Svbart@nginx.com \ 56216Svbart@nginx.com p++; \ 56316Svbart@nginx.com } 56416Svbart@nginx.com 56519Svbart@nginx.com for (n = (end - p) / 16; nxt_fast_path(n != 0); n--) { 56619Svbart@nginx.com nxt_http_lookup_field_end_step 56719Svbart@nginx.com nxt_http_lookup_field_end_step 56819Svbart@nginx.com nxt_http_lookup_field_end_step 56919Svbart@nginx.com nxt_http_lookup_field_end_step 57019Svbart@nginx.com 57119Svbart@nginx.com nxt_http_lookup_field_end_step 57219Svbart@nginx.com nxt_http_lookup_field_end_step 57319Svbart@nginx.com nxt_http_lookup_field_end_step 57419Svbart@nginx.com nxt_http_lookup_field_end_step 57519Svbart@nginx.com 57616Svbart@nginx.com nxt_http_lookup_field_end_step 57716Svbart@nginx.com nxt_http_lookup_field_end_step 57816Svbart@nginx.com nxt_http_lookup_field_end_step 57916Svbart@nginx.com nxt_http_lookup_field_end_step 58016Svbart@nginx.com 58116Svbart@nginx.com nxt_http_lookup_field_end_step 58216Svbart@nginx.com nxt_http_lookup_field_end_step 58316Svbart@nginx.com nxt_http_lookup_field_end_step 58416Svbart@nginx.com nxt_http_lookup_field_end_step 58516Svbart@nginx.com } 58616Svbart@nginx.com 58719Svbart@nginx.com for (n = (end - p) / 4; nxt_fast_path(n != 0); n--) { 58816Svbart@nginx.com nxt_http_lookup_field_end_step 58919Svbart@nginx.com nxt_http_lookup_field_end_step 59016Svbart@nginx.com nxt_http_lookup_field_end_step 59116Svbart@nginx.com nxt_http_lookup_field_end_step 59219Svbart@nginx.com } 59319Svbart@nginx.com 59419Svbart@nginx.com switch (end - p) { 59516Svbart@nginx.com case 3: 59616Svbart@nginx.com nxt_http_lookup_field_end_step 59739Svbart@nginx.com /* Fall through. */ 59816Svbart@nginx.com case 2: 59916Svbart@nginx.com nxt_http_lookup_field_end_step 60039Svbart@nginx.com /* Fall through. */ 60116Svbart@nginx.com case 1: 60216Svbart@nginx.com nxt_http_lookup_field_end_step 60339Svbart@nginx.com /* Fall through. */ 60416Svbart@nginx.com case 0: 60516Svbart@nginx.com break; 60616Svbart@nginx.com default: 60716Svbart@nginx.com nxt_unreachable(); 60816Svbart@nginx.com } 60916Svbart@nginx.com 61016Svbart@nginx.com #undef nxt_http_lookup_field_end_step 61116Svbart@nginx.com 61216Svbart@nginx.com return p; 61316Svbart@nginx.com } 61416Svbart@nginx.com 61516Svbart@nginx.com 61616Svbart@nginx.com static nxt_int_t 61716Svbart@nginx.com nxt_http_parse_field_end(nxt_http_request_parse_t *rp, u_char **pos, 61816Svbart@nginx.com u_char *end) 61916Svbart@nginx.com { 620*60Svbart@nginx.com u_char *p; 621*60Svbart@nginx.com nxt_http_field_t *field; 62216Svbart@nginx.com 62316Svbart@nginx.com p = *pos; 62416Svbart@nginx.com 62516Svbart@nginx.com if (nxt_fast_path(*p == '\r')) { 62616Svbart@nginx.com p++; 62716Svbart@nginx.com 62816Svbart@nginx.com if (nxt_slow_path(p == end)) { 62916Svbart@nginx.com rp->handler = &nxt_http_parse_field_end; 63016Svbart@nginx.com return NXT_AGAIN; 63116Svbart@nginx.com } 63216Svbart@nginx.com } 63316Svbart@nginx.com 63416Svbart@nginx.com if (nxt_fast_path(*p == '\n')) { 63516Svbart@nginx.com *pos = p + 1; 63616Svbart@nginx.com 637*60Svbart@nginx.com if (rp->field.name.length != 0) { 638*60Svbart@nginx.com field = nxt_list_add(rp->fields); 63916Svbart@nginx.com 640*60Svbart@nginx.com if (nxt_slow_path(field == NULL)) { 641*60Svbart@nginx.com return NXT_ERROR; 64216Svbart@nginx.com } 64316Svbart@nginx.com 644*60Svbart@nginx.com *field = rp->field; 645*60Svbart@nginx.com 646*60Svbart@nginx.com nxt_memzero(&rp->field, sizeof(nxt_http_field_t)); 64716Svbart@nginx.com 64816Svbart@nginx.com rp->handler = &nxt_http_parse_field_name; 64916Svbart@nginx.com return NXT_OK; 65016Svbart@nginx.com } 65116Svbart@nginx.com 65216Svbart@nginx.com return NXT_DONE; 65316Svbart@nginx.com } 65416Svbart@nginx.com 65516Svbart@nginx.com return NXT_ERROR; 65616Svbart@nginx.com } 65716Svbart@nginx.com 65816Svbart@nginx.com 659*60Svbart@nginx.com nxt_http_fields_hash_t * 660*60Svbart@nginx.com nxt_http_fields_hash_create(nxt_http_fields_hash_entry_t *entries, 661*60Svbart@nginx.com nxt_mem_pool_t *mp) 66216Svbart@nginx.com { 663*60Svbart@nginx.com size_t min_length, max_length, length, size; 664*60Svbart@nginx.com nxt_uint_t i, j, n; 665*60Svbart@nginx.com nxt_http_fields_hash_t *hash; 666*60Svbart@nginx.com nxt_http_fields_hash_elt_t *elt; 66716Svbart@nginx.com 66838Svbart@nginx.com min_length = 32 + 1; 66916Svbart@nginx.com max_length = 0; 67016Svbart@nginx.com 671*60Svbart@nginx.com for (i = 0; entries[i].handler != NULL; i++) { 672*60Svbart@nginx.com length = entries[i].name.length; 67316Svbart@nginx.com 67416Svbart@nginx.com if (length > 32) { 67516Svbart@nginx.com /* TODO */ 67616Svbart@nginx.com return NULL; 67716Svbart@nginx.com } 67816Svbart@nginx.com 67916Svbart@nginx.com min_length = nxt_min(length, min_length); 68016Svbart@nginx.com max_length = nxt_max(length, max_length); 68116Svbart@nginx.com } 68216Svbart@nginx.com 68338Svbart@nginx.com size = sizeof(nxt_http_fields_hash_t); 68416Svbart@nginx.com 68538Svbart@nginx.com if (min_length <= 32) { 68638Svbart@nginx.com size += (max_length - min_length + 1) 687*60Svbart@nginx.com * sizeof(nxt_http_fields_hash_elt_t *); 68838Svbart@nginx.com } 68916Svbart@nginx.com 69038Svbart@nginx.com hash = nxt_mem_zalloc(mp, size); 69116Svbart@nginx.com if (nxt_slow_path(hash == NULL)) { 69216Svbart@nginx.com return NULL; 69316Svbart@nginx.com } 69416Svbart@nginx.com 69516Svbart@nginx.com hash->min_length = min_length; 69616Svbart@nginx.com hash->max_length = max_length; 69716Svbart@nginx.com 698*60Svbart@nginx.com for (i = 0; entries[i].handler != NULL; i++) { 699*60Svbart@nginx.com length = entries[i].name.length; 700*60Svbart@nginx.com elt = hash->elts[length - min_length]; 70116Svbart@nginx.com 702*60Svbart@nginx.com if (elt != NULL) { 70316Svbart@nginx.com continue; 70416Svbart@nginx.com } 70516Svbart@nginx.com 70616Svbart@nginx.com n = 1; 70716Svbart@nginx.com 708*60Svbart@nginx.com for (j = i + 1; entries[j].handler != NULL; j++) { 709*60Svbart@nginx.com if (length == entries[j].name.length) { 71016Svbart@nginx.com n++; 71116Svbart@nginx.com } 71216Svbart@nginx.com } 71316Svbart@nginx.com 714*60Svbart@nginx.com size = sizeof(nxt_http_fields_hash_elt_t) + nxt_align_size(length, 8); 71516Svbart@nginx.com 716*60Svbart@nginx.com elt = nxt_mem_zalloc(mp, n * size 717*60Svbart@nginx.com + sizeof(nxt_http_fields_hash_elt_t)); 71816Svbart@nginx.com 719*60Svbart@nginx.com if (nxt_slow_path(elt == NULL)) { 72016Svbart@nginx.com return NULL; 72116Svbart@nginx.com } 72216Svbart@nginx.com 723*60Svbart@nginx.com hash->elts[length - min_length] = elt; 72416Svbart@nginx.com 725*60Svbart@nginx.com for (j = i; entries[j].handler != NULL; j++) { 726*60Svbart@nginx.com if (length != entries[j].name.length) { 72716Svbart@nginx.com continue; 72816Svbart@nginx.com } 72916Svbart@nginx.com 730*60Svbart@nginx.com elt->entry = &entries[j]; 73116Svbart@nginx.com 732*60Svbart@nginx.com nxt_memcpy_lowcase(elt->key->str, entries[j].name.start, length); 73316Svbart@nginx.com 73416Svbart@nginx.com n--; 73516Svbart@nginx.com 73616Svbart@nginx.com if (n == 0) { 73716Svbart@nginx.com break; 73816Svbart@nginx.com } 73916Svbart@nginx.com 740*60Svbart@nginx.com elt = (nxt_http_fields_hash_elt_t *) ((u_char *) elt + size); 74116Svbart@nginx.com } 74216Svbart@nginx.com } 74316Svbart@nginx.com 74416Svbart@nginx.com return hash; 74516Svbart@nginx.com } 746*60Svbart@nginx.com 747*60Svbart@nginx.com 748*60Svbart@nginx.com nxt_http_fields_hash_entry_t * 749*60Svbart@nginx.com nxt_http_fields_hash_lookup(nxt_http_fields_hash_t *hash, 750*60Svbart@nginx.com nxt_http_field_t *field) 751*60Svbart@nginx.com { 752*60Svbart@nginx.com nxt_http_fields_hash_elt_t *elt; 753*60Svbart@nginx.com 754*60Svbart@nginx.com if (field->name.length < hash->min_length) { 755*60Svbart@nginx.com return NULL; 756*60Svbart@nginx.com } 757*60Svbart@nginx.com 758*60Svbart@nginx.com if (field->name.length > hash->max_length) { 759*60Svbart@nginx.com 760*60Svbart@nginx.com if (field->name.length > 32 && hash->long_fields != NULL) { 761*60Svbart@nginx.com return nxt_http_fields_hash_lookup_long(hash, field); 762*60Svbart@nginx.com } 763*60Svbart@nginx.com 764*60Svbart@nginx.com return NULL; 765*60Svbart@nginx.com } 766*60Svbart@nginx.com 767*60Svbart@nginx.com elt = hash->elts[field->name.length - hash->min_length]; 768*60Svbart@nginx.com 769*60Svbart@nginx.com if (elt == NULL) { 770*60Svbart@nginx.com return NULL; 771*60Svbart@nginx.com } 772*60Svbart@nginx.com 773*60Svbart@nginx.com switch ((field->name.length + 7) / 8) { 774*60Svbart@nginx.com case 1: 775*60Svbart@nginx.com do { 776*60Svbart@nginx.com if (elt->key[0].ui64 == field->key.ui64[0]) { 777*60Svbart@nginx.com return elt->entry; 778*60Svbart@nginx.com } 779*60Svbart@nginx.com 780*60Svbart@nginx.com elt = nxt_http_fields_hash_next_elt(elt, 1); 781*60Svbart@nginx.com 782*60Svbart@nginx.com } while (elt->entry != NULL); 783*60Svbart@nginx.com 784*60Svbart@nginx.com break; 785*60Svbart@nginx.com 786*60Svbart@nginx.com case 2: 787*60Svbart@nginx.com do { 788*60Svbart@nginx.com if (elt->key[0].ui64 == field->key.ui64[0] 789*60Svbart@nginx.com && elt->key[1].ui64 == field->key.ui64[1]) 790*60Svbart@nginx.com { 791*60Svbart@nginx.com return elt->entry; 792*60Svbart@nginx.com } 793*60Svbart@nginx.com 794*60Svbart@nginx.com elt = nxt_http_fields_hash_next_elt(elt, 2); 795*60Svbart@nginx.com 796*60Svbart@nginx.com } while (elt->entry != NULL); 797*60Svbart@nginx.com 798*60Svbart@nginx.com break; 799*60Svbart@nginx.com 800*60Svbart@nginx.com case 3: 801*60Svbart@nginx.com do { 802*60Svbart@nginx.com if (elt->key[0].ui64 == field->key.ui64[0] 803*60Svbart@nginx.com && elt->key[1].ui64 == field->key.ui64[1] 804*60Svbart@nginx.com && elt->key[2].ui64 == field->key.ui64[2]) 805*60Svbart@nginx.com { 806*60Svbart@nginx.com return elt->entry; 807*60Svbart@nginx.com } 808*60Svbart@nginx.com 809*60Svbart@nginx.com elt = nxt_http_fields_hash_next_elt(elt, 3); 810*60Svbart@nginx.com 811*60Svbart@nginx.com } while (elt->entry != NULL); 812*60Svbart@nginx.com 813*60Svbart@nginx.com break; 814*60Svbart@nginx.com 815*60Svbart@nginx.com case 4: 816*60Svbart@nginx.com do { 817*60Svbart@nginx.com if (elt->key[0].ui64 == field->key.ui64[0] 818*60Svbart@nginx.com && elt->key[1].ui64 == field->key.ui64[1] 819*60Svbart@nginx.com && elt->key[2].ui64 == field->key.ui64[2] 820*60Svbart@nginx.com && elt->key[3].ui64 == field->key.ui64[3]) 821*60Svbart@nginx.com { 822*60Svbart@nginx.com return elt->entry; 823*60Svbart@nginx.com } 824*60Svbart@nginx.com 825*60Svbart@nginx.com elt = nxt_http_fields_hash_next_elt(elt, 4); 826*60Svbart@nginx.com 827*60Svbart@nginx.com } while (elt->entry != NULL); 828*60Svbart@nginx.com 829*60Svbart@nginx.com break; 830*60Svbart@nginx.com 831*60Svbart@nginx.com default: 832*60Svbart@nginx.com nxt_unreachable(); 833*60Svbart@nginx.com } 834*60Svbart@nginx.com 835*60Svbart@nginx.com return NULL; 836*60Svbart@nginx.com } 837*60Svbart@nginx.com 838*60Svbart@nginx.com 839*60Svbart@nginx.com static nxt_http_fields_hash_entry_t * 840*60Svbart@nginx.com nxt_http_fields_hash_lookup_long(nxt_http_fields_hash_t *hash, 841*60Svbart@nginx.com nxt_http_field_t *field) 842*60Svbart@nginx.com { 843*60Svbart@nginx.com /* TODO */ 844*60Svbart@nginx.com return NULL; 845*60Svbart@nginx.com } 846*60Svbart@nginx.com 847*60Svbart@nginx.com 848*60Svbart@nginx.com nxt_int_t 849*60Svbart@nginx.com nxt_http_fields_process(nxt_list_t *fields, nxt_http_fields_hash_t *hash, 850*60Svbart@nginx.com void *ctx, nxt_log_t *log) 851*60Svbart@nginx.com { 852*60Svbart@nginx.com nxt_int_t rc; 853*60Svbart@nginx.com nxt_http_field_t *field; 854*60Svbart@nginx.com nxt_http_fields_hash_entry_t *entry; 855*60Svbart@nginx.com 856*60Svbart@nginx.com nxt_list_each(field, fields) { 857*60Svbart@nginx.com entry = nxt_http_fields_hash_lookup(hash, field); 858*60Svbart@nginx.com 859*60Svbart@nginx.com if (entry != NULL) { 860*60Svbart@nginx.com rc = entry->handler(ctx, field, entry->data, log); 861*60Svbart@nginx.com 862*60Svbart@nginx.com if (rc != NXT_OK) { 863*60Svbart@nginx.com return rc; 864*60Svbart@nginx.com } 865*60Svbart@nginx.com } 866*60Svbart@nginx.com 867*60Svbart@nginx.com } nxt_list_loop; 868*60Svbart@nginx.com 869*60Svbart@nginx.com return NXT_OK; 870*60Svbart@nginx.com } 871