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
nxt_http_parse_target(u_char ** pos,const u_char * end)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
nxt_http_parse_request_init(nxt_http_request_parse_t * rp,nxt_mp_t * mp)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
nxt_http_parse_request(nxt_http_request_parse_t * rp,nxt_buf_mem_t * b)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
nxt_http_parse_fields(nxt_http_request_parse_t * rp,nxt_buf_mem_t * b)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
nxt_http_parse_request_line(nxt_http_request_parse_t * rp,u_char ** pos,const u_char * end)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
nxt_http_parse_unusual_target(nxt_http_request_parse_t * rp,u_char ** pos,const u_char * end)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
nxt_http_parse_field_name(nxt_http_request_parse_t * rp,u_char ** pos,const u_char * end)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
nxt_http_parse_field_value(nxt_http_request_parse_t * rp,u_char ** pos,const u_char * end)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 *
nxt_http_lookup_field_end(u_char * p,const u_char * end)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
nxt_http_parse_field_end(nxt_http_request_parse_t * rp,u_char ** pos,const u_char * end)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
nxt_http_parse_complex_target(nxt_http_request_parse_t * rp)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