xref: /unit/src/nxt_http_route.c (revision 1270)
1964Sigor@sysoev.ru 
2964Sigor@sysoev.ru /*
3964Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
4964Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
5964Sigor@sysoev.ru  */
6964Sigor@sysoev.ru 
7964Sigor@sysoev.ru #include <nxt_router.h>
8964Sigor@sysoev.ru #include <nxt_http.h>
9964Sigor@sysoev.ru 
10964Sigor@sysoev.ru 
11964Sigor@sysoev.ru typedef enum {
121059Sigor@sysoev.ru     NXT_HTTP_ROUTE_TABLE = 0,
131059Sigor@sysoev.ru     NXT_HTTP_ROUTE_STRING,
14964Sigor@sysoev.ru     NXT_HTTP_ROUTE_STRING_PTR,
15964Sigor@sysoev.ru     NXT_HTTP_ROUTE_HEADER,
16964Sigor@sysoev.ru     NXT_HTTP_ROUTE_ARGUMENT,
17964Sigor@sysoev.ru     NXT_HTTP_ROUTE_COOKIE,
181110Saxel.duch@nginx.com     NXT_HTTP_ROUTE_SCHEME,
19964Sigor@sysoev.ru } nxt_http_route_object_t;
20964Sigor@sysoev.ru 
21964Sigor@sysoev.ru 
22964Sigor@sysoev.ru typedef enum {
23964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_EXACT = 0,
24964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_BEGIN,
251032Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_MIDDLE,
26964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_END,
27964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_SUBSTRING,
28964Sigor@sysoev.ru } nxt_http_route_pattern_type_t;
29964Sigor@sysoev.ru 
30964Sigor@sysoev.ru 
31964Sigor@sysoev.ru typedef enum {
32964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_NOCASE = 0,
33964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_LOWCASE,
34964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_UPCASE,
35964Sigor@sysoev.ru } nxt_http_route_pattern_case_t;
36964Sigor@sysoev.ru 
37964Sigor@sysoev.ru 
38964Sigor@sysoev.ru typedef struct {
391264Sigor@sysoev.ru     nxt_conf_value_t               *pass;
401264Sigor@sysoev.ru     nxt_conf_value_t               *share;
41*1270Sigor@sysoev.ru     nxt_conf_value_t               *proxy;
421264Sigor@sysoev.ru } nxt_http_route_action_conf_t;
431264Sigor@sysoev.ru 
441264Sigor@sysoev.ru 
451264Sigor@sysoev.ru typedef struct {
46964Sigor@sysoev.ru     nxt_conf_value_t               *host;
47964Sigor@sysoev.ru     nxt_conf_value_t               *uri;
48964Sigor@sysoev.ru     nxt_conf_value_t               *method;
491059Sigor@sysoev.ru     nxt_conf_value_t               *headers;
501061Sigor@sysoev.ru     nxt_conf_value_t               *arguments;
511062Sigor@sysoev.ru     nxt_conf_value_t               *cookies;
521110Saxel.duch@nginx.com     nxt_conf_value_t               *scheme;
53964Sigor@sysoev.ru } nxt_http_route_match_conf_t;
54964Sigor@sysoev.ru 
55964Sigor@sysoev.ru 
56964Sigor@sysoev.ru typedef struct {
571032Sigor@sysoev.ru     u_char                         *start1;
581032Sigor@sysoev.ru     u_char                         *start2;
591032Sigor@sysoev.ru     uint32_t                       length1;
601032Sigor@sysoev.ru     uint32_t                       length2;
61964Sigor@sysoev.ru     uint32_t                       min_length;
62964Sigor@sysoev.ru 
63964Sigor@sysoev.ru     nxt_http_route_pattern_type_t  type:8;
64964Sigor@sysoev.ru     uint8_t                        case_sensitive;  /* 1 bit */
65964Sigor@sysoev.ru     uint8_t                        negative;        /* 1 bit */
66964Sigor@sysoev.ru     uint8_t                        any;             /* 1 bit */
67964Sigor@sysoev.ru } nxt_http_route_pattern_t;
68964Sigor@sysoev.ru 
69964Sigor@sysoev.ru 
70964Sigor@sysoev.ru typedef struct {
711061Sigor@sysoev.ru     uint16_t                       hash;
721061Sigor@sysoev.ru     uint16_t                       name_length;
731061Sigor@sysoev.ru     uint32_t                       value_length;
741061Sigor@sysoev.ru     u_char                         *name;
751061Sigor@sysoev.ru     u_char                         *value;
761061Sigor@sysoev.ru } nxt_http_name_value_t;
771061Sigor@sysoev.ru 
781061Sigor@sysoev.ru 
791061Sigor@sysoev.ru typedef struct {
801062Sigor@sysoev.ru     uint16_t                       hash;
811062Sigor@sysoev.ru     uint16_t                       name_length;
821062Sigor@sysoev.ru     uint32_t                       value_length;
831062Sigor@sysoev.ru     u_char                         *name;
841062Sigor@sysoev.ru     u_char                         *value;
851062Sigor@sysoev.ru } nxt_http_cookie_t;
861062Sigor@sysoev.ru 
871062Sigor@sysoev.ru 
881062Sigor@sysoev.ru typedef struct {
891059Sigor@sysoev.ru     /* The object must be the first field. */
901059Sigor@sysoev.ru     nxt_http_route_object_t        object:8;
91964Sigor@sysoev.ru     uint32_t                       items;
921059Sigor@sysoev.ru 
931059Sigor@sysoev.ru     union {
941059Sigor@sysoev.ru         uintptr_t                  offset;
951059Sigor@sysoev.ru 
961059Sigor@sysoev.ru         struct {
971059Sigor@sysoev.ru             u_char                 *start;
981059Sigor@sysoev.ru             uint16_t               hash;
991059Sigor@sysoev.ru             uint16_t               length;
1001059Sigor@sysoev.ru         } name;
1011059Sigor@sysoev.ru     } u;
1021059Sigor@sysoev.ru 
103964Sigor@sysoev.ru     nxt_http_route_pattern_t       pattern[0];
104964Sigor@sysoev.ru } nxt_http_route_rule_t;
105964Sigor@sysoev.ru 
106964Sigor@sysoev.ru 
107964Sigor@sysoev.ru typedef struct {
108964Sigor@sysoev.ru     uint32_t                       items;
1091059Sigor@sysoev.ru     nxt_http_route_rule_t          *rule[0];
1101059Sigor@sysoev.ru } nxt_http_route_ruleset_t;
1111059Sigor@sysoev.ru 
1121059Sigor@sysoev.ru 
1131059Sigor@sysoev.ru typedef struct {
1141059Sigor@sysoev.ru     /* The object must be the first field. */
1151059Sigor@sysoev.ru     nxt_http_route_object_t        object:8;
1161059Sigor@sysoev.ru     uint32_t                       items;
1171059Sigor@sysoev.ru     nxt_http_route_ruleset_t       *ruleset[0];
1181059Sigor@sysoev.ru } nxt_http_route_table_t;
1191059Sigor@sysoev.ru 
1201059Sigor@sysoev.ru 
1211059Sigor@sysoev.ru typedef union {
1221059Sigor@sysoev.ru     nxt_http_route_rule_t          *rule;
1231059Sigor@sysoev.ru     nxt_http_route_table_t         *table;
1241059Sigor@sysoev.ru } nxt_http_route_test_t;
1251059Sigor@sysoev.ru 
1261059Sigor@sysoev.ru 
1271059Sigor@sysoev.ru typedef struct {
1281059Sigor@sysoev.ru     uint32_t                       items;
1291264Sigor@sysoev.ru     nxt_http_action_t              action;
1301059Sigor@sysoev.ru     nxt_http_route_test_t          test[0];
131964Sigor@sysoev.ru } nxt_http_route_match_t;
132964Sigor@sysoev.ru 
133964Sigor@sysoev.ru 
134964Sigor@sysoev.ru struct nxt_http_route_s {
135964Sigor@sysoev.ru     nxt_str_t                      name;
136964Sigor@sysoev.ru     uint32_t                       items;
137964Sigor@sysoev.ru     nxt_http_route_match_t         *match[0];
138964Sigor@sysoev.ru };
139964Sigor@sysoev.ru 
140964Sigor@sysoev.ru 
141964Sigor@sysoev.ru struct nxt_http_routes_s {
142964Sigor@sysoev.ru     uint32_t                       items;
143964Sigor@sysoev.ru     nxt_http_route_t               *route[0];
144964Sigor@sysoev.ru };
145964Sigor@sysoev.ru 
146964Sigor@sysoev.ru 
1471062Sigor@sysoev.ru #define NJS_COOKIE_HASH                                                       \
1481062Sigor@sysoev.ru     (nxt_http_field_hash_end(                                                 \
1491062Sigor@sysoev.ru      nxt_http_field_hash_char(                                                \
1501062Sigor@sysoev.ru      nxt_http_field_hash_char(                                                \
1511062Sigor@sysoev.ru      nxt_http_field_hash_char(                                                \
1521062Sigor@sysoev.ru      nxt_http_field_hash_char(                                                \
1531062Sigor@sysoev.ru      nxt_http_field_hash_char(                                                \
1541062Sigor@sysoev.ru      nxt_http_field_hash_char(NXT_HTTP_FIELD_HASH_INIT,                       \
1551062Sigor@sysoev.ru         'c'), 'o'), 'o'), 'k'), 'i'), 'e')) & 0xFFFF)
1561062Sigor@sysoev.ru 
1571062Sigor@sysoev.ru 
158964Sigor@sysoev.ru static nxt_http_route_t *nxt_http_route_create(nxt_task_t *task,
159964Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv);
160964Sigor@sysoev.ru static nxt_http_route_match_t *nxt_http_route_match_create(nxt_task_t *task,
161964Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv);
1621264Sigor@sysoev.ru static nxt_int_t nxt_http_route_action_create(nxt_router_temp_conf_t *tmcf,
1631264Sigor@sysoev.ru     nxt_conf_value_t *cv, nxt_http_route_match_t *match);
1641059Sigor@sysoev.ru static nxt_http_route_table_t *nxt_http_route_table_create(nxt_task_t *task,
1651061Sigor@sysoev.ru     nxt_mp_t *mp, nxt_conf_value_t *table_cv, nxt_http_route_object_t object,
1661061Sigor@sysoev.ru     nxt_bool_t case_sensitive);
1671059Sigor@sysoev.ru static nxt_http_route_ruleset_t *nxt_http_route_ruleset_create(nxt_task_t *task,
1681061Sigor@sysoev.ru     nxt_mp_t *mp, nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object,
1691061Sigor@sysoev.ru     nxt_bool_t case_sensitive);
1701061Sigor@sysoev.ru static nxt_http_route_rule_t *nxt_http_route_rule_name_create(nxt_task_t *task,
1711061Sigor@sysoev.ru     nxt_mp_t *mp, nxt_conf_value_t *rule_cv, nxt_str_t *name,
1721061Sigor@sysoev.ru     nxt_bool_t case_sensitive);
173964Sigor@sysoev.ru static nxt_http_route_rule_t *nxt_http_route_rule_create(nxt_task_t *task,
1741059Sigor@sysoev.ru     nxt_mp_t *mp, nxt_conf_value_t *cv, nxt_bool_t case_sensitive,
1751059Sigor@sysoev.ru     nxt_http_route_pattern_case_t pattern_case);
176964Sigor@sysoev.ru static int nxt_http_pattern_compare(const void *one, const void *two);
177964Sigor@sysoev.ru static nxt_int_t nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp,
178964Sigor@sysoev.ru     nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern,
179964Sigor@sysoev.ru     nxt_http_route_pattern_case_t pattern_case);
1801032Sigor@sysoev.ru static u_char *nxt_http_route_pattern_copy(nxt_mp_t *mp, nxt_str_t *test,
1811032Sigor@sysoev.ru     nxt_http_route_pattern_case_t pattern_case);
182964Sigor@sysoev.ru 
183964Sigor@sysoev.ru static void nxt_http_route_resolve(nxt_task_t *task,
184964Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_http_route_t *route);
1851264Sigor@sysoev.ru static void nxt_http_action_resolve(nxt_task_t *task,
1861264Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_http_action_t *action);
187964Sigor@sysoev.ru static nxt_http_route_t *nxt_http_route_find(nxt_http_routes_t *routes,
188964Sigor@sysoev.ru     nxt_str_t *name);
189964Sigor@sysoev.ru static void nxt_http_route_cleanup(nxt_task_t *task, nxt_http_route_t *routes);
190964Sigor@sysoev.ru 
1911264Sigor@sysoev.ru static nxt_http_action_t *nxt_http_route_handler(nxt_task_t *task,
1921264Sigor@sysoev.ru     nxt_http_request_t *r, nxt_http_action_t *start);
1931264Sigor@sysoev.ru static nxt_http_action_t *nxt_http_route_match(nxt_http_request_t *r,
194964Sigor@sysoev.ru     nxt_http_route_match_t *match);
1951060Sigor@sysoev.ru static nxt_int_t nxt_http_route_table(nxt_http_request_t *r,
1961059Sigor@sysoev.ru     nxt_http_route_table_t *table);
1971060Sigor@sysoev.ru static nxt_int_t nxt_http_route_ruleset(nxt_http_request_t *r,
1981059Sigor@sysoev.ru     nxt_http_route_ruleset_t *ruleset);
1991060Sigor@sysoev.ru static nxt_int_t nxt_http_route_rule(nxt_http_request_t *r,
200964Sigor@sysoev.ru     nxt_http_route_rule_t *rule);
2011060Sigor@sysoev.ru static nxt_int_t nxt_http_route_header(nxt_http_request_t *r,
2021059Sigor@sysoev.ru     nxt_http_route_rule_t *rule);
2031061Sigor@sysoev.ru static nxt_int_t nxt_http_route_arguments(nxt_http_request_t *r,
2041061Sigor@sysoev.ru     nxt_http_route_rule_t *rule);
2051061Sigor@sysoev.ru static nxt_array_t *nxt_http_route_arguments_parse(nxt_http_request_t *r);
2061061Sigor@sysoev.ru static nxt_http_name_value_t *nxt_http_route_argument(nxt_array_t *array,
2071061Sigor@sysoev.ru     u_char *name, size_t name_length, uint32_t hash, u_char *start,
2081061Sigor@sysoev.ru     u_char *end);
2091061Sigor@sysoev.ru static nxt_int_t nxt_http_route_test_argument(nxt_http_request_t *r,
2101061Sigor@sysoev.ru     nxt_http_route_rule_t *rule, nxt_array_t *array);
2111110Saxel.duch@nginx.com static nxt_int_t nxt_http_route_scheme(nxt_http_request_t *r,
2121110Saxel.duch@nginx.com     nxt_http_route_rule_t *rule);
2131062Sigor@sysoev.ru static nxt_int_t nxt_http_route_cookies(nxt_http_request_t *r,
2141062Sigor@sysoev.ru     nxt_http_route_rule_t *rule);
2151062Sigor@sysoev.ru static nxt_array_t *nxt_http_route_cookies_parse(nxt_http_request_t *r);
2161062Sigor@sysoev.ru static nxt_int_t nxt_http_route_cookie_parse(nxt_array_t *cookies,
2171062Sigor@sysoev.ru     u_char *start, u_char *end);
2181062Sigor@sysoev.ru static nxt_http_name_value_t *nxt_http_route_cookie(nxt_array_t *array,
2191062Sigor@sysoev.ru     u_char *name, size_t name_length, u_char *start, u_char *end);
2201062Sigor@sysoev.ru static nxt_int_t nxt_http_route_test_cookie(nxt_http_request_t *r,
2211062Sigor@sysoev.ru     nxt_http_route_rule_t *rule, nxt_array_t *array);
2221060Sigor@sysoev.ru static nxt_int_t nxt_http_route_test_rule(nxt_http_request_t *r,
2231059Sigor@sysoev.ru     nxt_http_route_rule_t *rule, u_char *start, size_t length);
2241060Sigor@sysoev.ru static nxt_int_t nxt_http_route_pattern(nxt_http_request_t *r,
225964Sigor@sysoev.ru     nxt_http_route_pattern_t *pattern, u_char *start, size_t length);
2261060Sigor@sysoev.ru static nxt_int_t nxt_http_route_memcmp(u_char *start, u_char *test,
2271032Sigor@sysoev.ru     size_t length, nxt_bool_t case_sensitive);
228964Sigor@sysoev.ru 
229964Sigor@sysoev.ru 
230964Sigor@sysoev.ru nxt_http_routes_t *
231964Sigor@sysoev.ru nxt_http_routes_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
232964Sigor@sysoev.ru     nxt_conf_value_t *routes_conf)
233964Sigor@sysoev.ru {
234964Sigor@sysoev.ru     size_t             size;
235964Sigor@sysoev.ru     uint32_t           i, n, next;
236964Sigor@sysoev.ru     nxt_mp_t           *mp;
237964Sigor@sysoev.ru     nxt_str_t          name, *string;
238964Sigor@sysoev.ru     nxt_bool_t         object;
239964Sigor@sysoev.ru     nxt_conf_value_t   *route_conf;
240964Sigor@sysoev.ru     nxt_http_route_t   *route;
241964Sigor@sysoev.ru     nxt_http_routes_t  *routes;
242964Sigor@sysoev.ru 
243964Sigor@sysoev.ru     object = (nxt_conf_type(routes_conf) == NXT_CONF_OBJECT);
244964Sigor@sysoev.ru     n = object ? nxt_conf_object_members_count(routes_conf) : 1;
245964Sigor@sysoev.ru     size = sizeof(nxt_http_routes_t) + n * sizeof(nxt_http_route_t *);
246964Sigor@sysoev.ru 
247964Sigor@sysoev.ru     mp = tmcf->router_conf->mem_pool;
248964Sigor@sysoev.ru 
249964Sigor@sysoev.ru     routes = nxt_mp_alloc(mp, size);
250964Sigor@sysoev.ru     if (nxt_slow_path(routes == NULL)) {
251964Sigor@sysoev.ru         return NULL;
252964Sigor@sysoev.ru     }
253964Sigor@sysoev.ru 
254964Sigor@sysoev.ru     routes->items = n;
255964Sigor@sysoev.ru 
256964Sigor@sysoev.ru     if (object) {
257964Sigor@sysoev.ru         next = 0;
258964Sigor@sysoev.ru 
259964Sigor@sysoev.ru         for (i = 0; i < n; i++) {
260964Sigor@sysoev.ru             route_conf = nxt_conf_next_object_member(routes_conf, &name, &next);
261964Sigor@sysoev.ru 
262964Sigor@sysoev.ru             route = nxt_http_route_create(task, tmcf, route_conf);
263964Sigor@sysoev.ru             if (nxt_slow_path(route == NULL)) {
264964Sigor@sysoev.ru                 return NULL;
265964Sigor@sysoev.ru             }
266964Sigor@sysoev.ru 
267964Sigor@sysoev.ru             routes->route[i] = route;
268964Sigor@sysoev.ru 
269964Sigor@sysoev.ru             string = nxt_str_dup(mp, &route->name, &name);
270964Sigor@sysoev.ru             if (nxt_slow_path(string == NULL)) {
271964Sigor@sysoev.ru                 return NULL;
272964Sigor@sysoev.ru             }
273964Sigor@sysoev.ru         }
274964Sigor@sysoev.ru 
275964Sigor@sysoev.ru     } else {
276964Sigor@sysoev.ru         route = nxt_http_route_create(task, tmcf, routes_conf);
277964Sigor@sysoev.ru         if (nxt_slow_path(route == NULL)) {
278964Sigor@sysoev.ru             return NULL;
279964Sigor@sysoev.ru         }
280964Sigor@sysoev.ru 
281964Sigor@sysoev.ru         routes->route[0] = route;
282964Sigor@sysoev.ru 
283964Sigor@sysoev.ru         route->name.length = 0;
284964Sigor@sysoev.ru         route->name.start = NULL;
285964Sigor@sysoev.ru     }
286964Sigor@sysoev.ru 
287964Sigor@sysoev.ru     return routes;
288964Sigor@sysoev.ru }
289964Sigor@sysoev.ru 
290964Sigor@sysoev.ru 
291964Sigor@sysoev.ru static nxt_conf_map_t  nxt_http_route_match_conf[] = {
292964Sigor@sysoev.ru     {
2931110Saxel.duch@nginx.com         nxt_string("scheme"),
2941110Saxel.duch@nginx.com         NXT_CONF_MAP_PTR,
2951110Saxel.duch@nginx.com         offsetof(nxt_http_route_match_conf_t, scheme)
2961110Saxel.duch@nginx.com     },
2971110Saxel.duch@nginx.com     {
298964Sigor@sysoev.ru         nxt_string("host"),
299964Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
300964Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, host),
301964Sigor@sysoev.ru     },
302964Sigor@sysoev.ru 
303964Sigor@sysoev.ru     {
304964Sigor@sysoev.ru         nxt_string("uri"),
305964Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
306964Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, uri),
307964Sigor@sysoev.ru     },
308964Sigor@sysoev.ru 
309964Sigor@sysoev.ru     {
310964Sigor@sysoev.ru         nxt_string("method"),
311964Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
312964Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, method),
313964Sigor@sysoev.ru     },
3141059Sigor@sysoev.ru 
3151059Sigor@sysoev.ru     {
3161059Sigor@sysoev.ru         nxt_string("headers"),
3171059Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
3181059Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, headers),
3191059Sigor@sysoev.ru     },
3201061Sigor@sysoev.ru 
3211061Sigor@sysoev.ru     {
3221061Sigor@sysoev.ru         nxt_string("arguments"),
3231061Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
3241061Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, arguments),
3251061Sigor@sysoev.ru     },
3261062Sigor@sysoev.ru 
3271062Sigor@sysoev.ru     {
3281062Sigor@sysoev.ru         nxt_string("cookies"),
3291062Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
3301062Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, cookies),
3311062Sigor@sysoev.ru     },
332964Sigor@sysoev.ru };
333964Sigor@sysoev.ru 
334964Sigor@sysoev.ru 
335964Sigor@sysoev.ru static nxt_http_route_t *
336964Sigor@sysoev.ru nxt_http_route_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
337964Sigor@sysoev.ru     nxt_conf_value_t *cv)
338964Sigor@sysoev.ru {
339964Sigor@sysoev.ru     size_t                  size;
340964Sigor@sysoev.ru     uint32_t                i, n;
341964Sigor@sysoev.ru     nxt_conf_value_t        *value;
342964Sigor@sysoev.ru     nxt_http_route_t        *route;
343964Sigor@sysoev.ru     nxt_http_route_match_t  *match, **m;
344964Sigor@sysoev.ru 
345964Sigor@sysoev.ru     n = nxt_conf_array_elements_count(cv);
346964Sigor@sysoev.ru     size = sizeof(nxt_http_route_t) + n * sizeof(nxt_http_route_match_t *);
347964Sigor@sysoev.ru 
348964Sigor@sysoev.ru     route = nxt_mp_alloc(tmcf->router_conf->mem_pool, size);
349964Sigor@sysoev.ru     if (nxt_slow_path(route == NULL)) {
350964Sigor@sysoev.ru         return NULL;
351964Sigor@sysoev.ru     }
352964Sigor@sysoev.ru 
353964Sigor@sysoev.ru     route->items = n;
354964Sigor@sysoev.ru     m = &route->match[0];
355964Sigor@sysoev.ru 
356964Sigor@sysoev.ru     for (i = 0; i < n; i++) {
357964Sigor@sysoev.ru         value = nxt_conf_get_array_element(cv, i);
358964Sigor@sysoev.ru 
359964Sigor@sysoev.ru         match = nxt_http_route_match_create(task, tmcf, value);
360964Sigor@sysoev.ru         if (match == NULL) {
361964Sigor@sysoev.ru             return NULL;
362964Sigor@sysoev.ru         }
363964Sigor@sysoev.ru 
364964Sigor@sysoev.ru         *m++ = match;
365964Sigor@sysoev.ru     }
366964Sigor@sysoev.ru 
367964Sigor@sysoev.ru     return route;
368964Sigor@sysoev.ru }
369964Sigor@sysoev.ru 
370964Sigor@sysoev.ru 
371964Sigor@sysoev.ru static nxt_http_route_match_t *
372964Sigor@sysoev.ru nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
373964Sigor@sysoev.ru     nxt_conf_value_t *cv)
374964Sigor@sysoev.ru {
375964Sigor@sysoev.ru     size_t                       size;
376964Sigor@sysoev.ru     uint32_t                     n;
3771059Sigor@sysoev.ru     nxt_mp_t                     *mp;
378964Sigor@sysoev.ru     nxt_int_t                    ret;
3791264Sigor@sysoev.ru     nxt_conf_value_t             *match_conf;
3801059Sigor@sysoev.ru     nxt_http_route_test_t        *test;
3811059Sigor@sysoev.ru     nxt_http_route_rule_t        *rule;
3821059Sigor@sysoev.ru     nxt_http_route_table_t       *table;
383964Sigor@sysoev.ru     nxt_http_route_match_t       *match;
384964Sigor@sysoev.ru     nxt_http_route_match_conf_t  mtcf;
385964Sigor@sysoev.ru 
386964Sigor@sysoev.ru     static nxt_str_t  match_path = nxt_string("/match");
387964Sigor@sysoev.ru 
388964Sigor@sysoev.ru     match_conf = nxt_conf_get_path(cv, &match_path);
389964Sigor@sysoev.ru 
390964Sigor@sysoev.ru     n = (match_conf != NULL) ? nxt_conf_object_members_count(match_conf) : 0;
391964Sigor@sysoev.ru     size = sizeof(nxt_http_route_match_t) + n * sizeof(nxt_http_route_rule_t *);
392964Sigor@sysoev.ru 
3931059Sigor@sysoev.ru     mp = tmcf->router_conf->mem_pool;
3941059Sigor@sysoev.ru 
3951059Sigor@sysoev.ru     match = nxt_mp_alloc(mp, size);
396964Sigor@sysoev.ru     if (nxt_slow_path(match == NULL)) {
397964Sigor@sysoev.ru         return NULL;
398964Sigor@sysoev.ru     }
399964Sigor@sysoev.ru 
4001264Sigor@sysoev.ru     match->action.u.route = NULL;
4011264Sigor@sysoev.ru     match->action.handler = NULL;
402964Sigor@sysoev.ru     match->items = n;
403964Sigor@sysoev.ru 
4041264Sigor@sysoev.ru     ret = nxt_http_route_action_create(tmcf, cv, match);
4051264Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
406964Sigor@sysoev.ru         return NULL;
407964Sigor@sysoev.ru     }
408964Sigor@sysoev.ru 
409964Sigor@sysoev.ru     if (n == 0) {
410964Sigor@sysoev.ru         return match;
411964Sigor@sysoev.ru     }
412964Sigor@sysoev.ru 
413964Sigor@sysoev.ru     nxt_memzero(&mtcf, sizeof(mtcf));
414964Sigor@sysoev.ru 
415964Sigor@sysoev.ru     ret = nxt_conf_map_object(tmcf->mem_pool,
416964Sigor@sysoev.ru                               match_conf, nxt_http_route_match_conf,
417964Sigor@sysoev.ru                               nxt_nitems(nxt_http_route_match_conf), &mtcf);
418964Sigor@sysoev.ru     if (ret != NXT_OK) {
419964Sigor@sysoev.ru         return NULL;
420964Sigor@sysoev.ru     }
421964Sigor@sysoev.ru 
4221059Sigor@sysoev.ru     test = &match->test[0];
423964Sigor@sysoev.ru 
4241110Saxel.duch@nginx.com     if (mtcf.scheme != NULL) {
4251110Saxel.duch@nginx.com         rule = nxt_http_route_rule_create(task, mp, mtcf.scheme, 1,
4261110Saxel.duch@nginx.com                                           NXT_HTTP_ROUTE_PATTERN_NOCASE);
4271110Saxel.duch@nginx.com         if (rule == NULL) {
4281110Saxel.duch@nginx.com             return NULL;
4291110Saxel.duch@nginx.com         }
4301110Saxel.duch@nginx.com 
4311110Saxel.duch@nginx.com         rule->object = NXT_HTTP_ROUTE_SCHEME;
4321110Saxel.duch@nginx.com         test->rule = rule;
4331110Saxel.duch@nginx.com         test++;
4341110Saxel.duch@nginx.com     }
4351110Saxel.duch@nginx.com 
436964Sigor@sysoev.ru     if (mtcf.host != NULL) {
4371059Sigor@sysoev.ru         rule = nxt_http_route_rule_create(task, mp, mtcf.host, 1,
438964Sigor@sysoev.ru                                           NXT_HTTP_ROUTE_PATTERN_LOWCASE);
439964Sigor@sysoev.ru         if (rule == NULL) {
440964Sigor@sysoev.ru             return NULL;
441964Sigor@sysoev.ru         }
442964Sigor@sysoev.ru 
4431059Sigor@sysoev.ru         rule->u.offset = offsetof(nxt_http_request_t, host);
444964Sigor@sysoev.ru         rule->object = NXT_HTTP_ROUTE_STRING;
4451059Sigor@sysoev.ru         test->rule = rule;
4461059Sigor@sysoev.ru         test++;
447964Sigor@sysoev.ru     }
448964Sigor@sysoev.ru 
449964Sigor@sysoev.ru     if (mtcf.uri != NULL) {
4501059Sigor@sysoev.ru         rule = nxt_http_route_rule_create(task, mp, mtcf.uri, 1,
451964Sigor@sysoev.ru                                           NXT_HTTP_ROUTE_PATTERN_NOCASE);
452964Sigor@sysoev.ru         if (rule == NULL) {
453964Sigor@sysoev.ru             return NULL;
454964Sigor@sysoev.ru         }
455964Sigor@sysoev.ru 
4561059Sigor@sysoev.ru         rule->u.offset = offsetof(nxt_http_request_t, path);
457964Sigor@sysoev.ru         rule->object = NXT_HTTP_ROUTE_STRING_PTR;
4581059Sigor@sysoev.ru         test->rule = rule;
4591059Sigor@sysoev.ru         test++;
460964Sigor@sysoev.ru     }
461964Sigor@sysoev.ru 
462964Sigor@sysoev.ru     if (mtcf.method != NULL) {
4631059Sigor@sysoev.ru         rule = nxt_http_route_rule_create(task, mp, mtcf.method, 1,
464964Sigor@sysoev.ru                                           NXT_HTTP_ROUTE_PATTERN_UPCASE);
465964Sigor@sysoev.ru         if (rule == NULL) {
466964Sigor@sysoev.ru             return NULL;
467964Sigor@sysoev.ru         }
468964Sigor@sysoev.ru 
4691059Sigor@sysoev.ru         rule->u.offset = offsetof(nxt_http_request_t, method);
470964Sigor@sysoev.ru         rule->object = NXT_HTTP_ROUTE_STRING_PTR;
4711059Sigor@sysoev.ru         test->rule = rule;
4721059Sigor@sysoev.ru         test++;
4731059Sigor@sysoev.ru     }
4741059Sigor@sysoev.ru 
4751059Sigor@sysoev.ru     if (mtcf.headers != NULL) {
4761061Sigor@sysoev.ru         table = nxt_http_route_table_create(task, mp, mtcf.headers,
4771061Sigor@sysoev.ru                                             NXT_HTTP_ROUTE_HEADER, 0);
4781061Sigor@sysoev.ru         if (table == NULL) {
4791061Sigor@sysoev.ru             return NULL;
4801061Sigor@sysoev.ru         }
4811061Sigor@sysoev.ru 
4821061Sigor@sysoev.ru         test->table = table;
4831061Sigor@sysoev.ru         test++;
4841061Sigor@sysoev.ru     }
4851061Sigor@sysoev.ru 
4861061Sigor@sysoev.ru     if (mtcf.arguments != NULL) {
4871061Sigor@sysoev.ru         table = nxt_http_route_table_create(task, mp, mtcf.arguments,
4881061Sigor@sysoev.ru                                             NXT_HTTP_ROUTE_ARGUMENT, 1);
4891059Sigor@sysoev.ru         if (table == NULL) {
4901059Sigor@sysoev.ru             return NULL;
4911059Sigor@sysoev.ru         }
4921059Sigor@sysoev.ru 
4931059Sigor@sysoev.ru         test->table = table;
4941059Sigor@sysoev.ru         test++;
495964Sigor@sysoev.ru     }
496964Sigor@sysoev.ru 
4971062Sigor@sysoev.ru     if (mtcf.cookies != NULL) {
4981062Sigor@sysoev.ru         table = nxt_http_route_table_create(task, mp, mtcf.cookies,
4991079Sigor@sysoev.ru                                             NXT_HTTP_ROUTE_COOKIE, 1);
5001062Sigor@sysoev.ru         if (table == NULL) {
5011062Sigor@sysoev.ru             return NULL;
5021062Sigor@sysoev.ru         }
5031062Sigor@sysoev.ru 
5041062Sigor@sysoev.ru         test->table = table;
5051062Sigor@sysoev.ru         test++;
5061062Sigor@sysoev.ru     }
5071062Sigor@sysoev.ru 
508964Sigor@sysoev.ru     return match;
509964Sigor@sysoev.ru }
510964Sigor@sysoev.ru 
511964Sigor@sysoev.ru 
5121264Sigor@sysoev.ru static nxt_conf_map_t  nxt_http_route_action_conf[] = {
5131264Sigor@sysoev.ru     {
5141264Sigor@sysoev.ru         nxt_string("pass"),
5151264Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
5161264Sigor@sysoev.ru         offsetof(nxt_http_route_action_conf_t, pass)
5171264Sigor@sysoev.ru     },
5181264Sigor@sysoev.ru     {
5191264Sigor@sysoev.ru         nxt_string("share"),
5201264Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
5211264Sigor@sysoev.ru         offsetof(nxt_http_route_action_conf_t, share)
5221264Sigor@sysoev.ru     },
523*1270Sigor@sysoev.ru     {
524*1270Sigor@sysoev.ru         nxt_string("proxy"),
525*1270Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
526*1270Sigor@sysoev.ru         offsetof(nxt_http_route_action_conf_t, proxy)
527*1270Sigor@sysoev.ru     },
5281264Sigor@sysoev.ru };
5291264Sigor@sysoev.ru 
5301264Sigor@sysoev.ru 
5311264Sigor@sysoev.ru static nxt_int_t
5321264Sigor@sysoev.ru nxt_http_route_action_create(nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv,
5331264Sigor@sysoev.ru     nxt_http_route_match_t *match)
5341264Sigor@sysoev.ru {
535*1270Sigor@sysoev.ru     nxt_mp_t                      *mp;
5361264Sigor@sysoev.ru     nxt_int_t                     ret;
5371264Sigor@sysoev.ru     nxt_str_t                     name, *string;
5381264Sigor@sysoev.ru     nxt_conf_value_t              *conf, *action_conf;
5391264Sigor@sysoev.ru     nxt_http_route_action_conf_t  accf;
5401264Sigor@sysoev.ru 
5411264Sigor@sysoev.ru     static nxt_str_t  action_path = nxt_string("/action");
5421264Sigor@sysoev.ru 
5431264Sigor@sysoev.ru     action_conf = nxt_conf_get_path(cv, &action_path);
5441264Sigor@sysoev.ru     if (action_conf == NULL) {
5451264Sigor@sysoev.ru         return NXT_ERROR;
5461264Sigor@sysoev.ru     }
5471264Sigor@sysoev.ru 
5481264Sigor@sysoev.ru     nxt_memzero(&accf, sizeof(accf));
5491264Sigor@sysoev.ru 
5501264Sigor@sysoev.ru     ret = nxt_conf_map_object(tmcf->mem_pool,
5511264Sigor@sysoev.ru                               action_conf, nxt_http_route_action_conf,
5521264Sigor@sysoev.ru                               nxt_nitems(nxt_http_route_action_conf), &accf);
5531264Sigor@sysoev.ru     if (ret != NXT_OK) {
5541264Sigor@sysoev.ru         return ret;
5551264Sigor@sysoev.ru     }
5561264Sigor@sysoev.ru 
5571264Sigor@sysoev.ru     conf = accf.pass;
5581264Sigor@sysoev.ru 
5591264Sigor@sysoev.ru     if (accf.share != NULL) {
5601264Sigor@sysoev.ru         conf = accf.share;
5611264Sigor@sysoev.ru         match->action.handler = nxt_http_static_handler;
562*1270Sigor@sysoev.ru 
563*1270Sigor@sysoev.ru     } else if (accf.proxy != NULL) {
564*1270Sigor@sysoev.ru         conf = accf.proxy;
5651264Sigor@sysoev.ru     }
5661264Sigor@sysoev.ru 
5671264Sigor@sysoev.ru     nxt_conf_get_string(conf, &name);
5681264Sigor@sysoev.ru 
569*1270Sigor@sysoev.ru     mp = tmcf->router_conf->mem_pool;
570*1270Sigor@sysoev.ru 
571*1270Sigor@sysoev.ru     string = nxt_str_dup(mp, &match->action.name, &name);
5721264Sigor@sysoev.ru     if (nxt_slow_path(string == NULL)) {
5731264Sigor@sysoev.ru         return NXT_ERROR;
5741264Sigor@sysoev.ru     }
5751264Sigor@sysoev.ru 
576*1270Sigor@sysoev.ru     if (accf.proxy != NULL) {
577*1270Sigor@sysoev.ru         return nxt_http_proxy_create(mp, &match->action);
578*1270Sigor@sysoev.ru     }
579*1270Sigor@sysoev.ru 
5801264Sigor@sysoev.ru     return NXT_OK;
5811264Sigor@sysoev.ru }
5821264Sigor@sysoev.ru 
5831264Sigor@sysoev.ru 
5841059Sigor@sysoev.ru static nxt_http_route_table_t *
5851059Sigor@sysoev.ru nxt_http_route_table_create(nxt_task_t *task, nxt_mp_t *mp,
5861061Sigor@sysoev.ru     nxt_conf_value_t *table_cv, nxt_http_route_object_t object,
5871061Sigor@sysoev.ru     nxt_bool_t case_sensitive)
5881059Sigor@sysoev.ru {
5891059Sigor@sysoev.ru     size_t                    size;
5901059Sigor@sysoev.ru     uint32_t                  i, n;
5911059Sigor@sysoev.ru     nxt_bool_t                array;
5921059Sigor@sysoev.ru     nxt_conf_value_t          *ruleset_cv;
5931059Sigor@sysoev.ru     nxt_http_route_table_t    *table;
5941059Sigor@sysoev.ru     nxt_http_route_ruleset_t  *ruleset;
5951059Sigor@sysoev.ru 
5961059Sigor@sysoev.ru     array = (nxt_conf_type(table_cv) == NXT_CONF_ARRAY);
5971059Sigor@sysoev.ru     n = array ? nxt_conf_array_elements_count(table_cv) : 1;
5981059Sigor@sysoev.ru     size = sizeof(nxt_http_route_table_t)
5991059Sigor@sysoev.ru            + n * sizeof(nxt_http_route_ruleset_t *);
6001059Sigor@sysoev.ru 
6011059Sigor@sysoev.ru     table = nxt_mp_alloc(mp, size);
6021059Sigor@sysoev.ru     if (nxt_slow_path(table == NULL)) {
6031059Sigor@sysoev.ru         return NULL;
6041059Sigor@sysoev.ru     }
6051059Sigor@sysoev.ru 
6061059Sigor@sysoev.ru     table->items = n;
6071059Sigor@sysoev.ru     table->object = NXT_HTTP_ROUTE_TABLE;
6081059Sigor@sysoev.ru 
6091059Sigor@sysoev.ru     if (!array) {
6101061Sigor@sysoev.ru         ruleset = nxt_http_route_ruleset_create(task, mp, table_cv,
6111061Sigor@sysoev.ru                                                 object, case_sensitive);
6121059Sigor@sysoev.ru         if (nxt_slow_path(ruleset == NULL)) {
6131059Sigor@sysoev.ru             return NULL;
6141059Sigor@sysoev.ru         }
6151059Sigor@sysoev.ru 
6161059Sigor@sysoev.ru         table->ruleset[0] = ruleset;
6171059Sigor@sysoev.ru 
6181059Sigor@sysoev.ru         return table;
6191059Sigor@sysoev.ru     }
6201059Sigor@sysoev.ru 
6211059Sigor@sysoev.ru     for (i = 0; i < n; i++) {
6221059Sigor@sysoev.ru         ruleset_cv = nxt_conf_get_array_element(table_cv, i);
6231059Sigor@sysoev.ru 
6241061Sigor@sysoev.ru         ruleset = nxt_http_route_ruleset_create(task, mp, ruleset_cv,
6251061Sigor@sysoev.ru                                                 object, case_sensitive);
6261059Sigor@sysoev.ru         if (nxt_slow_path(ruleset == NULL)) {
6271059Sigor@sysoev.ru             return NULL;
6281059Sigor@sysoev.ru         }
6291059Sigor@sysoev.ru 
6301059Sigor@sysoev.ru         table->ruleset[i] = ruleset;
6311059Sigor@sysoev.ru     }
6321059Sigor@sysoev.ru 
6331059Sigor@sysoev.ru     return table;
6341059Sigor@sysoev.ru }
6351059Sigor@sysoev.ru 
6361059Sigor@sysoev.ru 
6371059Sigor@sysoev.ru static nxt_http_route_ruleset_t *
6381059Sigor@sysoev.ru nxt_http_route_ruleset_create(nxt_task_t *task, nxt_mp_t *mp,
6391061Sigor@sysoev.ru     nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object,
6401061Sigor@sysoev.ru     nxt_bool_t case_sensitive)
6411059Sigor@sysoev.ru {
6421059Sigor@sysoev.ru     size_t                    size;
6431059Sigor@sysoev.ru     uint32_t                  i, n, next;
6441059Sigor@sysoev.ru     nxt_str_t                 name;
6451059Sigor@sysoev.ru     nxt_conf_value_t          *rule_cv;
6461059Sigor@sysoev.ru     nxt_http_route_rule_t     *rule;
6471059Sigor@sysoev.ru     nxt_http_route_ruleset_t  *ruleset;
6481059Sigor@sysoev.ru 
6491059Sigor@sysoev.ru     n = nxt_conf_object_members_count(ruleset_cv);
6501059Sigor@sysoev.ru     size = sizeof(nxt_http_route_ruleset_t)
6511059Sigor@sysoev.ru            + n * sizeof(nxt_http_route_rule_t *);
6521059Sigor@sysoev.ru 
6531059Sigor@sysoev.ru     ruleset = nxt_mp_alloc(mp, size);
6541059Sigor@sysoev.ru     if (nxt_slow_path(ruleset == NULL)) {
6551059Sigor@sysoev.ru         return NULL;
6561059Sigor@sysoev.ru     }
6571059Sigor@sysoev.ru 
6581059Sigor@sysoev.ru     ruleset->items = n;
6591059Sigor@sysoev.ru 
6601059Sigor@sysoev.ru     next = 0;
6611059Sigor@sysoev.ru 
6621059Sigor@sysoev.ru     for (i = 0; i < n; i++) {
6631059Sigor@sysoev.ru         rule_cv = nxt_conf_next_object_member(ruleset_cv, &name, &next);
6641059Sigor@sysoev.ru 
6651061Sigor@sysoev.ru         rule = nxt_http_route_rule_name_create(task, mp, rule_cv, &name,
6661061Sigor@sysoev.ru                                                case_sensitive);
6671059Sigor@sysoev.ru         if (nxt_slow_path(rule == NULL)) {
6681059Sigor@sysoev.ru             return NULL;
6691059Sigor@sysoev.ru         }
6701059Sigor@sysoev.ru 
6711061Sigor@sysoev.ru         rule->object = object;
6721059Sigor@sysoev.ru         ruleset->rule[i] = rule;
6731059Sigor@sysoev.ru     }
6741059Sigor@sysoev.ru 
6751059Sigor@sysoev.ru     return ruleset;
6761059Sigor@sysoev.ru }
6771059Sigor@sysoev.ru 
6781059Sigor@sysoev.ru 
679964Sigor@sysoev.ru static nxt_http_route_rule_t *
6801061Sigor@sysoev.ru nxt_http_route_rule_name_create(nxt_task_t *task, nxt_mp_t *mp,
6811061Sigor@sysoev.ru     nxt_conf_value_t *rule_cv, nxt_str_t *name, nxt_bool_t case_sensitive)
6821059Sigor@sysoev.ru {
6831059Sigor@sysoev.ru     u_char                 c, *p;
6841059Sigor@sysoev.ru     uint32_t               hash;
6851059Sigor@sysoev.ru     nxt_uint_t             i;
6861059Sigor@sysoev.ru     nxt_http_route_rule_t  *rule;
6871059Sigor@sysoev.ru 
6881061Sigor@sysoev.ru     rule = nxt_http_route_rule_create(task, mp, rule_cv, case_sensitive,
6891059Sigor@sysoev.ru                                       NXT_HTTP_ROUTE_PATTERN_NOCASE);
6901059Sigor@sysoev.ru     if (nxt_slow_path(rule == NULL)) {
6911059Sigor@sysoev.ru         return NULL;
6921059Sigor@sysoev.ru     }
6931059Sigor@sysoev.ru 
6941059Sigor@sysoev.ru     rule->u.name.length = name->length;
6951059Sigor@sysoev.ru 
6961059Sigor@sysoev.ru     p = nxt_mp_nget(mp, name->length);
6971059Sigor@sysoev.ru     if (nxt_slow_path(p == NULL)) {
6981059Sigor@sysoev.ru         return NULL;
6991059Sigor@sysoev.ru     }
7001059Sigor@sysoev.ru 
7011059Sigor@sysoev.ru     rule->u.name.start = p;
7021059Sigor@sysoev.ru 
7031059Sigor@sysoev.ru     hash = NXT_HTTP_FIELD_HASH_INIT;
7041059Sigor@sysoev.ru 
7051059Sigor@sysoev.ru     for (i = 0; i < name->length; i++) {
7061059Sigor@sysoev.ru         c = name->start[i];
7071059Sigor@sysoev.ru         *p++ = c;
7081059Sigor@sysoev.ru 
7091079Sigor@sysoev.ru         c = case_sensitive ? c : nxt_lowcase(c);
7101059Sigor@sysoev.ru         hash = nxt_http_field_hash_char(hash, c);
7111059Sigor@sysoev.ru     }
7121059Sigor@sysoev.ru 
7131059Sigor@sysoev.ru     rule->u.name.hash = nxt_http_field_hash_end(hash) & 0xFFFF;
7141059Sigor@sysoev.ru 
7151059Sigor@sysoev.ru     return rule;
7161059Sigor@sysoev.ru }
7171059Sigor@sysoev.ru 
7181059Sigor@sysoev.ru 
7191059Sigor@sysoev.ru static nxt_http_route_rule_t *
7201059Sigor@sysoev.ru nxt_http_route_rule_create(nxt_task_t *task, nxt_mp_t *mp,
721964Sigor@sysoev.ru     nxt_conf_value_t *cv, nxt_bool_t case_sensitive,
722964Sigor@sysoev.ru     nxt_http_route_pattern_case_t pattern_case)
723964Sigor@sysoev.ru {
724964Sigor@sysoev.ru     size_t                    size;
725964Sigor@sysoev.ru     uint32_t                  i, n;
726964Sigor@sysoev.ru     nxt_int_t                 ret;
727964Sigor@sysoev.ru     nxt_bool_t                string;
728964Sigor@sysoev.ru     nxt_conf_value_t          *value;
729964Sigor@sysoev.ru     nxt_http_route_rule_t     *rule;
730964Sigor@sysoev.ru     nxt_http_route_pattern_t  *pattern;
731964Sigor@sysoev.ru 
732964Sigor@sysoev.ru     string = (nxt_conf_type(cv) != NXT_CONF_ARRAY);
733964Sigor@sysoev.ru     n = string ? 1 : nxt_conf_array_elements_count(cv);
734964Sigor@sysoev.ru     size = sizeof(nxt_http_route_rule_t) + n * sizeof(nxt_http_route_pattern_t);
735964Sigor@sysoev.ru 
736964Sigor@sysoev.ru     rule = nxt_mp_alloc(mp, size);
737964Sigor@sysoev.ru     if (nxt_slow_path(rule == NULL)) {
738964Sigor@sysoev.ru         return NULL;
739964Sigor@sysoev.ru     }
740964Sigor@sysoev.ru 
741964Sigor@sysoev.ru     rule->items = n;
742964Sigor@sysoev.ru 
743964Sigor@sysoev.ru     pattern = &rule->pattern[0];
744964Sigor@sysoev.ru 
745964Sigor@sysoev.ru     if (string) {
746964Sigor@sysoev.ru         pattern[0].case_sensitive = case_sensitive;
747964Sigor@sysoev.ru         ret = nxt_http_route_pattern_create(task, mp, cv, &pattern[0],
748964Sigor@sysoev.ru                                             pattern_case);
749964Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
750964Sigor@sysoev.ru             return NULL;
751964Sigor@sysoev.ru         }
752964Sigor@sysoev.ru 
753964Sigor@sysoev.ru         return rule;
754964Sigor@sysoev.ru     }
755964Sigor@sysoev.ru 
756964Sigor@sysoev.ru     nxt_conf_array_qsort(cv, nxt_http_pattern_compare);
757964Sigor@sysoev.ru 
758964Sigor@sysoev.ru     for (i = 0; i < n; i++) {
759964Sigor@sysoev.ru         pattern[i].case_sensitive = case_sensitive;
760964Sigor@sysoev.ru         value = nxt_conf_get_array_element(cv, i);
761964Sigor@sysoev.ru 
762964Sigor@sysoev.ru         ret = nxt_http_route_pattern_create(task, mp, value, &pattern[i],
763964Sigor@sysoev.ru                                             pattern_case);
764964Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
765964Sigor@sysoev.ru             return NULL;
766964Sigor@sysoev.ru         }
767964Sigor@sysoev.ru     }
768964Sigor@sysoev.ru 
769964Sigor@sysoev.ru     return rule;
770964Sigor@sysoev.ru }
771964Sigor@sysoev.ru 
772964Sigor@sysoev.ru 
773964Sigor@sysoev.ru static int
774964Sigor@sysoev.ru nxt_http_pattern_compare(const void *one, const void *two)
775964Sigor@sysoev.ru {
776964Sigor@sysoev.ru     nxt_str_t         test;
777964Sigor@sysoev.ru     nxt_bool_t        negative1, negative2;
778964Sigor@sysoev.ru     nxt_conf_value_t  *value;
779964Sigor@sysoev.ru 
780964Sigor@sysoev.ru     value = (nxt_conf_value_t *) one;
781964Sigor@sysoev.ru     nxt_conf_get_string(value, &test);
782964Sigor@sysoev.ru     negative1 = (test.length != 0 && test.start[0] == '!');
783964Sigor@sysoev.ru 
784964Sigor@sysoev.ru     value = (nxt_conf_value_t *) two;
785964Sigor@sysoev.ru     nxt_conf_get_string(value, &test);
786964Sigor@sysoev.ru     negative2 = (test.length != 0 && test.start[0] == '!');
787964Sigor@sysoev.ru 
788964Sigor@sysoev.ru     return (negative2 - negative1);
789964Sigor@sysoev.ru }
790964Sigor@sysoev.ru 
791964Sigor@sysoev.ru 
792964Sigor@sysoev.ru static nxt_int_t
793964Sigor@sysoev.ru nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp,
794964Sigor@sysoev.ru     nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern,
795964Sigor@sysoev.ru     nxt_http_route_pattern_case_t pattern_case)
796964Sigor@sysoev.ru {
797964Sigor@sysoev.ru     u_char                         *start;
798964Sigor@sysoev.ru     nxt_str_t                      test;
7991032Sigor@sysoev.ru     nxt_uint_t                     n, length;
800964Sigor@sysoev.ru     nxt_http_route_pattern_type_t  type;
801964Sigor@sysoev.ru 
8021032Sigor@sysoev.ru     /* Suppress warning about uninitialized variable. */
8031032Sigor@sysoev.ru     length = 0;
8041032Sigor@sysoev.ru 
805964Sigor@sysoev.ru     type = NXT_HTTP_ROUTE_PATTERN_EXACT;
806964Sigor@sysoev.ru 
807964Sigor@sysoev.ru     nxt_conf_get_string(cv, &test);
808964Sigor@sysoev.ru 
809964Sigor@sysoev.ru     pattern->negative = 0;
810964Sigor@sysoev.ru     pattern->any = 1;
811964Sigor@sysoev.ru 
812964Sigor@sysoev.ru     if (test.length != 0) {
813964Sigor@sysoev.ru 
814964Sigor@sysoev.ru         if (test.start[0] == '!') {
815964Sigor@sysoev.ru             test.start++;
816964Sigor@sysoev.ru             test.length--;
817964Sigor@sysoev.ru 
818964Sigor@sysoev.ru             pattern->negative = 1;
819964Sigor@sysoev.ru             pattern->any = 0;
820964Sigor@sysoev.ru         }
821964Sigor@sysoev.ru 
822964Sigor@sysoev.ru         if (test.length != 0) {
823964Sigor@sysoev.ru 
824964Sigor@sysoev.ru             if (test.start[0] == '*') {
825964Sigor@sysoev.ru                 test.start++;
826964Sigor@sysoev.ru                 test.length--;
827964Sigor@sysoev.ru 
828964Sigor@sysoev.ru                 if (test.length != 0) {
829964Sigor@sysoev.ru                     if (test.start[test.length - 1] == '*') {
830964Sigor@sysoev.ru                         test.length--;
831964Sigor@sysoev.ru                         type = NXT_HTTP_ROUTE_PATTERN_SUBSTRING;
832964Sigor@sysoev.ru 
833964Sigor@sysoev.ru                     } else {
834964Sigor@sysoev.ru                         type = NXT_HTTP_ROUTE_PATTERN_END;
835964Sigor@sysoev.ru                     }
836964Sigor@sysoev.ru 
837964Sigor@sysoev.ru                 } else {
838964Sigor@sysoev.ru                     type = NXT_HTTP_ROUTE_PATTERN_BEGIN;
839964Sigor@sysoev.ru                 }
840964Sigor@sysoev.ru 
841964Sigor@sysoev.ru             } else if (test.start[test.length - 1] == '*') {
842964Sigor@sysoev.ru                 test.length--;
843964Sigor@sysoev.ru                 type = NXT_HTTP_ROUTE_PATTERN_BEGIN;
8441032Sigor@sysoev.ru 
8451032Sigor@sysoev.ru             } else {
8461032Sigor@sysoev.ru                 length = test.length - 1;
8471032Sigor@sysoev.ru 
8481032Sigor@sysoev.ru                 for (n = 1; n < length; n++) {
8491032Sigor@sysoev.ru                     if (test.start[n] == '*') {
8501032Sigor@sysoev.ru                         test.length = n;
8511032Sigor@sysoev.ru                         type = NXT_HTTP_ROUTE_PATTERN_MIDDLE;
8521032Sigor@sysoev.ru                         break;
8531032Sigor@sysoev.ru                     }
8541032Sigor@sysoev.ru                 }
855964Sigor@sysoev.ru             }
856964Sigor@sysoev.ru         }
857964Sigor@sysoev.ru     }
858964Sigor@sysoev.ru 
859964Sigor@sysoev.ru     pattern->type = type;
860964Sigor@sysoev.ru     pattern->min_length = test.length;
8611032Sigor@sysoev.ru     pattern->length1 = test.length;
862964Sigor@sysoev.ru 
8631032Sigor@sysoev.ru     start = nxt_http_route_pattern_copy(mp, &test, pattern_case);
864964Sigor@sysoev.ru     if (nxt_slow_path(start == NULL)) {
865964Sigor@sysoev.ru         return NXT_ERROR;
866964Sigor@sysoev.ru     }
867964Sigor@sysoev.ru 
8681032Sigor@sysoev.ru     pattern->start1 = start;
8691032Sigor@sysoev.ru 
8701032Sigor@sysoev.ru     if (type == NXT_HTTP_ROUTE_PATTERN_MIDDLE) {
8711032Sigor@sysoev.ru         length -= test.length;
8721032Sigor@sysoev.ru         pattern->length2 = length;
8731032Sigor@sysoev.ru         pattern->min_length += length;
8741032Sigor@sysoev.ru 
8751032Sigor@sysoev.ru         test.start = &test.start[test.length + 1];
8761032Sigor@sysoev.ru         test.length = length;
8771032Sigor@sysoev.ru 
8781032Sigor@sysoev.ru         start = nxt_http_route_pattern_copy(mp, &test, pattern_case);
8791032Sigor@sysoev.ru         if (nxt_slow_path(start == NULL)) {
8801032Sigor@sysoev.ru             return NXT_ERROR;
8811032Sigor@sysoev.ru         }
8821032Sigor@sysoev.ru 
8831032Sigor@sysoev.ru         pattern->start2 = start;
8841032Sigor@sysoev.ru     }
8851032Sigor@sysoev.ru 
8861032Sigor@sysoev.ru     return NXT_OK;
8871032Sigor@sysoev.ru }
8881032Sigor@sysoev.ru 
8891032Sigor@sysoev.ru 
8901032Sigor@sysoev.ru static u_char *
8911032Sigor@sysoev.ru nxt_http_route_pattern_copy(nxt_mp_t *mp, nxt_str_t *test,
8921032Sigor@sysoev.ru     nxt_http_route_pattern_case_t pattern_case)
8931032Sigor@sysoev.ru {
8941032Sigor@sysoev.ru     u_char  *start;
8951032Sigor@sysoev.ru 
8961032Sigor@sysoev.ru     start = nxt_mp_nget(mp, test->length);
8971032Sigor@sysoev.ru     if (nxt_slow_path(start == NULL)) {
8981032Sigor@sysoev.ru         return start;
8991032Sigor@sysoev.ru     }
900964Sigor@sysoev.ru 
901964Sigor@sysoev.ru     switch (pattern_case) {
902964Sigor@sysoev.ru 
903964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_UPCASE:
9041032Sigor@sysoev.ru         nxt_memcpy_upcase(start, test->start, test->length);
905964Sigor@sysoev.ru         break;
906964Sigor@sysoev.ru 
907964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_LOWCASE:
9081032Sigor@sysoev.ru         nxt_memcpy_lowcase(start, test->start, test->length);
909964Sigor@sysoev.ru         break;
910964Sigor@sysoev.ru 
911964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_NOCASE:
9121032Sigor@sysoev.ru         nxt_memcpy(start, test->start, test->length);
913964Sigor@sysoev.ru         break;
914964Sigor@sysoev.ru     }
915964Sigor@sysoev.ru 
9161032Sigor@sysoev.ru     return start;
917964Sigor@sysoev.ru }
918964Sigor@sysoev.ru 
919964Sigor@sysoev.ru 
920964Sigor@sysoev.ru void
921964Sigor@sysoev.ru nxt_http_routes_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
922964Sigor@sysoev.ru {
9231033Svbart@nginx.com     nxt_http_route_t   **route, **end;
924964Sigor@sysoev.ru     nxt_http_routes_t  *routes;
925964Sigor@sysoev.ru 
926964Sigor@sysoev.ru     routes = tmcf->router_conf->routes;
9271059Sigor@sysoev.ru 
928964Sigor@sysoev.ru     if (routes != NULL) {
929964Sigor@sysoev.ru         route = &routes->route[0];
9301033Svbart@nginx.com         end = route + routes->items;
931964Sigor@sysoev.ru 
9321033Svbart@nginx.com         while (route < end) {
933964Sigor@sysoev.ru             nxt_http_route_resolve(task, tmcf, *route);
934964Sigor@sysoev.ru 
935964Sigor@sysoev.ru             route++;
936964Sigor@sysoev.ru         }
937964Sigor@sysoev.ru     }
938964Sigor@sysoev.ru }
939964Sigor@sysoev.ru 
940964Sigor@sysoev.ru 
941964Sigor@sysoev.ru static void
942964Sigor@sysoev.ru nxt_http_route_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
943964Sigor@sysoev.ru     nxt_http_route_t *route)
944964Sigor@sysoev.ru {
9451264Sigor@sysoev.ru     nxt_http_action_t       *action;
9461033Svbart@nginx.com     nxt_http_route_match_t  **match, **end;
947964Sigor@sysoev.ru 
948964Sigor@sysoev.ru     match = &route->match[0];
9491033Svbart@nginx.com     end = match + route->items;
950964Sigor@sysoev.ru 
9511033Svbart@nginx.com     while (match < end) {
9521264Sigor@sysoev.ru         action = &(*match)->action;
9531183Svbart@nginx.com 
9541264Sigor@sysoev.ru         if (action->handler == NULL) {
9551264Sigor@sysoev.ru             nxt_http_action_resolve(task, tmcf, &(*match)->action);
9561183Svbart@nginx.com         }
957964Sigor@sysoev.ru 
958964Sigor@sysoev.ru         match++;
959964Sigor@sysoev.ru     }
960964Sigor@sysoev.ru }
961964Sigor@sysoev.ru 
962964Sigor@sysoev.ru 
963964Sigor@sysoev.ru static void
9641264Sigor@sysoev.ru nxt_http_action_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
9651264Sigor@sysoev.ru     nxt_http_action_t *action)
966964Sigor@sysoev.ru {
967964Sigor@sysoev.ru     nxt_str_t  name;
968964Sigor@sysoev.ru 
9691264Sigor@sysoev.ru     name = action->name;
970964Sigor@sysoev.ru 
971964Sigor@sysoev.ru     if (nxt_str_start(&name, "applications/", 13)) {
972964Sigor@sysoev.ru         name.length -= 13;
973964Sigor@sysoev.ru         name.start += 13;
974964Sigor@sysoev.ru 
9751264Sigor@sysoev.ru         action->u.application = nxt_router_listener_application(tmcf, &name);
9761264Sigor@sysoev.ru         nxt_router_app_use(task, action->u.application, 1);
977964Sigor@sysoev.ru 
9781264Sigor@sysoev.ru         action->handler = nxt_http_application_handler;
979964Sigor@sysoev.ru 
980964Sigor@sysoev.ru     } else if (nxt_str_start(&name, "routes", 6)) {
981964Sigor@sysoev.ru 
982964Sigor@sysoev.ru         if (name.length == 6) {
983964Sigor@sysoev.ru             name.length = 0;
984964Sigor@sysoev.ru             name.start = NULL;
985964Sigor@sysoev.ru 
986964Sigor@sysoev.ru         } else if (name.start[6] == '/') {
987964Sigor@sysoev.ru             name.length -= 7;
988964Sigor@sysoev.ru             name.start += 7;
989964Sigor@sysoev.ru         }
990964Sigor@sysoev.ru 
9911264Sigor@sysoev.ru         action->u.route = nxt_http_route_find(tmcf->router_conf->routes, &name);
992964Sigor@sysoev.ru 
9931264Sigor@sysoev.ru         action->handler = nxt_http_route_handler;
994964Sigor@sysoev.ru     }
995964Sigor@sysoev.ru }
996964Sigor@sysoev.ru 
997964Sigor@sysoev.ru 
998964Sigor@sysoev.ru static nxt_http_route_t *
999964Sigor@sysoev.ru nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name)
1000964Sigor@sysoev.ru {
10011033Svbart@nginx.com     nxt_http_route_t  **route, **end;
1002964Sigor@sysoev.ru 
1003964Sigor@sysoev.ru     route = &routes->route[0];
10041033Svbart@nginx.com     end = route + routes->items;
1005964Sigor@sysoev.ru 
10061058Sigor@sysoev.ru     while (route < end) {
1007964Sigor@sysoev.ru         if (nxt_strstr_eq(&(*route)->name, name)) {
1008964Sigor@sysoev.ru             return *route;
1009964Sigor@sysoev.ru         }
1010964Sigor@sysoev.ru 
1011964Sigor@sysoev.ru         route++;
10121058Sigor@sysoev.ru     }
1013964Sigor@sysoev.ru 
1014964Sigor@sysoev.ru     return NULL;
1015964Sigor@sysoev.ru }
1016964Sigor@sysoev.ru 
1017964Sigor@sysoev.ru 
10181264Sigor@sysoev.ru nxt_http_action_t *
10191264Sigor@sysoev.ru nxt_http_action_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1020964Sigor@sysoev.ru     nxt_str_t *name)
1021964Sigor@sysoev.ru {
10221264Sigor@sysoev.ru     nxt_http_action_t  *action;
1023964Sigor@sysoev.ru 
10241264Sigor@sysoev.ru     action = nxt_mp_alloc(tmcf->router_conf->mem_pool,
10251264Sigor@sysoev.ru                           sizeof(nxt_http_action_t));
10261264Sigor@sysoev.ru     if (nxt_slow_path(action == NULL)) {
1027964Sigor@sysoev.ru         return NULL;
1028964Sigor@sysoev.ru     }
1029964Sigor@sysoev.ru 
10301264Sigor@sysoev.ru     action->name = *name;
1031*1270Sigor@sysoev.ru     action->handler = NULL;
1032964Sigor@sysoev.ru 
10331264Sigor@sysoev.ru     nxt_http_action_resolve(task, tmcf, action);
1034964Sigor@sysoev.ru 
10351264Sigor@sysoev.ru     return action;
1036964Sigor@sysoev.ru }
1037964Sigor@sysoev.ru 
1038964Sigor@sysoev.ru 
1039964Sigor@sysoev.ru /* COMPATIBILITY: listener application. */
1040964Sigor@sysoev.ru 
10411264Sigor@sysoev.ru nxt_http_action_t *
1042964Sigor@sysoev.ru nxt_http_pass_application(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1043964Sigor@sysoev.ru     nxt_str_t *name)
1044964Sigor@sysoev.ru {
10451264Sigor@sysoev.ru     nxt_http_action_t  *action;
1046964Sigor@sysoev.ru 
10471264Sigor@sysoev.ru     action = nxt_mp_alloc(tmcf->router_conf->mem_pool,
10481264Sigor@sysoev.ru                           sizeof(nxt_http_action_t));
10491264Sigor@sysoev.ru     if (nxt_slow_path(action == NULL)) {
1050964Sigor@sysoev.ru         return NULL;
1051964Sigor@sysoev.ru     }
1052964Sigor@sysoev.ru 
10531264Sigor@sysoev.ru     action->name = *name;
1054964Sigor@sysoev.ru 
10551264Sigor@sysoev.ru     action->u.application = nxt_router_listener_application(tmcf, name);
10561264Sigor@sysoev.ru     nxt_router_app_use(task, action->u.application, 1);
1057964Sigor@sysoev.ru 
10581264Sigor@sysoev.ru     action->handler = nxt_http_application_handler;
1059964Sigor@sysoev.ru 
10601264Sigor@sysoev.ru     return action;
1061964Sigor@sysoev.ru }
1062964Sigor@sysoev.ru 
1063964Sigor@sysoev.ru 
1064964Sigor@sysoev.ru void
1065964Sigor@sysoev.ru nxt_http_routes_cleanup(nxt_task_t *task, nxt_http_routes_t *routes)
1066964Sigor@sysoev.ru {
10671033Svbart@nginx.com     nxt_http_route_t  **route, **end;
1068964Sigor@sysoev.ru 
1069964Sigor@sysoev.ru     if (routes != NULL) {
1070964Sigor@sysoev.ru         route = &routes->route[0];
10711033Svbart@nginx.com         end = route + routes->items;
1072964Sigor@sysoev.ru 
10731058Sigor@sysoev.ru         while (route < end) {
1074964Sigor@sysoev.ru             nxt_http_route_cleanup(task, *route);
1075964Sigor@sysoev.ru 
1076964Sigor@sysoev.ru             route++;
10771058Sigor@sysoev.ru         }
1078964Sigor@sysoev.ru     }
1079964Sigor@sysoev.ru }
1080964Sigor@sysoev.ru 
1081964Sigor@sysoev.ru 
1082964Sigor@sysoev.ru static void
1083964Sigor@sysoev.ru nxt_http_route_cleanup(nxt_task_t *task, nxt_http_route_t *route)
1084964Sigor@sysoev.ru {
10851033Svbart@nginx.com     nxt_http_route_match_t  **match, **end;
1086964Sigor@sysoev.ru 
1087964Sigor@sysoev.ru     match = &route->match[0];
10881033Svbart@nginx.com     end = match + route->items;
1089964Sigor@sysoev.ru 
10901058Sigor@sysoev.ru     while (match < end) {
10911264Sigor@sysoev.ru         nxt_http_action_cleanup(task, &(*match)->action);
1092964Sigor@sysoev.ru 
1093964Sigor@sysoev.ru         match++;
10941058Sigor@sysoev.ru     }
1095964Sigor@sysoev.ru }
1096964Sigor@sysoev.ru 
1097964Sigor@sysoev.ru 
1098964Sigor@sysoev.ru void
10991264Sigor@sysoev.ru nxt_http_action_cleanup(nxt_task_t *task, nxt_http_action_t *action)
1100964Sigor@sysoev.ru {
11011264Sigor@sysoev.ru     if (action->handler == nxt_http_application_handler) {
11021264Sigor@sysoev.ru         nxt_router_app_use(task, action->u.application, -1);
1103964Sigor@sysoev.ru     }
1104964Sigor@sysoev.ru }
1105964Sigor@sysoev.ru 
1106964Sigor@sysoev.ru 
11071264Sigor@sysoev.ru static nxt_http_action_t *
11081264Sigor@sysoev.ru nxt_http_route_handler(nxt_task_t *task, nxt_http_request_t *r,
11091264Sigor@sysoev.ru     nxt_http_action_t *start)
1110964Sigor@sysoev.ru {
1111964Sigor@sysoev.ru     nxt_http_route_t        *route;
11121264Sigor@sysoev.ru     nxt_http_action_t       *action;
11131033Svbart@nginx.com     nxt_http_route_match_t  **match, **end;
1114964Sigor@sysoev.ru 
1115964Sigor@sysoev.ru     route = start->u.route;
1116964Sigor@sysoev.ru     match = &route->match[0];
11171033Svbart@nginx.com     end = match + route->items;
1118964Sigor@sysoev.ru 
11191033Svbart@nginx.com     while (match < end) {
11201264Sigor@sysoev.ru         action = nxt_http_route_match(r, *match);
11211264Sigor@sysoev.ru         if (action != NULL) {
11221264Sigor@sysoev.ru             return action;
1123964Sigor@sysoev.ru         }
1124964Sigor@sysoev.ru 
1125964Sigor@sysoev.ru         match++;
1126964Sigor@sysoev.ru     }
1127964Sigor@sysoev.ru 
1128964Sigor@sysoev.ru     nxt_http_request_error(task, r, NXT_HTTP_NOT_FOUND);
1129964Sigor@sysoev.ru 
1130964Sigor@sysoev.ru     return NULL;
1131964Sigor@sysoev.ru }
1132964Sigor@sysoev.ru 
1133964Sigor@sysoev.ru 
11341264Sigor@sysoev.ru static nxt_http_action_t *
1135964Sigor@sysoev.ru nxt_http_route_match(nxt_http_request_t *r, nxt_http_route_match_t *match)
1136964Sigor@sysoev.ru {
11371060Sigor@sysoev.ru     nxt_int_t              ret;
11381059Sigor@sysoev.ru     nxt_http_route_test_t  *test, *end;
11391059Sigor@sysoev.ru 
11401059Sigor@sysoev.ru     test = &match->test[0];
11411059Sigor@sysoev.ru     end = test + match->items;
1142964Sigor@sysoev.ru 
11431059Sigor@sysoev.ru     while (test < end) {
11441059Sigor@sysoev.ru         if (test->rule->object != NXT_HTTP_ROUTE_TABLE) {
11451059Sigor@sysoev.ru             ret = nxt_http_route_rule(r, test->rule);
1146964Sigor@sysoev.ru 
11471059Sigor@sysoev.ru         } else {
11481059Sigor@sysoev.ru             ret = nxt_http_route_table(r, test->table);
11491059Sigor@sysoev.ru         }
11501059Sigor@sysoev.ru 
11511060Sigor@sysoev.ru         if (ret <= 0) {
11521264Sigor@sysoev.ru             /* 0 => NULL, -1 => NXT_HTTP_ACTION_ERROR. */
11531264Sigor@sysoev.ru             return (nxt_http_action_t *) (intptr_t) ret;
1154964Sigor@sysoev.ru         }
1155964Sigor@sysoev.ru 
11561059Sigor@sysoev.ru         test++;
1157964Sigor@sysoev.ru     }
1158964Sigor@sysoev.ru 
11591264Sigor@sysoev.ru     return &match->action;
1160964Sigor@sysoev.ru }
1161964Sigor@sysoev.ru 
1162964Sigor@sysoev.ru 
11631060Sigor@sysoev.ru static nxt_int_t
11641059Sigor@sysoev.ru nxt_http_route_table(nxt_http_request_t *r, nxt_http_route_table_t *table)
1165964Sigor@sysoev.ru {
11661060Sigor@sysoev.ru     nxt_int_t                 ret;
11671059Sigor@sysoev.ru     nxt_http_route_ruleset_t  **ruleset, **end;
11681059Sigor@sysoev.ru 
11691059Sigor@sysoev.ru     ret = 1;
11701059Sigor@sysoev.ru     ruleset = &table->ruleset[0];
11711059Sigor@sysoev.ru     end = ruleset + table->items;
11721059Sigor@sysoev.ru 
11731059Sigor@sysoev.ru     while (ruleset < end) {
11741059Sigor@sysoev.ru         ret = nxt_http_route_ruleset(r, *ruleset);
11751059Sigor@sysoev.ru 
11761060Sigor@sysoev.ru         if (ret != 0) {
11771059Sigor@sysoev.ru             return ret;
11781059Sigor@sysoev.ru         }
1179964Sigor@sysoev.ru 
11801059Sigor@sysoev.ru         ruleset++;
11811059Sigor@sysoev.ru     }
11821059Sigor@sysoev.ru 
11831059Sigor@sysoev.ru     return ret;
11841059Sigor@sysoev.ru }
11851059Sigor@sysoev.ru 
1186964Sigor@sysoev.ru 
11871060Sigor@sysoev.ru static nxt_int_t
11881059Sigor@sysoev.ru nxt_http_route_ruleset(nxt_http_request_t *r, nxt_http_route_ruleset_t *ruleset)
11891059Sigor@sysoev.ru {
11901060Sigor@sysoev.ru     nxt_int_t              ret;
11911059Sigor@sysoev.ru     nxt_http_route_rule_t  **rule, **end;
1192964Sigor@sysoev.ru 
11931059Sigor@sysoev.ru     rule = &ruleset->rule[0];
11941059Sigor@sysoev.ru     end = rule + ruleset->items;
1195964Sigor@sysoev.ru 
11961059Sigor@sysoev.ru     while (rule < end) {
11971060Sigor@sysoev.ru         ret = nxt_http_route_rule(r, *rule);
11981060Sigor@sysoev.ru 
11991060Sigor@sysoev.ru         if (ret <= 0) {
12001060Sigor@sysoev.ru             return ret;
1201964Sigor@sysoev.ru         }
1202964Sigor@sysoev.ru 
12031059Sigor@sysoev.ru         rule++;
12041059Sigor@sysoev.ru     }
12051059Sigor@sysoev.ru 
12061059Sigor@sysoev.ru     return 1;
12071059Sigor@sysoev.ru }
12081059Sigor@sysoev.ru 
1209964Sigor@sysoev.ru 
12101060Sigor@sysoev.ru static nxt_int_t
12111059Sigor@sysoev.ru nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
12121059Sigor@sysoev.ru {
12131059Sigor@sysoev.ru     void       *p, **pp;
12141059Sigor@sysoev.ru     u_char     *start;
12151059Sigor@sysoev.ru     size_t     length;
12161059Sigor@sysoev.ru     nxt_str_t  *s;
12171059Sigor@sysoev.ru 
12181059Sigor@sysoev.ru     switch (rule->object) {
12191059Sigor@sysoev.ru 
12201059Sigor@sysoev.ru     case NXT_HTTP_ROUTE_HEADER:
12211059Sigor@sysoev.ru         return nxt_http_route_header(r, rule);
1222964Sigor@sysoev.ru 
12231059Sigor@sysoev.ru     case NXT_HTTP_ROUTE_ARGUMENT:
12241061Sigor@sysoev.ru         return nxt_http_route_arguments(r, rule);
1225964Sigor@sysoev.ru 
12261059Sigor@sysoev.ru     case NXT_HTTP_ROUTE_COOKIE:
12271062Sigor@sysoev.ru         return nxt_http_route_cookies(r, rule);
12281059Sigor@sysoev.ru 
12291110Saxel.duch@nginx.com     case NXT_HTTP_ROUTE_SCHEME:
12301110Saxel.duch@nginx.com         return nxt_http_route_scheme(r, rule);
12311110Saxel.duch@nginx.com 
12321059Sigor@sysoev.ru     default:
12331059Sigor@sysoev.ru         break;
12341059Sigor@sysoev.ru     }
1235964Sigor@sysoev.ru 
12361059Sigor@sysoev.ru     p = nxt_pointer_to(r, rule->u.offset);
12371059Sigor@sysoev.ru 
12381059Sigor@sysoev.ru     if (rule->object == NXT_HTTP_ROUTE_STRING) {
12391059Sigor@sysoev.ru         s = p;
1240964Sigor@sysoev.ru 
12411059Sigor@sysoev.ru     } else {
12421059Sigor@sysoev.ru         /* NXT_HTTP_ROUTE_STRING_PTR */
12431059Sigor@sysoev.ru         pp = p;
12441059Sigor@sysoev.ru         s = *pp;
1245964Sigor@sysoev.ru 
12461059Sigor@sysoev.ru         if (s == NULL) {
1247964Sigor@sysoev.ru             return 0;
1248964Sigor@sysoev.ru         }
1249964Sigor@sysoev.ru     }
1250964Sigor@sysoev.ru 
12511059Sigor@sysoev.ru     length = s->length;
12521059Sigor@sysoev.ru     start = s->start;
12531059Sigor@sysoev.ru 
12541059Sigor@sysoev.ru     return nxt_http_route_test_rule(r, rule, start, length);
12551059Sigor@sysoev.ru }
12561059Sigor@sysoev.ru 
12571059Sigor@sysoev.ru 
12581060Sigor@sysoev.ru static nxt_int_t
12591059Sigor@sysoev.ru nxt_http_route_header(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
12601059Sigor@sysoev.ru {
12611060Sigor@sysoev.ru     nxt_int_t         ret;
12621059Sigor@sysoev.ru     nxt_http_field_t  *f;
12631059Sigor@sysoev.ru 
12641059Sigor@sysoev.ru     ret = 0;
12651059Sigor@sysoev.ru 
12661059Sigor@sysoev.ru     nxt_list_each(f, r->fields) {
12671059Sigor@sysoev.ru 
12681059Sigor@sysoev.ru         if (rule->u.name.hash != f->hash
12691059Sigor@sysoev.ru             || rule->u.name.length != f->name_length
12701059Sigor@sysoev.ru             || nxt_strncasecmp(rule->u.name.start, f->name, f->name_length)
12711059Sigor@sysoev.ru                != 0)
12721059Sigor@sysoev.ru         {
12731059Sigor@sysoev.ru             continue;
12741059Sigor@sysoev.ru         }
12751059Sigor@sysoev.ru 
12761059Sigor@sysoev.ru         ret = nxt_http_route_test_rule(r, rule, f->value, f->value_length);
12771059Sigor@sysoev.ru 
12781060Sigor@sysoev.ru         if (ret == 0) {
12791059Sigor@sysoev.ru             return ret;
12801059Sigor@sysoev.ru         }
12811059Sigor@sysoev.ru 
12821059Sigor@sysoev.ru     } nxt_list_loop;
12831059Sigor@sysoev.ru 
12841059Sigor@sysoev.ru     return ret;
12851059Sigor@sysoev.ru }
12861059Sigor@sysoev.ru 
12871059Sigor@sysoev.ru 
12881060Sigor@sysoev.ru static nxt_int_t
12891061Sigor@sysoev.ru nxt_http_route_arguments(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
12901061Sigor@sysoev.ru {
12911061Sigor@sysoev.ru     nxt_array_t  *arguments;
12921061Sigor@sysoev.ru 
12931061Sigor@sysoev.ru     if (r->args == NULL) {
12941061Sigor@sysoev.ru         return 0;
12951061Sigor@sysoev.ru     }
12961061Sigor@sysoev.ru 
12971061Sigor@sysoev.ru     arguments = nxt_http_route_arguments_parse(r);
12981061Sigor@sysoev.ru     if (nxt_slow_path(arguments == NULL)) {
12991061Sigor@sysoev.ru         return -1;
13001061Sigor@sysoev.ru     }
13011061Sigor@sysoev.ru 
13021061Sigor@sysoev.ru     return nxt_http_route_test_argument(r, rule, arguments);
13031061Sigor@sysoev.ru }
13041061Sigor@sysoev.ru 
13051061Sigor@sysoev.ru 
13061061Sigor@sysoev.ru static nxt_array_t *
13071061Sigor@sysoev.ru nxt_http_route_arguments_parse(nxt_http_request_t *r)
13081061Sigor@sysoev.ru {
13091061Sigor@sysoev.ru     size_t                 name_length;
13101061Sigor@sysoev.ru     u_char                 c, *p, *start, *end, *name;
13111061Sigor@sysoev.ru     uint32_t               hash;
13121061Sigor@sysoev.ru     nxt_bool_t             valid;
13131061Sigor@sysoev.ru     nxt_array_t            *args;
13141061Sigor@sysoev.ru     nxt_http_name_value_t  *nv;
13151061Sigor@sysoev.ru 
13161061Sigor@sysoev.ru     if (r->arguments != NULL) {
13171061Sigor@sysoev.ru         return r->arguments;
13181061Sigor@sysoev.ru     }
13191061Sigor@sysoev.ru 
13201061Sigor@sysoev.ru     args = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t));
13211061Sigor@sysoev.ru     if (nxt_slow_path(args == NULL)) {
13221061Sigor@sysoev.ru         return NULL;
13231061Sigor@sysoev.ru     }
13241061Sigor@sysoev.ru 
13251061Sigor@sysoev.ru     hash = NXT_HTTP_FIELD_HASH_INIT;
13261061Sigor@sysoev.ru     valid = 1;
13271061Sigor@sysoev.ru     name = NULL;
13281061Sigor@sysoev.ru     name_length = 0;
13291061Sigor@sysoev.ru 
13301061Sigor@sysoev.ru     start = r->args->start;
13311061Sigor@sysoev.ru     end = start + r->args->length;
13321061Sigor@sysoev.ru 
13331061Sigor@sysoev.ru     for (p = start; p < end; p++) {
13341061Sigor@sysoev.ru         c = *p;
13351061Sigor@sysoev.ru 
13361061Sigor@sysoev.ru         if (c == '=') {
13371061Sigor@sysoev.ru             name_length = p - start;
13381061Sigor@sysoev.ru             name = start;
13391061Sigor@sysoev.ru             start = p + 1;
13401061Sigor@sysoev.ru             valid = (name_length != 0);
13411061Sigor@sysoev.ru 
13421061Sigor@sysoev.ru         } else if (c == '&') {
13431061Sigor@sysoev.ru             if (valid) {
13441061Sigor@sysoev.ru                 nv = nxt_http_route_argument(args, name, name_length, hash,
13451061Sigor@sysoev.ru                                              start, p);
13461061Sigor@sysoev.ru                 if (nxt_slow_path(nv == NULL)) {
13471061Sigor@sysoev.ru                     return NULL;
13481061Sigor@sysoev.ru                 }
13491061Sigor@sysoev.ru             }
13501061Sigor@sysoev.ru 
13511061Sigor@sysoev.ru             hash = NXT_HTTP_FIELD_HASH_INIT;
13521061Sigor@sysoev.ru             valid = 1;
13531061Sigor@sysoev.ru             name = NULL;
13541061Sigor@sysoev.ru             start = p + 1;
13551061Sigor@sysoev.ru 
13561061Sigor@sysoev.ru         } else if (name == NULL) {
13571061Sigor@sysoev.ru             hash = nxt_http_field_hash_char(hash, c);
13581061Sigor@sysoev.ru         }
13591061Sigor@sysoev.ru     }
13601061Sigor@sysoev.ru 
13611061Sigor@sysoev.ru     if (valid) {
13621061Sigor@sysoev.ru         nv = nxt_http_route_argument(args, name, name_length, hash, start, p);
13631061Sigor@sysoev.ru         if (nxt_slow_path(nv == NULL)) {
13641061Sigor@sysoev.ru             return NULL;
13651061Sigor@sysoev.ru         }
13661061Sigor@sysoev.ru     }
13671061Sigor@sysoev.ru 
13681061Sigor@sysoev.ru     r->arguments = args;
13691061Sigor@sysoev.ru 
13701061Sigor@sysoev.ru     return args;
13711061Sigor@sysoev.ru }
13721061Sigor@sysoev.ru 
13731061Sigor@sysoev.ru 
13741061Sigor@sysoev.ru static nxt_http_name_value_t *
13751061Sigor@sysoev.ru nxt_http_route_argument(nxt_array_t *array, u_char *name, size_t name_length,
13761061Sigor@sysoev.ru     uint32_t hash, u_char *start, u_char *end)
13771061Sigor@sysoev.ru {
13781061Sigor@sysoev.ru     size_t                 length;
13791061Sigor@sysoev.ru     nxt_http_name_value_t  *nv;
13801061Sigor@sysoev.ru 
13811061Sigor@sysoev.ru     nv = nxt_array_add(array);
13821061Sigor@sysoev.ru     if (nxt_slow_path(nv == NULL)) {
13831061Sigor@sysoev.ru         return NULL;
13841061Sigor@sysoev.ru     }
13851061Sigor@sysoev.ru 
13861061Sigor@sysoev.ru     nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF;
13871061Sigor@sysoev.ru 
13881061Sigor@sysoev.ru     length = end - start;
13891061Sigor@sysoev.ru 
13901061Sigor@sysoev.ru     if (name == NULL) {
13911061Sigor@sysoev.ru         name_length = length;
13921061Sigor@sysoev.ru         name = start;
13931061Sigor@sysoev.ru         length = 0;
13941061Sigor@sysoev.ru     }
13951061Sigor@sysoev.ru 
13961061Sigor@sysoev.ru     nv->name_length = name_length;
13971061Sigor@sysoev.ru     nv->value_length = length;
13981061Sigor@sysoev.ru     nv->name = name;
13991061Sigor@sysoev.ru     nv->value = start;
14001061Sigor@sysoev.ru 
14011061Sigor@sysoev.ru     return nv;
14021061Sigor@sysoev.ru }
14031061Sigor@sysoev.ru 
14041061Sigor@sysoev.ru 
14051061Sigor@sysoev.ru static nxt_int_t
14061061Sigor@sysoev.ru nxt_http_route_test_argument(nxt_http_request_t *r,
14071061Sigor@sysoev.ru     nxt_http_route_rule_t *rule, nxt_array_t *array)
14081061Sigor@sysoev.ru {
14091061Sigor@sysoev.ru     nxt_bool_t             ret;
14101061Sigor@sysoev.ru     nxt_http_name_value_t  *nv, *end;
14111061Sigor@sysoev.ru 
14121061Sigor@sysoev.ru     ret = 0;
14131061Sigor@sysoev.ru 
14141061Sigor@sysoev.ru     nv = array->elts;
14151061Sigor@sysoev.ru     end = nv + array->nelts;
14161061Sigor@sysoev.ru 
14171061Sigor@sysoev.ru     while (nv < end) {
14181061Sigor@sysoev.ru 
14191061Sigor@sysoev.ru         if (rule->u.name.hash == nv->hash
14201061Sigor@sysoev.ru             && rule->u.name.length == nv->name_length
14211061Sigor@sysoev.ru             && nxt_memcmp(rule->u.name.start, nv->name, nv->name_length) == 0)
14221061Sigor@sysoev.ru         {
14231061Sigor@sysoev.ru             ret = nxt_http_route_test_rule(r, rule, nv->value,
14241061Sigor@sysoev.ru                                            nv->value_length);
14251061Sigor@sysoev.ru             if (ret == 0) {
14261061Sigor@sysoev.ru                 break;
14271061Sigor@sysoev.ru             }
14281061Sigor@sysoev.ru         }
14291061Sigor@sysoev.ru 
14301061Sigor@sysoev.ru         nv++;
14311061Sigor@sysoev.ru     }
14321061Sigor@sysoev.ru 
14331061Sigor@sysoev.ru     return ret;
14341061Sigor@sysoev.ru }
14351061Sigor@sysoev.ru 
14361061Sigor@sysoev.ru 
14371061Sigor@sysoev.ru static nxt_int_t
14381110Saxel.duch@nginx.com nxt_http_route_scheme(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
14391110Saxel.duch@nginx.com {
14401110Saxel.duch@nginx.com     nxt_bool_t  tls, https;
14411110Saxel.duch@nginx.com 
14421110Saxel.duch@nginx.com     https = (rule->pattern[0].length1 == nxt_length("https"));
14431110Saxel.duch@nginx.com     tls = (r->tls != NULL);
14441110Saxel.duch@nginx.com 
14451110Saxel.duch@nginx.com     return (tls == https);
14461110Saxel.duch@nginx.com }
14471110Saxel.duch@nginx.com 
14481110Saxel.duch@nginx.com 
14491110Saxel.duch@nginx.com static nxt_int_t
14501062Sigor@sysoev.ru nxt_http_route_cookies(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
14511062Sigor@sysoev.ru {
14521062Sigor@sysoev.ru     nxt_array_t  *cookies;
14531062Sigor@sysoev.ru 
14541062Sigor@sysoev.ru     cookies = nxt_http_route_cookies_parse(r);
14551062Sigor@sysoev.ru     if (nxt_slow_path(cookies == NULL)) {
14561062Sigor@sysoev.ru         return -1;
14571062Sigor@sysoev.ru     }
14581062Sigor@sysoev.ru 
14591062Sigor@sysoev.ru     return nxt_http_route_test_cookie(r, rule, cookies);
14601062Sigor@sysoev.ru }
14611062Sigor@sysoev.ru 
14621062Sigor@sysoev.ru 
14631062Sigor@sysoev.ru static nxt_array_t *
14641062Sigor@sysoev.ru nxt_http_route_cookies_parse(nxt_http_request_t *r)
14651062Sigor@sysoev.ru {
14661062Sigor@sysoev.ru     nxt_int_t         ret;
14671062Sigor@sysoev.ru     nxt_array_t       *cookies;
14681062Sigor@sysoev.ru     nxt_http_field_t  *f;
14691062Sigor@sysoev.ru 
14701062Sigor@sysoev.ru     if (r->cookies != NULL) {
14711062Sigor@sysoev.ru         return r->cookies;
14721062Sigor@sysoev.ru     }
14731062Sigor@sysoev.ru 
14741062Sigor@sysoev.ru     cookies = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t));
14751062Sigor@sysoev.ru     if (nxt_slow_path(cookies == NULL)) {
14761062Sigor@sysoev.ru         return NULL;
14771062Sigor@sysoev.ru     }
14781062Sigor@sysoev.ru 
14791062Sigor@sysoev.ru     nxt_list_each(f, r->fields) {
14801062Sigor@sysoev.ru 
14811062Sigor@sysoev.ru         if (f->hash != NJS_COOKIE_HASH
14821062Sigor@sysoev.ru             || f->name_length != 6
14831062Sigor@sysoev.ru             || nxt_strncasecmp(f->name, (u_char *) "Cookie", 6) != 0)
14841062Sigor@sysoev.ru         {
14851062Sigor@sysoev.ru             continue;
14861062Sigor@sysoev.ru         }
14871062Sigor@sysoev.ru 
14881062Sigor@sysoev.ru         ret = nxt_http_route_cookie_parse(cookies, f->value,
14891062Sigor@sysoev.ru                                           f->value + f->value_length);
14901062Sigor@sysoev.ru         if (ret != NXT_OK) {
14911062Sigor@sysoev.ru             return NULL;
14921062Sigor@sysoev.ru         }
14931062Sigor@sysoev.ru 
14941062Sigor@sysoev.ru     } nxt_list_loop;
14951062Sigor@sysoev.ru 
14961062Sigor@sysoev.ru     r->cookies = cookies;
14971062Sigor@sysoev.ru 
14981062Sigor@sysoev.ru     return cookies;
14991062Sigor@sysoev.ru }
15001062Sigor@sysoev.ru 
15011062Sigor@sysoev.ru 
15021062Sigor@sysoev.ru static nxt_int_t
15031062Sigor@sysoev.ru nxt_http_route_cookie_parse(nxt_array_t *cookies, u_char *start, u_char *end)
15041062Sigor@sysoev.ru {
15051062Sigor@sysoev.ru     size_t                 name_length;
15061062Sigor@sysoev.ru     u_char                 c, *p, *name;
15071062Sigor@sysoev.ru     nxt_http_name_value_t  *nv;
15081062Sigor@sysoev.ru 
15091062Sigor@sysoev.ru     name = NULL;
15101062Sigor@sysoev.ru     name_length = 0;
15111062Sigor@sysoev.ru 
15121062Sigor@sysoev.ru     for (p = start; p < end; p++) {
15131062Sigor@sysoev.ru         c = *p;
15141062Sigor@sysoev.ru 
15151062Sigor@sysoev.ru         if (c == '=') {
15161062Sigor@sysoev.ru             while (start[0] == ' ') { start++; }
15171062Sigor@sysoev.ru 
15181062Sigor@sysoev.ru             name_length = p - start;
15191062Sigor@sysoev.ru 
15201062Sigor@sysoev.ru             if (name_length != 0) {
15211062Sigor@sysoev.ru                 name = start;
15221062Sigor@sysoev.ru             }
15231062Sigor@sysoev.ru 
15241062Sigor@sysoev.ru             start = p + 1;
15251062Sigor@sysoev.ru 
15261062Sigor@sysoev.ru         } else if (c == ';') {
15271062Sigor@sysoev.ru             if (name != NULL) {
15281062Sigor@sysoev.ru                 nv = nxt_http_route_cookie(cookies, name, name_length,
15291062Sigor@sysoev.ru                                            start, p);
15301062Sigor@sysoev.ru                 if (nxt_slow_path(nv == NULL)) {
15311062Sigor@sysoev.ru                     return NXT_ERROR;
15321062Sigor@sysoev.ru                 }
15331062Sigor@sysoev.ru             }
15341062Sigor@sysoev.ru 
15351062Sigor@sysoev.ru             name = NULL;
15361062Sigor@sysoev.ru             start = p + 1;
15371062Sigor@sysoev.ru          }
15381062Sigor@sysoev.ru     }
15391062Sigor@sysoev.ru 
15401062Sigor@sysoev.ru     if (name != NULL) {
15411062Sigor@sysoev.ru         nv = nxt_http_route_cookie(cookies, name, name_length, start, p);
15421062Sigor@sysoev.ru         if (nxt_slow_path(nv == NULL)) {
15431062Sigor@sysoev.ru             return NXT_ERROR;
15441062Sigor@sysoev.ru         }
15451062Sigor@sysoev.ru     }
15461062Sigor@sysoev.ru 
15471062Sigor@sysoev.ru     return NXT_OK;
15481062Sigor@sysoev.ru }
15491062Sigor@sysoev.ru 
15501062Sigor@sysoev.ru 
15511062Sigor@sysoev.ru static nxt_http_name_value_t *
15521062Sigor@sysoev.ru nxt_http_route_cookie(nxt_array_t *array, u_char *name, size_t name_length,
15531062Sigor@sysoev.ru     u_char *start, u_char *end)
15541062Sigor@sysoev.ru {
15551062Sigor@sysoev.ru     u_char                 c, *p;
15561062Sigor@sysoev.ru     uint32_t               hash;
15571062Sigor@sysoev.ru     nxt_http_name_value_t  *nv;
15581062Sigor@sysoev.ru 
15591062Sigor@sysoev.ru     nv = nxt_array_add(array);
15601062Sigor@sysoev.ru     if (nxt_slow_path(nv == NULL)) {
15611062Sigor@sysoev.ru         return NULL;
15621062Sigor@sysoev.ru     }
15631062Sigor@sysoev.ru 
15641062Sigor@sysoev.ru     nv->name_length = name_length;
15651062Sigor@sysoev.ru     nv->name = name;
15661062Sigor@sysoev.ru 
15671062Sigor@sysoev.ru     hash = NXT_HTTP_FIELD_HASH_INIT;
15681062Sigor@sysoev.ru 
15691062Sigor@sysoev.ru     for (p = name; p < name + name_length; p++) {
15701062Sigor@sysoev.ru         c = *p;
15711062Sigor@sysoev.ru         hash = nxt_http_field_hash_char(hash, c);
15721062Sigor@sysoev.ru     }
15731062Sigor@sysoev.ru 
15741062Sigor@sysoev.ru     nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF;
15751062Sigor@sysoev.ru 
15761062Sigor@sysoev.ru     while (start < end && end[-1] == ' ') { end--; }
15771062Sigor@sysoev.ru 
15781062Sigor@sysoev.ru     nv->value_length = end - start;
15791062Sigor@sysoev.ru     nv->value = start;
15801062Sigor@sysoev.ru 
15811062Sigor@sysoev.ru     return nv;
15821062Sigor@sysoev.ru }
15831062Sigor@sysoev.ru 
15841062Sigor@sysoev.ru 
15851062Sigor@sysoev.ru static nxt_int_t
15861062Sigor@sysoev.ru nxt_http_route_test_cookie(nxt_http_request_t *r,
15871062Sigor@sysoev.ru     nxt_http_route_rule_t *rule, nxt_array_t *array)
15881062Sigor@sysoev.ru {
15891062Sigor@sysoev.ru     nxt_bool_t             ret;
15901062Sigor@sysoev.ru     nxt_http_name_value_t  *nv, *end;
15911062Sigor@sysoev.ru 
15921062Sigor@sysoev.ru     ret = 0;
15931062Sigor@sysoev.ru 
15941062Sigor@sysoev.ru     nv = array->elts;
15951062Sigor@sysoev.ru     end = nv + array->nelts;
15961062Sigor@sysoev.ru 
15971062Sigor@sysoev.ru     while (nv < end) {
15981062Sigor@sysoev.ru 
15991062Sigor@sysoev.ru         if (rule->u.name.hash == nv->hash
16001062Sigor@sysoev.ru             && rule->u.name.length == nv->name_length
16011079Sigor@sysoev.ru             && nxt_memcmp(rule->u.name.start, nv->name, nv->name_length) == 0)
16021062Sigor@sysoev.ru         {
16031062Sigor@sysoev.ru             ret = nxt_http_route_test_rule(r, rule, nv->value,
16041062Sigor@sysoev.ru                                            nv->value_length);
16051062Sigor@sysoev.ru             if (ret == 0) {
16061062Sigor@sysoev.ru                 break;
16071062Sigor@sysoev.ru             }
16081062Sigor@sysoev.ru         }
16091062Sigor@sysoev.ru 
16101062Sigor@sysoev.ru         nv++;
16111062Sigor@sysoev.ru     }
16121062Sigor@sysoev.ru 
16131062Sigor@sysoev.ru     return ret;
16141062Sigor@sysoev.ru }
16151062Sigor@sysoev.ru 
16161062Sigor@sysoev.ru 
16171062Sigor@sysoev.ru static nxt_int_t
16181059Sigor@sysoev.ru nxt_http_route_test_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule,
16191059Sigor@sysoev.ru     u_char *start, size_t length)
16201059Sigor@sysoev.ru {
16211060Sigor@sysoev.ru     nxt_int_t                 ret;
16221059Sigor@sysoev.ru     nxt_http_route_pattern_t  *pattern, *end;
16231059Sigor@sysoev.ru 
16241057Sigor@sysoev.ru     ret = 1;
1625964Sigor@sysoev.ru     pattern = &rule->pattern[0];
16261033Svbart@nginx.com     end = pattern + rule->items;
1627964Sigor@sysoev.ru 
16281057Sigor@sysoev.ru     while (pattern < end) {
1629964Sigor@sysoev.ru         ret = nxt_http_route_pattern(r, pattern, start, length);
1630964Sigor@sysoev.ru 
16311060Sigor@sysoev.ru         /* nxt_http_route_pattern() returns either 1 or 0. */
1632964Sigor@sysoev.ru         ret ^= pattern->negative;
1633964Sigor@sysoev.ru 
1634964Sigor@sysoev.ru         if (pattern->any == ret) {
1635964Sigor@sysoev.ru             return ret;
1636964Sigor@sysoev.ru         }
1637964Sigor@sysoev.ru 
1638964Sigor@sysoev.ru         pattern++;
16391057Sigor@sysoev.ru     }
1640964Sigor@sysoev.ru 
1641964Sigor@sysoev.ru     return ret;
1642964Sigor@sysoev.ru }
1643964Sigor@sysoev.ru 
1644964Sigor@sysoev.ru 
16451060Sigor@sysoev.ru static nxt_int_t
1646964Sigor@sysoev.ru nxt_http_route_pattern(nxt_http_request_t *r, nxt_http_route_pattern_t *pattern,
1647964Sigor@sysoev.ru     u_char *start, size_t length)
1648964Sigor@sysoev.ru {
16491060Sigor@sysoev.ru     u_char     *p, *end, *test;
16501060Sigor@sysoev.ru     size_t     test_length;
16511060Sigor@sysoev.ru     nxt_int_t  ret;
1652964Sigor@sysoev.ru 
1653964Sigor@sysoev.ru     if (length < pattern->min_length) {
1654964Sigor@sysoev.ru         return 0;
1655964Sigor@sysoev.ru     }
1656964Sigor@sysoev.ru 
16571032Sigor@sysoev.ru     test = pattern->start1;
16581032Sigor@sysoev.ru     test_length = pattern->length1;
1659964Sigor@sysoev.ru 
1660964Sigor@sysoev.ru     switch (pattern->type) {
1661964Sigor@sysoev.ru 
1662964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_EXACT:
16631032Sigor@sysoev.ru         if (length != test_length) {
1664964Sigor@sysoev.ru             return 0;
1665964Sigor@sysoev.ru         }
1666964Sigor@sysoev.ru 
1667964Sigor@sysoev.ru         break;
1668964Sigor@sysoev.ru 
1669964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_BEGIN:
1670964Sigor@sysoev.ru         break;
1671964Sigor@sysoev.ru 
16721032Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_MIDDLE:
16731032Sigor@sysoev.ru         ret = nxt_http_route_memcmp(start, test, test_length,
16741032Sigor@sysoev.ru                                     pattern->case_sensitive);
16751032Sigor@sysoev.ru         if (!ret) {
16761032Sigor@sysoev.ru             return ret;
16771032Sigor@sysoev.ru         }
16781032Sigor@sysoev.ru 
16791032Sigor@sysoev.ru         test = pattern->start2;
16801032Sigor@sysoev.ru         test_length = pattern->length2;
16811032Sigor@sysoev.ru 
16821032Sigor@sysoev.ru         /* Fall through. */
16831032Sigor@sysoev.ru 
1684964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_END:
16851032Sigor@sysoev.ru         start += length - test_length;
1686964Sigor@sysoev.ru         break;
1687964Sigor@sysoev.ru 
1688964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_SUBSTRING:
16891032Sigor@sysoev.ru         end = start + length;
16901032Sigor@sysoev.ru 
1691964Sigor@sysoev.ru         if (pattern->case_sensitive) {
16921032Sigor@sysoev.ru             p = nxt_memstrn(start, end, (char *) test, test_length);
16931032Sigor@sysoev.ru 
16941032Sigor@sysoev.ru         } else {
16951032Sigor@sysoev.ru             p = nxt_memcasestrn(start, end, (char *) test, test_length);
1696964Sigor@sysoev.ru         }
1697964Sigor@sysoev.ru 
16981032Sigor@sysoev.ru         return (p != NULL);
1699964Sigor@sysoev.ru     }
1700964Sigor@sysoev.ru 
17011032Sigor@sysoev.ru     return nxt_http_route_memcmp(start, test, test_length,
17021032Sigor@sysoev.ru                                  pattern->case_sensitive);
17031032Sigor@sysoev.ru }
17041032Sigor@sysoev.ru 
17051032Sigor@sysoev.ru 
17061060Sigor@sysoev.ru static nxt_int_t
17071032Sigor@sysoev.ru nxt_http_route_memcmp(u_char *start, u_char *test, size_t test_length,
17081032Sigor@sysoev.ru     nxt_bool_t case_sensitive)
17091032Sigor@sysoev.ru {
17101032Sigor@sysoev.ru     nxt_int_t  n;
17111032Sigor@sysoev.ru 
17121032Sigor@sysoev.ru     if (case_sensitive) {
17131032Sigor@sysoev.ru         n = nxt_memcmp(start, test, test_length);
17141032Sigor@sysoev.ru 
17151032Sigor@sysoev.ru     } else {
17161032Sigor@sysoev.ru         n = nxt_memcasecmp(start, test, test_length);
1717964Sigor@sysoev.ru     }
1718964Sigor@sysoev.ru 
17191032Sigor@sysoev.ru     return (n == 0);
1720964Sigor@sysoev.ru }
1721