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 static nxt_int_t nxt_http_parse_unusual_target(nxt_http_request_parse_t *rp, 1116Svbart@nginx.com u_char **pos, u_char *end); 1216Svbart@nginx.com static nxt_int_t nxt_http_parse_request_line(nxt_http_request_parse_t *rp, 1316Svbart@nginx.com u_char **pos, u_char *end); 1416Svbart@nginx.com static nxt_int_t nxt_http_parse_field_name(nxt_http_request_parse_t *rp, 1516Svbart@nginx.com u_char **pos, u_char *end); 1616Svbart@nginx.com static nxt_int_t nxt_http_parse_field_value(nxt_http_request_parse_t *rp, 1716Svbart@nginx.com u_char **pos, u_char *end); 1816Svbart@nginx.com static u_char *nxt_http_lookup_field_end(u_char *p, u_char *end); 1916Svbart@nginx.com static nxt_int_t nxt_http_parse_field_end(nxt_http_request_parse_t *rp, 2016Svbart@nginx.com u_char **pos, u_char *end); 2116Svbart@nginx.com 22417Svbart@nginx.com static nxt_int_t nxt_http_parse_complex_target(nxt_http_request_parse_t *rp); 23417Svbart@nginx.com 24417Svbart@nginx.com static nxt_int_t nxt_http_field_hash_test(nxt_lvlhsh_query_t *lhq, void *data); 25417Svbart@nginx.com static void *nxt_http_field_hash_alloc(void *pool, size_t size); 26417Svbart@nginx.com static void nxt_http_field_hash_free(void *pool, void *p); 27417Svbart@nginx.com 28417Svbart@nginx.com static nxt_int_t nxt_http_field_hash_collision(nxt_lvlhsh_query_t *lhq, 29417Svbart@nginx.com void *data); 3016Svbart@nginx.com 31417Svbart@nginx.com 32417Svbart@nginx.com #define NXT_HTTP_MAX_FIELD_NAME 0xff 33417Svbart@nginx.com #define NXT_HTTP_MAX_FIELD_VALUE NXT_INT32_T_MAX 34417Svbart@nginx.com 35417Svbart@nginx.com #define NXT_HTTP_FIELD_LVLHSH_SHIFT 5 36417Svbart@nginx.com 37417Svbart@nginx.com #define NXT_HTTP_FIELD_HASH_INIT 159406 38417Svbart@nginx.com #define nxt_http_field_hash_char(h, c) (((h) << 4) + (h) + (c)) 39417Svbart@nginx.com #define nxt_http_field_hash_end(h) (((h) >> 16) ^ (h)) 40112Smax.romanov@nginx.com 4116Svbart@nginx.com 4216Svbart@nginx.com typedef enum { 4316Svbart@nginx.com NXT_HTTP_TARGET_SPACE = 1, /* \s */ 4416Svbart@nginx.com NXT_HTTP_TARGET_HASH, /* # */ 4516Svbart@nginx.com NXT_HTTP_TARGET_AGAIN, 4616Svbart@nginx.com NXT_HTTP_TARGET_BAD, /* \0\r\n */ 4716Svbart@nginx.com 4816Svbart@nginx.com /* traps below are used for extended check only */ 4916Svbart@nginx.com 5016Svbart@nginx.com NXT_HTTP_TARGET_SLASH = 5, /* / */ 5116Svbart@nginx.com NXT_HTTP_TARGET_DOT, /* . */ 5216Svbart@nginx.com NXT_HTTP_TARGET_ARGS_MARK, /* ? */ 5316Svbart@nginx.com NXT_HTTP_TARGET_QUOTE_MARK, /* % */ 5416Svbart@nginx.com NXT_HTTP_TARGET_PLUS, /* + */ 5516Svbart@nginx.com } nxt_http_target_traps_e; 5616Svbart@nginx.com 5716Svbart@nginx.com 5816Svbart@nginx.com static const uint8_t nxt_http_target_chars[256] nxt_aligned(64) = { 5916Svbart@nginx.com /* \0 \n \r */ 6016Svbart@nginx.com 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 4, 0, 0, 6116Svbart@nginx.com 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6252Svbart@nginx.com 6352Svbart@nginx.com /* \s ! " # $ % & ' ( ) * + , - . / */ 6416Svbart@nginx.com 1, 0, 0, 2, 0, 8, 0, 0, 0, 0, 0, 9, 0, 0, 6, 5, 6552Svbart@nginx.com 6652Svbart@nginx.com /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 6716Svbart@nginx.com 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 6816Svbart@nginx.com }; 6916Svbart@nginx.com 7016Svbart@nginx.com 7116Svbart@nginx.com nxt_inline nxt_http_target_traps_e 7216Svbart@nginx.com nxt_http_parse_target(u_char **pos, u_char *end) 7316Svbart@nginx.com { 7416Svbart@nginx.com u_char *p; 7516Svbart@nginx.com nxt_uint_t trap; 7616Svbart@nginx.com 7716Svbart@nginx.com p = *pos; 7816Svbart@nginx.com 79409Svbart@nginx.com while (nxt_fast_path(end - p >= 10)) { 8016Svbart@nginx.com 81409Svbart@nginx.com #define nxt_target_test_char(ch) \ 82409Svbart@nginx.com \ 83409Svbart@nginx.com trap = nxt_http_target_chars[ch]; \ 8416Svbart@nginx.com \ 85409Svbart@nginx.com if (nxt_slow_path(trap != 0)) { \ 86409Svbart@nginx.com *pos = &(ch); \ 87409Svbart@nginx.com return trap; \ 8816Svbart@nginx.com } 8916Svbart@nginx.com 90409Svbart@nginx.com /* enddef */ 91409Svbart@nginx.com 92409Svbart@nginx.com nxt_target_test_char(p[0]); 93409Svbart@nginx.com nxt_target_test_char(p[1]); 94409Svbart@nginx.com nxt_target_test_char(p[2]); 95409Svbart@nginx.com nxt_target_test_char(p[3]); 9616Svbart@nginx.com 97409Svbart@nginx.com nxt_target_test_char(p[4]); 98409Svbart@nginx.com nxt_target_test_char(p[5]); 99409Svbart@nginx.com nxt_target_test_char(p[6]); 100409Svbart@nginx.com nxt_target_test_char(p[7]); 10116Svbart@nginx.com 102409Svbart@nginx.com nxt_target_test_char(p[8]); 103409Svbart@nginx.com nxt_target_test_char(p[9]); 10416Svbart@nginx.com 105409Svbart@nginx.com p += 10; 10616Svbart@nginx.com } 10716Svbart@nginx.com 108410Svbart@nginx.com while (p != end) { 109410Svbart@nginx.com nxt_target_test_char(*p); p++; 110410Svbart@nginx.com } 111410Svbart@nginx.com 112409Svbart@nginx.com return NXT_HTTP_TARGET_AGAIN; 11316Svbart@nginx.com } 11416Svbart@nginx.com 11516Svbart@nginx.com 11616Svbart@nginx.com nxt_int_t 117417Svbart@nginx.com nxt_http_parse_request_init(nxt_http_request_parse_t *rp, nxt_mp_t *mp) 118417Svbart@nginx.com { 119417Svbart@nginx.com rp->mem_pool = mp; 120417Svbart@nginx.com 121417Svbart@nginx.com rp->fields = nxt_list_create(mp, 8, sizeof(nxt_http_field_t)); 122417Svbart@nginx.com if (nxt_slow_path(rp->fields == NULL)){ 123417Svbart@nginx.com return NXT_ERROR; 124417Svbart@nginx.com } 125417Svbart@nginx.com 126417Svbart@nginx.com rp->field_hash = NXT_HTTP_FIELD_HASH_INIT; 127417Svbart@nginx.com 128417Svbart@nginx.com return NXT_OK; 129417Svbart@nginx.com } 130417Svbart@nginx.com 131417Svbart@nginx.com 132417Svbart@nginx.com nxt_int_t 13316Svbart@nginx.com nxt_http_parse_request(nxt_http_request_parse_t *rp, nxt_buf_mem_t *b) 13416Svbart@nginx.com { 13516Svbart@nginx.com nxt_int_t rc; 13616Svbart@nginx.com 13716Svbart@nginx.com if (rp->handler == NULL) { 13816Svbart@nginx.com rp->handler = &nxt_http_parse_request_line; 13916Svbart@nginx.com } 14016Svbart@nginx.com 14116Svbart@nginx.com do { 14216Svbart@nginx.com rc = rp->handler(rp, &b->pos, b->free); 14316Svbart@nginx.com } while (rc == NXT_OK); 14416Svbart@nginx.com 14516Svbart@nginx.com return rc; 14616Svbart@nginx.com } 14716Svbart@nginx.com 14816Svbart@nginx.com 149422Svbart@nginx.com nxt_int_t 150422Svbart@nginx.com nxt_http_parse_fields(nxt_http_request_parse_t *rp, nxt_buf_mem_t *b) 151422Svbart@nginx.com { 152422Svbart@nginx.com nxt_int_t rc; 153422Svbart@nginx.com 154422Svbart@nginx.com if (rp->handler == NULL) { 155422Svbart@nginx.com rp->handler = &nxt_http_parse_field_name; 156422Svbart@nginx.com } 157422Svbart@nginx.com 158422Svbart@nginx.com do { 159422Svbart@nginx.com rc = rp->handler(rp, &b->pos, b->free); 160422Svbart@nginx.com } while (rc == NXT_OK); 161422Svbart@nginx.com 162422Svbart@nginx.com return rc; 163422Svbart@nginx.com } 164422Svbart@nginx.com 165422Svbart@nginx.com 16616Svbart@nginx.com static nxt_int_t 16716Svbart@nginx.com nxt_http_parse_request_line(nxt_http_request_parse_t *rp, u_char **pos, 16816Svbart@nginx.com u_char *end) 16916Svbart@nginx.com { 17016Svbart@nginx.com u_char *p, ch, *after_slash; 17116Svbart@nginx.com nxt_int_t rc; 172481Svbart@nginx.com nxt_http_ver_t ver; 17316Svbart@nginx.com nxt_http_target_traps_e trap; 17416Svbart@nginx.com 17516Svbart@nginx.com static const nxt_http_ver_t http11 = { "HTTP/1.1" }; 17616Svbart@nginx.com static const nxt_http_ver_t http10 = { "HTTP/1.0" }; 17716Svbart@nginx.com 17816Svbart@nginx.com p = *pos; 17916Svbart@nginx.com 18016Svbart@nginx.com rp->method.start = p; 18116Svbart@nginx.com 182409Svbart@nginx.com for ( ;; ) { 183409Svbart@nginx.com 184409Svbart@nginx.com while (nxt_fast_path(end - p >= 8)) { 18516Svbart@nginx.com 186409Svbart@nginx.com #define nxt_method_test_char(ch) \ 187409Svbart@nginx.com \ 188409Svbart@nginx.com if (nxt_slow_path((ch) < 'A' || (ch) > 'Z')) { \ 189409Svbart@nginx.com p = &(ch); \ 190409Svbart@nginx.com goto method_unusual_char; \ 19116Svbart@nginx.com } 19216Svbart@nginx.com 193409Svbart@nginx.com /* enddef */ 194409Svbart@nginx.com 195409Svbart@nginx.com nxt_method_test_char(p[0]); 196409Svbart@nginx.com nxt_method_test_char(p[1]); 197409Svbart@nginx.com nxt_method_test_char(p[2]); 198409Svbart@nginx.com nxt_method_test_char(p[3]); 19916Svbart@nginx.com 200409Svbart@nginx.com nxt_method_test_char(p[4]); 201409Svbart@nginx.com nxt_method_test_char(p[5]); 202409Svbart@nginx.com nxt_method_test_char(p[6]); 203409Svbart@nginx.com nxt_method_test_char(p[7]); 20416Svbart@nginx.com 205409Svbart@nginx.com p += 8; 206409Svbart@nginx.com } 20716Svbart@nginx.com 208410Svbart@nginx.com while (p != end) { 209410Svbart@nginx.com nxt_method_test_char(*p); p++; 210410Svbart@nginx.com } 211410Svbart@nginx.com 212409Svbart@nginx.com return NXT_AGAIN; 213409Svbart@nginx.com 214409Svbart@nginx.com method_unusual_char: 215409Svbart@nginx.com 216409Svbart@nginx.com ch = *p; 21716Svbart@nginx.com 21816Svbart@nginx.com if (nxt_fast_path(ch == ' ')) { 21916Svbart@nginx.com rp->method.length = p - rp->method.start; 22016Svbart@nginx.com break; 22116Svbart@nginx.com } 22216Svbart@nginx.com 22316Svbart@nginx.com if (ch == '_' || ch == '-') { 224409Svbart@nginx.com p++; 22516Svbart@nginx.com continue; 22616Svbart@nginx.com } 22716Svbart@nginx.com 22816Svbart@nginx.com if (rp->method.start == p && (ch == NXT_CR || ch == NXT_LF)) { 22916Svbart@nginx.com rp->method.start++; 230409Svbart@nginx.com p++; 23116Svbart@nginx.com continue; 23216Svbart@nginx.com } 23316Svbart@nginx.com 234480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 23516Svbart@nginx.com } 23616Svbart@nginx.com 23716Svbart@nginx.com p++; 23816Svbart@nginx.com 23916Svbart@nginx.com if (nxt_slow_path(p == end)) { 24016Svbart@nginx.com return NXT_AGAIN; 24116Svbart@nginx.com } 24216Svbart@nginx.com 24316Svbart@nginx.com /* target */ 24416Svbart@nginx.com 24516Svbart@nginx.com ch = *p; 24616Svbart@nginx.com 24716Svbart@nginx.com if (nxt_slow_path(ch != '/')) { 24816Svbart@nginx.com rc = nxt_http_parse_unusual_target(rp, &p, end); 24916Svbart@nginx.com 25016Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 25116Svbart@nginx.com return rc; 25216Svbart@nginx.com } 25316Svbart@nginx.com } 25416Svbart@nginx.com 25516Svbart@nginx.com rp->target_start = p; 25616Svbart@nginx.com 25716Svbart@nginx.com after_slash = p + 1; 25816Svbart@nginx.com 25916Svbart@nginx.com for ( ;; ) { 26016Svbart@nginx.com p++; 26116Svbart@nginx.com 26216Svbart@nginx.com trap = nxt_http_parse_target(&p, end); 26316Svbart@nginx.com 26416Svbart@nginx.com switch (trap) { 26516Svbart@nginx.com case NXT_HTTP_TARGET_SLASH: 26616Svbart@nginx.com if (nxt_slow_path(after_slash == p)) { 26716Svbart@nginx.com rp->complex_target = 1; 26816Svbart@nginx.com goto rest_of_target; 26916Svbart@nginx.com } 27016Svbart@nginx.com 27116Svbart@nginx.com after_slash = p + 1; 27216Svbart@nginx.com 27316Svbart@nginx.com rp->exten_start = NULL; 27416Svbart@nginx.com continue; 27516Svbart@nginx.com 27616Svbart@nginx.com case NXT_HTTP_TARGET_DOT: 27716Svbart@nginx.com if (nxt_slow_path(after_slash == p)) { 27816Svbart@nginx.com rp->complex_target = 1; 27916Svbart@nginx.com goto rest_of_target; 28016Svbart@nginx.com } 28116Svbart@nginx.com 28216Svbart@nginx.com rp->exten_start = p + 1; 28316Svbart@nginx.com continue; 28416Svbart@nginx.com 28516Svbart@nginx.com case NXT_HTTP_TARGET_ARGS_MARK: 28616Svbart@nginx.com rp->args_start = p + 1; 28716Svbart@nginx.com goto rest_of_target; 28816Svbart@nginx.com 28916Svbart@nginx.com case NXT_HTTP_TARGET_SPACE: 29016Svbart@nginx.com rp->target_end = p; 29116Svbart@nginx.com goto space_after_target; 29216Svbart@nginx.com 29316Svbart@nginx.com case NXT_HTTP_TARGET_QUOTE_MARK: 29416Svbart@nginx.com rp->quoted_target = 1; 29516Svbart@nginx.com goto rest_of_target; 29616Svbart@nginx.com 29716Svbart@nginx.com case NXT_HTTP_TARGET_PLUS: 29816Svbart@nginx.com rp->plus_in_target = 1; 29916Svbart@nginx.com continue; 30016Svbart@nginx.com 30116Svbart@nginx.com case NXT_HTTP_TARGET_HASH: 30216Svbart@nginx.com rp->complex_target = 1; 30316Svbart@nginx.com goto rest_of_target; 30416Svbart@nginx.com 30516Svbart@nginx.com case NXT_HTTP_TARGET_AGAIN: 30616Svbart@nginx.com return NXT_AGAIN; 30716Svbart@nginx.com 30816Svbart@nginx.com case NXT_HTTP_TARGET_BAD: 309480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 31016Svbart@nginx.com } 31116Svbart@nginx.com 31216Svbart@nginx.com nxt_unreachable(); 31316Svbart@nginx.com } 31416Svbart@nginx.com 31516Svbart@nginx.com rest_of_target: 31616Svbart@nginx.com 31716Svbart@nginx.com for ( ;; ) { 31816Svbart@nginx.com p++; 31916Svbart@nginx.com 32019Svbart@nginx.com trap = nxt_http_parse_target(&p, end); 32116Svbart@nginx.com 32216Svbart@nginx.com switch (trap) { 32316Svbart@nginx.com case NXT_HTTP_TARGET_SPACE: 32416Svbart@nginx.com rp->target_end = p; 32516Svbart@nginx.com goto space_after_target; 32616Svbart@nginx.com 32716Svbart@nginx.com case NXT_HTTP_TARGET_HASH: 32816Svbart@nginx.com rp->complex_target = 1; 32916Svbart@nginx.com continue; 33016Svbart@nginx.com 33116Svbart@nginx.com case NXT_HTTP_TARGET_AGAIN: 33216Svbart@nginx.com return NXT_AGAIN; 33316Svbart@nginx.com 33416Svbart@nginx.com case NXT_HTTP_TARGET_BAD: 335480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 33616Svbart@nginx.com 33716Svbart@nginx.com default: 33816Svbart@nginx.com continue; 33916Svbart@nginx.com } 34016Svbart@nginx.com 34116Svbart@nginx.com nxt_unreachable(); 34216Svbart@nginx.com } 34316Svbart@nginx.com 34416Svbart@nginx.com space_after_target: 34516Svbart@nginx.com 34616Svbart@nginx.com if (nxt_slow_path(end - p < 10)) { 347410Svbart@nginx.com 348410Svbart@nginx.com do { 349410Svbart@nginx.com p++; 350410Svbart@nginx.com 351410Svbart@nginx.com if (p == end) { 352410Svbart@nginx.com return NXT_AGAIN; 353410Svbart@nginx.com } 354410Svbart@nginx.com 355410Svbart@nginx.com } while (*p == ' '); 356410Svbart@nginx.com 357410Svbart@nginx.com if (nxt_memcmp(p, "HTTP/", nxt_min(end - p, 5)) == 0) { 358410Svbart@nginx.com 359410Svbart@nginx.com switch (end - p) { 360410Svbart@nginx.com case 8: 361410Svbart@nginx.com if (p[7] < '0' || p[7] > '9') { 362410Svbart@nginx.com break; 363410Svbart@nginx.com } 364410Svbart@nginx.com /* Fall through. */ 365410Svbart@nginx.com case 7: 366410Svbart@nginx.com if (p[6] != '.') { 367410Svbart@nginx.com break; 368410Svbart@nginx.com } 369410Svbart@nginx.com /* Fall through. */ 370410Svbart@nginx.com case 6: 371410Svbart@nginx.com if (p[5] < '0' || p[5] > '9') { 372410Svbart@nginx.com break; 373410Svbart@nginx.com } 374410Svbart@nginx.com /* Fall through. */ 375410Svbart@nginx.com default: 376410Svbart@nginx.com return NXT_AGAIN; 377410Svbart@nginx.com } 378410Svbart@nginx.com } 379410Svbart@nginx.com 380410Svbart@nginx.com rp->space_in_target = 1; 381410Svbart@nginx.com goto rest_of_target; 38216Svbart@nginx.com } 38316Svbart@nginx.com 38416Svbart@nginx.com /* " HTTP/1.1\r\n" or " HTTP/1.1\n" */ 38516Svbart@nginx.com 386*482Svbart@nginx.com if (nxt_slow_path(p[9] != '\r' && p[9] != '\n')) { 387*482Svbart@nginx.com 388*482Svbart@nginx.com if (p[1] == ' ') { 389*482Svbart@nginx.com /* surplus space after tartet */ 390*482Svbart@nginx.com p++; 391*482Svbart@nginx.com goto space_after_target; 392*482Svbart@nginx.com } 393*482Svbart@nginx.com 394*482Svbart@nginx.com rp->space_in_target = 1; 395*482Svbart@nginx.com goto rest_of_target; 396*482Svbart@nginx.com } 397*482Svbart@nginx.com 398481Svbart@nginx.com nxt_memcpy(ver.str, &p[1], 8); 39916Svbart@nginx.com 400*482Svbart@nginx.com if (nxt_fast_path(ver.ui64 == http11.ui64 401*482Svbart@nginx.com || ver.ui64 == http10.ui64 402*482Svbart@nginx.com || (nxt_memcmp(ver.str, "HTTP/1.", 7) == 0 403*482Svbart@nginx.com && ver.s.minor >= '0' && ver.s.minor <= '9'))) 40416Svbart@nginx.com { 405481Svbart@nginx.com rp->version.ui64 = ver.ui64; 40616Svbart@nginx.com 40716Svbart@nginx.com if (nxt_fast_path(p[9] == '\r')) { 40816Svbart@nginx.com p += 10; 40916Svbart@nginx.com 41016Svbart@nginx.com if (nxt_slow_path(p == end)) { 41116Svbart@nginx.com return NXT_AGAIN; 41216Svbart@nginx.com } 41316Svbart@nginx.com 41416Svbart@nginx.com if (nxt_slow_path(*p != '\n')) { 415480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 41616Svbart@nginx.com } 41716Svbart@nginx.com 41816Svbart@nginx.com *pos = p + 1; 419112Smax.romanov@nginx.com 420112Smax.romanov@nginx.com } else { 421112Smax.romanov@nginx.com *pos = p + 10; 422112Smax.romanov@nginx.com } 423112Smax.romanov@nginx.com 424112Smax.romanov@nginx.com if (rp->complex_target != 0 || rp->quoted_target != 0) { 425112Smax.romanov@nginx.com rc = nxt_http_parse_complex_target(rp); 426112Smax.romanov@nginx.com 427112Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 428112Smax.romanov@nginx.com return rc; 429112Smax.romanov@nginx.com } 430112Smax.romanov@nginx.com 43116Svbart@nginx.com return nxt_http_parse_field_name(rp, pos, end); 43216Svbart@nginx.com } 43316Svbart@nginx.com 434112Smax.romanov@nginx.com rp->path.start = rp->target_start; 435112Smax.romanov@nginx.com 436112Smax.romanov@nginx.com if (rp->args_start != NULL) { 437112Smax.romanov@nginx.com rp->path.length = rp->args_start - rp->target_start - 1; 438112Smax.romanov@nginx.com 439112Smax.romanov@nginx.com rp->args.start = rp->args_start; 440112Smax.romanov@nginx.com rp->args.length = rp->target_end - rp->args_start; 441112Smax.romanov@nginx.com 442112Smax.romanov@nginx.com } else { 443112Smax.romanov@nginx.com rp->path.length = rp->target_end - rp->target_start; 444112Smax.romanov@nginx.com } 445112Smax.romanov@nginx.com 446112Smax.romanov@nginx.com if (rp->exten_start) { 447112Smax.romanov@nginx.com rp->exten.length = rp->path.start + rp->path.length - 448112Smax.romanov@nginx.com rp->exten_start; 449112Smax.romanov@nginx.com rp->exten.start = rp->exten_start; 450112Smax.romanov@nginx.com } 451112Smax.romanov@nginx.com 45216Svbart@nginx.com return nxt_http_parse_field_name(rp, pos, end); 45316Svbart@nginx.com } 45416Svbart@nginx.com 455*482Svbart@nginx.com if (nxt_memcmp(ver.s.prefix, "HTTP/", 5) == 0 456*482Svbart@nginx.com && ver.s.major >= '0' && ver.s.major <= '9' 457*482Svbart@nginx.com && ver.s.point == '.' 458*482Svbart@nginx.com && ver.s.minor >= '0' && ver.s.minor <= '9') 459*482Svbart@nginx.com { 460*482Svbart@nginx.com return NXT_HTTP_PARSE_UNSUPPORTED_VERSION; 46116Svbart@nginx.com } 46216Svbart@nginx.com 463*482Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 46416Svbart@nginx.com } 46516Svbart@nginx.com 46616Svbart@nginx.com 46716Svbart@nginx.com static nxt_int_t 46816Svbart@nginx.com nxt_http_parse_unusual_target(nxt_http_request_parse_t *rp, u_char **pos, 46916Svbart@nginx.com u_char *end) 47016Svbart@nginx.com { 47116Svbart@nginx.com u_char *p, ch; 47216Svbart@nginx.com 47316Svbart@nginx.com p = *pos; 47416Svbart@nginx.com 47516Svbart@nginx.com ch = *p; 47616Svbart@nginx.com 47716Svbart@nginx.com if (ch == ' ') { 47816Svbart@nginx.com /* skip surplus spaces before target */ 47916Svbart@nginx.com 48016Svbart@nginx.com do { 48116Svbart@nginx.com p++; 48216Svbart@nginx.com 48316Svbart@nginx.com if (nxt_slow_path(p == end)) { 48416Svbart@nginx.com return NXT_AGAIN; 48516Svbart@nginx.com } 48616Svbart@nginx.com 48716Svbart@nginx.com ch = *p; 48816Svbart@nginx.com 48916Svbart@nginx.com } while (ch == ' '); 49016Svbart@nginx.com 49116Svbart@nginx.com if (ch == '/') { 49216Svbart@nginx.com *pos = p; 49316Svbart@nginx.com return NXT_OK; 49416Svbart@nginx.com } 49516Svbart@nginx.com } 49616Svbart@nginx.com 49716Svbart@nginx.com /* absolute path or '*' */ 49816Svbart@nginx.com 49916Svbart@nginx.com /* TODO */ 50016Svbart@nginx.com 501480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 50216Svbart@nginx.com } 50316Svbart@nginx.com 50416Svbart@nginx.com 50516Svbart@nginx.com static nxt_int_t 50616Svbart@nginx.com nxt_http_parse_field_name(nxt_http_request_parse_t *rp, u_char **pos, 50716Svbart@nginx.com u_char *end) 50816Svbart@nginx.com { 509417Svbart@nginx.com u_char *p, c; 510417Svbart@nginx.com size_t len; 511417Svbart@nginx.com uint32_t hash; 51216Svbart@nginx.com 51316Svbart@nginx.com static const u_char normal[256] nxt_aligned(64) = 51416Svbart@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" 51516Svbart@nginx.com "\0\0\0\0\0\0\0\0\0\0\0\0\0-\0\0" "0123456789\0\0\0\0\0\0" 51616Svbart@nginx.com 51716Svbart@nginx.com /* These 64 bytes should reside in one cache line. */ 518454Svbart@nginx.com "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0_" 51916Svbart@nginx.com "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0" 52016Svbart@nginx.com 52116Svbart@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" 52216Svbart@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" 52316Svbart@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" 52416Svbart@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"; 52516Svbart@nginx.com 526417Svbart@nginx.com p = *pos + rp->field_name.length; 527417Svbart@nginx.com hash = rp->field_hash; 52816Svbart@nginx.com 529417Svbart@nginx.com while (nxt_fast_path(end - p >= 8)) { 530409Svbart@nginx.com 531417Svbart@nginx.com #define nxt_field_name_test_char(ch) \ 532409Svbart@nginx.com \ 53319Svbart@nginx.com c = normal[ch]; \ 53419Svbart@nginx.com \ 53519Svbart@nginx.com if (nxt_slow_path(c == '\0')) { \ 536417Svbart@nginx.com p = &(ch); \ 53719Svbart@nginx.com goto name_end; \ 53819Svbart@nginx.com } \ 53919Svbart@nginx.com \ 540417Svbart@nginx.com hash = nxt_http_field_hash_char(hash, c); 541409Svbart@nginx.com 542409Svbart@nginx.com /* enddef */ 54316Svbart@nginx.com 544417Svbart@nginx.com nxt_field_name_test_char(p[0]); 545417Svbart@nginx.com nxt_field_name_test_char(p[1]); 546417Svbart@nginx.com nxt_field_name_test_char(p[2]); 547417Svbart@nginx.com nxt_field_name_test_char(p[3]); 54816Svbart@nginx.com 549417Svbart@nginx.com nxt_field_name_test_char(p[4]); 550417Svbart@nginx.com nxt_field_name_test_char(p[5]); 551417Svbart@nginx.com nxt_field_name_test_char(p[6]); 552417Svbart@nginx.com nxt_field_name_test_char(p[7]); 553417Svbart@nginx.com 554417Svbart@nginx.com p += 8; 55519Svbart@nginx.com } 55616Svbart@nginx.com 557417Svbart@nginx.com while (nxt_fast_path(p != end)) { 558417Svbart@nginx.com nxt_field_name_test_char(*p); p++; 55919Svbart@nginx.com } 56016Svbart@nginx.com 561417Svbart@nginx.com len = p - *pos; 562417Svbart@nginx.com 563417Svbart@nginx.com if (nxt_slow_path(len > NXT_HTTP_MAX_FIELD_NAME)) { 564480Svbart@nginx.com return NXT_HTTP_PARSE_TOO_LARGE_FIELD; 565417Svbart@nginx.com } 566417Svbart@nginx.com 567417Svbart@nginx.com rp->field_hash = hash; 568417Svbart@nginx.com rp->field_name.length = len; 569417Svbart@nginx.com 57016Svbart@nginx.com rp->handler = &nxt_http_parse_field_name; 57116Svbart@nginx.com 57216Svbart@nginx.com return NXT_AGAIN; 57319Svbart@nginx.com 57419Svbart@nginx.com name_end: 57519Svbart@nginx.com 576417Svbart@nginx.com if (nxt_fast_path(*p == ':')) { 577417Svbart@nginx.com if (nxt_slow_path(p == *pos)) { 578480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 57919Svbart@nginx.com } 58019Svbart@nginx.com 581417Svbart@nginx.com len = p - *pos; 582417Svbart@nginx.com 583417Svbart@nginx.com if (nxt_slow_path(len > NXT_HTTP_MAX_FIELD_NAME)) { 584480Svbart@nginx.com return NXT_HTTP_PARSE_TOO_LARGE_FIELD; 585417Svbart@nginx.com } 58619Svbart@nginx.com 587417Svbart@nginx.com rp->field_hash = hash; 588417Svbart@nginx.com 589417Svbart@nginx.com rp->field_name.length = len; 590417Svbart@nginx.com rp->field_name.start = *pos; 591417Svbart@nginx.com 592417Svbart@nginx.com *pos = p + 1; 59319Svbart@nginx.com 59419Svbart@nginx.com return nxt_http_parse_field_value(rp, pos, end); 59519Svbart@nginx.com } 59619Svbart@nginx.com 597417Svbart@nginx.com if (nxt_slow_path(p != *pos)) { 598480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 59959Svbart@nginx.com } 60019Svbart@nginx.com 60119Svbart@nginx.com return nxt_http_parse_field_end(rp, pos, end); 60216Svbart@nginx.com } 60316Svbart@nginx.com 60416Svbart@nginx.com 60516Svbart@nginx.com static nxt_int_t 60616Svbart@nginx.com nxt_http_parse_field_value(nxt_http_request_parse_t *rp, u_char **pos, 60716Svbart@nginx.com u_char *end) 60816Svbart@nginx.com { 60916Svbart@nginx.com u_char *p, ch; 610417Svbart@nginx.com size_t len; 61116Svbart@nginx.com 61216Svbart@nginx.com p = *pos; 61316Svbart@nginx.com 61416Svbart@nginx.com for ( ;; ) { 61516Svbart@nginx.com if (nxt_slow_path(p == end)) { 61616Svbart@nginx.com *pos = p; 61716Svbart@nginx.com rp->handler = &nxt_http_parse_field_value; 61816Svbart@nginx.com return NXT_AGAIN; 61916Svbart@nginx.com } 62016Svbart@nginx.com 62116Svbart@nginx.com if (*p != ' ') { 62216Svbart@nginx.com break; 62316Svbart@nginx.com } 62416Svbart@nginx.com 62516Svbart@nginx.com p++; 62616Svbart@nginx.com } 62716Svbart@nginx.com 62816Svbart@nginx.com *pos = p; 62916Svbart@nginx.com 63067Svbart@nginx.com p += rp->field_value.length; 63116Svbart@nginx.com 63216Svbart@nginx.com for ( ;; ) { 63316Svbart@nginx.com p = nxt_http_lookup_field_end(p, end); 63416Svbart@nginx.com 63516Svbart@nginx.com if (nxt_slow_path(p == end)) { 636417Svbart@nginx.com len = p - *pos; 637417Svbart@nginx.com 638417Svbart@nginx.com if (nxt_slow_path(len > NXT_HTTP_MAX_FIELD_VALUE)) { 639480Svbart@nginx.com return NXT_HTTP_PARSE_TOO_LARGE_FIELD; 640417Svbart@nginx.com } 641417Svbart@nginx.com 642417Svbart@nginx.com rp->field_value.length = len; 64316Svbart@nginx.com rp->handler = &nxt_http_parse_field_value; 64416Svbart@nginx.com return NXT_AGAIN; 64516Svbart@nginx.com } 64616Svbart@nginx.com 64716Svbart@nginx.com ch = *p; 64816Svbart@nginx.com 64916Svbart@nginx.com if (nxt_fast_path(ch == '\r' || ch == '\n')) { 65016Svbart@nginx.com break; 65116Svbart@nginx.com } 65216Svbart@nginx.com 65316Svbart@nginx.com if (ch == '\0') { 654480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 65516Svbart@nginx.com } 65616Svbart@nginx.com } 65716Svbart@nginx.com 65816Svbart@nginx.com if (nxt_fast_path(p != *pos)) { 65916Svbart@nginx.com while (p[-1] == ' ') { 66016Svbart@nginx.com p--; 66116Svbart@nginx.com } 66216Svbart@nginx.com } 66316Svbart@nginx.com 664417Svbart@nginx.com len = p - *pos; 665417Svbart@nginx.com 666417Svbart@nginx.com if (nxt_slow_path(len > NXT_HTTP_MAX_FIELD_VALUE)) { 667480Svbart@nginx.com return NXT_HTTP_PARSE_TOO_LARGE_FIELD; 668417Svbart@nginx.com } 669417Svbart@nginx.com 670417Svbart@nginx.com rp->field_value.length = len; 67167Svbart@nginx.com rp->field_value.start = *pos; 67216Svbart@nginx.com 67316Svbart@nginx.com *pos = p; 67416Svbart@nginx.com 67516Svbart@nginx.com return nxt_http_parse_field_end(rp, pos, end); 67616Svbart@nginx.com } 67716Svbart@nginx.com 67816Svbart@nginx.com 67916Svbart@nginx.com static u_char * 68016Svbart@nginx.com nxt_http_lookup_field_end(u_char *p, u_char *end) 68116Svbart@nginx.com { 682409Svbart@nginx.com while (nxt_fast_path(end - p >= 16)) { 683409Svbart@nginx.com 684409Svbart@nginx.com #define nxt_field_end_test_char(ch) \ 685409Svbart@nginx.com \ 686409Svbart@nginx.com if (nxt_slow_path((ch) < 0x10)) { \ 687409Svbart@nginx.com return &(ch); \ 688409Svbart@nginx.com } 689409Svbart@nginx.com 690409Svbart@nginx.com /* enddef */ 691409Svbart@nginx.com 692409Svbart@nginx.com nxt_field_end_test_char(p[0]); 693409Svbart@nginx.com nxt_field_end_test_char(p[1]); 694409Svbart@nginx.com nxt_field_end_test_char(p[2]); 695409Svbart@nginx.com nxt_field_end_test_char(p[3]); 69616Svbart@nginx.com 697409Svbart@nginx.com nxt_field_end_test_char(p[4]); 698409Svbart@nginx.com nxt_field_end_test_char(p[5]); 699409Svbart@nginx.com nxt_field_end_test_char(p[6]); 700409Svbart@nginx.com nxt_field_end_test_char(p[7]); 701409Svbart@nginx.com 702409Svbart@nginx.com nxt_field_end_test_char(p[8]); 703409Svbart@nginx.com nxt_field_end_test_char(p[9]); 704409Svbart@nginx.com nxt_field_end_test_char(p[10]); 705409Svbart@nginx.com nxt_field_end_test_char(p[11]); 706409Svbart@nginx.com 707409Svbart@nginx.com nxt_field_end_test_char(p[12]); 708409Svbart@nginx.com nxt_field_end_test_char(p[13]); 709409Svbart@nginx.com nxt_field_end_test_char(p[14]); 710409Svbart@nginx.com nxt_field_end_test_char(p[15]); 711409Svbart@nginx.com 712409Svbart@nginx.com p += 16; 71316Svbart@nginx.com } 71416Svbart@nginx.com 715409Svbart@nginx.com while (nxt_fast_path(end - p >= 4)) { 71619Svbart@nginx.com 717409Svbart@nginx.com nxt_field_end_test_char(p[0]); 718409Svbart@nginx.com nxt_field_end_test_char(p[1]); 719409Svbart@nginx.com nxt_field_end_test_char(p[2]); 720409Svbart@nginx.com nxt_field_end_test_char(p[3]); 72116Svbart@nginx.com 722409Svbart@nginx.com p += 4; 72319Svbart@nginx.com } 72419Svbart@nginx.com 72519Svbart@nginx.com switch (end - p) { 72616Svbart@nginx.com case 3: 727409Svbart@nginx.com nxt_field_end_test_char(*p); p++; 72839Svbart@nginx.com /* Fall through. */ 72916Svbart@nginx.com case 2: 730409Svbart@nginx.com nxt_field_end_test_char(*p); p++; 73139Svbart@nginx.com /* Fall through. */ 73216Svbart@nginx.com case 1: 733409Svbart@nginx.com nxt_field_end_test_char(*p); p++; 73439Svbart@nginx.com /* Fall through. */ 73516Svbart@nginx.com case 0: 73616Svbart@nginx.com break; 73716Svbart@nginx.com default: 73816Svbart@nginx.com nxt_unreachable(); 73916Svbart@nginx.com } 74016Svbart@nginx.com 74116Svbart@nginx.com return p; 74216Svbart@nginx.com } 74316Svbart@nginx.com 74416Svbart@nginx.com 74516Svbart@nginx.com static nxt_int_t 74616Svbart@nginx.com nxt_http_parse_field_end(nxt_http_request_parse_t *rp, u_char **pos, 74716Svbart@nginx.com u_char *end) 74816Svbart@nginx.com { 74960Svbart@nginx.com u_char *p; 75060Svbart@nginx.com nxt_http_field_t *field; 75116Svbart@nginx.com 75216Svbart@nginx.com p = *pos; 75316Svbart@nginx.com 75416Svbart@nginx.com if (nxt_fast_path(*p == '\r')) { 75516Svbart@nginx.com p++; 75616Svbart@nginx.com 75716Svbart@nginx.com if (nxt_slow_path(p == end)) { 75816Svbart@nginx.com rp->handler = &nxt_http_parse_field_end; 75916Svbart@nginx.com return NXT_AGAIN; 76016Svbart@nginx.com } 76116Svbart@nginx.com } 76216Svbart@nginx.com 76316Svbart@nginx.com if (nxt_fast_path(*p == '\n')) { 76416Svbart@nginx.com *pos = p + 1; 76516Svbart@nginx.com 76667Svbart@nginx.com if (rp->field_name.length != 0) { 76760Svbart@nginx.com field = nxt_list_add(rp->fields); 76816Svbart@nginx.com 76960Svbart@nginx.com if (nxt_slow_path(field == NULL)) { 77060Svbart@nginx.com return NXT_ERROR; 77116Svbart@nginx.com } 77216Svbart@nginx.com 773417Svbart@nginx.com field->hash = nxt_http_field_hash_end(rp->field_hash); 774417Svbart@nginx.com field->skip = 0; 77560Svbart@nginx.com 776417Svbart@nginx.com field->name_length = rp->field_name.length; 777417Svbart@nginx.com field->value_length = rp->field_value.length; 778417Svbart@nginx.com field->name = rp->field_name.start; 779417Svbart@nginx.com field->value = rp->field_value.start; 78067Svbart@nginx.com 781417Svbart@nginx.com rp->field_hash = NXT_HTTP_FIELD_HASH_INIT; 78267Svbart@nginx.com 78367Svbart@nginx.com rp->field_name.length = 0; 78467Svbart@nginx.com rp->field_value.length = 0; 78516Svbart@nginx.com 78616Svbart@nginx.com rp->handler = &nxt_http_parse_field_name; 78716Svbart@nginx.com return NXT_OK; 78816Svbart@nginx.com } 78916Svbart@nginx.com 79016Svbart@nginx.com return NXT_DONE; 79116Svbart@nginx.com } 79216Svbart@nginx.com 793480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 79416Svbart@nginx.com } 79516Svbart@nginx.com 79616Svbart@nginx.com 797112Smax.romanov@nginx.com #define \ 798112Smax.romanov@nginx.com nxt_http_is_normal(c) \ 799112Smax.romanov@nginx.com (nxt_fast_path((nxt_http_normal[c / 8] & (1 << (c & 7))) != 0)) 800112Smax.romanov@nginx.com 801112Smax.romanov@nginx.com 802112Smax.romanov@nginx.com static const uint8_t nxt_http_normal[32] nxt_aligned(32) = { 803112Smax.romanov@nginx.com 804112Smax.romanov@nginx.com /* \0 \r \n */ 805112Smax.romanov@nginx.com 0xfe, 0xdb, 0xff, 0xff, /* 1111 1110 1101 1011 1111 1111 1111 1111 */ 806112Smax.romanov@nginx.com 807112Smax.romanov@nginx.com /* '&%$ #"! /.-, |*)( 7654 3210 ?>=< ;:98 */ 808112Smax.romanov@nginx.com 0xd6, 0x37, 0xff, 0x7f, /* 1101 0110 0011 0111 1111 1111 0111 1111 */ 809112Smax.romanov@nginx.com 810112Smax.romanov@nginx.com /* GFED CBA@ ONML KJIH WVUT SRQP _^]\ [ZYX */ 811112Smax.romanov@nginx.com 0xff, 0xff, 0xff, 0xff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 812112Smax.romanov@nginx.com 813112Smax.romanov@nginx.com /* gfed cba` onml kjih wvut srqp ~}| {zyx */ 814112Smax.romanov@nginx.com 0xff, 0xff, 0xff, 0xff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 815112Smax.romanov@nginx.com 816112Smax.romanov@nginx.com 0xff, 0xff, 0xff, 0xff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 817112Smax.romanov@nginx.com 0xff, 0xff, 0xff, 0xff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 818112Smax.romanov@nginx.com 0xff, 0xff, 0xff, 0xff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 819112Smax.romanov@nginx.com 0xff, 0xff, 0xff, 0xff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 820112Smax.romanov@nginx.com }; 821112Smax.romanov@nginx.com 822112Smax.romanov@nginx.com 823112Smax.romanov@nginx.com static nxt_int_t 824112Smax.romanov@nginx.com nxt_http_parse_complex_target(nxt_http_request_parse_t *rp) 825112Smax.romanov@nginx.com { 826112Smax.romanov@nginx.com u_char *p, *u, c, ch, high; 827112Smax.romanov@nginx.com enum { 828112Smax.romanov@nginx.com sw_normal = 0, 829112Smax.romanov@nginx.com sw_slash, 830112Smax.romanov@nginx.com sw_dot, 831112Smax.romanov@nginx.com sw_dot_dot, 832112Smax.romanov@nginx.com sw_quoted, 833112Smax.romanov@nginx.com sw_quoted_second, 834112Smax.romanov@nginx.com } state, saved_state; 835112Smax.romanov@nginx.com 836112Smax.romanov@nginx.com nxt_prefetch(nxt_http_normal); 837112Smax.romanov@nginx.com 838112Smax.romanov@nginx.com state = sw_normal; 839112Smax.romanov@nginx.com saved_state = sw_normal; 840112Smax.romanov@nginx.com p = rp->target_start; 841112Smax.romanov@nginx.com 842112Smax.romanov@nginx.com u = nxt_mp_alloc(rp->mem_pool, rp->target_end - p + 1); 843112Smax.romanov@nginx.com 844112Smax.romanov@nginx.com if (nxt_slow_path(u == NULL)) { 845112Smax.romanov@nginx.com return NXT_ERROR; 846112Smax.romanov@nginx.com } 847112Smax.romanov@nginx.com 848112Smax.romanov@nginx.com rp->path.length = 0; 849112Smax.romanov@nginx.com rp->path.start = u; 850112Smax.romanov@nginx.com 851112Smax.romanov@nginx.com high = '\0'; 852112Smax.romanov@nginx.com rp->exten_start = NULL; 853112Smax.romanov@nginx.com rp->args_start = NULL; 854112Smax.romanov@nginx.com 855112Smax.romanov@nginx.com while (p < rp->target_end) { 856112Smax.romanov@nginx.com 857112Smax.romanov@nginx.com ch = *p++; 858112Smax.romanov@nginx.com 859112Smax.romanov@nginx.com again: 860112Smax.romanov@nginx.com 861112Smax.romanov@nginx.com switch (state) { 862112Smax.romanov@nginx.com 863112Smax.romanov@nginx.com case sw_normal: 864112Smax.romanov@nginx.com 865112Smax.romanov@nginx.com if (nxt_http_is_normal(ch)) { 866112Smax.romanov@nginx.com *u++ = ch; 867112Smax.romanov@nginx.com continue; 868112Smax.romanov@nginx.com } 869112Smax.romanov@nginx.com 870112Smax.romanov@nginx.com switch (ch) { 871112Smax.romanov@nginx.com case '/': 872112Smax.romanov@nginx.com rp->exten_start = NULL; 873112Smax.romanov@nginx.com state = sw_slash; 874112Smax.romanov@nginx.com *u++ = ch; 875112Smax.romanov@nginx.com continue; 876112Smax.romanov@nginx.com case '%': 877112Smax.romanov@nginx.com saved_state = state; 878112Smax.romanov@nginx.com state = sw_quoted; 879112Smax.romanov@nginx.com continue; 880112Smax.romanov@nginx.com case '?': 881112Smax.romanov@nginx.com rp->args_start = p; 882112Smax.romanov@nginx.com goto args; 883112Smax.romanov@nginx.com case '#': 884112Smax.romanov@nginx.com goto done; 885112Smax.romanov@nginx.com case '.': 886112Smax.romanov@nginx.com rp->exten_start = u + 1; 887112Smax.romanov@nginx.com *u++ = ch; 888112Smax.romanov@nginx.com continue; 889112Smax.romanov@nginx.com case '+': 890112Smax.romanov@nginx.com rp->plus_in_target = 1; 891112Smax.romanov@nginx.com /* Fall through. */ 892112Smax.romanov@nginx.com default: 893112Smax.romanov@nginx.com *u++ = ch; 894112Smax.romanov@nginx.com continue; 895112Smax.romanov@nginx.com } 896112Smax.romanov@nginx.com 897112Smax.romanov@nginx.com break; 898112Smax.romanov@nginx.com 899112Smax.romanov@nginx.com case sw_slash: 900112Smax.romanov@nginx.com 901112Smax.romanov@nginx.com if (nxt_http_is_normal(ch)) { 902112Smax.romanov@nginx.com state = sw_normal; 903112Smax.romanov@nginx.com *u++ = ch; 904112Smax.romanov@nginx.com continue; 905112Smax.romanov@nginx.com } 906112Smax.romanov@nginx.com 907112Smax.romanov@nginx.com switch (ch) { 908112Smax.romanov@nginx.com case '/': 909112Smax.romanov@nginx.com continue; 910112Smax.romanov@nginx.com case '.': 911112Smax.romanov@nginx.com state = sw_dot; 912112Smax.romanov@nginx.com *u++ = ch; 913112Smax.romanov@nginx.com continue; 914112Smax.romanov@nginx.com case '%': 915112Smax.romanov@nginx.com saved_state = state; 916112Smax.romanov@nginx.com state = sw_quoted; 917112Smax.romanov@nginx.com continue; 918112Smax.romanov@nginx.com case '?': 919112Smax.romanov@nginx.com rp->args_start = p; 920112Smax.romanov@nginx.com goto args; 921112Smax.romanov@nginx.com case '#': 922112Smax.romanov@nginx.com goto done; 923112Smax.romanov@nginx.com case '+': 924112Smax.romanov@nginx.com rp->plus_in_target = 1; 925112Smax.romanov@nginx.com /* Fall through. */ 926112Smax.romanov@nginx.com default: 927112Smax.romanov@nginx.com state = sw_normal; 928112Smax.romanov@nginx.com *u++ = ch; 929112Smax.romanov@nginx.com continue; 930112Smax.romanov@nginx.com } 931112Smax.romanov@nginx.com 932112Smax.romanov@nginx.com break; 933112Smax.romanov@nginx.com 934112Smax.romanov@nginx.com case sw_dot: 935112Smax.romanov@nginx.com 936112Smax.romanov@nginx.com if (nxt_http_is_normal(ch)) { 937112Smax.romanov@nginx.com state = sw_normal; 938112Smax.romanov@nginx.com *u++ = ch; 939112Smax.romanov@nginx.com continue; 940112Smax.romanov@nginx.com } 941112Smax.romanov@nginx.com 942112Smax.romanov@nginx.com switch (ch) { 943112Smax.romanov@nginx.com case '/': 944112Smax.romanov@nginx.com state = sw_slash; 945112Smax.romanov@nginx.com u--; 946112Smax.romanov@nginx.com continue; 947112Smax.romanov@nginx.com case '.': 948112Smax.romanov@nginx.com state = sw_dot_dot; 949112Smax.romanov@nginx.com *u++ = ch; 950112Smax.romanov@nginx.com continue; 951112Smax.romanov@nginx.com case '%': 952112Smax.romanov@nginx.com saved_state = state; 953112Smax.romanov@nginx.com state = sw_quoted; 954112Smax.romanov@nginx.com continue; 955112Smax.romanov@nginx.com case '?': 956112Smax.romanov@nginx.com rp->args_start = p; 957112Smax.romanov@nginx.com goto args; 958112Smax.romanov@nginx.com case '#': 959112Smax.romanov@nginx.com goto done; 960112Smax.romanov@nginx.com case '+': 961112Smax.romanov@nginx.com rp->plus_in_target = 1; 962112Smax.romanov@nginx.com /* Fall through. */ 963112Smax.romanov@nginx.com default: 964112Smax.romanov@nginx.com state = sw_normal; 965112Smax.romanov@nginx.com *u++ = ch; 966112Smax.romanov@nginx.com continue; 967112Smax.romanov@nginx.com } 968112Smax.romanov@nginx.com 969112Smax.romanov@nginx.com break; 970112Smax.romanov@nginx.com 971112Smax.romanov@nginx.com case sw_dot_dot: 972112Smax.romanov@nginx.com 973112Smax.romanov@nginx.com if (nxt_http_is_normal(ch)) { 974112Smax.romanov@nginx.com state = sw_normal; 975112Smax.romanov@nginx.com *u++ = ch; 976112Smax.romanov@nginx.com continue; 977112Smax.romanov@nginx.com } 978112Smax.romanov@nginx.com 979112Smax.romanov@nginx.com switch (ch) { 980112Smax.romanov@nginx.com case '/': 981112Smax.romanov@nginx.com state = sw_slash; 982112Smax.romanov@nginx.com u -= 5; 983112Smax.romanov@nginx.com for ( ;; ) { 984112Smax.romanov@nginx.com if (u < rp->path.start) { 985480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 986112Smax.romanov@nginx.com } 987112Smax.romanov@nginx.com if (*u == '/') { 988112Smax.romanov@nginx.com u++; 989112Smax.romanov@nginx.com break; 990112Smax.romanov@nginx.com } 991112Smax.romanov@nginx.com u--; 992112Smax.romanov@nginx.com } 993112Smax.romanov@nginx.com break; 994112Smax.romanov@nginx.com 995112Smax.romanov@nginx.com case '%': 996112Smax.romanov@nginx.com saved_state = state; 997112Smax.romanov@nginx.com state = sw_quoted; 998112Smax.romanov@nginx.com continue; 999112Smax.romanov@nginx.com case '?': 1000112Smax.romanov@nginx.com rp->args_start = p; 1001112Smax.romanov@nginx.com goto args; 1002112Smax.romanov@nginx.com case '#': 1003112Smax.romanov@nginx.com goto done; 1004112Smax.romanov@nginx.com case '+': 1005112Smax.romanov@nginx.com rp->plus_in_target = 1; 1006112Smax.romanov@nginx.com /* Fall through. */ 1007112Smax.romanov@nginx.com default: 1008112Smax.romanov@nginx.com state = sw_normal; 1009112Smax.romanov@nginx.com *u++ = ch; 1010112Smax.romanov@nginx.com continue; 1011112Smax.romanov@nginx.com } 1012112Smax.romanov@nginx.com 1013112Smax.romanov@nginx.com break; 1014112Smax.romanov@nginx.com 1015112Smax.romanov@nginx.com case sw_quoted: 1016112Smax.romanov@nginx.com rp->quoted_target = 1; 1017112Smax.romanov@nginx.com 1018112Smax.romanov@nginx.com if (ch >= '0' && ch <= '9') { 1019112Smax.romanov@nginx.com high = (u_char) (ch - '0'); 1020112Smax.romanov@nginx.com state = sw_quoted_second; 1021112Smax.romanov@nginx.com continue; 1022112Smax.romanov@nginx.com } 1023112Smax.romanov@nginx.com 1024112Smax.romanov@nginx.com c = (u_char) (ch | 0x20); 1025112Smax.romanov@nginx.com if (c >= 'a' && c <= 'f') { 1026112Smax.romanov@nginx.com high = (u_char) (c - 'a' + 10); 1027112Smax.romanov@nginx.com state = sw_quoted_second; 1028112Smax.romanov@nginx.com continue; 1029112Smax.romanov@nginx.com } 1030112Smax.romanov@nginx.com 1031480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 1032112Smax.romanov@nginx.com 1033112Smax.romanov@nginx.com case sw_quoted_second: 1034112Smax.romanov@nginx.com if (ch >= '0' && ch <= '9') { 1035112Smax.romanov@nginx.com ch = (u_char) ((high << 4) + ch - '0'); 1036112Smax.romanov@nginx.com 1037112Smax.romanov@nginx.com if (ch == '%' || ch == '#') { 1038112Smax.romanov@nginx.com state = sw_normal; 1039112Smax.romanov@nginx.com *u++ = ch; 1040112Smax.romanov@nginx.com continue; 1041112Smax.romanov@nginx.com 1042112Smax.romanov@nginx.com } else if (ch == '\0') { 1043480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 1044112Smax.romanov@nginx.com } 1045112Smax.romanov@nginx.com 1046112Smax.romanov@nginx.com state = saved_state; 1047112Smax.romanov@nginx.com goto again; 1048112Smax.romanov@nginx.com } 1049112Smax.romanov@nginx.com 1050112Smax.romanov@nginx.com c = (u_char) (ch | 0x20); 1051112Smax.romanov@nginx.com if (c >= 'a' && c <= 'f') { 1052112Smax.romanov@nginx.com ch = (u_char) ((high << 4) + c - 'a' + 10); 1053112Smax.romanov@nginx.com 1054112Smax.romanov@nginx.com if (ch == '?') { 1055112Smax.romanov@nginx.com state = sw_normal; 1056112Smax.romanov@nginx.com *u++ = ch; 1057112Smax.romanov@nginx.com continue; 1058112Smax.romanov@nginx.com 1059112Smax.romanov@nginx.com } else if (ch == '+') { 1060112Smax.romanov@nginx.com rp->plus_in_target = 1; 1061112Smax.romanov@nginx.com } 1062112Smax.romanov@nginx.com 1063112Smax.romanov@nginx.com state = saved_state; 1064112Smax.romanov@nginx.com goto again; 1065112Smax.romanov@nginx.com } 1066112Smax.romanov@nginx.com 1067480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 1068112Smax.romanov@nginx.com } 1069112Smax.romanov@nginx.com } 1070112Smax.romanov@nginx.com 1071112Smax.romanov@nginx.com if (state >= sw_quoted) { 1072480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 1073112Smax.romanov@nginx.com } 1074112Smax.romanov@nginx.com 1075112Smax.romanov@nginx.com args: 1076112Smax.romanov@nginx.com 1077112Smax.romanov@nginx.com for (/* void */; p < rp->target_end; p++) { 1078