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 32611Svbart@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 3716Svbart@nginx.com 3816Svbart@nginx.com typedef enum { 3916Svbart@nginx.com NXT_HTTP_TARGET_SPACE = 1, /* \s */ 4016Svbart@nginx.com NXT_HTTP_TARGET_HASH, /* # */ 4116Svbart@nginx.com NXT_HTTP_TARGET_AGAIN, 4216Svbart@nginx.com NXT_HTTP_TARGET_BAD, /* \0\r\n */ 4316Svbart@nginx.com 4416Svbart@nginx.com /* traps below are used for extended check only */ 4516Svbart@nginx.com 4616Svbart@nginx.com NXT_HTTP_TARGET_SLASH = 5, /* / */ 4716Svbart@nginx.com NXT_HTTP_TARGET_DOT, /* . */ 4816Svbart@nginx.com NXT_HTTP_TARGET_ARGS_MARK, /* ? */ 4916Svbart@nginx.com NXT_HTTP_TARGET_QUOTE_MARK, /* % */ 5016Svbart@nginx.com } nxt_http_target_traps_e; 5116Svbart@nginx.com 5216Svbart@nginx.com 5316Svbart@nginx.com static const uint8_t nxt_http_target_chars[256] nxt_aligned(64) = { 5416Svbart@nginx.com /* \0 \n \r */ 5516Svbart@nginx.com 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 4, 0, 0, 5616Svbart@nginx.com 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5752Svbart@nginx.com 5852Svbart@nginx.com /* \s ! " # $ % & ' ( ) * + , - . / */ 591170Svbart@nginx.com 1, 0, 0, 2, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 6, 5, 6052Svbart@nginx.com 6152Svbart@nginx.com /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 6216Svbart@nginx.com 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 6316Svbart@nginx.com }; 6416Svbart@nginx.com 6516Svbart@nginx.com 6616Svbart@nginx.com nxt_inline nxt_http_target_traps_e 6716Svbart@nginx.com nxt_http_parse_target(u_char **pos, u_char *end) 6816Svbart@nginx.com { 6916Svbart@nginx.com u_char *p; 7016Svbart@nginx.com nxt_uint_t trap; 7116Svbart@nginx.com 7216Svbart@nginx.com p = *pos; 7316Svbart@nginx.com 74409Svbart@nginx.com while (nxt_fast_path(end - p >= 10)) { 7516Svbart@nginx.com 76409Svbart@nginx.com #define nxt_target_test_char(ch) \ 77409Svbart@nginx.com \ 78409Svbart@nginx.com trap = nxt_http_target_chars[ch]; \ 7916Svbart@nginx.com \ 80409Svbart@nginx.com if (nxt_slow_path(trap != 0)) { \ 81409Svbart@nginx.com *pos = &(ch); \ 82409Svbart@nginx.com return trap; \ 8316Svbart@nginx.com } 8416Svbart@nginx.com 85409Svbart@nginx.com /* enddef */ 86409Svbart@nginx.com 87409Svbart@nginx.com nxt_target_test_char(p[0]); 88409Svbart@nginx.com nxt_target_test_char(p[1]); 89409Svbart@nginx.com nxt_target_test_char(p[2]); 90409Svbart@nginx.com nxt_target_test_char(p[3]); 9116Svbart@nginx.com 92409Svbart@nginx.com nxt_target_test_char(p[4]); 93409Svbart@nginx.com nxt_target_test_char(p[5]); 94409Svbart@nginx.com nxt_target_test_char(p[6]); 95409Svbart@nginx.com nxt_target_test_char(p[7]); 9616Svbart@nginx.com 97409Svbart@nginx.com nxt_target_test_char(p[8]); 98409Svbart@nginx.com nxt_target_test_char(p[9]); 9916Svbart@nginx.com 100409Svbart@nginx.com p += 10; 10116Svbart@nginx.com } 10216Svbart@nginx.com 103410Svbart@nginx.com while (p != end) { 104410Svbart@nginx.com nxt_target_test_char(*p); p++; 105410Svbart@nginx.com } 106410Svbart@nginx.com 107409Svbart@nginx.com return NXT_HTTP_TARGET_AGAIN; 10816Svbart@nginx.com } 10916Svbart@nginx.com 11016Svbart@nginx.com 11116Svbart@nginx.com nxt_int_t 112417Svbart@nginx.com nxt_http_parse_request_init(nxt_http_request_parse_t *rp, nxt_mp_t *mp) 113417Svbart@nginx.com { 114417Svbart@nginx.com rp->mem_pool = mp; 115417Svbart@nginx.com 116417Svbart@nginx.com rp->fields = nxt_list_create(mp, 8, sizeof(nxt_http_field_t)); 1171008Szelenkov@nginx.com if (nxt_slow_path(rp->fields == NULL)) { 118417Svbart@nginx.com return NXT_ERROR; 119417Svbart@nginx.com } 120417Svbart@nginx.com 121417Svbart@nginx.com rp->field_hash = NXT_HTTP_FIELD_HASH_INIT; 122417Svbart@nginx.com 123417Svbart@nginx.com return NXT_OK; 124417Svbart@nginx.com } 125417Svbart@nginx.com 126417Svbart@nginx.com 127417Svbart@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 144422Svbart@nginx.com nxt_int_t 145422Svbart@nginx.com nxt_http_parse_fields(nxt_http_request_parse_t *rp, nxt_buf_mem_t *b) 146422Svbart@nginx.com { 147422Svbart@nginx.com nxt_int_t rc; 148422Svbart@nginx.com 149422Svbart@nginx.com if (rp->handler == NULL) { 150422Svbart@nginx.com rp->handler = &nxt_http_parse_field_name; 151422Svbart@nginx.com } 152422Svbart@nginx.com 153422Svbart@nginx.com do { 154422Svbart@nginx.com rc = rp->handler(rp, &b->pos, b->free); 155422Svbart@nginx.com } while (rc == NXT_OK); 156422Svbart@nginx.com 157422Svbart@nginx.com return rc; 158422Svbart@nginx.com } 159422Svbart@nginx.com 160422Svbart@nginx.com 16116Svbart@nginx.com static nxt_int_t 16216Svbart@nginx.com nxt_http_parse_request_line(nxt_http_request_parse_t *rp, u_char **pos, 16316Svbart@nginx.com u_char *end) 16416Svbart@nginx.com { 1651168Svbart@nginx.com u_char *p, ch, *after_slash, *exten, *args; 16616Svbart@nginx.com nxt_int_t rc; 1671171Svbart@nginx.com nxt_bool_t rest; 168481Svbart@nginx.com nxt_http_ver_t ver; 16916Svbart@nginx.com nxt_http_target_traps_e trap; 17016Svbart@nginx.com 17116Svbart@nginx.com static const nxt_http_ver_t http11 = { "HTTP/1.1" }; 17216Svbart@nginx.com static const nxt_http_ver_t http10 = { "HTTP/1.0" }; 17316Svbart@nginx.com 17416Svbart@nginx.com p = *pos; 17516Svbart@nginx.com 17616Svbart@nginx.com rp->method.start = p; 17716Svbart@nginx.com 178409Svbart@nginx.com for ( ;; ) { 179409Svbart@nginx.com 180409Svbart@nginx.com while (nxt_fast_path(end - p >= 8)) { 18116Svbart@nginx.com 182409Svbart@nginx.com #define nxt_method_test_char(ch) \ 183409Svbart@nginx.com \ 184409Svbart@nginx.com if (nxt_slow_path((ch) < 'A' || (ch) > 'Z')) { \ 185409Svbart@nginx.com p = &(ch); \ 186409Svbart@nginx.com goto method_unusual_char; \ 18716Svbart@nginx.com } 18816Svbart@nginx.com 189409Svbart@nginx.com /* enddef */ 190409Svbart@nginx.com 191409Svbart@nginx.com nxt_method_test_char(p[0]); 192409Svbart@nginx.com nxt_method_test_char(p[1]); 193409Svbart@nginx.com nxt_method_test_char(p[2]); 194409Svbart@nginx.com nxt_method_test_char(p[3]); 19516Svbart@nginx.com 196409Svbart@nginx.com nxt_method_test_char(p[4]); 197409Svbart@nginx.com nxt_method_test_char(p[5]); 198409Svbart@nginx.com nxt_method_test_char(p[6]); 199409Svbart@nginx.com nxt_method_test_char(p[7]); 20016Svbart@nginx.com 201409Svbart@nginx.com p += 8; 202409Svbart@nginx.com } 20316Svbart@nginx.com 204410Svbart@nginx.com while (p != end) { 205410Svbart@nginx.com nxt_method_test_char(*p); p++; 206410Svbart@nginx.com } 207410Svbart@nginx.com 208623Svbart@nginx.com rp->method.length = p - rp->method.start; 209623Svbart@nginx.com 210409Svbart@nginx.com return NXT_AGAIN; 211409Svbart@nginx.com 212409Svbart@nginx.com method_unusual_char: 213409Svbart@nginx.com 214409Svbart@nginx.com ch = *p; 21516Svbart@nginx.com 21616Svbart@nginx.com if (nxt_fast_path(ch == ' ')) { 21716Svbart@nginx.com rp->method.length = p - rp->method.start; 21816Svbart@nginx.com break; 21916Svbart@nginx.com } 22016Svbart@nginx.com 22116Svbart@nginx.com if (ch == '_' || ch == '-') { 222409Svbart@nginx.com p++; 22316Svbart@nginx.com continue; 22416Svbart@nginx.com } 22516Svbart@nginx.com 226704Sigor@sysoev.ru if (rp->method.start == p && (ch == '\r' || ch == '\n')) { 22716Svbart@nginx.com rp->method.start++; 228409Svbart@nginx.com p++; 22916Svbart@nginx.com continue; 23016Svbart@nginx.com } 23116Svbart@nginx.com 232623Svbart@nginx.com rp->method.length = p - rp->method.start; 233623Svbart@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; 2581168Svbart@nginx.com exten = NULL; 2591168Svbart@nginx.com args = NULL; 2601171Svbart@nginx.com rest = 0; 2611171Svbart@nginx.com 2621171Svbart@nginx.com continue_target: 26316Svbart@nginx.com 26416Svbart@nginx.com for ( ;; ) { 26516Svbart@nginx.com p++; 26616Svbart@nginx.com 26716Svbart@nginx.com trap = nxt_http_parse_target(&p, end); 26816Svbart@nginx.com 26916Svbart@nginx.com switch (trap) { 27016Svbart@nginx.com case NXT_HTTP_TARGET_SLASH: 27116Svbart@nginx.com if (nxt_slow_path(after_slash == p)) { 27216Svbart@nginx.com rp->complex_target = 1; 27316Svbart@nginx.com goto rest_of_target; 27416Svbart@nginx.com } 27516Svbart@nginx.com 27616Svbart@nginx.com after_slash = p + 1; 2771168Svbart@nginx.com exten = NULL; 27816Svbart@nginx.com continue; 27916Svbart@nginx.com 28016Svbart@nginx.com case NXT_HTTP_TARGET_DOT: 28116Svbart@nginx.com if (nxt_slow_path(after_slash == p)) { 28216Svbart@nginx.com rp->complex_target = 1; 28316Svbart@nginx.com goto rest_of_target; 28416Svbart@nginx.com } 28516Svbart@nginx.com 2861168Svbart@nginx.com exten = p + 1; 28716Svbart@nginx.com continue; 28816Svbart@nginx.com 28916Svbart@nginx.com case NXT_HTTP_TARGET_ARGS_MARK: 2901168Svbart@nginx.com args = p + 1; 29116Svbart@nginx.com goto rest_of_target; 29216Svbart@nginx.com 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_QUOTE_MARK: 29816Svbart@nginx.com rp->quoted_target = 1; 29916Svbart@nginx.com goto rest_of_target; 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: 306621Svbart@nginx.com rp->target_end = p; 30716Svbart@nginx.com return NXT_AGAIN; 30816Svbart@nginx.com 30916Svbart@nginx.com case NXT_HTTP_TARGET_BAD: 310621Svbart@nginx.com rp->target_end = p; 311480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 31216Svbart@nginx.com } 31316Svbart@nginx.com 31416Svbart@nginx.com nxt_unreachable(); 31516Svbart@nginx.com } 31616Svbart@nginx.com 31716Svbart@nginx.com rest_of_target: 31816Svbart@nginx.com 3191171Svbart@nginx.com rest = 1; 3201171Svbart@nginx.com 32116Svbart@nginx.com for ( ;; ) { 32216Svbart@nginx.com p++; 32316Svbart@nginx.com 32419Svbart@nginx.com trap = nxt_http_parse_target(&p, end); 32516Svbart@nginx.com 32616Svbart@nginx.com switch (trap) { 32716Svbart@nginx.com case NXT_HTTP_TARGET_SPACE: 32816Svbart@nginx.com rp->target_end = p; 32916Svbart@nginx.com goto space_after_target; 33016Svbart@nginx.com 33116Svbart@nginx.com case NXT_HTTP_TARGET_HASH: 33216Svbart@nginx.com rp->complex_target = 1; 33316Svbart@nginx.com continue; 33416Svbart@nginx.com 33516Svbart@nginx.com case NXT_HTTP_TARGET_AGAIN: 336621Svbart@nginx.com rp->target_end = p; 33716Svbart@nginx.com return NXT_AGAIN; 33816Svbart@nginx.com 33916Svbart@nginx.com case NXT_HTTP_TARGET_BAD: 340621Svbart@nginx.com rp->target_end = p; 341480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 34216Svbart@nginx.com 34316Svbart@nginx.com default: 34416Svbart@nginx.com continue; 34516Svbart@nginx.com } 34616Svbart@nginx.com 34716Svbart@nginx.com nxt_unreachable(); 34816Svbart@nginx.com } 34916Svbart@nginx.com 35016Svbart@nginx.com space_after_target: 35116Svbart@nginx.com 35216Svbart@nginx.com if (nxt_slow_path(end - p < 10)) { 353410Svbart@nginx.com 354410Svbart@nginx.com do { 355410Svbart@nginx.com p++; 356410Svbart@nginx.com 357410Svbart@nginx.com if (p == end) { 358410Svbart@nginx.com return NXT_AGAIN; 359410Svbart@nginx.com } 360410Svbart@nginx.com 361410Svbart@nginx.com } while (*p == ' '); 362410Svbart@nginx.com 363410Svbart@nginx.com if (nxt_memcmp(p, "HTTP/", nxt_min(end - p, 5)) == 0) { 364410Svbart@nginx.com 365410Svbart@nginx.com switch (end - p) { 366410Svbart@nginx.com case 8: 367410Svbart@nginx.com if (p[7] < '0' || p[7] > '9') { 368410Svbart@nginx.com break; 369410Svbart@nginx.com } 370410Svbart@nginx.com /* Fall through. */ 371410Svbart@nginx.com case 7: 372410Svbart@nginx.com if (p[6] != '.') { 373410Svbart@nginx.com break; 374410Svbart@nginx.com } 375410Svbart@nginx.com /* Fall through. */ 376410Svbart@nginx.com case 6: 377410Svbart@nginx.com if (p[5] < '0' || p[5] > '9') { 378410Svbart@nginx.com break; 379410Svbart@nginx.com } 380410Svbart@nginx.com /* Fall through. */ 381410Svbart@nginx.com default: 382410Svbart@nginx.com return NXT_AGAIN; 383410Svbart@nginx.com } 384410Svbart@nginx.com } 385410Svbart@nginx.com 386410Svbart@nginx.com rp->space_in_target = 1; 3871171Svbart@nginx.com 3881171Svbart@nginx.com if (rest) { 3891171Svbart@nginx.com goto rest_of_target; 3901171Svbart@nginx.com } 3911171Svbart@nginx.com 3921171Svbart@nginx.com goto continue_target; 39316Svbart@nginx.com } 39416Svbart@nginx.com 39516Svbart@nginx.com /* " HTTP/1.1\r\n" or " HTTP/1.1\n" */ 39616Svbart@nginx.com 397482Svbart@nginx.com if (nxt_slow_path(p[9] != '\r' && p[9] != '\n')) { 398482Svbart@nginx.com 399482Svbart@nginx.com if (p[1] == ' ') { 400482Svbart@nginx.com /* surplus space after tartet */ 401482Svbart@nginx.com p++; 402482Svbart@nginx.com goto space_after_target; 403482Svbart@nginx.com } 404482Svbart@nginx.com 405482Svbart@nginx.com rp->space_in_target = 1; 4061171Svbart@nginx.com 4071171Svbart@nginx.com if (rest) { 4081171Svbart@nginx.com goto rest_of_target; 4091171Svbart@nginx.com } 4101171Svbart@nginx.com 4111171Svbart@nginx.com goto continue_target; 412482Svbart@nginx.com } 413482Svbart@nginx.com 414481Svbart@nginx.com nxt_memcpy(ver.str, &p[1], 8); 41516Svbart@nginx.com 416482Svbart@nginx.com if (nxt_fast_path(ver.ui64 == http11.ui64 417482Svbart@nginx.com || ver.ui64 == http10.ui64 418482Svbart@nginx.com || (nxt_memcmp(ver.str, "HTTP/1.", 7) == 0 419482Svbart@nginx.com && ver.s.minor >= '0' && ver.s.minor <= '9'))) 42016Svbart@nginx.com { 421481Svbart@nginx.com rp->version.ui64 = ver.ui64; 42216Svbart@nginx.com 42316Svbart@nginx.com if (nxt_fast_path(p[9] == '\r')) { 42416Svbart@nginx.com p += 10; 42516Svbart@nginx.com 42616Svbart@nginx.com if (nxt_slow_path(p == end)) { 42716Svbart@nginx.com return NXT_AGAIN; 42816Svbart@nginx.com } 42916Svbart@nginx.com 43016Svbart@nginx.com if (nxt_slow_path(*p != '\n')) { 431480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 43216Svbart@nginx.com } 43316Svbart@nginx.com 43416Svbart@nginx.com *pos = p + 1; 435112Smax.romanov@nginx.com 436112Smax.romanov@nginx.com } else { 437112Smax.romanov@nginx.com *pos = p + 10; 438112Smax.romanov@nginx.com } 439112Smax.romanov@nginx.com 440112Smax.romanov@nginx.com if (rp->complex_target != 0 || rp->quoted_target != 0) { 441112Smax.romanov@nginx.com rc = nxt_http_parse_complex_target(rp); 442112Smax.romanov@nginx.com 443112Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 444112Smax.romanov@nginx.com return rc; 445112Smax.romanov@nginx.com } 446112Smax.romanov@nginx.com 44716Svbart@nginx.com return nxt_http_parse_field_name(rp, pos, end); 44816Svbart@nginx.com } 44916Svbart@nginx.com 450112Smax.romanov@nginx.com rp->path.start = rp->target_start; 451112Smax.romanov@nginx.com 4521168Svbart@nginx.com if (args != NULL) { 4531168Svbart@nginx.com rp->path.length = args - rp->target_start - 1; 454112Smax.romanov@nginx.com 4551168Svbart@nginx.com rp->args.length = rp->target_end - args; 4561168Svbart@nginx.com rp->args.start = args; 457112Smax.romanov@nginx.com 458112Smax.romanov@nginx.com } else { 459112Smax.romanov@nginx.com rp->path.length = rp->target_end - rp->target_start; 460112Smax.romanov@nginx.com } 461112Smax.romanov@nginx.com 4621168Svbart@nginx.com if (exten != NULL) { 4631168Svbart@nginx.com rp->exten.length = (rp->path.start + rp->path.length) - exten; 4641168Svbart@nginx.com rp->exten.start = exten; 465112Smax.romanov@nginx.com } 466112Smax.romanov@nginx.com 46716Svbart@nginx.com return nxt_http_parse_field_name(rp, pos, end); 46816Svbart@nginx.com } 46916Svbart@nginx.com 470482Svbart@nginx.com if (nxt_memcmp(ver.s.prefix, "HTTP/", 5) == 0 471482Svbart@nginx.com && ver.s.major >= '0' && ver.s.major <= '9' 472482Svbart@nginx.com && ver.s.point == '.' 473482Svbart@nginx.com && ver.s.minor >= '0' && ver.s.minor <= '9') 474482Svbart@nginx.com { 475622Svbart@nginx.com rp->version.ui64 = ver.ui64; 476482Svbart@nginx.com return NXT_HTTP_PARSE_UNSUPPORTED_VERSION; 47716Svbart@nginx.com } 47816Svbart@nginx.com 479482Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 48016Svbart@nginx.com } 48116Svbart@nginx.com 48216Svbart@nginx.com 48316Svbart@nginx.com static nxt_int_t 48416Svbart@nginx.com nxt_http_parse_unusual_target(nxt_http_request_parse_t *rp, u_char **pos, 48516Svbart@nginx.com u_char *end) 48616Svbart@nginx.com { 48716Svbart@nginx.com u_char *p, ch; 48816Svbart@nginx.com 48916Svbart@nginx.com p = *pos; 49016Svbart@nginx.com 49116Svbart@nginx.com ch = *p; 49216Svbart@nginx.com 49316Svbart@nginx.com if (ch == ' ') { 49416Svbart@nginx.com /* skip surplus spaces before target */ 49516Svbart@nginx.com 49616Svbart@nginx.com do { 49716Svbart@nginx.com p++; 49816Svbart@nginx.com 49916Svbart@nginx.com if (nxt_slow_path(p == end)) { 50016Svbart@nginx.com return NXT_AGAIN; 50116Svbart@nginx.com } 50216Svbart@nginx.com 50316Svbart@nginx.com ch = *p; 50416Svbart@nginx.com 50516Svbart@nginx.com } while (ch == ' '); 50616Svbart@nginx.com 50716Svbart@nginx.com if (ch == '/') { 50816Svbart@nginx.com *pos = p; 50916Svbart@nginx.com return NXT_OK; 51016Svbart@nginx.com } 51116Svbart@nginx.com } 51216Svbart@nginx.com 51316Svbart@nginx.com /* absolute path or '*' */ 51416Svbart@nginx.com 51516Svbart@nginx.com /* TODO */ 51616Svbart@nginx.com 517480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 51816Svbart@nginx.com } 51916Svbart@nginx.com 52016Svbart@nginx.com 52116Svbart@nginx.com static nxt_int_t 52216Svbart@nginx.com nxt_http_parse_field_name(nxt_http_request_parse_t *rp, u_char **pos, 52316Svbart@nginx.com u_char *end) 52416Svbart@nginx.com { 525417Svbart@nginx.com u_char *p, c; 526417Svbart@nginx.com size_t len; 527417Svbart@nginx.com uint32_t hash; 52816Svbart@nginx.com 52916Svbart@nginx.com static const u_char normal[256] nxt_aligned(64) = 53016Svbart@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" 53116Svbart@nginx.com "\0\0\0\0\0\0\0\0\0\0\0\0\0-\0\0" "0123456789\0\0\0\0\0\0" 53216Svbart@nginx.com 53316Svbart@nginx.com /* These 64 bytes should reside in one cache line. */ 534454Svbart@nginx.com "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0_" 53516Svbart@nginx.com "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0" 53616Svbart@nginx.com 53716Svbart@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" 53816Svbart@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" 53916Svbart@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" 54016Svbart@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"; 54116Svbart@nginx.com 542417Svbart@nginx.com p = *pos + rp->field_name.length; 543417Svbart@nginx.com hash = rp->field_hash; 54416Svbart@nginx.com 545417Svbart@nginx.com while (nxt_fast_path(end - p >= 8)) { 546409Svbart@nginx.com 547417Svbart@nginx.com #define nxt_field_name_test_char(ch) \ 548409Svbart@nginx.com \ 54919Svbart@nginx.com c = normal[ch]; \ 55019Svbart@nginx.com \ 55119Svbart@nginx.com if (nxt_slow_path(c == '\0')) { \ 552417Svbart@nginx.com p = &(ch); \ 55319Svbart@nginx.com goto name_end; \ 55419Svbart@nginx.com } \ 55519Svbart@nginx.com \ 556417Svbart@nginx.com hash = nxt_http_field_hash_char(hash, c); 557409Svbart@nginx.com 558409Svbart@nginx.com /* enddef */ 55916Svbart@nginx.com 560417Svbart@nginx.com nxt_field_name_test_char(p[0]); 561417Svbart@nginx.com nxt_field_name_test_char(p[1]); 562417Svbart@nginx.com nxt_field_name_test_char(p[2]); 563417Svbart@nginx.com nxt_field_name_test_char(p[3]); 56416Svbart@nginx.com 565417Svbart@nginx.com nxt_field_name_test_char(p[4]); 566417Svbart@nginx.com nxt_field_name_test_char(p[5]); 567417Svbart@nginx.com nxt_field_name_test_char(p[6]); 568417Svbart@nginx.com nxt_field_name_test_char(p[7]); 569417Svbart@nginx.com 570417Svbart@nginx.com p += 8; 57119Svbart@nginx.com } 57216Svbart@nginx.com 573417Svbart@nginx.com while (nxt_fast_path(p != end)) { 574417Svbart@nginx.com nxt_field_name_test_char(*p); p++; 57519Svbart@nginx.com } 57616Svbart@nginx.com 577417Svbart@nginx.com len = p - *pos; 578417Svbart@nginx.com 579417Svbart@nginx.com if (nxt_slow_path(len > NXT_HTTP_MAX_FIELD_NAME)) { 580480Svbart@nginx.com return NXT_HTTP_PARSE_TOO_LARGE_FIELD; 581417Svbart@nginx.com } 582417Svbart@nginx.com 583417Svbart@nginx.com rp->field_hash = hash; 584417Svbart@nginx.com rp->field_name.length = len; 585417Svbart@nginx.com 58616Svbart@nginx.com rp->handler = &nxt_http_parse_field_name; 58716Svbart@nginx.com 58816Svbart@nginx.com return NXT_AGAIN; 58919Svbart@nginx.com 59019Svbart@nginx.com name_end: 59119Svbart@nginx.com 592417Svbart@nginx.com if (nxt_fast_path(*p == ':')) { 593417Svbart@nginx.com if (nxt_slow_path(p == *pos)) { 594480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 59519Svbart@nginx.com } 59619Svbart@nginx.com 597417Svbart@nginx.com len = p - *pos; 598417Svbart@nginx.com 599417Svbart@nginx.com if (nxt_slow_path(len > NXT_HTTP_MAX_FIELD_NAME)) { 600480Svbart@nginx.com return NXT_HTTP_PARSE_TOO_LARGE_FIELD; 601417Svbart@nginx.com } 60219Svbart@nginx.com 603417Svbart@nginx.com rp->field_hash = hash; 604417Svbart@nginx.com 605417Svbart@nginx.com rp->field_name.length = len; 606417Svbart@nginx.com rp->field_name.start = *pos; 607417Svbart@nginx.com 608417Svbart@nginx.com *pos = p + 1; 60919Svbart@nginx.com 61019Svbart@nginx.com return nxt_http_parse_field_value(rp, pos, end); 61119Svbart@nginx.com } 61219Svbart@nginx.com 613417Svbart@nginx.com if (nxt_slow_path(p != *pos)) { 614480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 61559Svbart@nginx.com } 61619Svbart@nginx.com 61719Svbart@nginx.com return nxt_http_parse_field_end(rp, pos, end); 61816Svbart@nginx.com } 61916Svbart@nginx.com 62016Svbart@nginx.com 62116Svbart@nginx.com static nxt_int_t 62216Svbart@nginx.com nxt_http_parse_field_value(nxt_http_request_parse_t *rp, u_char **pos, 62316Svbart@nginx.com u_char *end) 62416Svbart@nginx.com { 625574Svbart@nginx.com u_char *p, *start, ch; 626417Svbart@nginx.com size_t len; 62716Svbart@nginx.com 62816Svbart@nginx.com p = *pos; 62916Svbart@nginx.com 63016Svbart@nginx.com for ( ;; ) { 63116Svbart@nginx.com if (nxt_slow_path(p == end)) { 63216Svbart@nginx.com *pos = p; 63316Svbart@nginx.com rp->handler = &nxt_http_parse_field_value; 63416Svbart@nginx.com return NXT_AGAIN; 63516Svbart@nginx.com } 63616Svbart@nginx.com 637577Svbart@nginx.com ch = *p; 638577Svbart@nginx.com 639577Svbart@nginx.com if (ch != ' ' && ch != '\t') { 64016Svbart@nginx.com break; 64116Svbart@nginx.com } 64216Svbart@nginx.com 64316Svbart@nginx.com p++; 64416Svbart@nginx.com } 64516Svbart@nginx.com 646574Svbart@nginx.com start = p; 64716Svbart@nginx.com 64867Svbart@nginx.com p += rp->field_value.length; 64916Svbart@nginx.com 650576Svbart@nginx.com for ( ;; ) { 651576Svbart@nginx.com p = nxt_http_lookup_field_end(p, end); 652417Svbart@nginx.com 653576Svbart@nginx.com if (nxt_slow_path(p == end)) { 654576Svbart@nginx.com *pos = start; 655576Svbart@nginx.com 656576Svbart@nginx.com len = p - start; 657574Svbart@nginx.com 658576Svbart@nginx.com if (nxt_slow_path(len > NXT_HTTP_MAX_FIELD_VALUE)) { 659576Svbart@nginx.com return NXT_HTTP_PARSE_TOO_LARGE_FIELD; 660576Svbart@nginx.com } 661417Svbart@nginx.com 662576Svbart@nginx.com rp->field_value.length = len; 663576Svbart@nginx.com rp->handler = &nxt_http_parse_field_value; 664576Svbart@nginx.com return NXT_AGAIN; 66516Svbart@nginx.com } 66616Svbart@nginx.com 667576Svbart@nginx.com ch = *p; 668576Svbart@nginx.com 669576Svbart@nginx.com if (nxt_fast_path(ch == '\r' || ch == '\n')) { 670576Svbart@nginx.com break; 671576Svbart@nginx.com } 67216Svbart@nginx.com 673576Svbart@nginx.com if (ch != '\t') { 674576Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 675576Svbart@nginx.com } 67616Svbart@nginx.com 677576Svbart@nginx.com p++; 67816Svbart@nginx.com } 67916Svbart@nginx.com 680574Svbart@nginx.com *pos = p; 681574Svbart@nginx.com 682574Svbart@nginx.com if (nxt_fast_path(p != start)) { 683577Svbart@nginx.com 684577Svbart@nginx.com while (p[-1] == ' ' || p[-1] == '\t') { 68516Svbart@nginx.com p--; 68616Svbart@nginx.com } 68716Svbart@nginx.com } 68816Svbart@nginx.com 689574Svbart@nginx.com len = p - start; 690417Svbart@nginx.com 691417Svbart@nginx.com if (nxt_slow_path(len > NXT_HTTP_MAX_FIELD_VALUE)) { 692480Svbart@nginx.com return NXT_HTTP_PARSE_TOO_LARGE_FIELD; 693417Svbart@nginx.com } 694417Svbart@nginx.com 695417Svbart@nginx.com rp->field_value.length = len; 696574Svbart@nginx.com rp->field_value.start = start; 69716Svbart@nginx.com 69816Svbart@nginx.com return nxt_http_parse_field_end(rp, pos, end); 69916Svbart@nginx.com } 70016Svbart@nginx.com 70116Svbart@nginx.com 70216Svbart@nginx.com static u_char * 70316Svbart@nginx.com nxt_http_lookup_field_end(u_char *p, u_char *end) 70416Svbart@nginx.com { 705409Svbart@nginx.com while (nxt_fast_path(end - p >= 16)) { 706409Svbart@nginx.com 707409Svbart@nginx.com #define nxt_field_end_test_char(ch) \ 708409Svbart@nginx.com \ 709712Svbart@nginx.com if (nxt_slow_path((ch) < 0x20)) { \ 710409Svbart@nginx.com return &(ch); \ 711409Svbart@nginx.com } 712409Svbart@nginx.com 713409Svbart@nginx.com /* enddef */ 714409Svbart@nginx.com 715409Svbart@nginx.com nxt_field_end_test_char(p[0]); 716409Svbart@nginx.com nxt_field_end_test_char(p[1]); 717409Svbart@nginx.com nxt_field_end_test_char(p[2]); 718409Svbart@nginx.com nxt_field_end_test_char(p[3]); 71916Svbart@nginx.com 720409Svbart@nginx.com nxt_field_end_test_char(p[4]); 721409Svbart@nginx.com nxt_field_end_test_char(p[5]); 722409Svbart@nginx.com nxt_field_end_test_char(p[6]); 723409Svbart@nginx.com nxt_field_end_test_char(p[7]); 724409Svbart@nginx.com 725409Svbart@nginx.com nxt_field_end_test_char(p[8]); 726409Svbart@nginx.com nxt_field_end_test_char(p[9]); 727409Svbart@nginx.com nxt_field_end_test_char(p[10]); 728409Svbart@nginx.com nxt_field_end_test_char(p[11]); 729409Svbart@nginx.com 730409Svbart@nginx.com nxt_field_end_test_char(p[12]); 731409Svbart@nginx.com nxt_field_end_test_char(p[13]); 732409Svbart@nginx.com nxt_field_end_test_char(p[14]); 733409Svbart@nginx.com nxt_field_end_test_char(p[15]); 734409Svbart@nginx.com 735409Svbart@nginx.com p += 16; 73616Svbart@nginx.com } 73716Svbart@nginx.com 738409Svbart@nginx.com while (nxt_fast_path(end - p >= 4)) { 73919Svbart@nginx.com 740409Svbart@nginx.com nxt_field_end_test_char(p[0]); 741409Svbart@nginx.com nxt_field_end_test_char(p[1]); 742409Svbart@nginx.com nxt_field_end_test_char(p[2]); 743409Svbart@nginx.com nxt_field_end_test_char(p[3]); 74416Svbart@nginx.com 745409Svbart@nginx.com p += 4; 74619Svbart@nginx.com } 74719Svbart@nginx.com 74819Svbart@nginx.com switch (end - p) { 74916Svbart@nginx.com case 3: 750409Svbart@nginx.com nxt_field_end_test_char(*p); p++; 75139Svbart@nginx.com /* Fall through. */ 75216Svbart@nginx.com case 2: 753409Svbart@nginx.com nxt_field_end_test_char(*p); p++; 75439Svbart@nginx.com /* Fall through. */ 75516Svbart@nginx.com case 1: 756409Svbart@nginx.com nxt_field_end_test_char(*p); p++; 75739Svbart@nginx.com /* Fall through. */ 75816Svbart@nginx.com case 0: 75916Svbart@nginx.com break; 76016Svbart@nginx.com default: 76116Svbart@nginx.com nxt_unreachable(); 76216Svbart@nginx.com } 76316Svbart@nginx.com 76416Svbart@nginx.com return p; 76516Svbart@nginx.com } 76616Svbart@nginx.com 76716Svbart@nginx.com 76816Svbart@nginx.com static nxt_int_t 76916Svbart@nginx.com nxt_http_parse_field_end(nxt_http_request_parse_t *rp, u_char **pos, 77016Svbart@nginx.com u_char *end) 77116Svbart@nginx.com { 77260Svbart@nginx.com u_char *p; 77360Svbart@nginx.com nxt_http_field_t *field; 77416Svbart@nginx.com 77516Svbart@nginx.com p = *pos; 77616Svbart@nginx.com 77716Svbart@nginx.com if (nxt_fast_path(*p == '\r')) { 77816Svbart@nginx.com p++; 77916Svbart@nginx.com 78016Svbart@nginx.com if (nxt_slow_path(p == end)) { 78116Svbart@nginx.com rp->handler = &nxt_http_parse_field_end; 78216Svbart@nginx.com return NXT_AGAIN; 78316Svbart@nginx.com } 78416Svbart@nginx.com } 78516Svbart@nginx.com 78616Svbart@nginx.com if (nxt_fast_path(*p == '\n')) { 78716Svbart@nginx.com *pos = p + 1; 78816Svbart@nginx.com 78967Svbart@nginx.com if (rp->field_name.length != 0) { 79060Svbart@nginx.com field = nxt_list_add(rp->fields); 79116Svbart@nginx.com 79260Svbart@nginx.com if (nxt_slow_path(field == NULL)) { 79360Svbart@nginx.com return NXT_ERROR; 79416Svbart@nginx.com } 79516Svbart@nginx.com 796417Svbart@nginx.com field->hash = nxt_http_field_hash_end(rp->field_hash); 797417Svbart@nginx.com field->skip = 0; 79860Svbart@nginx.com 799417Svbart@nginx.com field->name_length = rp->field_name.length; 800417Svbart@nginx.com field->value_length = rp->field_value.length; 801417Svbart@nginx.com field->name = rp->field_name.start; 802417Svbart@nginx.com field->value = rp->field_value.start; 80367Svbart@nginx.com 804417Svbart@nginx.com rp->field_hash = NXT_HTTP_FIELD_HASH_INIT; 80567Svbart@nginx.com 80667Svbart@nginx.com rp->field_name.length = 0; 80767Svbart@nginx.com rp->field_value.length = 0; 80816Svbart@nginx.com 80916Svbart@nginx.com rp->handler = &nxt_http_parse_field_name; 81016Svbart@nginx.com return NXT_OK; 81116Svbart@nginx.com } 81216Svbart@nginx.com 81316Svbart@nginx.com return NXT_DONE; 81416Svbart@nginx.com } 81516Svbart@nginx.com 816480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 81716Svbart@nginx.com } 81816Svbart@nginx.com 81916Svbart@nginx.com 820112Smax.romanov@nginx.com #define \ 821112Smax.romanov@nginx.com nxt_http_is_normal(c) \ 822112Smax.romanov@nginx.com (nxt_fast_path((nxt_http_normal[c / 8] & (1 << (c & 7))) != 0)) 823112Smax.romanov@nginx.com 824112Smax.romanov@nginx.com 825112Smax.romanov@nginx.com static const uint8_t nxt_http_normal[32] nxt_aligned(32) = { 826112Smax.romanov@nginx.com 827112Smax.romanov@nginx.com /* \0 \r \n */ 828611Svbart@nginx.com 0xFE, 0xDB, 0xFF, 0xFF, /* 1111 1110 1101 1011 1111 1111 1111 1111 */ 829112Smax.romanov@nginx.com 830112Smax.romanov@nginx.com /* '&%$ #"! /.-, |*)( 7654 3210 ?>=< ;:98 */ 831611Svbart@nginx.com 0xD6, 0x37, 0xFF, 0x7F, /* 1101 0110 0011 0111 1111 1111 0111 1111 */ 832112Smax.romanov@nginx.com 833112Smax.romanov@nginx.com /* GFED CBA@ ONML KJIH WVUT SRQP _^]\ [ZYX */ 834611Svbart@nginx.com 0xFF, 0xFF, 0xFF, 0xFF, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 835112Smax.romanov@nginx.com 836112Smax.romanov@nginx.com /* gfed cba` onml kjih wvut srqp ~}| {zyx */ 837611Svbart@nginx.com 0xFF, 0xFF, 0xFF, 0xFF, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 838112Smax.romanov@nginx.com 839611Svbart@nginx.com 0xFF, 0xFF, 0xFF, 0xFF, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 840611Svbart@nginx.com 0xFF, 0xFF, 0xFF, 0xFF, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 841611Svbart@nginx.com 0xFF, 0xFF, 0xFF, 0xFF, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 842611Svbart@nginx.com 0xFF, 0xFF, 0xFF, 0xFF, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 843112Smax.romanov@nginx.com }; 844112Smax.romanov@nginx.com 845112Smax.romanov@nginx.com 846112Smax.romanov@nginx.com static nxt_int_t 847112Smax.romanov@nginx.com nxt_http_parse_complex_target(nxt_http_request_parse_t *rp) 848112Smax.romanov@nginx.com { 8491168Svbart@nginx.com u_char *p, *u, c, ch, high, *exten, *args; 8501168Svbart@nginx.com 851112Smax.romanov@nginx.com enum { 852112Smax.romanov@nginx.com sw_normal = 0, 853112Smax.romanov@nginx.com sw_slash, 854112Smax.romanov@nginx.com sw_dot, 855112Smax.romanov@nginx.com sw_dot_dot, 856112Smax.romanov@nginx.com sw_quoted, 857112Smax.romanov@nginx.com sw_quoted_second, 858112Smax.romanov@nginx.com } state, saved_state; 859112Smax.romanov@nginx.com 860112Smax.romanov@nginx.com nxt_prefetch(nxt_http_normal); 861112Smax.romanov@nginx.com 862112Smax.romanov@nginx.com state = sw_normal; 863112Smax.romanov@nginx.com saved_state = sw_normal; 864112Smax.romanov@nginx.com p = rp->target_start; 865112Smax.romanov@nginx.com 866112Smax.romanov@nginx.com u = nxt_mp_alloc(rp->mem_pool, rp->target_end - p + 1); 867112Smax.romanov@nginx.com if (nxt_slow_path(u == NULL)) { 868112Smax.romanov@nginx.com return NXT_ERROR; 869112Smax.romanov@nginx.com } 870112Smax.romanov@nginx.com 871112Smax.romanov@nginx.com rp->path.length = 0; 872112Smax.romanov@nginx.com rp->path.start = u; 873112Smax.romanov@nginx.com 874112Smax.romanov@nginx.com high = '\0'; 8751168Svbart@nginx.com exten = NULL; 8761168Svbart@nginx.com args = NULL; 877112Smax.romanov@nginx.com 878112Smax.romanov@nginx.com while (p < rp->target_end) { 879112Smax.romanov@nginx.com 880112Smax.romanov@nginx.com ch = *p++; 881112Smax.romanov@nginx.com 882112Smax.romanov@nginx.com again: 883112Smax.romanov@nginx.com 884112Smax.romanov@nginx.com switch (state) { 885112Smax.romanov@nginx.com 886112Smax.romanov@nginx.com case sw_normal: 887112Smax.romanov@nginx.com 888112Smax.romanov@nginx.com if (nxt_http_is_normal(ch)) { 889112Smax.romanov@nginx.com *u++ = ch; 890112Smax.romanov@nginx.com continue; 891112Smax.romanov@nginx.com } 892112Smax.romanov@nginx.com 893112Smax.romanov@nginx.com switch (ch) { 894112Smax.romanov@nginx.com case '/': 8951168Svbart@nginx.com exten = NULL; 896112Smax.romanov@nginx.com state = sw_slash; 897112Smax.romanov@nginx.com *u++ = ch; 898112Smax.romanov@nginx.com continue; 899112Smax.romanov@nginx.com case '%': 900112Smax.romanov@nginx.com saved_state = state; 901112Smax.romanov@nginx.com state = sw_quoted; 902112Smax.romanov@nginx.com continue; 903112Smax.romanov@nginx.com case '?': 9041168Svbart@nginx.com args = p; 905112Smax.romanov@nginx.com goto args; 906112Smax.romanov@nginx.com case '#': 907112Smax.romanov@nginx.com goto done; 908112Smax.romanov@nginx.com case '.': 9091168Svbart@nginx.com exten = u + 1; 910112Smax.romanov@nginx.com *u++ = ch; 911112Smax.romanov@nginx.com continue; 912112Smax.romanov@nginx.com default: 913112Smax.romanov@nginx.com *u++ = ch; 914112Smax.romanov@nginx.com continue; 915112Smax.romanov@nginx.com } 916112Smax.romanov@nginx.com 917112Smax.romanov@nginx.com break; 918112Smax.romanov@nginx.com 919112Smax.romanov@nginx.com case sw_slash: 920112Smax.romanov@nginx.com 921112Smax.romanov@nginx.com if (nxt_http_is_normal(ch)) { 922112Smax.romanov@nginx.com state = sw_normal; 923112Smax.romanov@nginx.com *u++ = ch; 924112Smax.romanov@nginx.com continue; 925112Smax.romanov@nginx.com } 926112Smax.romanov@nginx.com 927112Smax.romanov@nginx.com switch (ch) { 928112Smax.romanov@nginx.com case '/': 929112Smax.romanov@nginx.com continue; 930112Smax.romanov@nginx.com case '.': 931112Smax.romanov@nginx.com state = sw_dot; 932112Smax.romanov@nginx.com *u++ = ch; 933112Smax.romanov@nginx.com continue; 934112Smax.romanov@nginx.com case '%': 935112Smax.romanov@nginx.com saved_state = state; 936112Smax.romanov@nginx.com state = sw_quoted; 937112Smax.romanov@nginx.com continue; 938112Smax.romanov@nginx.com case '?': 9391168Svbart@nginx.com args = p; 940112Smax.romanov@nginx.com goto args; 941112Smax.romanov@nginx.com case '#': 942112Smax.romanov@nginx.com goto done; 943112Smax.romanov@nginx.com default: 944112Smax.romanov@nginx.com state = sw_normal; 945112Smax.romanov@nginx.com *u++ = ch; 946112Smax.romanov@nginx.com continue; 947112Smax.romanov@nginx.com } 948112Smax.romanov@nginx.com 949112Smax.romanov@nginx.com break; 950112Smax.romanov@nginx.com 951112Smax.romanov@nginx.com case sw_dot: 952112Smax.romanov@nginx.com 953112Smax.romanov@nginx.com if (nxt_http_is_normal(ch)) { 954112Smax.romanov@nginx.com state = sw_normal; 955112Smax.romanov@nginx.com *u++ = ch; 956112Smax.romanov@nginx.com continue; 957112Smax.romanov@nginx.com } 958112Smax.romanov@nginx.com 959112Smax.romanov@nginx.com switch (ch) { 960112Smax.romanov@nginx.com case '/': 961112Smax.romanov@nginx.com state = sw_slash; 962112Smax.romanov@nginx.com u--; 963112Smax.romanov@nginx.com continue; 964112Smax.romanov@nginx.com case '.': 965112Smax.romanov@nginx.com state = sw_dot_dot; 966112Smax.romanov@nginx.com *u++ = ch; 967112Smax.romanov@nginx.com continue; 968112Smax.romanov@nginx.com case '%': 969112Smax.romanov@nginx.com saved_state = state; 970112Smax.romanov@nginx.com state = sw_quoted; 971112Smax.romanov@nginx.com continue; 972112Smax.romanov@nginx.com case '?': 973*1213Svbart@nginx.com u--; 9741168Svbart@nginx.com args = p; 975112Smax.romanov@nginx.com goto args; 976112Smax.romanov@nginx.com case '#': 977*1213Svbart@nginx.com u--; 978112Smax.romanov@nginx.com goto done; 979112Smax.romanov@nginx.com default: 980112Smax.romanov@nginx.com state = sw_normal; 981112Smax.romanov@nginx.com *u++ = ch; 982112Smax.romanov@nginx.com continue; 983112Smax.romanov@nginx.com } 984112Smax.romanov@nginx.com 985112Smax.romanov@nginx.com break; 986112Smax.romanov@nginx.com 987112Smax.romanov@nginx.com case sw_dot_dot: 988112Smax.romanov@nginx.com 989112Smax.romanov@nginx.com if (nxt_http_is_normal(ch)) { 990112Smax.romanov@nginx.com state = sw_normal; 991112Smax.romanov@nginx.com *u++ = ch; 992112Smax.romanov@nginx.com continue; 993112Smax.romanov@nginx.com } 994112Smax.romanov@nginx.com 995112Smax.romanov@nginx.com switch (ch) { 996*1213Svbart@nginx.com 997112Smax.romanov@nginx.com case '/': 998*1213Svbart@nginx.com case '?': 999*1213Svbart@nginx.com case '#': 1000112Smax.romanov@nginx.com u -= 5; 1001*1213Svbart@nginx.com 1002112Smax.romanov@nginx.com for ( ;; ) { 1003112Smax.romanov@nginx.com if (u < rp->path.start) { 1004480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 1005112Smax.romanov@nginx.com } 1006*1213Svbart@nginx.com 1007112Smax.romanov@nginx.com if (*u == '/') { 1008112Smax.romanov@nginx.com u++; 1009112Smax.romanov@nginx.com break; 1010112Smax.romanov@nginx.com } 1011*1213Svbart@nginx.com 1012112Smax.romanov@nginx.com u--; 1013112Smax.romanov@nginx.com } 1014*1213Svbart@nginx.com 1015*1213Svbart@nginx.com if (ch == '?') { 1016*1213Svbart@nginx.com args = p; 1017*1213Svbart@nginx.com goto args; 1018*1213Svbart@nginx.com } 1019*1213Svbart@nginx.com 1020*1213Svbart@nginx.com if (ch == '#') { 1021*1213Svbart@nginx.com goto done; 1022*1213Svbart@nginx.com } 1023*1213Svbart@nginx.com 1024*1213Svbart@nginx.com state = sw_slash; 1025112Smax.romanov@nginx.com break; 1026112Smax.romanov@nginx.com 1027112Smax.romanov@nginx.com case '%': 1028112Smax.romanov@nginx.com saved_state = state; 1029112Smax.romanov@nginx.com state = sw_quoted; 1030112Smax.romanov@nginx.com continue; 1031*1213Svbart@nginx.com 1032112Smax.romanov@nginx.com default: 1033112Smax.romanov@nginx.com state = sw_normal; 1034112Smax.romanov@nginx.com *u++ = ch; 1035112Smax.romanov@nginx.com continue; 1036112Smax.romanov@nginx.com } 1037112Smax.romanov@nginx.com 1038112Smax.romanov@nginx.com break; 1039112Smax.romanov@nginx.com 1040112Smax.romanov@nginx.com case sw_quoted: 1041112Smax.romanov@nginx.com rp->quoted_target = 1; 1042112Smax.romanov@nginx.com 1043112Smax.romanov@nginx.com if (ch >= '0' && ch <= '9') { 1044112Smax.romanov@nginx.com high = (u_char) (ch - '0'); 1045112Smax.romanov@nginx.com state = sw_quoted_second; 1046112Smax.romanov@nginx.com continue; 1047112Smax.romanov@nginx.com } 1048112Smax.romanov@nginx.com 1049112Smax.romanov@nginx.com c = (u_char) (ch | 0x20); 1050112Smax.romanov@nginx.com if (c >= 'a' && c <= 'f') { 1051112Smax.romanov@nginx.com high = (u_char) (c - 'a' + 10); 1052112Smax.romanov@nginx.com state = sw_quoted_second; 1053112Smax.romanov@nginx.com continue; 1054112Smax.romanov@nginx.com } 1055112Smax.romanov@nginx.com 1056480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 1057112Smax.romanov@nginx.com 1058112Smax.romanov@nginx.com case sw_quoted_second: 1059112Smax.romanov@nginx.com if (ch >= '0' && ch <= '9') { 1060112Smax.romanov@nginx.com ch = (u_char) ((high << 4) + ch - '0'); 1061112Smax.romanov@nginx.com 10621167Svbart@nginx.com if (ch == '%') { 1063112Smax.romanov@nginx.com state = sw_normal; 10641167Svbart@nginx.com *u++ = '%'; 10651167Svbart@nginx.com 10661167Svbart@nginx.com if (rp->encoded_slashes) { 10671167Svbart@nginx.com *u++ = '2'; 10681167Svbart@nginx.com *u++ = '5'; 10691167Svbart@nginx.com } 1070