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, 11*2139Sandrew@digital-domain.net u_char **pos, const u_char *end); 1216Svbart@nginx.com static nxt_int_t nxt_http_parse_request_line(nxt_http_request_parse_t *rp, 13*2139Sandrew@digital-domain.net u_char **pos, const u_char *end); 1416Svbart@nginx.com static nxt_int_t nxt_http_parse_field_name(nxt_http_request_parse_t *rp, 15*2139Sandrew@digital-domain.net u_char **pos, const u_char *end); 1616Svbart@nginx.com static nxt_int_t nxt_http_parse_field_value(nxt_http_request_parse_t *rp, 17*2139Sandrew@digital-domain.net u_char **pos, const u_char *end); 18*2139Sandrew@digital-domain.net static u_char *nxt_http_lookup_field_end(u_char *p, const u_char *end); 1916Svbart@nginx.com static nxt_int_t nxt_http_parse_field_end(nxt_http_request_parse_t *rp, 20*2139Sandrew@digital-domain.net u_char **pos, const 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 26417Svbart@nginx.com static nxt_int_t nxt_http_field_hash_collision(nxt_lvlhsh_query_t *lhq, 27417Svbart@nginx.com void *data); 2816Svbart@nginx.com 29417Svbart@nginx.com 30611Svbart@nginx.com #define NXT_HTTP_MAX_FIELD_NAME 0xFF 31417Svbart@nginx.com #define NXT_HTTP_MAX_FIELD_VALUE NXT_INT32_T_MAX 32417Svbart@nginx.com 33417Svbart@nginx.com #define NXT_HTTP_FIELD_LVLHSH_SHIFT 5 34417Svbart@nginx.com 3516Svbart@nginx.com 3616Svbart@nginx.com typedef enum { 3716Svbart@nginx.com NXT_HTTP_TARGET_SPACE = 1, /* \s */ 3816Svbart@nginx.com NXT_HTTP_TARGET_HASH, /* # */ 3916Svbart@nginx.com NXT_HTTP_TARGET_AGAIN, 4016Svbart@nginx.com NXT_HTTP_TARGET_BAD, /* \0\r\n */ 4116Svbart@nginx.com 4216Svbart@nginx.com /* traps below are used for extended check only */ 4316Svbart@nginx.com 4416Svbart@nginx.com NXT_HTTP_TARGET_SLASH = 5, /* / */ 4516Svbart@nginx.com NXT_HTTP_TARGET_DOT, /* . */ 4616Svbart@nginx.com NXT_HTTP_TARGET_ARGS_MARK, /* ? */ 4716Svbart@nginx.com NXT_HTTP_TARGET_QUOTE_MARK, /* % */ 4816Svbart@nginx.com } nxt_http_target_traps_e; 4916Svbart@nginx.com 5016Svbart@nginx.com 5116Svbart@nginx.com static const uint8_t nxt_http_target_chars[256] nxt_aligned(64) = { 5216Svbart@nginx.com /* \0 \n \r */ 5316Svbart@nginx.com 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 4, 0, 0, 5416Svbart@nginx.com 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5552Svbart@nginx.com 5652Svbart@nginx.com /* \s ! " # $ % & ' ( ) * + , - . / */ 571170Svbart@nginx.com 1, 0, 0, 2, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 6, 5, 5852Svbart@nginx.com 5952Svbart@nginx.com /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 6016Svbart@nginx.com 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 6116Svbart@nginx.com }; 6216Svbart@nginx.com 6316Svbart@nginx.com 6416Svbart@nginx.com nxt_inline nxt_http_target_traps_e 65*2139Sandrew@digital-domain.net nxt_http_parse_target(u_char **pos, const u_char *end) 6616Svbart@nginx.com { 6716Svbart@nginx.com u_char *p; 6816Svbart@nginx.com nxt_uint_t trap; 6916Svbart@nginx.com 7016Svbart@nginx.com p = *pos; 7116Svbart@nginx.com 72409Svbart@nginx.com while (nxt_fast_path(end - p >= 10)) { 7316Svbart@nginx.com 74409Svbart@nginx.com #define nxt_target_test_char(ch) \ 75409Svbart@nginx.com \ 76409Svbart@nginx.com trap = nxt_http_target_chars[ch]; \ 7716Svbart@nginx.com \ 78409Svbart@nginx.com if (nxt_slow_path(trap != 0)) { \ 79409Svbart@nginx.com *pos = &(ch); \ 80409Svbart@nginx.com return trap; \ 8116Svbart@nginx.com } 8216Svbart@nginx.com 83409Svbart@nginx.com /* enddef */ 84409Svbart@nginx.com 85409Svbart@nginx.com nxt_target_test_char(p[0]); 86409Svbart@nginx.com nxt_target_test_char(p[1]); 87409Svbart@nginx.com nxt_target_test_char(p[2]); 88409Svbart@nginx.com nxt_target_test_char(p[3]); 8916Svbart@nginx.com 90409Svbart@nginx.com nxt_target_test_char(p[4]); 91409Svbart@nginx.com nxt_target_test_char(p[5]); 92409Svbart@nginx.com nxt_target_test_char(p[6]); 93409Svbart@nginx.com nxt_target_test_char(p[7]); 9416Svbart@nginx.com 95409Svbart@nginx.com nxt_target_test_char(p[8]); 96409Svbart@nginx.com nxt_target_test_char(p[9]); 9716Svbart@nginx.com 98409Svbart@nginx.com p += 10; 9916Svbart@nginx.com } 10016Svbart@nginx.com 101410Svbart@nginx.com while (p != end) { 102410Svbart@nginx.com nxt_target_test_char(*p); p++; 103410Svbart@nginx.com } 104410Svbart@nginx.com 105409Svbart@nginx.com return NXT_HTTP_TARGET_AGAIN; 10616Svbart@nginx.com } 10716Svbart@nginx.com 10816Svbart@nginx.com 10916Svbart@nginx.com nxt_int_t 110417Svbart@nginx.com nxt_http_parse_request_init(nxt_http_request_parse_t *rp, nxt_mp_t *mp) 111417Svbart@nginx.com { 112417Svbart@nginx.com rp->mem_pool = mp; 113417Svbart@nginx.com 114417Svbart@nginx.com rp->fields = nxt_list_create(mp, 8, sizeof(nxt_http_field_t)); 1151008Szelenkov@nginx.com if (nxt_slow_path(rp->fields == NULL)) { 116417Svbart@nginx.com return NXT_ERROR; 117417Svbart@nginx.com } 118417Svbart@nginx.com 119417Svbart@nginx.com rp->field_hash = NXT_HTTP_FIELD_HASH_INIT; 120417Svbart@nginx.com 121417Svbart@nginx.com return NXT_OK; 122417Svbart@nginx.com } 123417Svbart@nginx.com 124417Svbart@nginx.com 125417Svbart@nginx.com nxt_int_t 12616Svbart@nginx.com nxt_http_parse_request(nxt_http_request_parse_t *rp, nxt_buf_mem_t *b) 12716Svbart@nginx.com { 12816Svbart@nginx.com nxt_int_t rc; 12916Svbart@nginx.com 13016Svbart@nginx.com if (rp->handler == NULL) { 13116Svbart@nginx.com rp->handler = &nxt_http_parse_request_line; 13216Svbart@nginx.com } 13316Svbart@nginx.com 13416Svbart@nginx.com do { 13516Svbart@nginx.com rc = rp->handler(rp, &b->pos, b->free); 13616Svbart@nginx.com } while (rc == NXT_OK); 13716Svbart@nginx.com 13816Svbart@nginx.com return rc; 13916Svbart@nginx.com } 14016Svbart@nginx.com 14116Svbart@nginx.com 142422Svbart@nginx.com nxt_int_t 143422Svbart@nginx.com nxt_http_parse_fields(nxt_http_request_parse_t *rp, nxt_buf_mem_t *b) 144422Svbart@nginx.com { 145422Svbart@nginx.com nxt_int_t rc; 146422Svbart@nginx.com 147422Svbart@nginx.com if (rp->handler == NULL) { 148422Svbart@nginx.com rp->handler = &nxt_http_parse_field_name; 149422Svbart@nginx.com } 150422Svbart@nginx.com 151422Svbart@nginx.com do { 152422Svbart@nginx.com rc = rp->handler(rp, &b->pos, b->free); 153422Svbart@nginx.com } while (rc == NXT_OK); 154422Svbart@nginx.com 155422Svbart@nginx.com return rc; 156422Svbart@nginx.com } 157422Svbart@nginx.com 158422Svbart@nginx.com 15916Svbart@nginx.com static nxt_int_t 16016Svbart@nginx.com nxt_http_parse_request_line(nxt_http_request_parse_t *rp, u_char **pos, 161*2139Sandrew@digital-domain.net const u_char *end) 16216Svbart@nginx.com { 1631214Svbart@nginx.com u_char *p, ch, *after_slash, *args; 16416Svbart@nginx.com nxt_int_t rc; 1651171Svbart@nginx.com nxt_bool_t rest; 166481Svbart@nginx.com nxt_http_ver_t ver; 16716Svbart@nginx.com nxt_http_target_traps_e trap; 16816Svbart@nginx.com 16916Svbart@nginx.com static const nxt_http_ver_t http11 = { "HTTP/1.1" }; 17016Svbart@nginx.com static const nxt_http_ver_t http10 = { "HTTP/1.0" }; 17116Svbart@nginx.com 17216Svbart@nginx.com p = *pos; 17316Svbart@nginx.com 17416Svbart@nginx.com rp->method.start = p; 17516Svbart@nginx.com 176409Svbart@nginx.com for ( ;; ) { 177409Svbart@nginx.com 178409Svbart@nginx.com while (nxt_fast_path(end - p >= 8)) { 17916Svbart@nginx.com 180409Svbart@nginx.com #define nxt_method_test_char(ch) \ 181409Svbart@nginx.com \ 182409Svbart@nginx.com if (nxt_slow_path((ch) < 'A' || (ch) > 'Z')) { \ 183409Svbart@nginx.com p = &(ch); \ 184409Svbart@nginx.com goto method_unusual_char; \ 18516Svbart@nginx.com } 18616Svbart@nginx.com 187409Svbart@nginx.com /* enddef */ 188409Svbart@nginx.com 189409Svbart@nginx.com nxt_method_test_char(p[0]); 190409Svbart@nginx.com nxt_method_test_char(p[1]); 191409Svbart@nginx.com nxt_method_test_char(p[2]); 192409Svbart@nginx.com nxt_method_test_char(p[3]); 19316Svbart@nginx.com 194409Svbart@nginx.com nxt_method_test_char(p[4]); 195409Svbart@nginx.com nxt_method_test_char(p[5]); 196409Svbart@nginx.com nxt_method_test_char(p[6]); 197409Svbart@nginx.com nxt_method_test_char(p[7]); 19816Svbart@nginx.com 199409Svbart@nginx.com p += 8; 200409Svbart@nginx.com } 20116Svbart@nginx.com 202410Svbart@nginx.com while (p != end) { 203410Svbart@nginx.com nxt_method_test_char(*p); p++; 204410Svbart@nginx.com } 205410Svbart@nginx.com 206623Svbart@nginx.com rp->method.length = p - rp->method.start; 207623Svbart@nginx.com 208409Svbart@nginx.com return NXT_AGAIN; 209409Svbart@nginx.com 210409Svbart@nginx.com method_unusual_char: 211409Svbart@nginx.com 212409Svbart@nginx.com ch = *p; 21316Svbart@nginx.com 21416Svbart@nginx.com if (nxt_fast_path(ch == ' ')) { 21516Svbart@nginx.com rp->method.length = p - rp->method.start; 21616Svbart@nginx.com break; 21716Svbart@nginx.com } 21816Svbart@nginx.com 21916Svbart@nginx.com if (ch == '_' || ch == '-') { 220409Svbart@nginx.com p++; 22116Svbart@nginx.com continue; 22216Svbart@nginx.com } 22316Svbart@nginx.com 224704Sigor@sysoev.ru if (rp->method.start == p && (ch == '\r' || ch == '\n')) { 22516Svbart@nginx.com rp->method.start++; 226409Svbart@nginx.com p++; 22716Svbart@nginx.com continue; 22816Svbart@nginx.com } 22916Svbart@nginx.com 230623Svbart@nginx.com rp->method.length = p - rp->method.start; 231623Svbart@nginx.com 232480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 23316Svbart@nginx.com } 23416Svbart@nginx.com 23516Svbart@nginx.com p++; 23616Svbart@nginx.com 23716Svbart@nginx.com if (nxt_slow_path(p == end)) { 23816Svbart@nginx.com return NXT_AGAIN; 23916Svbart@nginx.com } 24016Svbart@nginx.com 24116Svbart@nginx.com /* target */ 24216Svbart@nginx.com 24316Svbart@nginx.com ch = *p; 24416Svbart@nginx.com 24516Svbart@nginx.com if (nxt_slow_path(ch != '/')) { 24616Svbart@nginx.com rc = nxt_http_parse_unusual_target(rp, &p, end); 24716Svbart@nginx.com 24816Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 24916Svbart@nginx.com return rc; 25016Svbart@nginx.com } 25116Svbart@nginx.com } 25216Svbart@nginx.com 25316Svbart@nginx.com rp->target_start = p; 25416Svbart@nginx.com 25516Svbart@nginx.com after_slash = p + 1; 2561168Svbart@nginx.com args = NULL; 2571171Svbart@nginx.com rest = 0; 2581171Svbart@nginx.com 2591171Svbart@nginx.com continue_target: 26016Svbart@nginx.com 26116Svbart@nginx.com for ( ;; ) { 26216Svbart@nginx.com p++; 26316Svbart@nginx.com 26416Svbart@nginx.com trap = nxt_http_parse_target(&p, end); 26516Svbart@nginx.com 26616Svbart@nginx.com switch (trap) { 26716Svbart@nginx.com case NXT_HTTP_TARGET_SLASH: 26816Svbart@nginx.com if (nxt_slow_path(after_slash == p)) { 26916Svbart@nginx.com rp->complex_target = 1; 27016Svbart@nginx.com goto rest_of_target; 27116Svbart@nginx.com } 27216Svbart@nginx.com 27316Svbart@nginx.com after_slash = p + 1; 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 continue; 28316Svbart@nginx.com 28416Svbart@nginx.com case NXT_HTTP_TARGET_ARGS_MARK: 2851168Svbart@nginx.com args = p + 1; 28616Svbart@nginx.com goto rest_of_target; 28716Svbart@nginx.com 28816Svbart@nginx.com case NXT_HTTP_TARGET_SPACE: 28916Svbart@nginx.com rp->target_end = p; 29016Svbart@nginx.com goto space_after_target; 2911709Svbart@nginx.com #if 0 29216Svbart@nginx.com case NXT_HTTP_TARGET_QUOTE_MARK: 29316Svbart@nginx.com rp->quoted_target = 1; 29416Svbart@nginx.com goto rest_of_target; 2951709Svbart@nginx.com #else 2961709Svbart@nginx.com case NXT_HTTP_TARGET_QUOTE_MARK: 2971709Svbart@nginx.com #endif 29816Svbart@nginx.com case NXT_HTTP_TARGET_HASH: 29916Svbart@nginx.com rp->complex_target = 1; 30016Svbart@nginx.com goto rest_of_target; 30116Svbart@nginx.com 30216Svbart@nginx.com case NXT_HTTP_TARGET_AGAIN: 303621Svbart@nginx.com rp->target_end = p; 30416Svbart@nginx.com return NXT_AGAIN; 30516Svbart@nginx.com 30616Svbart@nginx.com case NXT_HTTP_TARGET_BAD: 307621Svbart@nginx.com rp->target_end = p; 308480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 30916Svbart@nginx.com } 31016Svbart@nginx.com 31116Svbart@nginx.com nxt_unreachable(); 31216Svbart@nginx.com } 31316Svbart@nginx.com 31416Svbart@nginx.com rest_of_target: 31516Svbart@nginx.com 3161171Svbart@nginx.com rest = 1; 3171171Svbart@nginx.com 31816Svbart@nginx.com for ( ;; ) { 31916Svbart@nginx.com p++; 32016Svbart@nginx.com 32119Svbart@nginx.com trap = nxt_http_parse_target(&p, end); 32216Svbart@nginx.com 32316Svbart@nginx.com switch (trap) { 32416Svbart@nginx.com case NXT_HTTP_TARGET_SPACE: 32516Svbart@nginx.com rp->target_end = p; 32616Svbart@nginx.com goto space_after_target; 32716Svbart@nginx.com 32816Svbart@nginx.com case NXT_HTTP_TARGET_HASH: 32916Svbart@nginx.com rp->complex_target = 1; 33016Svbart@nginx.com continue; 33116Svbart@nginx.com 33216Svbart@nginx.com case NXT_HTTP_TARGET_AGAIN: 333621Svbart@nginx.com rp->target_end = p; 33416Svbart@nginx.com return NXT_AGAIN; 33516Svbart@nginx.com 33616Svbart@nginx.com case NXT_HTTP_TARGET_BAD: 337621Svbart@nginx.com rp->target_end = p; 338480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 33916Svbart@nginx.com 34016Svbart@nginx.com default: 34116Svbart@nginx.com continue; 34216Svbart@nginx.com } 34316Svbart@nginx.com 34416Svbart@nginx.com nxt_unreachable(); 34516Svbart@nginx.com } 34616Svbart@nginx.com 34716Svbart@nginx.com space_after_target: 34816Svbart@nginx.com 34916Svbart@nginx.com if (nxt_slow_path(end - p < 10)) { 350410Svbart@nginx.com 351410Svbart@nginx.com do { 352410Svbart@nginx.com p++; 353410Svbart@nginx.com 354410Svbart@nginx.com if (p == end) { 355410Svbart@nginx.com return NXT_AGAIN; 356410Svbart@nginx.com } 357410Svbart@nginx.com 358410Svbart@nginx.com } while (*p == ' '); 359410Svbart@nginx.com 360410Svbart@nginx.com if (nxt_memcmp(p, "HTTP/", nxt_min(end - p, 5)) == 0) { 361410Svbart@nginx.com 362410Svbart@nginx.com switch (end - p) { 363410Svbart@nginx.com case 8: 364410Svbart@nginx.com if (p[7] < '0' || p[7] > '9') { 365410Svbart@nginx.com break; 366410Svbart@nginx.com } 367410Svbart@nginx.com /* Fall through. */ 368410Svbart@nginx.com case 7: 369410Svbart@nginx.com if (p[6] != '.') { 370410Svbart@nginx.com break; 371410Svbart@nginx.com } 372410Svbart@nginx.com /* Fall through. */ 373410Svbart@nginx.com case 6: 374410Svbart@nginx.com if (p[5] < '0' || p[5] > '9') { 375410Svbart@nginx.com break; 376410Svbart@nginx.com } 377410Svbart@nginx.com /* Fall through. */ 378410Svbart@nginx.com default: 379410Svbart@nginx.com return NXT_AGAIN; 380410Svbart@nginx.com } 381410Svbart@nginx.com } 382410Svbart@nginx.com 3831709Svbart@nginx.com //rp->space_in_target = 1; 3841171Svbart@nginx.com 3851171Svbart@nginx.com if (rest) { 3861171Svbart@nginx.com goto rest_of_target; 3871171Svbart@nginx.com } 3881171Svbart@nginx.com 3891171Svbart@nginx.com goto continue_target; 39016Svbart@nginx.com } 39116Svbart@nginx.com 39216Svbart@nginx.com /* " HTTP/1.1\r\n" or " HTTP/1.1\n" */ 39316Svbart@nginx.com 394482Svbart@nginx.com if (nxt_slow_path(p[9] != '\r' && p[9] != '\n')) { 395482Svbart@nginx.com 396482Svbart@nginx.com if (p[1] == ' ') { 397482Svbart@nginx.com /* surplus space after tartet */ 398482Svbart@nginx.com p++; 399482Svbart@nginx.com goto space_after_target; 400482Svbart@nginx.com } 401482Svbart@nginx.com 4021709Svbart@nginx.com //rp->space_in_target = 1; 4031171Svbart@nginx.com 4041171Svbart@nginx.com if (rest) { 4051171Svbart@nginx.com goto rest_of_target; 4061171Svbart@nginx.com } 4071171Svbart@nginx.com 4081171Svbart@nginx.com goto continue_target; 409482Svbart@nginx.com } 410482Svbart@nginx.com 411481Svbart@nginx.com nxt_memcpy(ver.str, &p[1], 8); 41216Svbart@nginx.com 413482Svbart@nginx.com if (nxt_fast_path(ver.ui64 == http11.ui64 414482Svbart@nginx.com || ver.ui64 == http10.ui64 415482Svbart@nginx.com || (nxt_memcmp(ver.str, "HTTP/1.", 7) == 0 416482Svbart@nginx.com && ver.s.minor >= '0' && ver.s.minor <= '9'))) 41716Svbart@nginx.com { 418481Svbart@nginx.com rp->version.ui64 = ver.ui64; 41916Svbart@nginx.com 42016Svbart@nginx.com if (nxt_fast_path(p[9] == '\r')) { 42116Svbart@nginx.com p += 10; 42216Svbart@nginx.com 42316Svbart@nginx.com if (nxt_slow_path(p == end)) { 42416Svbart@nginx.com return NXT_AGAIN; 42516Svbart@nginx.com } 42616Svbart@nginx.com 42716Svbart@nginx.com if (nxt_slow_path(*p != '\n')) { 428480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 42916Svbart@nginx.com } 43016Svbart@nginx.com 43116Svbart@nginx.com *pos = p + 1; 432112Smax.romanov@nginx.com 433112Smax.romanov@nginx.com } else { 434112Smax.romanov@nginx.com *pos = p + 10; 435112Smax.romanov@nginx.com } 436112Smax.romanov@nginx.com 4371709Svbart@nginx.com if (rp->complex_target != 0 4381709Svbart@nginx.com #if 0 4391709Svbart@nginx.com || rp->quoted_target != 0 4401709Svbart@nginx.com #endif 4411709Svbart@nginx.com ) 4421709Svbart@nginx.com { 443112Smax.romanov@nginx.com rc = nxt_http_parse_complex_target(rp); 444112Smax.romanov@nginx.com 445112Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 446112Smax.romanov@nginx.com return rc; 447112Smax.romanov@nginx.com } 448112Smax.romanov@nginx.com 44916Svbart@nginx.com return nxt_http_parse_field_name(rp, pos, end); 45016Svbart@nginx.com } 45116Svbart@nginx.com 452112Smax.romanov@nginx.com rp->path.start = rp->target_start; 453112Smax.romanov@nginx.com 4541168Svbart@nginx.com if (args != NULL) { 4551168Svbart@nginx.com rp->path.length = args - rp->target_start - 1; 456112Smax.romanov@nginx.com 4571168Svbart@nginx.com rp->args.length = rp->target_end - args; 4581168Svbart@nginx.com rp->args.start = args; 459112Smax.romanov@nginx.com 460112Smax.romanov@nginx.com } else { 461112Smax.romanov@nginx.com rp->path.length = rp->target_end - rp->target_start; 462112Smax.romanov@nginx.com } 463112Smax.romanov@nginx.com 46416Svbart@nginx.com return nxt_http_parse_field_name(rp, pos, end); 46516Svbart@nginx.com } 46616Svbart@nginx.com 467482Svbart@nginx.com if (nxt_memcmp(ver.s.prefix, "HTTP/", 5) == 0 468482Svbart@nginx.com && ver.s.major >= '0' && ver.s.major <= '9' 469482Svbart@nginx.com && ver.s.point == '.' 470482Svbart@nginx.com && ver.s.minor >= '0' && ver.s.minor <= '9') 471482Svbart@nginx.com { 472622Svbart@nginx.com rp->version.ui64 = ver.ui64; 473482Svbart@nginx.com return NXT_HTTP_PARSE_UNSUPPORTED_VERSION; 47416Svbart@nginx.com } 47516Svbart@nginx.com 476482Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 47716Svbart@nginx.com } 47816Svbart@nginx.com 47916Svbart@nginx.com 48016Svbart@nginx.com static nxt_int_t 48116Svbart@nginx.com nxt_http_parse_unusual_target(nxt_http_request_parse_t *rp, u_char **pos, 482*2139Sandrew@digital-domain.net const u_char *end) 48316Svbart@nginx.com { 48416Svbart@nginx.com u_char *p, ch; 48516Svbart@nginx.com 48616Svbart@nginx.com p = *pos; 48716Svbart@nginx.com 48816Svbart@nginx.com ch = *p; 48916Svbart@nginx.com 49016Svbart@nginx.com if (ch == ' ') { 49116Svbart@nginx.com /* skip surplus spaces before target */ 49216Svbart@nginx.com 49316Svbart@nginx.com do { 49416Svbart@nginx.com p++; 49516Svbart@nginx.com 49616Svbart@nginx.com if (nxt_slow_path(p == end)) { 49716Svbart@nginx.com return NXT_AGAIN; 49816Svbart@nginx.com } 49916Svbart@nginx.com 50016Svbart@nginx.com ch = *p; 50116Svbart@nginx.com 50216Svbart@nginx.com } while (ch == ' '); 50316Svbart@nginx.com 50416Svbart@nginx.com if (ch == '/') { 50516Svbart@nginx.com *pos = p; 50616Svbart@nginx.com return NXT_OK; 50716Svbart@nginx.com } 50816Svbart@nginx.com } 50916Svbart@nginx.com 51016Svbart@nginx.com /* absolute path or '*' */ 51116Svbart@nginx.com 51216Svbart@nginx.com /* TODO */ 51316Svbart@nginx.com 514480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 51516Svbart@nginx.com } 51616Svbart@nginx.com 51716Svbart@nginx.com 51816Svbart@nginx.com static nxt_int_t 51916Svbart@nginx.com nxt_http_parse_field_name(nxt_http_request_parse_t *rp, u_char **pos, 520*2139Sandrew@digital-domain.net const u_char *end) 52116Svbart@nginx.com { 522417Svbart@nginx.com u_char *p, c; 523417Svbart@nginx.com size_t len; 524417Svbart@nginx.com uint32_t hash; 52516Svbart@nginx.com 52616Svbart@nginx.com static const u_char normal[256] nxt_aligned(64) = 52716Svbart@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" 5281709Svbart@nginx.com /* \s ! " # $ % & ' ( ) * + , . / : ; < = > ? */ 5291709Svbart@nginx.com "\0\1\0\1\1\1\1\1\0\0\1\1\0" "-" "\1\0" "0123456789" "\0\0\0\0\0\0" 53016Svbart@nginx.com 5311709Svbart@nginx.com /* @ [ \ ] ^ _ */ 5321709Svbart@nginx.com "\0" "abcdefghijklmnopqrstuvwxyz" "\0\0\0\1\1" 5331709Svbart@nginx.com /* ` { | } ~ */ 5341709Svbart@nginx.com "\1" "abcdefghijklmnopqrstuvwxyz" "\0\1\0\1\0" 53516Svbart@nginx.com 53616Svbart@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" 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 541417Svbart@nginx.com p = *pos + rp->field_name.length; 542417Svbart@nginx.com hash = rp->field_hash; 54316Svbart@nginx.com 544417Svbart@nginx.com while (nxt_fast_path(end - p >= 8)) { 545409Svbart@nginx.com 546417Svbart@nginx.com #define nxt_field_name_test_char(ch) \ 547409Svbart@nginx.com \ 54819Svbart@nginx.com c = normal[ch]; \ 54919Svbart@nginx.com \ 5501709Svbart@nginx.com if (nxt_slow_path(c <= '\1')) { \ 5511709Svbart@nginx.com if (c == '\0') { \ 5521709Svbart@nginx.com p = &(ch); \ 5531709Svbart@nginx.com goto name_end; \ 5541709Svbart@nginx.com } \ 5551709Svbart@nginx.com \ 5561709Svbart@nginx.com rp->skip_field = rp->discard_unsafe_fields; \ 5571709Svbart@nginx.com c = ch; \ 55819Svbart@nginx.com } \ 55919Svbart@nginx.com \ 560417Svbart@nginx.com hash = nxt_http_field_hash_char(hash, c); 561409Svbart@nginx.com 562409Svbart@nginx.com /* enddef */ 56316Svbart@nginx.com 564417Svbart@nginx.com nxt_field_name_test_char(p[0]); 565417Svbart@nginx.com nxt_field_name_test_char(p[1]); 566417Svbart@nginx.com nxt_field_name_test_char(p[2]); 567417Svbart@nginx.com nxt_field_name_test_char(p[3]); 56816Svbart@nginx.com 569417Svbart@nginx.com nxt_field_name_test_char(p[4]); 570417Svbart@nginx.com nxt_field_name_test_char(p[5]); 571417Svbart@nginx.com nxt_field_name_test_char(p[6]); 572417Svbart@nginx.com nxt_field_name_test_char(p[7]); 573417Svbart@nginx.com 574417Svbart@nginx.com p += 8; 57519Svbart@nginx.com } 57616Svbart@nginx.com 577417Svbart@nginx.com while (nxt_fast_path(p != end)) { 578417Svbart@nginx.com nxt_field_name_test_char(*p); p++; 57919Svbart@nginx.com } 58016Svbart@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 } 586417Svbart@nginx.com 587417Svbart@nginx.com rp->field_hash = hash; 588417Svbart@nginx.com rp->field_name.length = len; 589417Svbart@nginx.com 59016Svbart@nginx.com rp->handler = &nxt_http_parse_field_name; 59116Svbart@nginx.com 59216Svbart@nginx.com return NXT_AGAIN; 59319Svbart@nginx.com 59419Svbart@nginx.com name_end: 59519Svbart@nginx.com 596417Svbart@nginx.com if (nxt_fast_path(*p == ':')) { 597417Svbart@nginx.com if (nxt_slow_path(p == *pos)) { 598480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 59919Svbart@nginx.com } 60019Svbart@nginx.com 601417Svbart@nginx.com len = p - *pos; 602417Svbart@nginx.com 603417Svbart@nginx.com if (nxt_slow_path(len > NXT_HTTP_MAX_FIELD_NAME)) { 604480Svbart@nginx.com return NXT_HTTP_PARSE_TOO_LARGE_FIELD; 605417Svbart@nginx.com } 60619Svbart@nginx.com 607417Svbart@nginx.com rp->field_hash = hash; 608417Svbart@nginx.com 609417Svbart@nginx.com rp->field_name.length = len; 610417Svbart@nginx.com rp->field_name.start = *pos; 611417Svbart@nginx.com 612417Svbart@nginx.com *pos = p + 1; 61319Svbart@nginx.com 61419Svbart@nginx.com return nxt_http_parse_field_value(rp, pos, end); 61519Svbart@nginx.com } 61619Svbart@nginx.com 617417Svbart@nginx.com if (nxt_slow_path(p != *pos)) { 618480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 61959Svbart@nginx.com } 62019Svbart@nginx.com 62119Svbart@nginx.com return nxt_http_parse_field_end(rp, pos, end); 62216Svbart@nginx.com } 62316Svbart@nginx.com 62416Svbart@nginx.com 62516Svbart@nginx.com static nxt_int_t 62616Svbart@nginx.com nxt_http_parse_field_value(nxt_http_request_parse_t *rp, u_char **pos, 627*2139Sandrew@digital-domain.net const u_char *end) 62816Svbart@nginx.com { 629574Svbart@nginx.com u_char *p, *start, ch; 630417Svbart@nginx.com size_t len; 63116Svbart@nginx.com 63216Svbart@nginx.com p = *pos; 63316Svbart@nginx.com 63416Svbart@nginx.com for ( ;; ) { 63516Svbart@nginx.com if (nxt_slow_path(p == end)) { 63616Svbart@nginx.com *pos = p; 63716Svbart@nginx.com rp->handler = &nxt_http_parse_field_value; 63816Svbart@nginx.com return NXT_AGAIN; 63916Svbart@nginx.com } 64016Svbart@nginx.com 641577Svbart@nginx.com ch = *p; 642577Svbart@nginx.com 643577Svbart@nginx.com if (ch != ' ' && ch != '\t') { 64416Svbart@nginx.com break; 64516Svbart@nginx.com } 64616Svbart@nginx.com 64716Svbart@nginx.com p++; 64816Svbart@nginx.com } 64916Svbart@nginx.com 650574Svbart@nginx.com start = p; 65116Svbart@nginx.com 65267Svbart@nginx.com p += rp->field_value.length; 65316Svbart@nginx.com 654576Svbart@nginx.com for ( ;; ) { 655576Svbart@nginx.com p = nxt_http_lookup_field_end(p, end); 656417Svbart@nginx.com 657576Svbart@nginx.com if (nxt_slow_path(p == end)) { 658576Svbart@nginx.com *pos = start; 659576Svbart@nginx.com 660576Svbart@nginx.com len = p - start; 661574Svbart@nginx.com 662576Svbart@nginx.com if (nxt_slow_path(len > NXT_HTTP_MAX_FIELD_VALUE)) { 663576Svbart@nginx.com return NXT_HTTP_PARSE_TOO_LARGE_FIELD; 664576Svbart@nginx.com } 665417Svbart@nginx.com 666576Svbart@nginx.com rp->field_value.length = len; 667576Svbart@nginx.com rp->handler = &nxt_http_parse_field_value; 668576Svbart@nginx.com return NXT_AGAIN; 66916Svbart@nginx.com } 67016Svbart@nginx.com 671576Svbart@nginx.com ch = *p; 672576Svbart@nginx.com 673576Svbart@nginx.com if (nxt_fast_path(ch == '\r' || ch == '\n')) { 674576Svbart@nginx.com break; 675576Svbart@nginx.com } 67616Svbart@nginx.com 677576Svbart@nginx.com if (ch != '\t') { 678576Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 679576Svbart@nginx.com } 68016Svbart@nginx.com 681576Svbart@nginx.com p++; 68216Svbart@nginx.com } 68316Svbart@nginx.com 684574Svbart@nginx.com *pos = p; 685574Svbart@nginx.com 686574Svbart@nginx.com if (nxt_fast_path(p != start)) { 687577Svbart@nginx.com 688577Svbart@nginx.com while (p[-1] == ' ' || p[-1] == '\t') { 68916Svbart@nginx.com p--; 69016Svbart@nginx.com } 69116Svbart@nginx.com } 69216Svbart@nginx.com 693574Svbart@nginx.com len = p - start; 694417Svbart@nginx.com 695417Svbart@nginx.com if (nxt_slow_path(len > NXT_HTTP_MAX_FIELD_VALUE)) { 696480Svbart@nginx.com return NXT_HTTP_PARSE_TOO_LARGE_FIELD; 697417Svbart@nginx.com } 698417Svbart@nginx.com 699417Svbart@nginx.com rp->field_value.length = len; 700574Svbart@nginx.com rp->field_value.start = start; 70116Svbart@nginx.com 70216Svbart@nginx.com return nxt_http_parse_field_end(rp, pos, end); 70316Svbart@nginx.com } 70416Svbart@nginx.com 70516Svbart@nginx.com 70616Svbart@nginx.com static u_char * 707*2139Sandrew@digital-domain.net nxt_http_lookup_field_end(u_char *p, const u_char *end) 70816Svbart@nginx.com { 709409Svbart@nginx.com while (nxt_fast_path(end - p >= 16)) { 710409Svbart@nginx.com 711409Svbart@nginx.com #define nxt_field_end_test_char(ch) \ 712409Svbart@nginx.com \ 713712Svbart@nginx.com if (nxt_slow_path((ch) < 0x20)) { \ 714409Svbart@nginx.com return &(ch); \ 715409Svbart@nginx.com } 716409Svbart@nginx.com 717409Svbart@nginx.com /* enddef */ 718409Svbart@nginx.com 719409Svbart@nginx.com nxt_field_end_test_char(p[0]); 720409Svbart@nginx.com nxt_field_end_test_char(p[1]); 721409Svbart@nginx.com nxt_field_end_test_char(p[2]); 722409Svbart@nginx.com nxt_field_end_test_char(p[3]); 72316Svbart@nginx.com 724409Svbart@nginx.com nxt_field_end_test_char(p[4]); 725409Svbart@nginx.com nxt_field_end_test_char(p[5]); 726409Svbart@nginx.com nxt_field_end_test_char(p[6]); 727409Svbart@nginx.com nxt_field_end_test_char(p[7]); 728409Svbart@nginx.com 729409Svbart@nginx.com nxt_field_end_test_char(p[8]); 730409Svbart@nginx.com nxt_field_end_test_char(p[9]); 731409Svbart@nginx.com nxt_field_end_test_char(p[10]); 732409Svbart@nginx.com nxt_field_end_test_char(p[11]); 733409Svbart@nginx.com 734409Svbart@nginx.com nxt_field_end_test_char(p[12]); 735409Svbart@nginx.com nxt_field_end_test_char(p[13]); 736409Svbart@nginx.com nxt_field_end_test_char(p[14]); 737409Svbart@nginx.com nxt_field_end_test_char(p[15]); 738409Svbart@nginx.com 739409Svbart@nginx.com p += 16; 74016Svbart@nginx.com } 74116Svbart@nginx.com 742409Svbart@nginx.com while (nxt_fast_path(end - p >= 4)) { 74319Svbart@nginx.com 744409Svbart@nginx.com nxt_field_end_test_char(p[0]); 745409Svbart@nginx.com nxt_field_end_test_char(p[1]); 746409Svbart@nginx.com nxt_field_end_test_char(p[2]); 747409Svbart@nginx.com nxt_field_end_test_char(p[3]); 74816Svbart@nginx.com 749409Svbart@nginx.com p += 4; 75019Svbart@nginx.com } 75119Svbart@nginx.com 75219Svbart@nginx.com switch (end - p) { 75316Svbart@nginx.com case 3: 754409Svbart@nginx.com nxt_field_end_test_char(*p); p++; 75539Svbart@nginx.com /* Fall through. */ 75616Svbart@nginx.com case 2: 757409Svbart@nginx.com nxt_field_end_test_char(*p); p++; 75839Svbart@nginx.com /* Fall through. */ 75916Svbart@nginx.com case 1: 760409Svbart@nginx.com nxt_field_end_test_char(*p); p++; 76139Svbart@nginx.com /* Fall through. */ 76216Svbart@nginx.com case 0: 76316Svbart@nginx.com break; 76416Svbart@nginx.com default: 76516Svbart@nginx.com nxt_unreachable(); 76616Svbart@nginx.com } 76716Svbart@nginx.com 76816Svbart@nginx.com return p; 76916Svbart@nginx.com } 77016Svbart@nginx.com 77116Svbart@nginx.com 77216Svbart@nginx.com static nxt_int_t 77316Svbart@nginx.com nxt_http_parse_field_end(nxt_http_request_parse_t *rp, u_char **pos, 774*2139Sandrew@digital-domain.net const u_char *end) 77516Svbart@nginx.com { 77660Svbart@nginx.com u_char *p; 77760Svbart@nginx.com nxt_http_field_t *field; 77816Svbart@nginx.com 77916Svbart@nginx.com p = *pos; 78016Svbart@nginx.com 78116Svbart@nginx.com if (nxt_fast_path(*p == '\r')) { 78216Svbart@nginx.com p++; 78316Svbart@nginx.com 78416Svbart@nginx.com if (nxt_slow_path(p == end)) { 78516Svbart@nginx.com rp->handler = &nxt_http_parse_field_end; 78616Svbart@nginx.com return NXT_AGAIN; 78716Svbart@nginx.com } 78816Svbart@nginx.com } 78916Svbart@nginx.com 79016Svbart@nginx.com if (nxt_fast_path(*p == '\n')) { 79116Svbart@nginx.com *pos = p + 1; 79216Svbart@nginx.com 79367Svbart@nginx.com if (rp->field_name.length != 0) { 7941709Svbart@nginx.com if (rp->skip_field) { 7951709Svbart@nginx.com rp->skip_field = 0; 79616Svbart@nginx.com 7971709Svbart@nginx.com } else { 7981709Svbart@nginx.com field = nxt_list_add(rp->fields); 7991709Svbart@nginx.com 8001709Svbart@nginx.com if (nxt_slow_path(field == NULL)) { 8011709Svbart@nginx.com return NXT_ERROR; 8021709Svbart@nginx.com } 80316Svbart@nginx.com 8041709Svbart@nginx.com field->hash = nxt_http_field_hash_end(rp->field_hash); 8051709Svbart@nginx.com field->skip = 0; 8061709Svbart@nginx.com field->hopbyhop = 0; 80760Svbart@nginx.com 8081709Svbart@nginx.com field->name_length = rp->field_name.length; 8091709Svbart@nginx.com field->value_length = rp->field_value.length; 8101709Svbart@nginx.com field->name = rp->field_name.start; 8111709Svbart@nginx.com field->value = rp->field_value.start; 8121709Svbart@nginx.com } 81367Svbart@nginx.com 814417Svbart@nginx.com rp->field_hash = NXT_HTTP_FIELD_HASH_INIT; 81567Svbart@nginx.com 81667Svbart@nginx.com rp->field_name.length = 0; 81767Svbart@nginx.com rp->field_value.length = 0; 81816Svbart@nginx.com 81916Svbart@nginx.com rp->handler = &nxt_http_parse_field_name; 82016Svbart@nginx.com return NXT_OK; 82116Svbart@nginx.com } 82216Svbart@nginx.com 82316Svbart@nginx.com return NXT_DONE; 82416Svbart@nginx.com } 82516Svbart@nginx.com 826480Svbart@nginx.com return NXT_HTTP_PARSE_INVALID; 82716Svbart@nginx.com } 82816Svbart@nginx.com 82916Svbart@nginx.com 8302084Salx.manpages@gmail.com #define nxt_http_is_normal(c) \ 831112Smax.romanov@nginx.com (nxt_fast_path((nxt_http_normal[c / 8] & (1 << (c & 7))) != 0)) 832112Smax.romanov@nginx.com 833112Smax.romanov@nginx.com 834112Smax.romanov@nginx.com static const uint8_t nxt_http_normal[32] nxt_aligned(32) = { 835112Smax.romanov@nginx.com 836112Smax.romanov@nginx.com /* \0 \r \n */ 837611Svbart@nginx.com 0xFE, 0xDB, 0xFF, 0xFF, /* 1111 1110 1101 1011 1111 1111 1111 1111 */ 838112Smax.romanov@nginx.com 839112Smax.romanov@nginx.com /* '&%$ #"! /.-, |*)( 7654 3210 ?>=< ;:98 */ 840611Svbart@nginx.com 0xD6, 0x37, 0xFF, 0x7F, /* 1101 0110 0011 0111 1111 1111 0111 1111 */ 841112Smax.romanov@nginx.com 842112Smax.romanov@nginx.com /* GFED CBA@ ONML KJIH WVUT SRQP _^]\ [ZYX */ 843611Svbart@nginx.com 0xFF, 0xFF, 0xFF, 0xFF, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 844112Smax.romanov@nginx.com 845112Smax.romanov@nginx.com /* gfed cba` onml kjih wvut srqp ~}| {zyx */ 846611Svbart@nginx.com 0xFF, 0xFF, 0xFF, 0xFF, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 847112Smax.romanov@nginx.com 848611Svbart@nginx.com 0xFF, 0xFF, 0xFF, 0xFF, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 849611Svbart@nginx.com 0xFF, 0xFF, 0xFF, 0xFF, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 850611Svbart@nginx.com 0xFF, 0xFF, 0xFF, 0xFF, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 851611Svbart@nginx.com 0xFF, 0xFF, 0xFF, 0xFF, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 852112Smax.romanov@nginx.com }; 853112Smax.romanov@nginx.com 854112Smax.romanov@nginx.com 855112Smax.romanov@nginx.com static nxt_int_t 856112Smax.romanov@nginx.com nxt_http_parse_complex_target(nxt_http_request_parse_t *rp) 857112Smax.romanov@nginx.com { 8581214Svbart@nginx.com u_char *p, *u, c, ch, high, *args; 8591168Svbart@nginx.com 860112Smax.romanov@nginx.com enum { 861112Smax.romanov@nginx.com sw_normal = 0, 862112Smax.romanov@nginx.com sw_slash, 863112Smax.romanov@nginx.com sw_dot, 864112Smax.romanov@nginx.com sw_dot_dot, 865112Smax.romanov@nginx.com sw_quoted, 866112Smax.romanov@nginx.com sw_quoted_second, 867112Smax.romanov@nginx.com } state, saved_state; 868112Smax.romanov@nginx.com 869112Smax.romanov@nginx.com nxt_prefetch(nxt_http_normal); 870112Smax.romanov@nginx.com 871112Smax.romanov@nginx.com state = sw_normal; 872112Smax.romanov@nginx.com saved_state = sw_normal; 873112Smax.romanov@nginx.com p = rp->target_start; 874112Smax.romanov@nginx.com 875112Smax.romanov@nginx.com u = nxt_mp_alloc(rp->mem_pool, rp->target_end - p + 1); 876112Smax.romanov@nginx.com if (nxt_slow_path(u == NULL)) { 877112Smax.romanov@nginx.com return NXT_ERROR; 878112Smax.romanov@nginx.com } 879112Smax.romanov@nginx.com 880112Smax.romanov@nginx.com rp->path.length = 0; 881112Smax.romanov@nginx.com rp->path.start = u; 882112Smax.romanov@nginx.com 883112Smax.romanov@nginx.com high = '\0'; 8841168Svbart@nginx.com args = NULL; 885112Smax.romanov@nginx.com 886112Smax.romanov@nginx.com while (p < rp->target_end) { 887112Smax.romanov@nginx.com 888112Smax.romanov@nginx.com ch = *p++; 889112Smax.romanov@nginx.com 890112Smax.romanov@nginx.com again: 891112Smax.romanov@nginx.com 892112Smax.romanov@nginx.com switch (state) { 893112Smax.romanov@nginx.com 894112Smax.romanov@nginx.com case sw_normal: 895112Smax.romanov@nginx.com 896112Smax.romanov@nginx.com if (nxt_http_is_normal(ch)) { 897112Smax.romanov@nginx.com *u++ = ch; 898112Smax.romanov@nginx.com continue; 899112Smax.romanov@nginx.com } 900112Smax.romanov@nginx.com 901112Smax.romanov@nginx.com switch (ch) { 902112Smax.romanov@nginx.com case '/': 903112Smax.romanov@nginx.com state = sw_slash; 904112Smax.romanov@nginx.com *u++ = ch; 905112Smax.romanov@nginx.com continue; 906112Smax.romanov@nginx.com case '%': 907112Smax.romanov@nginx.com saved_state = state; 908112Smax.romanov@nginx.com state = sw_quoted; 909112Smax.romanov@nginx.com continue; 910112Smax.romanov@nginx.com case '?': 9111168Svbart@nginx.com args = p; 912112Smax.romanov@nginx.com goto args; 913112Smax.romanov@nginx.com case '#': 914112Smax.romanov@nginx.com goto done; 915112Smax.romanov@nginx.com default: 916112Smax.romanov@nginx.com *u++ = ch; 917112Smax.romanov@nginx.com continue; 918112Smax.romanov@nginx.com } 919112Smax.romanov@nginx.com 920112Smax.romanov@nginx.com break; 921112Smax.romanov@nginx.com 922112Smax.romanov@nginx.com case sw_slash: 923112Smax.romanov@nginx.com 924112Smax.romanov@nginx.com if (nxt_http_is_normal(ch)) { 925112Smax.romanov@nginx.com state = sw_normal; 926112Smax.romanov@nginx.com *u++ = ch; 927112Smax.romanov@nginx.com continue; 928112Smax.romanov@nginx.com } 929112Smax.romanov@nginx.com 930112Smax.romanov@nginx.com switch (ch) { 931112Smax.romanov@nginx.com case '/': 932112Smax.romanov@nginx.com continue; 933112Smax.romanov@nginx.com case '.': 934112Smax.romanov@nginx.com state = sw_dot; 935112Smax.romanov@nginx.com *u++ = ch; 936112Smax.romanov@nginx.com continue; 937112Smax.romanov@nginx.com case '%': 938112Smax.romanov@nginx.com saved_state = state; 939112Smax.romanov@nginx.com state = sw_quoted; 940112Smax.romanov@nginx.com continue; 941112Smax.romanov@nginx.com case '?': 9421168Svbart@nginx.com args = p; 943112Smax.romanov@nginx.com goto args; 944112Smax.romanov@nginx.com case '#': 945112Smax.romanov@nginx.com goto done; 946112Smax.romanov@nginx.com default: 947112Smax.romanov@nginx.com state = sw_normal; 948112Smax.romanov@nginx.com *u++ = ch; 949112Smax.romanov@nginx.com continue; 950112Smax.romanov@nginx.com } 951112Smax.romanov@nginx.com 952112Smax.romanov@nginx.com break; 953112Smax.romanov@nginx.com 954112Smax.romanov@nginx.com case sw_dot: 955112Smax.romanov@nginx.com 956112Smax.romanov@nginx.com if (nxt_http_is_normal(ch)) { 957112Smax.romanov@nginx.com state = sw_normal; 958112Smax.romanov@nginx.com *u++ = ch; 959112Smax.romanov@nginx.com continue; 960112Smax.romanov@nginx.com } 961112Smax.romanov@nginx.com 962112Smax.romanov@nginx.com switch (ch) { 963112Smax.romanov@nginx.com case '/': 964112Smax.romanov@nginx.com state = sw_slash; 965112Smax.romanov@nginx.com u--; 966112Smax.romanov@nginx.com continue; 967112Smax.romanov@nginx.com case '.': 968112Smax.romanov@nginx.com state = sw_dot_dot; 969112Smax.romanov@nginx.com *u++ = ch; 970112Smax.romanov@nginx.com continue; 971112Smax.romanov@nginx.com case '%': 972112Smax.romanov@nginx.com saved_state = state; 973112Smax.romanov@nginx.com state = sw_quoted; 974112Smax.romanov@nginx.com continue; 975112Smax.romanov@nginx.com case '?': 9761213Svbart@nginx.com u--; 9771168Svbart@nginx.com args = p; 978112Smax.romanov@nginx.com goto args; 979112Smax.romanov@nginx.com case '#': 9801213Svbart@nginx.com u--; 981112Smax.romanov@nginx.com goto done; 982112Smax.romanov@nginx.com default: 983112Smax.romanov@nginx.com state = sw_normal; 984112Smax.romanov@nginx.com *u++ = ch; 985112Smax.romanov@nginx.com continue; 986112Smax.romanov@nginx.com } 987