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 { 1116Svbart@nginx.com nxt_http_field_handler_t handler; 1216Svbart@nginx.com uintptr_t data; 1316Svbart@nginx.com union { 1416Svbart@nginx.com uint8_t str[8]; 1516Svbart@nginx.com uint64_t ui64; 1616Svbart@nginx.com } key[]; 1716Svbart@nginx.com } nxt_http_fields_hash_entry_t; 1816Svbart@nginx.com 1916Svbart@nginx.com 2016Svbart@nginx.com #define nxt_http_fields_hash_next_entry(entry, n) \ 2116Svbart@nginx.com ((nxt_http_fields_hash_entry_t *) ((u_char *) (entry) \ 2216Svbart@nginx.com + sizeof(nxt_http_fields_hash_entry_t) \ 2316Svbart@nginx.com + n * 8)) 2416Svbart@nginx.com 2516Svbart@nginx.com 2616Svbart@nginx.com struct nxt_http_fields_hash_s { 2716Svbart@nginx.com size_t min_length; 2816Svbart@nginx.com size_t max_length; 2916Svbart@nginx.com void *long_fields; 3016Svbart@nginx.com nxt_http_fields_hash_entry_t *entries[]; 3116Svbart@nginx.com }; 3216Svbart@nginx.com 3316Svbart@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 4616Svbart@nginx.com static nxt_http_fields_hash_entry_t *nxt_http_fields_hash_lookup( 4716Svbart@nginx.com nxt_http_fields_hash_t *hash, uint64_t *key, nxt_str_t *value); 4816Svbart@nginx.com static nxt_http_fields_hash_entry_t *nxt_http_header_fields_hash_lookup_long( 4916Svbart@nginx.com nxt_http_fields_hash_t *hash, nxt_str_t *value); 5016Svbart@nginx.com 5116Svbart@nginx.com 5216Svbart@nginx.com typedef enum { 5316Svbart@nginx.com NXT_HTTP_TARGET_SPACE = 1, /* \s */ 5416Svbart@nginx.com NXT_HTTP_TARGET_HASH, /* # */ 5516Svbart@nginx.com NXT_HTTP_TARGET_AGAIN, 5616Svbart@nginx.com NXT_HTTP_TARGET_BAD, /* \0\r\n */ 5716Svbart@nginx.com 5816Svbart@nginx.com /* traps below are used for extended check only */ 5916Svbart@nginx.com 6016Svbart@nginx.com NXT_HTTP_TARGET_SLASH = 5, /* / */ 6116Svbart@nginx.com NXT_HTTP_TARGET_DOT, /* . */ 6216Svbart@nginx.com NXT_HTTP_TARGET_ARGS_MARK, /* ? */ 6316Svbart@nginx.com NXT_HTTP_TARGET_QUOTE_MARK, /* % */ 6416Svbart@nginx.com NXT_HTTP_TARGET_PLUS, /* + */ 6516Svbart@nginx.com } nxt_http_target_traps_e; 6616Svbart@nginx.com 6716Svbart@nginx.com 6816Svbart@nginx.com static const uint8_t nxt_http_target_chars[256] nxt_aligned(64) = { 6916Svbart@nginx.com /* \0 \n \r */ 7016Svbart@nginx.com 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 4, 0, 0, 7116Svbart@nginx.com 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7216Svbart@nginx.com /* 7316Svbart@nginx.com * \s ! " # $ % & ' ( ) * + , - . / 7416Svbart@nginx.com * 0 1 2 3 4 5 6 7 8 9 : ; < = > ? 7516Svbart@nginx.com */ 7616Svbart@nginx.com 1, 0, 0, 2, 0, 8, 0, 0, 0, 0, 0, 9, 0, 0, 6, 5, 7716Svbart@nginx.com 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7816Svbart@nginx.com }; 7916Svbart@nginx.com 8016Svbart@nginx.com 8116Svbart@nginx.com nxt_inline nxt_http_target_traps_e 8216Svbart@nginx.com nxt_http_parse_target(u_char **pos, u_char *end) 8316Svbart@nginx.com { 8416Svbart@nginx.com u_char *p; 8516Svbart@nginx.com nxt_uint_t trap; 8616Svbart@nginx.com 8716Svbart@nginx.com p = *pos; 8816Svbart@nginx.com 8916Svbart@nginx.com for ( ;; ) { 9016Svbart@nginx.com if (nxt_slow_path(end - p < 10)) { 9116Svbart@nginx.com return NXT_HTTP_TARGET_AGAIN; 9216Svbart@nginx.com } 9316Svbart@nginx.com 9416Svbart@nginx.com #define nxt_http_parse_target_step \ 9516Svbart@nginx.com { \ 9616Svbart@nginx.com trap = nxt_http_target_chars[*p]; \ 9716Svbart@nginx.com \ 9816Svbart@nginx.com if (nxt_slow_path(trap != 0)) { \ 9916Svbart@nginx.com break; \ 10016Svbart@nginx.com } \ 10116Svbart@nginx.com \ 10216Svbart@nginx.com p++; \ 10316Svbart@nginx.com } 10416Svbart@nginx.com 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 nxt_http_parse_target_step 10916Svbart@nginx.com 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 nxt_http_parse_target_step 11416Svbart@nginx.com 11516Svbart@nginx.com nxt_http_parse_target_step 11616Svbart@nginx.com nxt_http_parse_target_step 11716Svbart@nginx.com 11816Svbart@nginx.com #undef nxt_http_parse_target_step 11916Svbart@nginx.com } 12016Svbart@nginx.com 12116Svbart@nginx.com *pos = p; 12216Svbart@nginx.com 12316Svbart@nginx.com return trap; 12416Svbart@nginx.com } 12516Svbart@nginx.com 12616Svbart@nginx.com 12716Svbart@nginx.com nxt_int_t 12816Svbart@nginx.com nxt_http_parse_request(nxt_http_request_parse_t *rp, nxt_buf_mem_t *b) 12916Svbart@nginx.com { 13016Svbart@nginx.com nxt_int_t rc; 13116Svbart@nginx.com 13216Svbart@nginx.com if (rp->handler == NULL) { 13316Svbart@nginx.com rp->handler = &nxt_http_parse_request_line; 13416Svbart@nginx.com } 13516Svbart@nginx.com 13616Svbart@nginx.com do { 13716Svbart@nginx.com rc = rp->handler(rp, &b->pos, b->free); 13816Svbart@nginx.com } while (rc == NXT_OK); 13916Svbart@nginx.com 14016Svbart@nginx.com return rc; 14116Svbart@nginx.com } 14216Svbart@nginx.com 14316Svbart@nginx.com 14416Svbart@nginx.com static nxt_int_t 14516Svbart@nginx.com nxt_http_parse_request_line(nxt_http_request_parse_t *rp, u_char **pos, 14616Svbart@nginx.com u_char *end) 14716Svbart@nginx.com { 14816Svbart@nginx.com u_char *p, ch, *after_slash; 14916Svbart@nginx.com nxt_int_t rc; 15016Svbart@nginx.com nxt_http_ver_t version; 15116Svbart@nginx.com nxt_http_target_traps_e trap; 15216Svbart@nginx.com 15316Svbart@nginx.com static const nxt_http_ver_t http11 = { "HTTP/1.1" }; 15416Svbart@nginx.com static const nxt_http_ver_t http10 = { "HTTP/1.0" }; 15516Svbart@nginx.com 15616Svbart@nginx.com p = *pos; 15716Svbart@nginx.com 15816Svbart@nginx.com rp->method.start = p; 15916Svbart@nginx.com 16016Svbart@nginx.com for ( ;; p++) { 16116Svbart@nginx.com 16216Svbart@nginx.com for ( ;; ) { 16316Svbart@nginx.com if (nxt_slow_path(end - p < 12)) { 16416Svbart@nginx.com return NXT_AGAIN; 16516Svbart@nginx.com } 16616Svbart@nginx.com 16716Svbart@nginx.com #define nxt_http_parse_request_line_step \ 16816Svbart@nginx.com { \ 16916Svbart@nginx.com ch = *p; \ 17016Svbart@nginx.com \ 17116Svbart@nginx.com if (nxt_slow_path(ch < 'A' || ch > 'Z')) { \ 17216Svbart@nginx.com break; \ 17316Svbart@nginx.com } \ 17416Svbart@nginx.com \ 17516Svbart@nginx.com p++; \ 17616Svbart@nginx.com } 17716Svbart@nginx.com 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 nxt_http_parse_request_line_step 18216Svbart@nginx.com 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 nxt_http_parse_request_line_step 18716Svbart@nginx.com 18816Svbart@nginx.com #undef nxt_http_parse_request_line_step 18916Svbart@nginx.com } 19016Svbart@nginx.com 19116Svbart@nginx.com if (nxt_fast_path(ch == ' ')) { 19216Svbart@nginx.com rp->method.length = p - rp->method.start; 19316Svbart@nginx.com break; 19416Svbart@nginx.com } 19516Svbart@nginx.com 19616Svbart@nginx.com if (ch == '_' || ch == '-') { 19716Svbart@nginx.com continue; 19816Svbart@nginx.com } 19916Svbart@nginx.com 20016Svbart@nginx.com if (rp->method.start == p && (ch == NXT_CR || ch == NXT_LF)) { 20116Svbart@nginx.com rp->method.start++; 20216Svbart@nginx.com continue; 20316Svbart@nginx.com } 20416Svbart@nginx.com 20516Svbart@nginx.com return NXT_ERROR; 20616Svbart@nginx.com } 20716Svbart@nginx.com 20816Svbart@nginx.com p++; 20916Svbart@nginx.com 21016Svbart@nginx.com if (nxt_slow_path(p == end)) { 21116Svbart@nginx.com return NXT_AGAIN; 21216Svbart@nginx.com } 21316Svbart@nginx.com 21416Svbart@nginx.com /* target */ 21516Svbart@nginx.com 21616Svbart@nginx.com ch = *p; 21716Svbart@nginx.com 21816Svbart@nginx.com if (nxt_slow_path(ch != '/')) { 21916Svbart@nginx.com rc = nxt_http_parse_unusual_target(rp, &p, end); 22016Svbart@nginx.com 22116Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 22216Svbart@nginx.com return rc; 22316Svbart@nginx.com } 22416Svbart@nginx.com } 22516Svbart@nginx.com 22616Svbart@nginx.com rp->target_start = p; 22716Svbart@nginx.com 22816Svbart@nginx.com after_slash = p + 1; 22916Svbart@nginx.com 23016Svbart@nginx.com for ( ;; ) { 23116Svbart@nginx.com p++; 23216Svbart@nginx.com 23316Svbart@nginx.com trap = nxt_http_parse_target(&p, end); 23416Svbart@nginx.com 23516Svbart@nginx.com switch (trap) { 23616Svbart@nginx.com case NXT_HTTP_TARGET_SLASH: 23716Svbart@nginx.com if (nxt_slow_path(after_slash == p)) { 23816Svbart@nginx.com rp->complex_target = 1; 23916Svbart@nginx.com goto rest_of_target; 24016Svbart@nginx.com } 24116Svbart@nginx.com 24216Svbart@nginx.com after_slash = p + 1; 24316Svbart@nginx.com 24416Svbart@nginx.com rp->exten_start = NULL; 24516Svbart@nginx.com continue; 24616Svbart@nginx.com 24716Svbart@nginx.com case NXT_HTTP_TARGET_DOT: 24816Svbart@nginx.com if (nxt_slow_path(after_slash == p)) { 24916Svbart@nginx.com rp->complex_target = 1; 25016Svbart@nginx.com goto rest_of_target; 25116Svbart@nginx.com } 25216Svbart@nginx.com 25316Svbart@nginx.com rp->exten_start = p + 1; 25416Svbart@nginx.com continue; 25516Svbart@nginx.com 25616Svbart@nginx.com case NXT_HTTP_TARGET_ARGS_MARK: 25716Svbart@nginx.com rp->args_start = p + 1; 25816Svbart@nginx.com goto rest_of_target; 25916Svbart@nginx.com 26016Svbart@nginx.com case NXT_HTTP_TARGET_SPACE: 26116Svbart@nginx.com rp->target_end = p; 26216Svbart@nginx.com goto space_after_target; 26316Svbart@nginx.com 26416Svbart@nginx.com case NXT_HTTP_TARGET_QUOTE_MARK: 26516Svbart@nginx.com rp->quoted_target = 1; 26616Svbart@nginx.com goto rest_of_target; 26716Svbart@nginx.com 26816Svbart@nginx.com case NXT_HTTP_TARGET_PLUS: 26916Svbart@nginx.com rp->plus_in_target = 1; 27016Svbart@nginx.com continue; 27116Svbart@nginx.com 27216Svbart@nginx.com case NXT_HTTP_TARGET_HASH: 27316Svbart@nginx.com rp->complex_target = 1; 27416Svbart@nginx.com goto rest_of_target; 27516Svbart@nginx.com 27616Svbart@nginx.com case NXT_HTTP_TARGET_AGAIN: 27716Svbart@nginx.com return NXT_AGAIN; 27816Svbart@nginx.com 27916Svbart@nginx.com case NXT_HTTP_TARGET_BAD: 28016Svbart@nginx.com return NXT_ERROR; 28116Svbart@nginx.com } 28216Svbart@nginx.com 28316Svbart@nginx.com nxt_unreachable(); 28416Svbart@nginx.com } 28516Svbart@nginx.com 28616Svbart@nginx.com rest_of_target: 28716Svbart@nginx.com 28816Svbart@nginx.com for ( ;; ) { 28916Svbart@nginx.com p++; 29016Svbart@nginx.com 29119Svbart@nginx.com trap = nxt_http_parse_target(&p, end); 29216Svbart@nginx.com 29316Svbart@nginx.com switch (trap) { 29416Svbart@nginx.com case NXT_HTTP_TARGET_SPACE: 29516Svbart@nginx.com rp->target_end = p; 29616Svbart@nginx.com goto space_after_target; 29716Svbart@nginx.com 29816Svbart@nginx.com case NXT_HTTP_TARGET_HASH: 29916Svbart@nginx.com rp->complex_target = 1; 30016Svbart@nginx.com continue; 30116Svbart@nginx.com 30216Svbart@nginx.com case NXT_HTTP_TARGET_AGAIN: 30316Svbart@nginx.com return NXT_AGAIN; 30416Svbart@nginx.com 30516Svbart@nginx.com case NXT_HTTP_TARGET_BAD: 30616Svbart@nginx.com return NXT_ERROR; 30716Svbart@nginx.com 30816Svbart@nginx.com default: 30916Svbart@nginx.com continue; 31016Svbart@nginx.com } 31116Svbart@nginx.com 31216Svbart@nginx.com nxt_unreachable(); 31316Svbart@nginx.com } 31416Svbart@nginx.com 31516Svbart@nginx.com space_after_target: 31616Svbart@nginx.com 31716Svbart@nginx.com if (nxt_slow_path(end - p < 10)) { 31816Svbart@nginx.com return NXT_AGAIN; 31916Svbart@nginx.com } 32016Svbart@nginx.com 32116Svbart@nginx.com /* " HTTP/1.1\r\n" or " HTTP/1.1\n" */ 32216Svbart@nginx.com 32316Svbart@nginx.com nxt_memcpy(version.str, &p[1], 8); 32416Svbart@nginx.com 32516Svbart@nginx.com if (nxt_fast_path((version.ui64 == http11.ui64 32616Svbart@nginx.com || version.ui64 == http10.ui64 32716Svbart@nginx.com || (p[1] == 'H' 32816Svbart@nginx.com && p[2] == 'T' 32916Svbart@nginx.com && p[3] == 'T' 33016Svbart@nginx.com && p[4] == 'P' 33116Svbart@nginx.com && p[5] == '/' 33216Svbart@nginx.com && p[6] >= '0' && p[6] <= '9' 33316Svbart@nginx.com && p[7] == '.' 33416Svbart@nginx.com && p[8] >= '0' && p[8] <= '9')) 33516Svbart@nginx.com && (p[9] == '\r' || p[9] == '\n'))) 33616Svbart@nginx.com { 33716Svbart@nginx.com rp->version.ui64 = version.ui64; 33816Svbart@nginx.com 33916Svbart@nginx.com if (nxt_fast_path(p[9] == '\r')) { 34016Svbart@nginx.com p += 10; 34116Svbart@nginx.com 34216Svbart@nginx.com if (nxt_slow_path(p == end)) { 34316Svbart@nginx.com return NXT_AGAIN; 34416Svbart@nginx.com } 34516Svbart@nginx.com 34616Svbart@nginx.com if (nxt_slow_path(*p != '\n')) { 34716Svbart@nginx.com return NXT_ERROR; 34816Svbart@nginx.com } 34916Svbart@nginx.com 35016Svbart@nginx.com *pos = p + 1; 35116Svbart@nginx.com return nxt_http_parse_field_name(rp, pos, end); 35216Svbart@nginx.com } 35316Svbart@nginx.com 35416Svbart@nginx.com *pos = p + 10; 35516Svbart@nginx.com return nxt_http_parse_field_name(rp, pos, end); 35616Svbart@nginx.com } 35716Svbart@nginx.com 35816Svbart@nginx.com if (p[1] == ' ') { 35916Svbart@nginx.com /* surplus space after tartet */ 36016Svbart@nginx.com p++; 36116Svbart@nginx.com goto space_after_target; 36216Svbart@nginx.com } 36316Svbart@nginx.com 36416Svbart@nginx.com rp->space_in_target = 1; 36516Svbart@nginx.com goto rest_of_target; 36616Svbart@nginx.com } 36716Svbart@nginx.com 36816Svbart@nginx.com 36916Svbart@nginx.com static nxt_int_t 37016Svbart@nginx.com nxt_http_parse_unusual_target(nxt_http_request_parse_t *rp, u_char **pos, 37116Svbart@nginx.com u_char *end) 37216Svbart@nginx.com { 37316Svbart@nginx.com u_char *p, ch; 37416Svbart@nginx.com 37516Svbart@nginx.com p = *pos; 37616Svbart@nginx.com 37716Svbart@nginx.com ch = *p; 37816Svbart@nginx.com 37916Svbart@nginx.com if (ch == ' ') { 38016Svbart@nginx.com /* skip surplus spaces before target */ 38116Svbart@nginx.com 38216Svbart@nginx.com do { 38316Svbart@nginx.com p++; 38416Svbart@nginx.com 38516Svbart@nginx.com if (nxt_slow_path(p == end)) { 38616Svbart@nginx.com return NXT_AGAIN; 38716Svbart@nginx.com } 38816Svbart@nginx.com 38916Svbart@nginx.com ch = *p; 39016Svbart@nginx.com 39116Svbart@nginx.com } while (ch == ' '); 39216Svbart@nginx.com 39316Svbart@nginx.com if (ch == '/') { 39416Svbart@nginx.com *pos = p; 39516Svbart@nginx.com return NXT_OK; 39616Svbart@nginx.com } 39716Svbart@nginx.com } 39816Svbart@nginx.com 39916Svbart@nginx.com /* absolute path or '*' */ 40016Svbart@nginx.com 40116Svbart@nginx.com /* TODO */ 40216Svbart@nginx.com 40316Svbart@nginx.com return NXT_ERROR; 40416Svbart@nginx.com } 40516Svbart@nginx.com 40616Svbart@nginx.com 40716Svbart@nginx.com static nxt_int_t 40816Svbart@nginx.com nxt_http_parse_field_name(nxt_http_request_parse_t *rp, u_char **pos, 40916Svbart@nginx.com u_char *end) 41016Svbart@nginx.com { 41116Svbart@nginx.com u_char *p, ch, c; 41216Svbart@nginx.com size_t i, size; 41316Svbart@nginx.com 41416Svbart@nginx.com static const u_char normal[256] nxt_aligned(64) = 41516Svbart@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" 41616Svbart@nginx.com "\0\0\0\0\0\0\0\0\0\0\0\0\0-\0\0" "0123456789\0\0\0\0\0\0" 41716Svbart@nginx.com 41816Svbart@nginx.com /* These 64 bytes should reside in one cache line. */ 41916Svbart@nginx.com "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0" 42016Svbart@nginx.com "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0" 42116Svbart@nginx.com 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 "\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"; 42616Svbart@nginx.com 42716Svbart@nginx.com p = *pos; 42816Svbart@nginx.com 42916Svbart@nginx.com size = end - p; 43019Svbart@nginx.com i = rp->offset; 43116Svbart@nginx.com 43219Svbart@nginx.com #define nxt_http_parse_field_name_step \ 43319Svbart@nginx.com { \ 43419Svbart@nginx.com ch = p[i]; \ 43519Svbart@nginx.com c = normal[ch]; \ 43619Svbart@nginx.com \ 43719Svbart@nginx.com if (nxt_slow_path(c == '\0')) { \ 43819Svbart@nginx.com goto name_end; \ 43919Svbart@nginx.com } \ 44019Svbart@nginx.com \ 44119Svbart@nginx.com rp->field_name_key.str[i % 32] = c; \ 44219Svbart@nginx.com i++; \ 44319Svbart@nginx.com } 44416Svbart@nginx.com 44519Svbart@nginx.com while (nxt_fast_path(size - i >= 8)) { 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 44919Svbart@nginx.com nxt_http_parse_field_name_step 45016Svbart@nginx.com 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 nxt_http_parse_field_name_step 45519Svbart@nginx.com } 45616Svbart@nginx.com 45719Svbart@nginx.com while (nxt_fast_path(i != size)) { 45819Svbart@nginx.com nxt_http_parse_field_name_step 45919Svbart@nginx.com } 46016Svbart@nginx.com 46119Svbart@nginx.com #undef nxt_http_parse_field_name_step 46216Svbart@nginx.com 46316Svbart@nginx.com rp->offset = i; 46416Svbart@nginx.com rp->handler = &nxt_http_parse_field_name; 46516Svbart@nginx.com 46616Svbart@nginx.com return NXT_AGAIN; 46719Svbart@nginx.com 46819Svbart@nginx.com name_end: 46919Svbart@nginx.com 47019Svbart@nginx.com if (nxt_fast_path(ch == ':')) { 47119Svbart@nginx.com if (nxt_slow_path(i == 0)) { 47219Svbart@nginx.com return NXT_ERROR; 47319Svbart@nginx.com } 47419Svbart@nginx.com 47519Svbart@nginx.com *pos = &p[i] + 1; 47619Svbart@nginx.com 47719Svbart@nginx.com rp->field_name.start = p; 47819Svbart@nginx.com rp->field_name.length = i; 47919Svbart@nginx.com 48019Svbart@nginx.com rp->offset = 0; 48119Svbart@nginx.com 48219Svbart@nginx.com return nxt_http_parse_field_value(rp, pos, end); 48319Svbart@nginx.com } 48419Svbart@nginx.com 48519Svbart@nginx.com *pos = &p[i]; 48619Svbart@nginx.com 48719Svbart@nginx.com rp->field_name.length = 0; 48819Svbart@nginx.com 48919Svbart@nginx.com return nxt_http_parse_field_end(rp, pos, end); 49016Svbart@nginx.com } 49116Svbart@nginx.com 49216Svbart@nginx.com 49316Svbart@nginx.com static nxt_int_t 49416Svbart@nginx.com nxt_http_parse_field_value(nxt_http_request_parse_t *rp, u_char **pos, 49516Svbart@nginx.com u_char *end) 49616Svbart@nginx.com { 49716Svbart@nginx.com u_char *p, ch; 49816Svbart@nginx.com 49916Svbart@nginx.com p = *pos; 50016Svbart@nginx.com 50116Svbart@nginx.com for ( ;; ) { 50216Svbart@nginx.com if (nxt_slow_path(p == end)) { 50316Svbart@nginx.com *pos = p; 50416Svbart@nginx.com rp->handler = &nxt_http_parse_field_value; 50516Svbart@nginx.com return NXT_AGAIN; 50616Svbart@nginx.com } 50716Svbart@nginx.com 50816Svbart@nginx.com if (*p != ' ') { 50916Svbart@nginx.com break; 51016Svbart@nginx.com } 51116Svbart@nginx.com 51216Svbart@nginx.com p++; 51316Svbart@nginx.com } 51416Svbart@nginx.com 51516Svbart@nginx.com *pos = p; 51616Svbart@nginx.com 51716Svbart@nginx.com p += rp->offset; 51816Svbart@nginx.com 51916Svbart@nginx.com for ( ;; ) { 52016Svbart@nginx.com p = nxt_http_lookup_field_end(p, end); 52116Svbart@nginx.com 52216Svbart@nginx.com if (nxt_slow_path(p == end)) { 52316Svbart@nginx.com rp->offset = p - *pos; 52416Svbart@nginx.com rp->handler = &nxt_http_parse_field_value; 52516Svbart@nginx.com return NXT_AGAIN; 52616Svbart@nginx.com } 52716Svbart@nginx.com 52816Svbart@nginx.com ch = *p; 52916Svbart@nginx.com 53016Svbart@nginx.com if (nxt_fast_path(ch == '\r' || ch == '\n')) { 53116Svbart@nginx.com break; 53216Svbart@nginx.com } 53316Svbart@nginx.com 53416Svbart@nginx.com if (ch == '\0') { 53516Svbart@nginx.com return NXT_ERROR; 53616Svbart@nginx.com } 53716Svbart@nginx.com } 53816Svbart@nginx.com 53916Svbart@nginx.com if (nxt_fast_path(p != *pos)) { 54016Svbart@nginx.com while (p[-1] == ' ') { 54116Svbart@nginx.com p--; 54216Svbart@nginx.com } 54316Svbart@nginx.com } 54416Svbart@nginx.com 54516Svbart@nginx.com rp->offset = 0; 54616Svbart@nginx.com 54716Svbart@nginx.com rp->field_value.start = *pos; 54816Svbart@nginx.com rp->field_value.length = p - *pos; 54916Svbart@nginx.com 55016Svbart@nginx.com *pos = p; 55116Svbart@nginx.com 55216Svbart@nginx.com return nxt_http_parse_field_end(rp, pos, end); 55316Svbart@nginx.com } 55416Svbart@nginx.com 55516Svbart@nginx.com 55616Svbart@nginx.com static u_char * 55716Svbart@nginx.com nxt_http_lookup_field_end(u_char *p, u_char *end) 55816Svbart@nginx.com { 55916Svbart@nginx.com nxt_uint_t n; 56016Svbart@nginx.com 56116Svbart@nginx.com #define nxt_http_lookup_field_end_step \ 56216Svbart@nginx.com { \ 56319Svbart@nginx.com if (nxt_slow_path(*p < 0x10)) { \ 56416Svbart@nginx.com return p; \ 56516Svbart@nginx.com } \ 56616Svbart@nginx.com \ 56716Svbart@nginx.com p++; \ 56816Svbart@nginx.com } 56916Svbart@nginx.com 57019Svbart@nginx.com for (n = (end - p) / 16; nxt_fast_path(n != 0); n--) { 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 57619Svbart@nginx.com nxt_http_lookup_field_end_step 57719Svbart@nginx.com nxt_http_lookup_field_end_step 57819Svbart@nginx.com nxt_http_lookup_field_end_step 57919Svbart@nginx.com nxt_http_lookup_field_end_step 58019Svbart@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 nxt_http_lookup_field_end_step 58716Svbart@nginx.com nxt_http_lookup_field_end_step 58816Svbart@nginx.com nxt_http_lookup_field_end_step 58916Svbart@nginx.com nxt_http_lookup_field_end_step 59016Svbart@nginx.com } 59116Svbart@nginx.com 59219Svbart@nginx.com for (n = (end - p) / 4; nxt_fast_path(n != 0); n--) { 59316Svbart@nginx.com nxt_http_lookup_field_end_step 59419Svbart@nginx.com nxt_http_lookup_field_end_step 59516Svbart@nginx.com nxt_http_lookup_field_end_step 59616Svbart@nginx.com nxt_http_lookup_field_end_step 59719Svbart@nginx.com } 59819Svbart@nginx.com 59919Svbart@nginx.com switch (end - p) { 60016Svbart@nginx.com case 3: 60116Svbart@nginx.com nxt_http_lookup_field_end_step 60216Svbart@nginx.com case 2: 60316Svbart@nginx.com nxt_http_lookup_field_end_step 60416Svbart@nginx.com case 1: 60516Svbart@nginx.com nxt_http_lookup_field_end_step 60616Svbart@nginx.com case 0: 60716Svbart@nginx.com break; 60816Svbart@nginx.com default: 60916Svbart@nginx.com nxt_unreachable(); 61016Svbart@nginx.com } 61116Svbart@nginx.com 61216Svbart@nginx.com #undef nxt_http_lookup_field_end_step 61316Svbart@nginx.com 61416Svbart@nginx.com return p; 61516Svbart@nginx.com } 61616Svbart@nginx.com 61716Svbart@nginx.com 61816Svbart@nginx.com static nxt_int_t 61916Svbart@nginx.com nxt_http_parse_field_end(nxt_http_request_parse_t *rp, u_char **pos, 62016Svbart@nginx.com u_char *end) 62116Svbart@nginx.com { 62216Svbart@nginx.com u_char *p; 62316Svbart@nginx.com nxt_int_t rc; 62416Svbart@nginx.com nxt_http_fields_hash_entry_t *entry; 62516Svbart@nginx.com 62616Svbart@nginx.com p = *pos; 62716Svbart@nginx.com 62816Svbart@nginx.com if (nxt_fast_path(*p == '\r')) { 62916Svbart@nginx.com p++; 63016Svbart@nginx.com 63116Svbart@nginx.com if (nxt_slow_path(p == end)) { 63216Svbart@nginx.com rp->handler = &nxt_http_parse_field_end; 63316Svbart@nginx.com return NXT_AGAIN; 63416Svbart@nginx.com } 63516Svbart@nginx.com } 63616Svbart@nginx.com 63716Svbart@nginx.com if (nxt_fast_path(*p == '\n')) { 63816Svbart@nginx.com *pos = p + 1; 63916Svbart@nginx.com 64016Svbart@nginx.com if (rp->field_name.length != 0) { 64116Svbart@nginx.com entry = nxt_http_fields_hash_lookup(rp->hash, 64219Svbart@nginx.com rp->field_name_key.ui64, 64319Svbart@nginx.com &rp->field_name); 64416Svbart@nginx.com 64516Svbart@nginx.com if (entry != NULL) { 64616Svbart@nginx.com rc = entry->handler(rp->ctx, &rp->field_name, &rp->field_value, 64716Svbart@nginx.com entry->data); 64816Svbart@nginx.com 64916Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 65016Svbart@nginx.com return NXT_ERROR; 65116Svbart@nginx.com } 65216Svbart@nginx.com } 65316Svbart@nginx.com 65416Svbart@nginx.com nxt_memzero(rp->field_name_key.str, 32); 65516Svbart@nginx.com 65616Svbart@nginx.com rp->handler = &nxt_http_parse_field_name; 65716Svbart@nginx.com return NXT_OK; 65816Svbart@nginx.com } 65916Svbart@nginx.com 66016Svbart@nginx.com return NXT_DONE; 66116Svbart@nginx.com } 66216Svbart@nginx.com 66316Svbart@nginx.com return NXT_ERROR; 66416Svbart@nginx.com } 66516Svbart@nginx.com 66616Svbart@nginx.com 66716Svbart@nginx.com static nxt_http_fields_hash_entry_t * 66816Svbart@nginx.com nxt_http_fields_hash_lookup(nxt_http_fields_hash_t *hash, uint64_t *key, 66916Svbart@nginx.com nxt_str_t *value) 67016Svbart@nginx.com { 67116Svbart@nginx.com nxt_http_fields_hash_entry_t *entry; 67216Svbart@nginx.com 67316Svbart@nginx.com if (hash == NULL || value->length < hash->min_length) { 67416Svbart@nginx.com return NULL; 67516Svbart@nginx.com } 67616Svbart@nginx.com 67716Svbart@nginx.com if (value->length > hash->max_length) { 67816Svbart@nginx.com if (value->length > 32 && hash->long_fields != NULL) { 67916Svbart@nginx.com return nxt_http_header_fields_hash_lookup_long(hash, value); 68016Svbart@nginx.com } 68116Svbart@nginx.com 68216Svbart@nginx.com return NULL; 68316Svbart@nginx.com } 68416Svbart@nginx.com 68516Svbart@nginx.com entry = hash->entries[value->length - hash->min_length]; 68616Svbart@nginx.com 68716Svbart@nginx.com if (entry == NULL) { 68816Svbart@nginx.com return NULL; 68916Svbart@nginx.com } 69016Svbart@nginx.com 69116Svbart@nginx.com switch ((value->length + 7) / 8) { 69216Svbart@nginx.com case 1: 69316Svbart@nginx.com do { 69416Svbart@nginx.com if (entry->key[0].ui64 == key[0]) { 69516Svbart@nginx.com return entry; 69616Svbart@nginx.com } 69716Svbart@nginx.com 69816Svbart@nginx.com entry = nxt_http_fields_hash_next_entry(entry, 1); 69916Svbart@nginx.com 70016Svbart@nginx.com } while (entry->handler != NULL); 70116Svbart@nginx.com 70216Svbart@nginx.com break; 70316Svbart@nginx.com 70416Svbart@nginx.com case 2: 70516Svbart@nginx.com do { 70616Svbart@nginx.com if (entry->key[0].ui64 == key[0] 70716Svbart@nginx.com && entry->key[1].ui64 == key[1]) 70816Svbart@nginx.com { 70916Svbart@nginx.com return entry; 71016Svbart@nginx.com } 71116Svbart@nginx.com 71216Svbart@nginx.com entry = nxt_http_fields_hash_next_entry(entry, 2); 71316Svbart@nginx.com 71416Svbart@nginx.com } while (entry->handler != NULL); 71516Svbart@nginx.com 71616Svbart@nginx.com break; 71716Svbart@nginx.com 71816Svbart@nginx.com case 3: 71916Svbart@nginx.com do { 72016Svbart@nginx.com if (entry->key[0].ui64 == key[0] 72116Svbart@nginx.com && entry->key[1].ui64 == key[1] 72216Svbart@nginx.com && entry->key[2].ui64 == key[2]) 72316Svbart@nginx.com { 72416Svbart@nginx.com return entry; 72516Svbart@nginx.com } 72616Svbart@nginx.com 72716Svbart@nginx.com entry = nxt_http_fields_hash_next_entry(entry, 3); 72816Svbart@nginx.com 72916Svbart@nginx.com } while (entry->handler != NULL); 73016Svbart@nginx.com 73116Svbart@nginx.com break; 73216Svbart@nginx.com 73316Svbart@nginx.com case 4: 73416Svbart@nginx.com do { 73516Svbart@nginx.com if (entry->key[0].ui64 == key[0] 73616Svbart@nginx.com && entry->key[1].ui64 == key[1] 73716Svbart@nginx.com && entry->key[2].ui64 == key[2] 73816Svbart@nginx.com && entry->key[3].ui64 == key[3]) 73916Svbart@nginx.com { 74016Svbart@nginx.com return entry; 74116Svbart@nginx.com } 74216Svbart@nginx.com 74316Svbart@nginx.com entry = nxt_http_fields_hash_next_entry(entry, 4); 74416Svbart@nginx.com 74516Svbart@nginx.com } while (entry->handler != NULL); 74616Svbart@nginx.com 74716Svbart@nginx.com break; 74816Svbart@nginx.com 74916Svbart@nginx.com default: 75016Svbart@nginx.com nxt_unreachable(); 75116Svbart@nginx.com } 75216Svbart@nginx.com 75316Svbart@nginx.com return NULL; 75416Svbart@nginx.com } 75516Svbart@nginx.com 75616Svbart@nginx.com 75716Svbart@nginx.com static nxt_http_fields_hash_entry_t * 75816Svbart@nginx.com nxt_http_header_fields_hash_lookup_long(nxt_http_fields_hash_t *hash, 75916Svbart@nginx.com nxt_str_t *value) 76016Svbart@nginx.com { 76116Svbart@nginx.com /* TODO */ 76216Svbart@nginx.com return NULL; 76316Svbart@nginx.com } 76416Svbart@nginx.com 76516Svbart@nginx.com 76616Svbart@nginx.com nxt_http_fields_hash_t * 76716Svbart@nginx.com nxt_http_fields_hash(nxt_http_fields_t *fields, nxt_mem_pool_t *mp) 76816Svbart@nginx.com { 76916Svbart@nginx.com size_t min_length, max_length, length, size; 77016Svbart@nginx.com nxt_uint_t i, j, n; 77116Svbart@nginx.com nxt_http_fields_hash_t *hash; 77216Svbart@nginx.com nxt_http_fields_hash_entry_t *entry; 77316Svbart@nginx.com 774*38Svbart@nginx.com min_length = 32 + 1; 77516Svbart@nginx.com max_length = 0; 77616Svbart@nginx.com 77716Svbart@nginx.com for (i = 0; fields[i].handler != NULL; i++) { 77816Svbart@nginx.com length = fields[i].name.length; 77916Svbart@nginx.com 78016Svbart@nginx.com if (length > 32) { 78116Svbart@nginx.com /* TODO */ 78216Svbart@nginx.com return NULL; 78316Svbart@nginx.com } 78416Svbart@nginx.com 78516Svbart@nginx.com min_length = nxt_min(length, min_length); 78616Svbart@nginx.com max_length = nxt_max(length, max_length); 78716Svbart@nginx.com } 78816Svbart@nginx.com 789*38Svbart@nginx.com size = sizeof(nxt_http_fields_hash_t); 79016Svbart@nginx.com 791*38Svbart@nginx.com if (min_length <= 32) { 792*38Svbart@nginx.com size += (max_length - min_length + 1) 793*38Svbart@nginx.com * sizeof(nxt_http_fields_hash_entry_t *); 794*38Svbart@nginx.com } 79516Svbart@nginx.com 796*38Svbart@nginx.com hash = nxt_mem_zalloc(mp, size); 79716Svbart@nginx.com if (nxt_slow_path(hash == NULL)) { 79816Svbart@nginx.com return NULL; 79916Svbart@nginx.com } 80016Svbart@nginx.com 80116Svbart@nginx.com hash->min_length = min_length; 80216Svbart@nginx.com hash->max_length = max_length; 80316Svbart@nginx.com 80416Svbart@nginx.com for (i = 0; fields[i].handler != NULL; i++) { 80516Svbart@nginx.com length = fields[i].name.length; 80616Svbart@nginx.com entry = hash->entries[length - min_length]; 80716Svbart@nginx.com 80816Svbart@nginx.com if (entry != NULL) { 80916Svbart@nginx.com continue; 81016Svbart@nginx.com } 81116Svbart@nginx.com 81216Svbart@nginx.com n = 1; 81316Svbart@nginx.com 81416Svbart@nginx.com for (j = i + 1; fields[j].handler != NULL; j++) { 81516Svbart@nginx.com if (length == fields[j].name.length) { 81616Svbart@nginx.com n++; 81716Svbart@nginx.com } 81816Svbart@nginx.com } 81916Svbart@nginx.com 82016Svbart@nginx.com size = sizeof(nxt_http_fields_hash_entry_t) + nxt_align_size(length, 8); 82116Svbart@nginx.com 82216Svbart@nginx.com entry = nxt_mem_zalloc(mp, n * size 82316Svbart@nginx.com + sizeof(nxt_http_fields_hash_entry_t)); 82416Svbart@nginx.com 82516Svbart@nginx.com if (nxt_slow_path(entry == NULL)) { 82616Svbart@nginx.com return NULL; 82716Svbart@nginx.com } 82816Svbart@nginx.com 82916Svbart@nginx.com hash->entries[length - min_length] = entry; 83016Svbart@nginx.com 83116Svbart@nginx.com for (j = i; fields[j].handler != NULL; j++) { 83216Svbart@nginx.com if (length != fields[j].name.length) { 83316Svbart@nginx.com continue; 83416Svbart@nginx.com } 83516Svbart@nginx.com 83616Svbart@nginx.com entry->handler = fields[j].handler; 83716Svbart@nginx.com entry->data = fields[j].data; 83816Svbart@nginx.com 83916Svbart@nginx.com nxt_memcpy_lowcase(entry->key->str, fields[j].name.start, length); 84016Svbart@nginx.com 84116Svbart@nginx.com n--; 84216Svbart@nginx.com 84316Svbart@nginx.com if (n == 0) { 84416Svbart@nginx.com break; 84516Svbart@nginx.com } 84616Svbart@nginx.com 84716Svbart@nginx.com entry = (nxt_http_fields_hash_entry_t *) ((u_char *) entry + size); 84816Svbart@nginx.com } 84916Svbart@nginx.com } 85016Svbart@nginx.com 85116Svbart@nginx.com return hash; 85216Svbart@nginx.com } 853