xref: /unit/src/nxt_http_parse.c (revision 2448:243735980417)
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,
112139Sandrew@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,
132139Sandrew@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,
152139Sandrew@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,
172139Sandrew@digital-domain.net     u_char **pos, const u_char *end);
182139Sandrew@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,
202139Sandrew@digital-domain.net     u_char **pos, const u_char *end);
2116Svbart@nginx.com 
22417Svbart@nginx.com static nxt_int_t nxt_http_field_hash_test(nxt_lvlhsh_query_t *lhq, void *data);
23417Svbart@nginx.com 
24417Svbart@nginx.com static nxt_int_t nxt_http_field_hash_collision(nxt_lvlhsh_query_t *lhq,
25417Svbart@nginx.com     void *data);
2616Svbart@nginx.com 
27417Svbart@nginx.com 
28611Svbart@nginx.com #define NXT_HTTP_MAX_FIELD_NAME         0xFF
29417Svbart@nginx.com #define NXT_HTTP_MAX_FIELD_VALUE        NXT_INT32_T_MAX
30417Svbart@nginx.com 
31417Svbart@nginx.com #define NXT_HTTP_FIELD_LVLHSH_SHIFT     5
32417Svbart@nginx.com 
3316Svbart@nginx.com 
3416Svbart@nginx.com typedef enum {
3516Svbart@nginx.com     NXT_HTTP_TARGET_SPACE = 1,   /* \s  */
3616Svbart@nginx.com     NXT_HTTP_TARGET_HASH,        /*  #  */
3716Svbart@nginx.com     NXT_HTTP_TARGET_AGAIN,
3816Svbart@nginx.com     NXT_HTTP_TARGET_BAD,         /* \0\r\n */
3916Svbart@nginx.com 
4016Svbart@nginx.com     /* traps below are used for extended check only */
4116Svbart@nginx.com 
4216Svbart@nginx.com     NXT_HTTP_TARGET_SLASH = 5,   /*  /  */
4316Svbart@nginx.com     NXT_HTTP_TARGET_DOT,         /*  .  */
4416Svbart@nginx.com     NXT_HTTP_TARGET_ARGS_MARK,   /*  ?  */
4516Svbart@nginx.com     NXT_HTTP_TARGET_QUOTE_MARK,  /*  %  */
4616Svbart@nginx.com } nxt_http_target_traps_e;
4716Svbart@nginx.com 
4816Svbart@nginx.com 
4916Svbart@nginx.com static const uint8_t  nxt_http_target_chars[256] nxt_aligned(64) = {
5016Svbart@nginx.com     /* \0                               \n        \r       */
5116Svbart@nginx.com         4, 0, 0, 0,  0, 0, 0, 0,   0, 0, 4, 0,  0, 4, 0, 0,
5216Svbart@nginx.com         0, 0, 0, 0,  0, 0, 0, 0,   0, 0, 0, 0,  0, 0, 0, 0,
5352Svbart@nginx.com 
5452Svbart@nginx.com     /* \s  !  "  #   $  %  &  '    (  )  *  +   ,  -  .  / */
551170Svbart@nginx.com         1, 0, 0, 2,  0, 8, 0, 0,   0, 0, 0, 0,  0, 0, 6, 5,
5652Svbart@nginx.com 
5752Svbart@nginx.com     /*  0  1  2  3   4  5  6  7    8  9  :  ;   <  =  >  ? */
5816Svbart@nginx.com         0, 0, 0, 0,  0, 0, 0, 0,   0, 0, 0, 0,  0, 0, 0, 7,
5916Svbart@nginx.com };
6016Svbart@nginx.com 
6116Svbart@nginx.com 
6216Svbart@nginx.com nxt_inline nxt_http_target_traps_e
nxt_http_parse_target(u_char ** pos,const u_char * end)632139Sandrew@digital-domain.net nxt_http_parse_target(u_char **pos, const u_char *end)
6416Svbart@nginx.com {
6516Svbart@nginx.com     u_char      *p;
6616Svbart@nginx.com     nxt_uint_t  trap;
6716Svbart@nginx.com 
6816Svbart@nginx.com     p = *pos;
6916Svbart@nginx.com 
70409Svbart@nginx.com     while (nxt_fast_path(end - p >= 10)) {
7116Svbart@nginx.com 
72409Svbart@nginx.com #define nxt_target_test_char(ch)                                              \
73409Svbart@nginx.com                                                                               \
74409Svbart@nginx.com         trap = nxt_http_target_chars[ch];                                     \
7516Svbart@nginx.com                                                                               \
76409Svbart@nginx.com         if (nxt_slow_path(trap != 0)) {                                       \
77409Svbart@nginx.com             *pos = &(ch);                                                     \
78409Svbart@nginx.com             return trap;                                                      \
7916Svbart@nginx.com         }
8016Svbart@nginx.com 
81409Svbart@nginx.com /* enddef */
82409Svbart@nginx.com 
83409Svbart@nginx.com         nxt_target_test_char(p[0]);
84409Svbart@nginx.com         nxt_target_test_char(p[1]);
85409Svbart@nginx.com         nxt_target_test_char(p[2]);
86409Svbart@nginx.com         nxt_target_test_char(p[3]);
8716Svbart@nginx.com 
88409Svbart@nginx.com         nxt_target_test_char(p[4]);
89409Svbart@nginx.com         nxt_target_test_char(p[5]);
90409Svbart@nginx.com         nxt_target_test_char(p[6]);
91409Svbart@nginx.com         nxt_target_test_char(p[7]);
9216Svbart@nginx.com 
93409Svbart@nginx.com         nxt_target_test_char(p[8]);
94409Svbart@nginx.com         nxt_target_test_char(p[9]);
9516Svbart@nginx.com 
96409Svbart@nginx.com         p += 10;
9716Svbart@nginx.com     }
9816Svbart@nginx.com 
99410Svbart@nginx.com     while (p != end) {
100410Svbart@nginx.com         nxt_target_test_char(*p); p++;
101410Svbart@nginx.com     }
102410Svbart@nginx.com 
103409Svbart@nginx.com     return NXT_HTTP_TARGET_AGAIN;
10416Svbart@nginx.com }
10516Svbart@nginx.com 
10616Svbart@nginx.com 
10716Svbart@nginx.com nxt_int_t
nxt_http_parse_request_init(nxt_http_request_parse_t * rp,nxt_mp_t * mp)108417Svbart@nginx.com nxt_http_parse_request_init(nxt_http_request_parse_t *rp, nxt_mp_t *mp)
109417Svbart@nginx.com {
110417Svbart@nginx.com     rp->mem_pool = mp;
111417Svbart@nginx.com 
112417Svbart@nginx.com     rp->fields = nxt_list_create(mp, 8, sizeof(nxt_http_field_t));
1131008Szelenkov@nginx.com     if (nxt_slow_path(rp->fields == NULL)) {
114417Svbart@nginx.com         return NXT_ERROR;
115417Svbart@nginx.com     }
116417Svbart@nginx.com 
117417Svbart@nginx.com     rp->field_hash = NXT_HTTP_FIELD_HASH_INIT;
118417Svbart@nginx.com 
119417Svbart@nginx.com     return NXT_OK;
120417Svbart@nginx.com }
121417Svbart@nginx.com 
122417Svbart@nginx.com 
123417Svbart@nginx.com nxt_int_t
nxt_http_parse_request(nxt_http_request_parse_t * rp,nxt_buf_mem_t * b)12416Svbart@nginx.com nxt_http_parse_request(nxt_http_request_parse_t *rp, nxt_buf_mem_t *b)
12516Svbart@nginx.com {
12616Svbart@nginx.com     nxt_int_t  rc;
12716Svbart@nginx.com 
12816Svbart@nginx.com     if (rp->handler == NULL) {
12916Svbart@nginx.com         rp->handler = &nxt_http_parse_request_line;
13016Svbart@nginx.com     }
13116Svbart@nginx.com 
13216Svbart@nginx.com     do {
13316Svbart@nginx.com         rc = rp->handler(rp, &b->pos, b->free);
13416Svbart@nginx.com     } while (rc == NXT_OK);
13516Svbart@nginx.com 
13616Svbart@nginx.com     return rc;
13716Svbart@nginx.com }
13816Svbart@nginx.com 
13916Svbart@nginx.com 
140422Svbart@nginx.com nxt_int_t
nxt_http_parse_fields(nxt_http_request_parse_t * rp,nxt_buf_mem_t * b)141422Svbart@nginx.com nxt_http_parse_fields(nxt_http_request_parse_t *rp, nxt_buf_mem_t *b)
142422Svbart@nginx.com {
143422Svbart@nginx.com     nxt_int_t  rc;
144422Svbart@nginx.com 
145422Svbart@nginx.com     if (rp->handler == NULL) {
146422Svbart@nginx.com         rp->handler = &nxt_http_parse_field_name;
147422Svbart@nginx.com     }
148422Svbart@nginx.com 
149422Svbart@nginx.com     do {
150422Svbart@nginx.com         rc = rp->handler(rp, &b->pos, b->free);
151422Svbart@nginx.com     } while (rc == NXT_OK);
152422Svbart@nginx.com 
153422Svbart@nginx.com     return rc;
154422Svbart@nginx.com }
155422Svbart@nginx.com 
156422Svbart@nginx.com 
15716Svbart@nginx.com static nxt_int_t
nxt_http_parse_request_line(nxt_http_request_parse_t * rp,u_char ** pos,const u_char * end)15816Svbart@nginx.com nxt_http_parse_request_line(nxt_http_request_parse_t *rp, u_char **pos,
1592139Sandrew@digital-domain.net     const u_char *end)
16016Svbart@nginx.com {
1611214Svbart@nginx.com     u_char                   *p, ch, *after_slash, *args;
16216Svbart@nginx.com     nxt_int_t                rc;
1631171Svbart@nginx.com     nxt_bool_t               rest;
164481Svbart@nginx.com     nxt_http_ver_t           ver;
16516Svbart@nginx.com     nxt_http_target_traps_e  trap;
16616Svbart@nginx.com 
16716Svbart@nginx.com     static const nxt_http_ver_t  http11 = { "HTTP/1.1" };
16816Svbart@nginx.com     static const nxt_http_ver_t  http10 = { "HTTP/1.0" };
16916Svbart@nginx.com 
17016Svbart@nginx.com     p = *pos;
17116Svbart@nginx.com 
17216Svbart@nginx.com     rp->method.start = p;
17316Svbart@nginx.com 
174409Svbart@nginx.com     for ( ;; ) {
175409Svbart@nginx.com 
176409Svbart@nginx.com         while (nxt_fast_path(end - p >= 8)) {
17716Svbart@nginx.com 
178409Svbart@nginx.com #define nxt_method_test_char(ch)                                              \
179409Svbart@nginx.com                                                                               \
180409Svbart@nginx.com             if (nxt_slow_path((ch) < 'A' || (ch) > 'Z')) {                    \
181409Svbart@nginx.com                 p = &(ch);                                                    \
182409Svbart@nginx.com                 goto method_unusual_char;                                     \
18316Svbart@nginx.com             }
18416Svbart@nginx.com 
185409Svbart@nginx.com /* enddef */
186409Svbart@nginx.com 
187409Svbart@nginx.com             nxt_method_test_char(p[0]);
188409Svbart@nginx.com             nxt_method_test_char(p[1]);
189409Svbart@nginx.com             nxt_method_test_char(p[2]);
190409Svbart@nginx.com             nxt_method_test_char(p[3]);
19116Svbart@nginx.com 
192409Svbart@nginx.com             nxt_method_test_char(p[4]);
193409Svbart@nginx.com             nxt_method_test_char(p[5]);
194409Svbart@nginx.com             nxt_method_test_char(p[6]);
195409Svbart@nginx.com             nxt_method_test_char(p[7]);
19616Svbart@nginx.com 
197409Svbart@nginx.com             p += 8;
198409Svbart@nginx.com         }
19916Svbart@nginx.com 
200410Svbart@nginx.com         while (p != end) {
201410Svbart@nginx.com             nxt_method_test_char(*p); p++;
202410Svbart@nginx.com         }
203410Svbart@nginx.com 
204623Svbart@nginx.com         rp->method.length = p - rp->method.start;
205623Svbart@nginx.com 
206409Svbart@nginx.com         return NXT_AGAIN;
207409Svbart@nginx.com 
208409Svbart@nginx.com     method_unusual_char:
209409Svbart@nginx.com 
210409Svbart@nginx.com         ch = *p;
21116Svbart@nginx.com 
21216Svbart@nginx.com         if (nxt_fast_path(ch == ' ')) {
21316Svbart@nginx.com             rp->method.length = p - rp->method.start;
21416Svbart@nginx.com             break;
21516Svbart@nginx.com         }
21616Svbart@nginx.com 
21716Svbart@nginx.com         if (ch == '_' || ch == '-') {
218409Svbart@nginx.com             p++;
21916Svbart@nginx.com             continue;
22016Svbart@nginx.com         }
22116Svbart@nginx.com 
222704Sigor@sysoev.ru         if (rp->method.start == p && (ch == '\r' || ch == '\n')) {
22316Svbart@nginx.com             rp->method.start++;
224409Svbart@nginx.com             p++;
22516Svbart@nginx.com             continue;
22616Svbart@nginx.com         }
22716Svbart@nginx.com 
228623Svbart@nginx.com         rp->method.length = p - rp->method.start;
229623Svbart@nginx.com 
230480Svbart@nginx.com         return NXT_HTTP_PARSE_INVALID;
23116Svbart@nginx.com     }
23216Svbart@nginx.com 
23316Svbart@nginx.com     p++;
23416Svbart@nginx.com 
23516Svbart@nginx.com     if (nxt_slow_path(p == end)) {
23616Svbart@nginx.com         return NXT_AGAIN;
23716Svbart@nginx.com     }
23816Svbart@nginx.com 
23916Svbart@nginx.com     /* target */
24016Svbart@nginx.com 
24116Svbart@nginx.com     ch = *p;
24216Svbart@nginx.com 
24316Svbart@nginx.com     if (nxt_slow_path(ch != '/')) {
24416Svbart@nginx.com         rc = nxt_http_parse_unusual_target(rp, &p, end);
24516Svbart@nginx.com 
24616Svbart@nginx.com         if (nxt_slow_path(rc != NXT_OK)) {
24716Svbart@nginx.com             return rc;
24816Svbart@nginx.com         }
24916Svbart@nginx.com     }
25016Svbart@nginx.com 
25116Svbart@nginx.com     rp->target_start = p;
25216Svbart@nginx.com 
25316Svbart@nginx.com     after_slash = p + 1;
2541168Svbart@nginx.com     args = NULL;
2551171Svbart@nginx.com     rest = 0;
2561171Svbart@nginx.com 
2571171Svbart@nginx.com continue_target:
25816Svbart@nginx.com 
25916Svbart@nginx.com     for ( ;; ) {
26016Svbart@nginx.com         p++;
26116Svbart@nginx.com 
26216Svbart@nginx.com         trap = nxt_http_parse_target(&p, end);
26316Svbart@nginx.com 
26416Svbart@nginx.com         switch (trap) {
26516Svbart@nginx.com         case NXT_HTTP_TARGET_SLASH:
26616Svbart@nginx.com             if (nxt_slow_path(after_slash == p)) {
26716Svbart@nginx.com                 rp->complex_target = 1;
26816Svbart@nginx.com                 goto rest_of_target;
26916Svbart@nginx.com             }
27016Svbart@nginx.com 
27116Svbart@nginx.com             after_slash = p + 1;
27216Svbart@nginx.com             continue;
27316Svbart@nginx.com 
27416Svbart@nginx.com         case NXT_HTTP_TARGET_DOT:
27516Svbart@nginx.com             if (nxt_slow_path(after_slash == p)) {
27616Svbart@nginx.com                 rp->complex_target = 1;
27716Svbart@nginx.com                 goto rest_of_target;
27816Svbart@nginx.com             }
27916Svbart@nginx.com 
28016Svbart@nginx.com             continue;
28116Svbart@nginx.com 
28216Svbart@nginx.com         case NXT_HTTP_TARGET_ARGS_MARK:
2831168Svbart@nginx.com             args = p + 1;
28416Svbart@nginx.com             goto rest_of_target;
28516Svbart@nginx.com 
28616Svbart@nginx.com         case NXT_HTTP_TARGET_SPACE:
28716Svbart@nginx.com             rp->target_end = p;
28816Svbart@nginx.com             goto space_after_target;
2891709Svbart@nginx.com #if 0
29016Svbart@nginx.com         case NXT_HTTP_TARGET_QUOTE_MARK:
29116Svbart@nginx.com             rp->quoted_target = 1;
29216Svbart@nginx.com             goto rest_of_target;
2931709Svbart@nginx.com #else
2941709Svbart@nginx.com         case NXT_HTTP_TARGET_QUOTE_MARK:
2951709Svbart@nginx.com #endif
29616Svbart@nginx.com         case NXT_HTTP_TARGET_HASH:
29716Svbart@nginx.com             rp->complex_target = 1;
29816Svbart@nginx.com             goto rest_of_target;
29916Svbart@nginx.com 
30016Svbart@nginx.com         case NXT_HTTP_TARGET_AGAIN:
301621Svbart@nginx.com             rp->target_end = p;
30216Svbart@nginx.com             return NXT_AGAIN;
30316Svbart@nginx.com 
30416Svbart@nginx.com         case NXT_HTTP_TARGET_BAD:
305621Svbart@nginx.com             rp->target_end = p;
306480Svbart@nginx.com             return NXT_HTTP_PARSE_INVALID;
30716Svbart@nginx.com         }
30816Svbart@nginx.com 
30916Svbart@nginx.com         nxt_unreachable();
31016Svbart@nginx.com     }
31116Svbart@nginx.com 
31216Svbart@nginx.com rest_of_target:
31316Svbart@nginx.com 
3141171Svbart@nginx.com     rest = 1;
3151171Svbart@nginx.com 
31616Svbart@nginx.com     for ( ;; ) {
31716Svbart@nginx.com         p++;
31816Svbart@nginx.com 
31919Svbart@nginx.com         trap = nxt_http_parse_target(&p, end);
32016Svbart@nginx.com 
32116Svbart@nginx.com         switch (trap) {
32216Svbart@nginx.com         case NXT_HTTP_TARGET_SPACE:
32316Svbart@nginx.com             rp->target_end = p;
32416Svbart@nginx.com             goto space_after_target;
32516Svbart@nginx.com 
32616Svbart@nginx.com         case NXT_HTTP_TARGET_HASH:
32716Svbart@nginx.com             rp->complex_target = 1;
32816Svbart@nginx.com             continue;
32916Svbart@nginx.com 
33016Svbart@nginx.com         case NXT_HTTP_TARGET_AGAIN:
331621Svbart@nginx.com             rp->target_end = p;
33216Svbart@nginx.com             return NXT_AGAIN;
33316Svbart@nginx.com 
33416Svbart@nginx.com         case NXT_HTTP_TARGET_BAD:
335621Svbart@nginx.com             rp->target_end = p;
336480Svbart@nginx.com             return NXT_HTTP_PARSE_INVALID;
33716Svbart@nginx.com 
33816Svbart@nginx.com         default:
33916Svbart@nginx.com             continue;
34016Svbart@nginx.com         }
34116Svbart@nginx.com 
34216Svbart@nginx.com         nxt_unreachable();
34316Svbart@nginx.com     }
34416Svbart@nginx.com 
34516Svbart@nginx.com space_after_target:
34616Svbart@nginx.com 
34716Svbart@nginx.com     if (nxt_slow_path(end - p < 10)) {
348410Svbart@nginx.com 
349410Svbart@nginx.com         do {
350410Svbart@nginx.com             p++;
351410Svbart@nginx.com 
352410Svbart@nginx.com             if (p == end) {
353410Svbart@nginx.com                 return NXT_AGAIN;
354410Svbart@nginx.com             }
355410Svbart@nginx.com 
356410Svbart@nginx.com         } while (*p == ' ');
357410Svbart@nginx.com 
3582231Salx@nginx.com         if (memcmp(p, "HTTP/", nxt_min(end - p, 5)) == 0) {
359410Svbart@nginx.com 
360410Svbart@nginx.com             switch (end - p) {
361410Svbart@nginx.com             case 8:
362410Svbart@nginx.com                 if (p[7] < '0' || p[7] > '9') {
363410Svbart@nginx.com                     break;
364410Svbart@nginx.com                 }
365410Svbart@nginx.com                 /* Fall through. */
366410Svbart@nginx.com             case 7:
367410Svbart@nginx.com                 if (p[6] != '.') {
368410Svbart@nginx.com                     break;
369410Svbart@nginx.com                 }
370410Svbart@nginx.com                 /* Fall through. */
371410Svbart@nginx.com             case 6:
372410Svbart@nginx.com                 if (p[5] < '0' || p[5] > '9') {
373410Svbart@nginx.com                     break;
374410Svbart@nginx.com                 }
375410Svbart@nginx.com                 /* Fall through. */
376410Svbart@nginx.com             default:
377410Svbart@nginx.com                 return NXT_AGAIN;
378410Svbart@nginx.com             }
379410Svbart@nginx.com         }
380410Svbart@nginx.com 
3811709Svbart@nginx.com         //rp->space_in_target = 1;
3821171Svbart@nginx.com 
3831171Svbart@nginx.com         if (rest) {
3841171Svbart@nginx.com             goto rest_of_target;
3851171Svbart@nginx.com         }
3861171Svbart@nginx.com 
3871171Svbart@nginx.com         goto continue_target;
38816Svbart@nginx.com     }
38916Svbart@nginx.com 
39016Svbart@nginx.com     /* " HTTP/1.1\r\n" or " HTTP/1.1\n" */
39116Svbart@nginx.com 
392482Svbart@nginx.com     if (nxt_slow_path(p[9] != '\r' && p[9] != '\n')) {
393482Svbart@nginx.com 
394482Svbart@nginx.com         if (p[1] == ' ') {
395482Svbart@nginx.com             /* surplus space after tartet */
396482Svbart@nginx.com             p++;
397482Svbart@nginx.com             goto space_after_target;
398482Svbart@nginx.com         }
399482Svbart@nginx.com 
4001709Svbart@nginx.com         //rp->space_in_target = 1;
4011171Svbart@nginx.com 
4021171Svbart@nginx.com         if (rest) {
4031171Svbart@nginx.com             goto rest_of_target;
4041171Svbart@nginx.com         }
4051171Svbart@nginx.com 
4061171Svbart@nginx.com         goto continue_target;
407482Svbart@nginx.com     }
408482Svbart@nginx.com 
409481Svbart@nginx.com     nxt_memcpy(ver.str, &p[1], 8);
41016Svbart@nginx.com 
411482Svbart@nginx.com     if (nxt_fast_path(ver.ui64 == http11.ui64
412482Svbart@nginx.com                       || ver.ui64 == http10.ui64
4132231Salx@nginx.com                       || (memcmp(ver.str, "HTTP/1.", 7) == 0
414482Svbart@nginx.com                           && ver.s.minor >= '0' && ver.s.minor <= '9')))
41516Svbart@nginx.com     {
416481Svbart@nginx.com         rp->version.ui64 = ver.ui64;
41716Svbart@nginx.com 
4182430Salx@nginx.com         p += 9;
4192430Salx@nginx.com         if (nxt_fast_path(*p == '\r')) {
42016Svbart@nginx.com 
4212430Salx@nginx.com             if (nxt_slow_path(p + 1 == end)) {
42216Svbart@nginx.com                 return NXT_AGAIN;
42316Svbart@nginx.com             }
42416Svbart@nginx.com 
4252430Salx@nginx.com             if (nxt_slow_path(p[1] != '\n')) {
426480Svbart@nginx.com                 return NXT_HTTP_PARSE_INVALID;
42716Svbart@nginx.com             }
42816Svbart@nginx.com 
4292430Salx@nginx.com             *pos = p + 2;
430112Smax.romanov@nginx.com 
431112Smax.romanov@nginx.com         } else {
4322430Salx@nginx.com             *pos = p + 1;
433112Smax.romanov@nginx.com         }
434112Smax.romanov@nginx.com 
4352430Salx@nginx.com         rp->request_line_end = p;
4362430Salx@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 
4672231Salx@nginx.com     if (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,
4822139Sandrew@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,
5202139Sandrew@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,
6272139Sandrew@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)7072139Sandrew@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,
7742139Sandrew@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 
855*2448Sz.hong@f5.com 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             }
987112Smax.romanov@nginx.com 
988112Smax.romanov@nginx.com             break;
989112Smax.romanov@nginx.com 
990112Smax.romanov@nginx.com         case sw_dot_dot:
991112Smax.romanov@nginx.com 
992112Smax.romanov@nginx.com             if (nxt_http_is_normal(ch)) {
993112Smax.romanov@nginx.com                 state = sw_normal;
994112Smax.romanov@nginx.com                 *u++ = ch;
995112Smax.romanov@nginx.com                 continue;
996112Smax.romanov@nginx.com             }
997112Smax.romanov@nginx.com 
998112Smax.romanov@nginx.com             switch (ch) {
9991213Svbart@nginx.com 
1000112Smax.romanov@nginx.com             case '/':
10011213Svbart@nginx.com             case '?':
10021213Svbart@nginx.com             case '#':
1003112Smax.romanov@nginx.com                 u -= 5;
10041213Svbart@nginx.com 
1005112Smax.romanov@nginx.com                 for ( ;; ) {
1006112Smax.romanov@nginx.com                     if (u < rp->path.start) {
1007480Svbart@nginx.com                         return NXT_HTTP_PARSE_INVALID;
1008112Smax.romanov@nginx.com                     }
10091213Svbart@nginx.com 
1010112Smax.romanov@nginx.com                     if (*u == '/') {
1011112Smax.romanov@nginx.com                         u++;
1012112Smax.romanov@nginx.com                         break;
1013112Smax.romanov@nginx.com                     }
10141213Svbart@nginx.com 
1015112Smax.romanov@nginx.com                     u--;
1016112Smax.romanov@nginx.com                 }
10171213Svbart@nginx.com 
10181213Svbart@nginx.com                 if (ch == '?') {
10191213Svbart@nginx.com                     args = p;
10201213Svbart@nginx.com                     goto args;
10211213Svbart@nginx.com                 }
10221213Svbart@nginx.com 
10231213Svbart@nginx.com                 if (ch == '#') {
10241213Svbart@nginx.com                     goto done;
10251213Svbart@nginx.com                 }
10261213Svbart@nginx.com 
10271213Svbart@nginx.com                 state = sw_slash;
1028112Smax.romanov@nginx.com                 break;
1029112Smax.romanov@nginx.com 
1030112Smax.romanov@nginx.com             case '%':
1031112Smax.romanov@nginx.com                 saved_state = state;
1032112Smax.romanov@nginx.com                 state = sw_quoted;
1033112Smax.romanov@nginx.com                 continue;
10341213Svbart@nginx.com 
1035112Smax.romanov@nginx.com             default:
1036112Smax.romanov@nginx.com                 state = sw_normal;
1037112Smax.romanov@nginx.com                 *u++ = ch;
1038112Smax.romanov@nginx.com                 continue;
1039112Smax.romanov@nginx.com             }
1040112Smax.romanov@nginx.com 
1041112Smax.romanov@nginx.com             break;
1042112Smax.romanov@nginx.com 
1043112Smax.romanov@nginx.com         case sw_quoted:
10441709Svbart@nginx.com             //rp->quoted_target = 1;
1045112Smax.romanov@nginx.com 
1046112Smax.romanov@nginx.com             if (ch >= '0' && ch <= '9') {
1047112Smax.romanov@nginx.com                 high = (u_char) (ch - '0');
1048112Smax.romanov@nginx.com                 state = sw_quoted_second;
1049112Smax.romanov@nginx.com                 continue;
1050112Smax.romanov@nginx.com             }
1051112Smax.romanov@nginx.com 
1052112Smax.romanov@nginx.com             c = (u_char) (ch | 0x20);
1053112Smax.romanov@nginx.com             if (c >= 'a' && c <= 'f') {
1054112Smax.romanov@nginx.com                 high = (u_char) (c - 'a' + 10);
1055112Smax.romanov@nginx.com                 state = sw_quoted_second;
1056112Smax.romanov@nginx.com                 continue;
1057112Smax.romanov@nginx.com             }
1058112Smax.romanov@nginx.com 
1059480Svbart@nginx.com             return NXT_HTTP_PARSE_INVALID;
1060112Smax.romanov@nginx.com 
1061112Smax.romanov@nginx.com         case sw_quoted_second:
1062112Smax.romanov@nginx.com             if (ch >= '0' && ch <= '9') {
1063112Smax.romanov@nginx.com                 ch = (u_char) ((high << 4) + ch - '0');
1064112Smax.romanov@nginx.com 
10651167Svbart@nginx.com                 if (ch == '%') {
1066112Smax.romanov@nginx.com                     state = sw_normal;
10671167Svbart@nginx.com                     *u++ = '%';
10681167Svbart@nginx.com 
10691167Svbart@nginx.com                     if (rp->encoded_slashes) {
10701167Svbart@nginx.com                         *u++ = '2';
10711167Svbart@nginx.com                         *u++ = '5';
10721167Svbart@nginx.com                     }
10731167Svbart@nginx.com 
1074112Smax.romanov@nginx.com                     continue;
10751167Svbart@nginx.com                 }
1076112Smax.romanov@nginx.com 
10771167Svbart@nginx.com                 if (ch == '#') {
10781167Svbart@nginx.com                     state = sw_normal;
10791167Svbart@nginx.com                     *u++ = '#';
10801167Svbart@nginx.com                     continue;
10811167Svbart@nginx.com                 }
10821167Svbart@nginx.com 
10831167Svbart@nginx.com                 if (ch == '\0') {
1084480Svbart@nginx.com                     return NXT_HTTP_PARSE_INVALID;
1085112Smax.romanov@nginx.com                 }
1086112Smax.romanov@nginx.com 
1087112Smax.romanov@nginx.com                 state = saved_state;
1088112Smax.romanov@nginx.com                 goto again;
1089112Smax.romanov@nginx.com             }
1090112Smax.romanov@nginx.com 
1091112Smax.romanov@nginx.com             c = (u_char) (ch | 0x20);
1092112Smax.romanov@nginx.com             if (c >= 'a' && c <= 'f') {
1093112Smax.romanov@nginx.com                 ch = (u_char) ((high << 4) + c - 'a' + 10);
1094112Smax.romanov@nginx.com 
1095112Smax.romanov@nginx.com                 if (ch == '?') {
1096112Smax.romanov@nginx.com                     state = sw_normal;
1097112Smax.romanov@nginx.com                     *u++ = ch;
1098112Smax.romanov@nginx.com                     continue;
10991167Svbart@nginx.com                 }
1100112Smax.romanov@nginx.com 
11011167Svbart@nginx.com                 if (ch == '/' && rp->encoded_slashes) {
11021167Svbart@nginx.com                     state = sw_normal;
11031167Svbart@nginx.com                     *u++ = '%';
11041167Svbart@nginx.com                     *u++ = '2';
11051167Svbart@nginx.com                     *u++ = p[-1];  /* 'f' or 'F' */
11061167Svbart@nginx.com                     continue;
11071167Svbart@nginx.com                 }
11081167Svbart@nginx.com 
1109112Smax.romanov@nginx.com                 state = saved_state;
1110112Smax.romanov@nginx.com                 goto again;
1111112Smax.romanov@nginx.com             }
1112112Smax.romanov@nginx.com 
1113480Svbart@nginx.com             return NXT_HTTP_PARSE_INVALID;
1114112Smax.romanov@nginx.com         }
1115112Smax.romanov@nginx.com     }
1116112Smax.romanov@nginx.com 
11171213Svbart@nginx.com     if (state >= sw_dot) {
11181213Svbart@nginx.com         if (state >= sw_quoted) {
11191213Svbart@nginx.com             return NXT_HTTP_PARSE_INVALID;
11201213Svbart@nginx.com         }
11211213Svbart@nginx.com 
11221213Svbart@nginx.com         /* "/." and "/.." must be normalized similar to "/./" and "/../". */
11231213Svbart@nginx.com         ch = '/';
11241213Svbart@nginx.com         goto again;
1125112Smax.romanov@nginx.com     }
1126112Smax.romanov@nginx.com 
1127112Smax.romanov@nginx.com args:
1128112Smax.romanov@nginx.com 
1129112Smax.romanov@nginx.com     for (/* void */; p < rp->target_end; p++) {
1130112Smax.romanov@nginx.com         if (*p == '#') {
1131112Smax.romanov@nginx.com             break;
1132112Smax.romanov@nginx.com         }
1133112Smax.romanov@nginx.com     }
1134112Smax.romanov@nginx.com 
11351168Svbart@nginx.com     if (args != NULL) {
11361168Svbart@nginx.com         rp->args.length = p - args;
11371168Svbart@nginx.com         rp->args.start = args;
1138112Smax.romanov@nginx.com     }
1139112Smax.romanov@nginx.com 
1140112Smax.romanov@nginx.com done:
1141112Smax.romanov@nginx.com 
1142112Smax.romanov@nginx.com     rp->path.length = u - rp->path.start;
1143112Smax.romanov@nginx.com 
1144112Smax.romanov@nginx.com     return NXT_OK;
1145112Smax.romanov@nginx.com }
1146417Svbart@nginx.com 
1147417Svbart@nginx.com 
11481126Smax.romanov@nginx.com const nxt_lvlhsh_proto_t  nxt_http_fields_hash_proto  nxt_aligned(64) = {
1149417Svbart@nginx.com     NXT_LVLHSH_BUCKET_SIZE(64),
1150417Svbart@nginx.com     { NXT_HTTP_FIELD_LVLHSH_SHIFT, 0, 0, 0, 0, 0, 0, 0 },
1151417Svbart@nginx.com     nxt_http_field_hash_test,
11521459Smax.romanov@nginx.com     nxt_lvlhsh_alloc,
11531459Smax.romanov@nginx.com     nxt_lvlhsh_free,
1154417Svbart@nginx.com };
1155417Svbart@nginx.com 
1156417Svbart@nginx.com 
1157417Svbart@nginx.com static nxt_int_t
nxt_http_field_hash_test(nxt_lvlhsh_query_t * lhq,void * data)1158417Svbart@nginx.com nxt_http_field_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
1159417Svbart@nginx.com {
1160417Svbart@nginx.com     nxt_http_field_proc_t  *field;
1161417Svbart@nginx.com 
1162417Svbart@nginx.com     field = data;
1163417Svbart@nginx.com 
1164417Svbart@nginx.com     if (nxt_strcasestr_eq(&lhq->key, &field->name)) {
1165417Svbart@nginx.com         return NXT_OK;
1166417Svbart@nginx.com     }
1167417Svbart@nginx.com 
1168417Svbart@nginx.com     return NXT_DECLINED;
1169417Svbart@nginx.com }
1170417Svbart@nginx.com 
1171417Svbart@nginx.com 
1172417Svbart@nginx.com static nxt_int_t
nxt_http_field_hash_collision(nxt_lvlhsh_query_t * lhq,void * data)1173417Svbart@nginx.com nxt_http_field_hash_collision(nxt_lvlhsh_query_t *lhq, void *data)
1174417Svbart@nginx.com {
1175417Svbart@nginx.com     return NXT_OK;
1176417Svbart@nginx.com }
1177417Svbart@nginx.com 
1178417Svbart@nginx.com 
1179417Svbart@nginx.com nxt_int_t
nxt_http_fields_hash(nxt_lvlhsh_t * hash,nxt_http_field_proc_t items[],nxt_uint_t count)11801459Smax.romanov@nginx.com nxt_http_fields_hash(nxt_lvlhsh_t *hash,
1181417Svbart@nginx.com     nxt_http_field_proc_t items[], nxt_uint_t count)
1182417Svbart@nginx.com {
1183417Svbart@nginx.com     u_char              ch;
1184417Svbart@nginx.com     uint32_t            key;
1185417Svbart@nginx.com     nxt_str_t           *name;
1186417Svbart@nginx.com     nxt_int_t           ret;
1187417Svbart@nginx.com     nxt_uint_t          i, j;
1188417Svbart@nginx.com     nxt_lvlhsh_query_t  lhq;
1189417Svbart@nginx.com 
1190417Svbart@nginx.com     lhq.replace = 0;
1191417Svbart@nginx.com     lhq.proto = &nxt_http_fields_hash_proto;
1192417Svbart@nginx.com 
1193417Svbart@nginx.com     for (i = 0; i < count; i++) {
1194417Svbart@nginx.com         key = NXT_HTTP_FIELD_HASH_INIT;
1195417Svbart@nginx.com         name = &items[i].name;
1196417Svbart@nginx.com 
1197417Svbart@nginx.com         for (j = 0; j < name->length; j++) {
1198417Svbart@nginx.com             ch = nxt_lowcase(name->start[j]);
1199417Svbart@nginx.com             key = nxt_http_field_hash_char(key, ch);
1200417Svbart@nginx.com         }
1201417Svbart@nginx.com 
1202611Svbart@nginx.com         lhq.key_hash = nxt_http_field_hash_end(key) & 0xFFFF;
1203417Svbart@nginx.com         lhq.key = *name;
1204417Svbart@nginx.com         lhq.value = &items[i];
1205417Svbart@nginx.com 
1206417Svbart@nginx.com         ret = nxt_lvlhsh_insert(hash, &lhq);
1207417Svbart@nginx.com 
1208417Svbart@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
1209417Svbart@nginx.com             return NXT_ERROR;
1210417Svbart@nginx.com         }
1211417Svbart@nginx.com     }
1212417Svbart@nginx.com 
1213417Svbart@nginx.com     return NXT_OK;
1214417Svbart@nginx.com }
1215417Svbart@nginx.com 
1216417Svbart@nginx.com 
1217417Svbart@nginx.com nxt_uint_t
nxt_http_fields_hash_collisions(nxt_lvlhsh_t * hash,nxt_http_field_proc_t items[],nxt_uint_t count,nxt_bool_t level)12181459Smax.romanov@nginx.com nxt_http_fields_hash_collisions(nxt_lvlhsh_t *hash,
1219417Svbart@nginx.com     nxt_http_field_proc_t items[], nxt_uint_t count, nxt_bool_t level)
1220417Svbart@nginx.com {
1221417Svbart@nginx.com     u_char              ch;
1222417Svbart@nginx.com     uint32_t            key, mask;
1223417Svbart@nginx.com     nxt_str_t           *name;
1224417Svbart@nginx.com     nxt_uint_t          colls, i, j;
1225417Svbart@nginx.com     nxt_lvlhsh_proto_t  proto;
1226417Svbart@nginx.com     nxt_lvlhsh_query_t  lhq;
1227417Svbart@nginx.com 
1228417Svbart@nginx.com     proto = nxt_http_fields_hash_proto;
1229417Svbart@nginx.com     proto.test = nxt_http_field_hash_collision;
1230417Svbart@nginx.com 
1231417Svbart@nginx.com     lhq.replace = 0;
1232417Svbart@nginx.com     lhq.proto = &proto;
1233417Svbart@nginx.com 
1234611Svbart@nginx.com     mask = level ? (1 << NXT_HTTP_FIELD_LVLHSH_SHIFT) - 1 : 0xFFFF;
1235417Svbart@nginx.com 
1236417Svbart@nginx.com     colls = 0;
1237417Svbart@nginx.com 
1238417Svbart@nginx.com     for (i = 0; i < count; i++) {
1239417Svbart@nginx.com         key = NXT_HTTP_FIELD_HASH_INIT;
1240417Svbart@nginx.com         name = &items[i].name;
1241417Svbart@nginx.com 
1242417Svbart@nginx.com         for (j = 0; j < name->length; j++) {
1243417Svbart@nginx.com             ch = nxt_lowcase(name->start[j]);
1244417Svbart@nginx.com             key = nxt_http_field_hash_char(key, ch);
1245417Svbart@nginx.com         }
1246417Svbart@nginx.com 
1247417Svbart@nginx.com         lhq.key_hash = nxt_http_field_hash_end(key) & mask;
1248418Svbart@nginx.com         lhq.value = &items[i];
1249417Svbart@nginx.com 
1250417Svbart@nginx.com         if (nxt_lvlhsh_insert(hash, &lhq) == NXT_DECLINED) {
1251417Svbart@nginx.com             colls++;
1252417Svbart@nginx.com         }
1253417Svbart@nginx.com     }
1254417Svbart@nginx.com 
1255417Svbart@nginx.com     return colls;
1256417Svbart@nginx.com }
1257417Svbart@nginx.com 
1258417Svbart@nginx.com 
1259417Svbart@nginx.com nxt_int_t
nxt_http_fields_process(nxt_list_t * fields,nxt_lvlhsh_t * hash,void * ctx)1260417Svbart@nginx.com nxt_http_fields_process(nxt_list_t *fields, nxt_lvlhsh_t *hash, void *ctx)
1261417Svbart@nginx.com {
12621126Smax.romanov@nginx.com     nxt_int_t         ret;
12631126Smax.romanov@nginx.com     nxt_http_field_t  *field;
1264417Svbart@nginx.com 
1265417Svbart@nginx.com     nxt_list_each(field, fields) {
1266417Svbart@nginx.com 
12671126Smax.romanov@nginx.com         ret = nxt_http_field_process(field, hash, ctx);
1268417Svbart@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
1269417Svbart@nginx.com             return ret;
1270417Svbart@nginx.com         }
1271417Svbart@nginx.com 
1272417Svbart@nginx.com     } nxt_list_loop;
1273417Svbart@nginx.com 
1274417Svbart@nginx.com     return NXT_OK;
1275417Svbart@nginx.com }
1276