xref: /unit/src/nxt_http_route.c (revision 1324)
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>
9*1324Saxel.duch@nginx.com #include <nxt_sockaddr.h>
10*1324Saxel.duch@nginx.com #include <nxt_http_route_addr.h>
11964Sigor@sysoev.ru 
12964Sigor@sysoev.ru 
13964Sigor@sysoev.ru typedef enum {
141059Sigor@sysoev.ru     NXT_HTTP_ROUTE_TABLE = 0,
151059Sigor@sysoev.ru     NXT_HTTP_ROUTE_STRING,
16964Sigor@sysoev.ru     NXT_HTTP_ROUTE_STRING_PTR,
17964Sigor@sysoev.ru     NXT_HTTP_ROUTE_HEADER,
18964Sigor@sysoev.ru     NXT_HTTP_ROUTE_ARGUMENT,
19964Sigor@sysoev.ru     NXT_HTTP_ROUTE_COOKIE,
201110Saxel.duch@nginx.com     NXT_HTTP_ROUTE_SCHEME,
21*1324Saxel.duch@nginx.com     NXT_HTTP_ROUTE_SOURCE,
22964Sigor@sysoev.ru } nxt_http_route_object_t;
23964Sigor@sysoev.ru 
24964Sigor@sysoev.ru 
25964Sigor@sysoev.ru typedef enum {
26964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_EXACT = 0,
27964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_BEGIN,
281032Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_MIDDLE,
29964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_END,
30964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_SUBSTRING,
31964Sigor@sysoev.ru } nxt_http_route_pattern_type_t;
32964Sigor@sysoev.ru 
33964Sigor@sysoev.ru 
34964Sigor@sysoev.ru typedef enum {
35964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_NOCASE = 0,
36964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_LOWCASE,
37964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_UPCASE,
38964Sigor@sysoev.ru } nxt_http_route_pattern_case_t;
39964Sigor@sysoev.ru 
40964Sigor@sysoev.ru 
41964Sigor@sysoev.ru typedef struct {
421264Sigor@sysoev.ru     nxt_conf_value_t               *pass;
431264Sigor@sysoev.ru     nxt_conf_value_t               *share;
441270Sigor@sysoev.ru     nxt_conf_value_t               *proxy;
451264Sigor@sysoev.ru } nxt_http_route_action_conf_t;
461264Sigor@sysoev.ru 
471264Sigor@sysoev.ru 
481264Sigor@sysoev.ru typedef struct {
49964Sigor@sysoev.ru     nxt_conf_value_t               *host;
50964Sigor@sysoev.ru     nxt_conf_value_t               *uri;
51964Sigor@sysoev.ru     nxt_conf_value_t               *method;
521059Sigor@sysoev.ru     nxt_conf_value_t               *headers;
531061Sigor@sysoev.ru     nxt_conf_value_t               *arguments;
541062Sigor@sysoev.ru     nxt_conf_value_t               *cookies;
551110Saxel.duch@nginx.com     nxt_conf_value_t               *scheme;
56*1324Saxel.duch@nginx.com     nxt_conf_value_t               *source;
57964Sigor@sysoev.ru } nxt_http_route_match_conf_t;
58964Sigor@sysoev.ru 
59964Sigor@sysoev.ru 
60964Sigor@sysoev.ru typedef struct {
611032Sigor@sysoev.ru     u_char                         *start1;
621032Sigor@sysoev.ru     u_char                         *start2;
631032Sigor@sysoev.ru     uint32_t                       length1;
641032Sigor@sysoev.ru     uint32_t                       length2;
65964Sigor@sysoev.ru     uint32_t                       min_length;
66964Sigor@sysoev.ru 
67964Sigor@sysoev.ru     nxt_http_route_pattern_type_t  type:8;
68964Sigor@sysoev.ru     uint8_t                        case_sensitive;  /* 1 bit */
69964Sigor@sysoev.ru     uint8_t                        negative;        /* 1 bit */
70964Sigor@sysoev.ru     uint8_t                        any;             /* 1 bit */
71964Sigor@sysoev.ru } nxt_http_route_pattern_t;
72964Sigor@sysoev.ru 
73964Sigor@sysoev.ru 
74964Sigor@sysoev.ru typedef struct {
751061Sigor@sysoev.ru     uint16_t                       hash;
761061Sigor@sysoev.ru     uint16_t                       name_length;
771061Sigor@sysoev.ru     uint32_t                       value_length;
781061Sigor@sysoev.ru     u_char                         *name;
791061Sigor@sysoev.ru     u_char                         *value;
801061Sigor@sysoev.ru } nxt_http_name_value_t;
811061Sigor@sysoev.ru 
821061Sigor@sysoev.ru 
831061Sigor@sysoev.ru typedef struct {
841062Sigor@sysoev.ru     uint16_t                       hash;
851062Sigor@sysoev.ru     uint16_t                       name_length;
861062Sigor@sysoev.ru     uint32_t                       value_length;
871062Sigor@sysoev.ru     u_char                         *name;
881062Sigor@sysoev.ru     u_char                         *value;
891062Sigor@sysoev.ru } nxt_http_cookie_t;
901062Sigor@sysoev.ru 
911062Sigor@sysoev.ru 
921062Sigor@sysoev.ru typedef struct {
931059Sigor@sysoev.ru     /* The object must be the first field. */
941059Sigor@sysoev.ru     nxt_http_route_object_t        object:8;
95964Sigor@sysoev.ru     uint32_t                       items;
961059Sigor@sysoev.ru 
971059Sigor@sysoev.ru     union {
981059Sigor@sysoev.ru         uintptr_t                  offset;
991059Sigor@sysoev.ru 
1001059Sigor@sysoev.ru         struct {
1011059Sigor@sysoev.ru             u_char                 *start;
1021059Sigor@sysoev.ru             uint16_t               hash;
1031059Sigor@sysoev.ru             uint16_t               length;
1041059Sigor@sysoev.ru         } name;
1051059Sigor@sysoev.ru     } u;
1061059Sigor@sysoev.ru 
107964Sigor@sysoev.ru     nxt_http_route_pattern_t       pattern[0];
108964Sigor@sysoev.ru } nxt_http_route_rule_t;
109964Sigor@sysoev.ru 
110964Sigor@sysoev.ru 
111964Sigor@sysoev.ru typedef struct {
112964Sigor@sysoev.ru     uint32_t                       items;
1131059Sigor@sysoev.ru     nxt_http_route_rule_t          *rule[0];
1141059Sigor@sysoev.ru } nxt_http_route_ruleset_t;
1151059Sigor@sysoev.ru 
1161059Sigor@sysoev.ru 
1171059Sigor@sysoev.ru typedef struct {
1181059Sigor@sysoev.ru     /* The object must be the first field. */
1191059Sigor@sysoev.ru     nxt_http_route_object_t        object:8;
1201059Sigor@sysoev.ru     uint32_t                       items;
1211059Sigor@sysoev.ru     nxt_http_route_ruleset_t       *ruleset[0];
1221059Sigor@sysoev.ru } nxt_http_route_table_t;
1231059Sigor@sysoev.ru 
1241059Sigor@sysoev.ru 
125*1324Saxel.duch@nginx.com typedef struct {
126*1324Saxel.duch@nginx.com     /* The object must be the first field. */
127*1324Saxel.duch@nginx.com     nxt_http_route_object_t        object:8;
128*1324Saxel.duch@nginx.com     uint32_t                       items;
129*1324Saxel.duch@nginx.com     nxt_http_route_addr_pattern_t  addr_pattern[0];
130*1324Saxel.duch@nginx.com } nxt_http_route_addr_rule_t;
131*1324Saxel.duch@nginx.com 
132*1324Saxel.duch@nginx.com 
1331059Sigor@sysoev.ru typedef union {
1341059Sigor@sysoev.ru     nxt_http_route_rule_t          *rule;
1351059Sigor@sysoev.ru     nxt_http_route_table_t         *table;
136*1324Saxel.duch@nginx.com     nxt_http_route_addr_rule_t     *addr_rule;
1371059Sigor@sysoev.ru } nxt_http_route_test_t;
1381059Sigor@sysoev.ru 
1391059Sigor@sysoev.ru 
1401059Sigor@sysoev.ru typedef struct {
1411059Sigor@sysoev.ru     uint32_t                       items;
1421264Sigor@sysoev.ru     nxt_http_action_t              action;
1431059Sigor@sysoev.ru     nxt_http_route_test_t          test[0];
144964Sigor@sysoev.ru } nxt_http_route_match_t;
145964Sigor@sysoev.ru 
146964Sigor@sysoev.ru 
147964Sigor@sysoev.ru struct nxt_http_route_s {
148964Sigor@sysoev.ru     nxt_str_t                      name;
149964Sigor@sysoev.ru     uint32_t                       items;
150964Sigor@sysoev.ru     nxt_http_route_match_t         *match[0];
151964Sigor@sysoev.ru };
152964Sigor@sysoev.ru 
153964Sigor@sysoev.ru 
154964Sigor@sysoev.ru struct nxt_http_routes_s {
155964Sigor@sysoev.ru     uint32_t                       items;
156964Sigor@sysoev.ru     nxt_http_route_t               *route[0];
157964Sigor@sysoev.ru };
158964Sigor@sysoev.ru 
159964Sigor@sysoev.ru 
1601062Sigor@sysoev.ru #define NJS_COOKIE_HASH                                                       \
1611062Sigor@sysoev.ru     (nxt_http_field_hash_end(                                                 \
1621062Sigor@sysoev.ru      nxt_http_field_hash_char(                                                \
1631062Sigor@sysoev.ru      nxt_http_field_hash_char(                                                \
1641062Sigor@sysoev.ru      nxt_http_field_hash_char(                                                \
1651062Sigor@sysoev.ru      nxt_http_field_hash_char(                                                \
1661062Sigor@sysoev.ru      nxt_http_field_hash_char(                                                \
1671062Sigor@sysoev.ru      nxt_http_field_hash_char(NXT_HTTP_FIELD_HASH_INIT,                       \
1681062Sigor@sysoev.ru         'c'), 'o'), 'o'), 'k'), 'i'), 'e')) & 0xFFFF)
1691062Sigor@sysoev.ru 
1701062Sigor@sysoev.ru 
171964Sigor@sysoev.ru static nxt_http_route_t *nxt_http_route_create(nxt_task_t *task,
172964Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv);
173964Sigor@sysoev.ru static nxt_http_route_match_t *nxt_http_route_match_create(nxt_task_t *task,
174964Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv);
1751264Sigor@sysoev.ru static nxt_int_t nxt_http_route_action_create(nxt_router_temp_conf_t *tmcf,
1761264Sigor@sysoev.ru     nxt_conf_value_t *cv, nxt_http_route_match_t *match);
1771059Sigor@sysoev.ru static nxt_http_route_table_t *nxt_http_route_table_create(nxt_task_t *task,
1781061Sigor@sysoev.ru     nxt_mp_t *mp, nxt_conf_value_t *table_cv, nxt_http_route_object_t object,
1791061Sigor@sysoev.ru     nxt_bool_t case_sensitive);
1801059Sigor@sysoev.ru static nxt_http_route_ruleset_t *nxt_http_route_ruleset_create(nxt_task_t *task,
1811061Sigor@sysoev.ru     nxt_mp_t *mp, nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object,
1821061Sigor@sysoev.ru     nxt_bool_t case_sensitive);
1831061Sigor@sysoev.ru static nxt_http_route_rule_t *nxt_http_route_rule_name_create(nxt_task_t *task,
1841061Sigor@sysoev.ru     nxt_mp_t *mp, nxt_conf_value_t *rule_cv, nxt_str_t *name,
1851061Sigor@sysoev.ru     nxt_bool_t case_sensitive);
186*1324Saxel.duch@nginx.com static nxt_http_route_addr_rule_t *nxt_http_route_addr_rule_create(
187*1324Saxel.duch@nginx.com     nxt_task_t *task, nxt_mp_t *mp, nxt_conf_value_t *cv);
188964Sigor@sysoev.ru static nxt_http_route_rule_t *nxt_http_route_rule_create(nxt_task_t *task,
1891059Sigor@sysoev.ru     nxt_mp_t *mp, nxt_conf_value_t *cv, nxt_bool_t case_sensitive,
1901059Sigor@sysoev.ru     nxt_http_route_pattern_case_t pattern_case);
191964Sigor@sysoev.ru static int nxt_http_pattern_compare(const void *one, const void *two);
192964Sigor@sysoev.ru static nxt_int_t nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp,
193964Sigor@sysoev.ru     nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern,
194964Sigor@sysoev.ru     nxt_http_route_pattern_case_t pattern_case);
1951032Sigor@sysoev.ru static u_char *nxt_http_route_pattern_copy(nxt_mp_t *mp, nxt_str_t *test,
1961032Sigor@sysoev.ru     nxt_http_route_pattern_case_t pattern_case);
197964Sigor@sysoev.ru 
198964Sigor@sysoev.ru static void nxt_http_route_resolve(nxt_task_t *task,
199964Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_http_route_t *route);
2001264Sigor@sysoev.ru static void nxt_http_action_resolve(nxt_task_t *task,
2011264Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_http_action_t *action);
202964Sigor@sysoev.ru static nxt_http_route_t *nxt_http_route_find(nxt_http_routes_t *routes,
203964Sigor@sysoev.ru     nxt_str_t *name);
204964Sigor@sysoev.ru static void nxt_http_route_cleanup(nxt_task_t *task, nxt_http_route_t *routes);
205964Sigor@sysoev.ru 
2061264Sigor@sysoev.ru static nxt_http_action_t *nxt_http_route_handler(nxt_task_t *task,
2071264Sigor@sysoev.ru     nxt_http_request_t *r, nxt_http_action_t *start);
2081264Sigor@sysoev.ru static nxt_http_action_t *nxt_http_route_match(nxt_http_request_t *r,
209964Sigor@sysoev.ru     nxt_http_route_match_t *match);
2101060Sigor@sysoev.ru static nxt_int_t nxt_http_route_table(nxt_http_request_t *r,
2111059Sigor@sysoev.ru     nxt_http_route_table_t *table);
2121060Sigor@sysoev.ru static nxt_int_t nxt_http_route_ruleset(nxt_http_request_t *r,
2131059Sigor@sysoev.ru     nxt_http_route_ruleset_t *ruleset);
214*1324Saxel.duch@nginx.com static nxt_int_t nxt_http_route_addr_rule(nxt_http_request_t *r,
215*1324Saxel.duch@nginx.com     nxt_http_route_addr_rule_t *addr_rule, nxt_sockaddr_t *sockaddr);
2161060Sigor@sysoev.ru static nxt_int_t nxt_http_route_rule(nxt_http_request_t *r,
217964Sigor@sysoev.ru     nxt_http_route_rule_t *rule);
2181060Sigor@sysoev.ru static nxt_int_t nxt_http_route_header(nxt_http_request_t *r,
2191059Sigor@sysoev.ru     nxt_http_route_rule_t *rule);
2201061Sigor@sysoev.ru static nxt_int_t nxt_http_route_arguments(nxt_http_request_t *r,
2211061Sigor@sysoev.ru     nxt_http_route_rule_t *rule);
2221061Sigor@sysoev.ru static nxt_array_t *nxt_http_route_arguments_parse(nxt_http_request_t *r);
2231061Sigor@sysoev.ru static nxt_http_name_value_t *nxt_http_route_argument(nxt_array_t *array,
2241061Sigor@sysoev.ru     u_char *name, size_t name_length, uint32_t hash, u_char *start,
2251061Sigor@sysoev.ru     u_char *end);
2261061Sigor@sysoev.ru static nxt_int_t nxt_http_route_test_argument(nxt_http_request_t *r,
2271061Sigor@sysoev.ru     nxt_http_route_rule_t *rule, nxt_array_t *array);
2281110Saxel.duch@nginx.com static nxt_int_t nxt_http_route_scheme(nxt_http_request_t *r,
2291110Saxel.duch@nginx.com     nxt_http_route_rule_t *rule);
2301062Sigor@sysoev.ru static nxt_int_t nxt_http_route_cookies(nxt_http_request_t *r,
2311062Sigor@sysoev.ru     nxt_http_route_rule_t *rule);
2321062Sigor@sysoev.ru static nxt_array_t *nxt_http_route_cookies_parse(nxt_http_request_t *r);
2331062Sigor@sysoev.ru static nxt_int_t nxt_http_route_cookie_parse(nxt_array_t *cookies,
2341062Sigor@sysoev.ru     u_char *start, u_char *end);
2351062Sigor@sysoev.ru static nxt_http_name_value_t *nxt_http_route_cookie(nxt_array_t *array,
2361062Sigor@sysoev.ru     u_char *name, size_t name_length, u_char *start, u_char *end);
2371062Sigor@sysoev.ru static nxt_int_t nxt_http_route_test_cookie(nxt_http_request_t *r,
2381062Sigor@sysoev.ru     nxt_http_route_rule_t *rule, nxt_array_t *array);
2391060Sigor@sysoev.ru static nxt_int_t nxt_http_route_test_rule(nxt_http_request_t *r,
2401059Sigor@sysoev.ru     nxt_http_route_rule_t *rule, u_char *start, size_t length);
2411060Sigor@sysoev.ru static nxt_int_t nxt_http_route_pattern(nxt_http_request_t *r,
242964Sigor@sysoev.ru     nxt_http_route_pattern_t *pattern, u_char *start, size_t length);
2431060Sigor@sysoev.ru static nxt_int_t nxt_http_route_memcmp(u_char *start, u_char *test,
2441032Sigor@sysoev.ru     size_t length, nxt_bool_t case_sensitive);
245964Sigor@sysoev.ru 
246964Sigor@sysoev.ru 
247964Sigor@sysoev.ru nxt_http_routes_t *
248964Sigor@sysoev.ru nxt_http_routes_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
249964Sigor@sysoev.ru     nxt_conf_value_t *routes_conf)
250964Sigor@sysoev.ru {
251964Sigor@sysoev.ru     size_t             size;
252964Sigor@sysoev.ru     uint32_t           i, n, next;
253964Sigor@sysoev.ru     nxt_mp_t           *mp;
254964Sigor@sysoev.ru     nxt_str_t          name, *string;
255964Sigor@sysoev.ru     nxt_bool_t         object;
256964Sigor@sysoev.ru     nxt_conf_value_t   *route_conf;
257964Sigor@sysoev.ru     nxt_http_route_t   *route;
258964Sigor@sysoev.ru     nxt_http_routes_t  *routes;
259964Sigor@sysoev.ru 
260964Sigor@sysoev.ru     object = (nxt_conf_type(routes_conf) == NXT_CONF_OBJECT);
261964Sigor@sysoev.ru     n = object ? nxt_conf_object_members_count(routes_conf) : 1;
262964Sigor@sysoev.ru     size = sizeof(nxt_http_routes_t) + n * sizeof(nxt_http_route_t *);
263964Sigor@sysoev.ru 
264964Sigor@sysoev.ru     mp = tmcf->router_conf->mem_pool;
265964Sigor@sysoev.ru 
266964Sigor@sysoev.ru     routes = nxt_mp_alloc(mp, size);
267964Sigor@sysoev.ru     if (nxt_slow_path(routes == NULL)) {
268964Sigor@sysoev.ru         return NULL;
269964Sigor@sysoev.ru     }
270964Sigor@sysoev.ru 
271964Sigor@sysoev.ru     routes->items = n;
272964Sigor@sysoev.ru 
273964Sigor@sysoev.ru     if (object) {
274964Sigor@sysoev.ru         next = 0;
275964Sigor@sysoev.ru 
276964Sigor@sysoev.ru         for (i = 0; i < n; i++) {
277964Sigor@sysoev.ru             route_conf = nxt_conf_next_object_member(routes_conf, &name, &next);
278964Sigor@sysoev.ru 
279964Sigor@sysoev.ru             route = nxt_http_route_create(task, tmcf, route_conf);
280964Sigor@sysoev.ru             if (nxt_slow_path(route == NULL)) {
281964Sigor@sysoev.ru                 return NULL;
282964Sigor@sysoev.ru             }
283964Sigor@sysoev.ru 
284964Sigor@sysoev.ru             routes->route[i] = route;
285964Sigor@sysoev.ru 
286964Sigor@sysoev.ru             string = nxt_str_dup(mp, &route->name, &name);
287964Sigor@sysoev.ru             if (nxt_slow_path(string == NULL)) {
288964Sigor@sysoev.ru                 return NULL;
289964Sigor@sysoev.ru             }
290964Sigor@sysoev.ru         }
291964Sigor@sysoev.ru 
292964Sigor@sysoev.ru     } else {
293964Sigor@sysoev.ru         route = nxt_http_route_create(task, tmcf, routes_conf);
294964Sigor@sysoev.ru         if (nxt_slow_path(route == NULL)) {
295964Sigor@sysoev.ru             return NULL;
296964Sigor@sysoev.ru         }
297964Sigor@sysoev.ru 
298964Sigor@sysoev.ru         routes->route[0] = route;
299964Sigor@sysoev.ru 
300964Sigor@sysoev.ru         route->name.length = 0;
301964Sigor@sysoev.ru         route->name.start = NULL;
302964Sigor@sysoev.ru     }
303964Sigor@sysoev.ru 
304964Sigor@sysoev.ru     return routes;
305964Sigor@sysoev.ru }
306964Sigor@sysoev.ru 
307964Sigor@sysoev.ru 
308964Sigor@sysoev.ru static nxt_conf_map_t  nxt_http_route_match_conf[] = {
309964Sigor@sysoev.ru     {
3101110Saxel.duch@nginx.com         nxt_string("scheme"),
3111110Saxel.duch@nginx.com         NXT_CONF_MAP_PTR,
3121110Saxel.duch@nginx.com         offsetof(nxt_http_route_match_conf_t, scheme)
3131110Saxel.duch@nginx.com     },
3141110Saxel.duch@nginx.com     {
315964Sigor@sysoev.ru         nxt_string("host"),
316964Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
317964Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, host),
318964Sigor@sysoev.ru     },
319964Sigor@sysoev.ru 
320964Sigor@sysoev.ru     {
321964Sigor@sysoev.ru         nxt_string("uri"),
322964Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
323964Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, uri),
324964Sigor@sysoev.ru     },
325964Sigor@sysoev.ru 
326964Sigor@sysoev.ru     {
327964Sigor@sysoev.ru         nxt_string("method"),
328964Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
329964Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, method),
330964Sigor@sysoev.ru     },
3311059Sigor@sysoev.ru 
3321059Sigor@sysoev.ru     {
3331059Sigor@sysoev.ru         nxt_string("headers"),
3341059Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
3351059Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, headers),
3361059Sigor@sysoev.ru     },
3371061Sigor@sysoev.ru 
3381061Sigor@sysoev.ru     {
3391061Sigor@sysoev.ru         nxt_string("arguments"),
3401061Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
3411061Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, arguments),
3421061Sigor@sysoev.ru     },
3431062Sigor@sysoev.ru 
3441062Sigor@sysoev.ru     {
3451062Sigor@sysoev.ru         nxt_string("cookies"),
3461062Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
3471062Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, cookies),
3481062Sigor@sysoev.ru     },
349*1324Saxel.duch@nginx.com 
350*1324Saxel.duch@nginx.com     {
351*1324Saxel.duch@nginx.com         nxt_string("source"),
352*1324Saxel.duch@nginx.com         NXT_CONF_MAP_PTR,
353*1324Saxel.duch@nginx.com         offsetof(nxt_http_route_match_conf_t, source),
354*1324Saxel.duch@nginx.com     },
355964Sigor@sysoev.ru };
356964Sigor@sysoev.ru 
357964Sigor@sysoev.ru 
358964Sigor@sysoev.ru static nxt_http_route_t *
359964Sigor@sysoev.ru nxt_http_route_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
360964Sigor@sysoev.ru     nxt_conf_value_t *cv)
361964Sigor@sysoev.ru {
362964Sigor@sysoev.ru     size_t                  size;
363964Sigor@sysoev.ru     uint32_t                i, n;
364964Sigor@sysoev.ru     nxt_conf_value_t        *value;
365964Sigor@sysoev.ru     nxt_http_route_t        *route;
366964Sigor@sysoev.ru     nxt_http_route_match_t  *match, **m;
367964Sigor@sysoev.ru 
368964Sigor@sysoev.ru     n = nxt_conf_array_elements_count(cv);
369964Sigor@sysoev.ru     size = sizeof(nxt_http_route_t) + n * sizeof(nxt_http_route_match_t *);
370964Sigor@sysoev.ru 
371964Sigor@sysoev.ru     route = nxt_mp_alloc(tmcf->router_conf->mem_pool, size);
372964Sigor@sysoev.ru     if (nxt_slow_path(route == NULL)) {
373964Sigor@sysoev.ru         return NULL;
374964Sigor@sysoev.ru     }
375964Sigor@sysoev.ru 
376964Sigor@sysoev.ru     route->items = n;
377964Sigor@sysoev.ru     m = &route->match[0];
378964Sigor@sysoev.ru 
379964Sigor@sysoev.ru     for (i = 0; i < n; i++) {
380964Sigor@sysoev.ru         value = nxt_conf_get_array_element(cv, i);
381964Sigor@sysoev.ru 
382964Sigor@sysoev.ru         match = nxt_http_route_match_create(task, tmcf, value);
383964Sigor@sysoev.ru         if (match == NULL) {
384964Sigor@sysoev.ru             return NULL;
385964Sigor@sysoev.ru         }
386964Sigor@sysoev.ru 
387964Sigor@sysoev.ru         *m++ = match;
388964Sigor@sysoev.ru     }
389964Sigor@sysoev.ru 
390964Sigor@sysoev.ru     return route;
391964Sigor@sysoev.ru }
392964Sigor@sysoev.ru 
393964Sigor@sysoev.ru 
394964Sigor@sysoev.ru static nxt_http_route_match_t *
395964Sigor@sysoev.ru nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
396964Sigor@sysoev.ru     nxt_conf_value_t *cv)
397964Sigor@sysoev.ru {
398964Sigor@sysoev.ru     size_t                       size;
399964Sigor@sysoev.ru     uint32_t                     n;
4001059Sigor@sysoev.ru     nxt_mp_t                     *mp;
401964Sigor@sysoev.ru     nxt_int_t                    ret;
4021264Sigor@sysoev.ru     nxt_conf_value_t             *match_conf;
4031059Sigor@sysoev.ru     nxt_http_route_test_t        *test;
4041059Sigor@sysoev.ru     nxt_http_route_rule_t        *rule;
4051059Sigor@sysoev.ru     nxt_http_route_table_t       *table;
406964Sigor@sysoev.ru     nxt_http_route_match_t       *match;
407*1324Saxel.duch@nginx.com     nxt_http_route_addr_rule_t   *addr_rule;
408964Sigor@sysoev.ru     nxt_http_route_match_conf_t  mtcf;
409964Sigor@sysoev.ru 
410964Sigor@sysoev.ru     static nxt_str_t  match_path = nxt_string("/match");
411964Sigor@sysoev.ru 
412964Sigor@sysoev.ru     match_conf = nxt_conf_get_path(cv, &match_path);
413964Sigor@sysoev.ru 
414964Sigor@sysoev.ru     n = (match_conf != NULL) ? nxt_conf_object_members_count(match_conf) : 0;
415964Sigor@sysoev.ru     size = sizeof(nxt_http_route_match_t) + n * sizeof(nxt_http_route_rule_t *);
416964Sigor@sysoev.ru 
4171059Sigor@sysoev.ru     mp = tmcf->router_conf->mem_pool;
4181059Sigor@sysoev.ru 
4191059Sigor@sysoev.ru     match = nxt_mp_alloc(mp, size);
420964Sigor@sysoev.ru     if (nxt_slow_path(match == NULL)) {
421964Sigor@sysoev.ru         return NULL;
422964Sigor@sysoev.ru     }
423964Sigor@sysoev.ru 
4241264Sigor@sysoev.ru     match->action.u.route = NULL;
4251264Sigor@sysoev.ru     match->action.handler = NULL;
426964Sigor@sysoev.ru     match->items = n;
427964Sigor@sysoev.ru 
4281264Sigor@sysoev.ru     ret = nxt_http_route_action_create(tmcf, cv, match);
4291264Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
430964Sigor@sysoev.ru         return NULL;
431964Sigor@sysoev.ru     }
432964Sigor@sysoev.ru 
433964Sigor@sysoev.ru     if (n == 0) {
434964Sigor@sysoev.ru         return match;
435964Sigor@sysoev.ru     }
436964Sigor@sysoev.ru 
437964Sigor@sysoev.ru     nxt_memzero(&mtcf, sizeof(mtcf));
438964Sigor@sysoev.ru 
439964Sigor@sysoev.ru     ret = nxt_conf_map_object(tmcf->mem_pool,
440964Sigor@sysoev.ru                               match_conf, nxt_http_route_match_conf,
441964Sigor@sysoev.ru                               nxt_nitems(nxt_http_route_match_conf), &mtcf);
442964Sigor@sysoev.ru     if (ret != NXT_OK) {
443964Sigor@sysoev.ru         return NULL;
444964Sigor@sysoev.ru     }
445964Sigor@sysoev.ru 
4461059Sigor@sysoev.ru     test = &match->test[0];
447964Sigor@sysoev.ru 
4481110Saxel.duch@nginx.com     if (mtcf.scheme != NULL) {
4491110Saxel.duch@nginx.com         rule = nxt_http_route_rule_create(task, mp, mtcf.scheme, 1,
4501110Saxel.duch@nginx.com                                           NXT_HTTP_ROUTE_PATTERN_NOCASE);
4511110Saxel.duch@nginx.com         if (rule == NULL) {
4521110Saxel.duch@nginx.com             return NULL;
4531110Saxel.duch@nginx.com         }
4541110Saxel.duch@nginx.com 
4551110Saxel.duch@nginx.com         rule->object = NXT_HTTP_ROUTE_SCHEME;
4561110Saxel.duch@nginx.com         test->rule = rule;
4571110Saxel.duch@nginx.com         test++;
4581110Saxel.duch@nginx.com     }
4591110Saxel.duch@nginx.com 
460964Sigor@sysoev.ru     if (mtcf.host != NULL) {
4611059Sigor@sysoev.ru         rule = nxt_http_route_rule_create(task, mp, mtcf.host, 1,
462964Sigor@sysoev.ru                                           NXT_HTTP_ROUTE_PATTERN_LOWCASE);
463964Sigor@sysoev.ru         if (rule == NULL) {
464964Sigor@sysoev.ru             return NULL;
465964Sigor@sysoev.ru         }
466964Sigor@sysoev.ru 
4671059Sigor@sysoev.ru         rule->u.offset = offsetof(nxt_http_request_t, host);
468964Sigor@sysoev.ru         rule->object = NXT_HTTP_ROUTE_STRING;
4691059Sigor@sysoev.ru         test->rule = rule;
4701059Sigor@sysoev.ru         test++;
471964Sigor@sysoev.ru     }
472964Sigor@sysoev.ru 
473964Sigor@sysoev.ru     if (mtcf.uri != NULL) {
4741059Sigor@sysoev.ru         rule = nxt_http_route_rule_create(task, mp, mtcf.uri, 1,
475964Sigor@sysoev.ru                                           NXT_HTTP_ROUTE_PATTERN_NOCASE);
476964Sigor@sysoev.ru         if (rule == NULL) {
477964Sigor@sysoev.ru             return NULL;
478964Sigor@sysoev.ru         }
479964Sigor@sysoev.ru 
4801059Sigor@sysoev.ru         rule->u.offset = offsetof(nxt_http_request_t, path);
481964Sigor@sysoev.ru         rule->object = NXT_HTTP_ROUTE_STRING_PTR;
4821059Sigor@sysoev.ru         test->rule = rule;
4831059Sigor@sysoev.ru         test++;
484964Sigor@sysoev.ru     }
485964Sigor@sysoev.ru 
486964Sigor@sysoev.ru     if (mtcf.method != NULL) {
4871059Sigor@sysoev.ru         rule = nxt_http_route_rule_create(task, mp, mtcf.method, 1,
488964Sigor@sysoev.ru                                           NXT_HTTP_ROUTE_PATTERN_UPCASE);
489964Sigor@sysoev.ru         if (rule == NULL) {
490964Sigor@sysoev.ru             return NULL;
491964Sigor@sysoev.ru         }
492964Sigor@sysoev.ru 
4931059Sigor@sysoev.ru         rule->u.offset = offsetof(nxt_http_request_t, method);
494964Sigor@sysoev.ru         rule->object = NXT_HTTP_ROUTE_STRING_PTR;
4951059Sigor@sysoev.ru         test->rule = rule;
4961059Sigor@sysoev.ru         test++;
4971059Sigor@sysoev.ru     }
4981059Sigor@sysoev.ru 
4991059Sigor@sysoev.ru     if (mtcf.headers != NULL) {
5001061Sigor@sysoev.ru         table = nxt_http_route_table_create(task, mp, mtcf.headers,
5011061Sigor@sysoev.ru                                             NXT_HTTP_ROUTE_HEADER, 0);
5021061Sigor@sysoev.ru         if (table == NULL) {
5031061Sigor@sysoev.ru             return NULL;
5041061Sigor@sysoev.ru         }
5051061Sigor@sysoev.ru 
5061061Sigor@sysoev.ru         test->table = table;
5071061Sigor@sysoev.ru         test++;
5081061Sigor@sysoev.ru     }
5091061Sigor@sysoev.ru 
5101061Sigor@sysoev.ru     if (mtcf.arguments != NULL) {
5111061Sigor@sysoev.ru         table = nxt_http_route_table_create(task, mp, mtcf.arguments,
5121061Sigor@sysoev.ru                                             NXT_HTTP_ROUTE_ARGUMENT, 1);
5131059Sigor@sysoev.ru         if (table == NULL) {
5141059Sigor@sysoev.ru             return NULL;
5151059Sigor@sysoev.ru         }
5161059Sigor@sysoev.ru 
5171059Sigor@sysoev.ru         test->table = table;
5181059Sigor@sysoev.ru         test++;
519964Sigor@sysoev.ru     }
520964Sigor@sysoev.ru 
5211062Sigor@sysoev.ru     if (mtcf.cookies != NULL) {
5221062Sigor@sysoev.ru         table = nxt_http_route_table_create(task, mp, mtcf.cookies,
5231079Sigor@sysoev.ru                                             NXT_HTTP_ROUTE_COOKIE, 1);
5241062Sigor@sysoev.ru         if (table == NULL) {
5251062Sigor@sysoev.ru             return NULL;
5261062Sigor@sysoev.ru         }
5271062Sigor@sysoev.ru 
5281062Sigor@sysoev.ru         test->table = table;
5291062Sigor@sysoev.ru         test++;
5301062Sigor@sysoev.ru     }
5311062Sigor@sysoev.ru 
532*1324Saxel.duch@nginx.com     if (mtcf.source != NULL) {
533*1324Saxel.duch@nginx.com         addr_rule = nxt_http_route_addr_rule_create(task, mp, mtcf.source);
534*1324Saxel.duch@nginx.com         if (addr_rule == NULL) {
535*1324Saxel.duch@nginx.com             return NULL;
536*1324Saxel.duch@nginx.com         }
537*1324Saxel.duch@nginx.com 
538*1324Saxel.duch@nginx.com         addr_rule->object = NXT_HTTP_ROUTE_SOURCE;
539*1324Saxel.duch@nginx.com         test->addr_rule = addr_rule;
540*1324Saxel.duch@nginx.com         test++;
541*1324Saxel.duch@nginx.com     }
542*1324Saxel.duch@nginx.com 
543964Sigor@sysoev.ru     return match;
544964Sigor@sysoev.ru }
545964Sigor@sysoev.ru 
546964Sigor@sysoev.ru 
5471264Sigor@sysoev.ru static nxt_conf_map_t  nxt_http_route_action_conf[] = {
5481264Sigor@sysoev.ru     {
5491264Sigor@sysoev.ru         nxt_string("pass"),
5501264Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
5511264Sigor@sysoev.ru         offsetof(nxt_http_route_action_conf_t, pass)
5521264Sigor@sysoev.ru     },
5531264Sigor@sysoev.ru     {
5541264Sigor@sysoev.ru         nxt_string("share"),
5551264Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
5561264Sigor@sysoev.ru         offsetof(nxt_http_route_action_conf_t, share)
5571264Sigor@sysoev.ru     },
5581270Sigor@sysoev.ru     {
5591270Sigor@sysoev.ru         nxt_string("proxy"),
5601270Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
5611270Sigor@sysoev.ru         offsetof(nxt_http_route_action_conf_t, proxy)
5621270Sigor@sysoev.ru     },
5631264Sigor@sysoev.ru };
5641264Sigor@sysoev.ru 
5651264Sigor@sysoev.ru 
5661264Sigor@sysoev.ru static nxt_int_t
5671264Sigor@sysoev.ru nxt_http_route_action_create(nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv,
5681264Sigor@sysoev.ru     nxt_http_route_match_t *match)
5691264Sigor@sysoev.ru {
5701270Sigor@sysoev.ru     nxt_mp_t                      *mp;
5711264Sigor@sysoev.ru     nxt_int_t                     ret;
5721264Sigor@sysoev.ru     nxt_str_t                     name, *string;
5731264Sigor@sysoev.ru     nxt_conf_value_t              *conf, *action_conf;
5741264Sigor@sysoev.ru     nxt_http_route_action_conf_t  accf;
5751264Sigor@sysoev.ru 
5761264Sigor@sysoev.ru     static nxt_str_t  action_path = nxt_string("/action");
5771264Sigor@sysoev.ru 
5781264Sigor@sysoev.ru     action_conf = nxt_conf_get_path(cv, &action_path);
5791264Sigor@sysoev.ru     if (action_conf == NULL) {
5801264Sigor@sysoev.ru         return NXT_ERROR;
5811264Sigor@sysoev.ru     }
5821264Sigor@sysoev.ru 
5831264Sigor@sysoev.ru     nxt_memzero(&accf, sizeof(accf));
5841264Sigor@sysoev.ru 
5851264Sigor@sysoev.ru     ret = nxt_conf_map_object(tmcf->mem_pool,
5861264Sigor@sysoev.ru                               action_conf, nxt_http_route_action_conf,
5871264Sigor@sysoev.ru                               nxt_nitems(nxt_http_route_action_conf), &accf);
5881264Sigor@sysoev.ru     if (ret != NXT_OK) {
5891264Sigor@sysoev.ru         return ret;
5901264Sigor@sysoev.ru     }
5911264Sigor@sysoev.ru 
5921264Sigor@sysoev.ru     conf = accf.pass;
5931264Sigor@sysoev.ru 
5941264Sigor@sysoev.ru     if (accf.share != NULL) {
5951264Sigor@sysoev.ru         conf = accf.share;
5961264Sigor@sysoev.ru         match->action.handler = nxt_http_static_handler;
5971270Sigor@sysoev.ru 
5981270Sigor@sysoev.ru     } else if (accf.proxy != NULL) {
5991270Sigor@sysoev.ru         conf = accf.proxy;
6001264Sigor@sysoev.ru     }
6011264Sigor@sysoev.ru 
6021264Sigor@sysoev.ru     nxt_conf_get_string(conf, &name);
6031264Sigor@sysoev.ru 
6041270Sigor@sysoev.ru     mp = tmcf->router_conf->mem_pool;
6051270Sigor@sysoev.ru 
6061270Sigor@sysoev.ru     string = nxt_str_dup(mp, &match->action.name, &name);
6071264Sigor@sysoev.ru     if (nxt_slow_path(string == NULL)) {
6081264Sigor@sysoev.ru         return NXT_ERROR;
6091264Sigor@sysoev.ru     }
6101264Sigor@sysoev.ru 
6111270Sigor@sysoev.ru     if (accf.proxy != NULL) {
6121270Sigor@sysoev.ru         return nxt_http_proxy_create(mp, &match->action);
6131270Sigor@sysoev.ru     }
6141270Sigor@sysoev.ru 
6151264Sigor@sysoev.ru     return NXT_OK;
6161264Sigor@sysoev.ru }
6171264Sigor@sysoev.ru 
6181264Sigor@sysoev.ru 
6191059Sigor@sysoev.ru static nxt_http_route_table_t *
6201059Sigor@sysoev.ru nxt_http_route_table_create(nxt_task_t *task, nxt_mp_t *mp,
6211061Sigor@sysoev.ru     nxt_conf_value_t *table_cv, nxt_http_route_object_t object,
6221061Sigor@sysoev.ru     nxt_bool_t case_sensitive)
6231059Sigor@sysoev.ru {
6241059Sigor@sysoev.ru     size_t                    size;
6251059Sigor@sysoev.ru     uint32_t                  i, n;
6261059Sigor@sysoev.ru     nxt_bool_t                array;
6271059Sigor@sysoev.ru     nxt_conf_value_t          *ruleset_cv;
6281059Sigor@sysoev.ru     nxt_http_route_table_t    *table;
6291059Sigor@sysoev.ru     nxt_http_route_ruleset_t  *ruleset;
6301059Sigor@sysoev.ru 
6311059Sigor@sysoev.ru     array = (nxt_conf_type(table_cv) == NXT_CONF_ARRAY);
6321059Sigor@sysoev.ru     n = array ? nxt_conf_array_elements_count(table_cv) : 1;
6331059Sigor@sysoev.ru     size = sizeof(nxt_http_route_table_t)
6341059Sigor@sysoev.ru            + n * sizeof(nxt_http_route_ruleset_t *);
6351059Sigor@sysoev.ru 
6361059Sigor@sysoev.ru     table = nxt_mp_alloc(mp, size);
6371059Sigor@sysoev.ru     if (nxt_slow_path(table == NULL)) {
6381059Sigor@sysoev.ru         return NULL;
6391059Sigor@sysoev.ru     }
6401059Sigor@sysoev.ru 
6411059Sigor@sysoev.ru     table->items = n;
6421059Sigor@sysoev.ru     table->object = NXT_HTTP_ROUTE_TABLE;
6431059Sigor@sysoev.ru 
6441059Sigor@sysoev.ru     if (!array) {
6451061Sigor@sysoev.ru         ruleset = nxt_http_route_ruleset_create(task, mp, table_cv,
6461061Sigor@sysoev.ru                                                 object, case_sensitive);
6471059Sigor@sysoev.ru         if (nxt_slow_path(ruleset == NULL)) {
6481059Sigor@sysoev.ru             return NULL;
6491059Sigor@sysoev.ru         }
6501059Sigor@sysoev.ru 
6511059Sigor@sysoev.ru         table->ruleset[0] = ruleset;
6521059Sigor@sysoev.ru 
6531059Sigor@sysoev.ru         return table;
6541059Sigor@sysoev.ru     }
6551059Sigor@sysoev.ru 
6561059Sigor@sysoev.ru     for (i = 0; i < n; i++) {
6571059Sigor@sysoev.ru         ruleset_cv = nxt_conf_get_array_element(table_cv, i);
6581059Sigor@sysoev.ru 
6591061Sigor@sysoev.ru         ruleset = nxt_http_route_ruleset_create(task, mp, ruleset_cv,
6601061Sigor@sysoev.ru                                                 object, case_sensitive);
6611059Sigor@sysoev.ru         if (nxt_slow_path(ruleset == NULL)) {
6621059Sigor@sysoev.ru             return NULL;
6631059Sigor@sysoev.ru         }
6641059Sigor@sysoev.ru 
6651059Sigor@sysoev.ru         table->ruleset[i] = ruleset;
6661059Sigor@sysoev.ru     }
6671059Sigor@sysoev.ru 
6681059Sigor@sysoev.ru     return table;
6691059Sigor@sysoev.ru }
6701059Sigor@sysoev.ru 
6711059Sigor@sysoev.ru 
6721059Sigor@sysoev.ru static nxt_http_route_ruleset_t *
6731059Sigor@sysoev.ru nxt_http_route_ruleset_create(nxt_task_t *task, nxt_mp_t *mp,
6741061Sigor@sysoev.ru     nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object,
6751061Sigor@sysoev.ru     nxt_bool_t case_sensitive)
6761059Sigor@sysoev.ru {
6771059Sigor@sysoev.ru     size_t                    size;
6781059Sigor@sysoev.ru     uint32_t                  i, n, next;
6791059Sigor@sysoev.ru     nxt_str_t                 name;
6801059Sigor@sysoev.ru     nxt_conf_value_t          *rule_cv;
6811059Sigor@sysoev.ru     nxt_http_route_rule_t     *rule;
6821059Sigor@sysoev.ru     nxt_http_route_ruleset_t  *ruleset;
6831059Sigor@sysoev.ru 
6841059Sigor@sysoev.ru     n = nxt_conf_object_members_count(ruleset_cv);
6851059Sigor@sysoev.ru     size = sizeof(nxt_http_route_ruleset_t)
6861059Sigor@sysoev.ru            + n * sizeof(nxt_http_route_rule_t *);
6871059Sigor@sysoev.ru 
6881059Sigor@sysoev.ru     ruleset = nxt_mp_alloc(mp, size);
6891059Sigor@sysoev.ru     if (nxt_slow_path(ruleset == NULL)) {
6901059Sigor@sysoev.ru         return NULL;
6911059Sigor@sysoev.ru     }
6921059Sigor@sysoev.ru 
6931059Sigor@sysoev.ru     ruleset->items = n;
6941059Sigor@sysoev.ru 
6951059Sigor@sysoev.ru     next = 0;
6961059Sigor@sysoev.ru 
6971059Sigor@sysoev.ru     for (i = 0; i < n; i++) {
6981059Sigor@sysoev.ru         rule_cv = nxt_conf_next_object_member(ruleset_cv, &name, &next);
6991059Sigor@sysoev.ru 
7001061Sigor@sysoev.ru         rule = nxt_http_route_rule_name_create(task, mp, rule_cv, &name,
7011061Sigor@sysoev.ru                                                case_sensitive);
7021059Sigor@sysoev.ru         if (nxt_slow_path(rule == NULL)) {
7031059Sigor@sysoev.ru             return NULL;
7041059Sigor@sysoev.ru         }
7051059Sigor@sysoev.ru 
7061061Sigor@sysoev.ru         rule->object = object;
7071059Sigor@sysoev.ru         ruleset->rule[i] = rule;
7081059Sigor@sysoev.ru     }
7091059Sigor@sysoev.ru 
7101059Sigor@sysoev.ru     return ruleset;
7111059Sigor@sysoev.ru }
7121059Sigor@sysoev.ru 
7131059Sigor@sysoev.ru 
714964Sigor@sysoev.ru static nxt_http_route_rule_t *
7151061Sigor@sysoev.ru nxt_http_route_rule_name_create(nxt_task_t *task, nxt_mp_t *mp,
7161061Sigor@sysoev.ru     nxt_conf_value_t *rule_cv, nxt_str_t *name, nxt_bool_t case_sensitive)
7171059Sigor@sysoev.ru {
7181059Sigor@sysoev.ru     u_char                 c, *p;
7191059Sigor@sysoev.ru     uint32_t               hash;
7201059Sigor@sysoev.ru     nxt_uint_t             i;
7211059Sigor@sysoev.ru     nxt_http_route_rule_t  *rule;
7221059Sigor@sysoev.ru 
7231061Sigor@sysoev.ru     rule = nxt_http_route_rule_create(task, mp, rule_cv, case_sensitive,
7241059Sigor@sysoev.ru                                       NXT_HTTP_ROUTE_PATTERN_NOCASE);
7251059Sigor@sysoev.ru     if (nxt_slow_path(rule == NULL)) {
7261059Sigor@sysoev.ru         return NULL;
7271059Sigor@sysoev.ru     }
7281059Sigor@sysoev.ru 
7291059Sigor@sysoev.ru     rule->u.name.length = name->length;
7301059Sigor@sysoev.ru 
7311059Sigor@sysoev.ru     p = nxt_mp_nget(mp, name->length);
7321059Sigor@sysoev.ru     if (nxt_slow_path(p == NULL)) {
7331059Sigor@sysoev.ru         return NULL;
7341059Sigor@sysoev.ru     }
7351059Sigor@sysoev.ru 
7361059Sigor@sysoev.ru     rule->u.name.start = p;
7371059Sigor@sysoev.ru 
7381059Sigor@sysoev.ru     hash = NXT_HTTP_FIELD_HASH_INIT;
7391059Sigor@sysoev.ru 
7401059Sigor@sysoev.ru     for (i = 0; i < name->length; i++) {
7411059Sigor@sysoev.ru         c = name->start[i];
7421059Sigor@sysoev.ru         *p++ = c;
7431059Sigor@sysoev.ru 
7441079Sigor@sysoev.ru         c = case_sensitive ? c : nxt_lowcase(c);
7451059Sigor@sysoev.ru         hash = nxt_http_field_hash_char(hash, c);
7461059Sigor@sysoev.ru     }
7471059Sigor@sysoev.ru 
7481059Sigor@sysoev.ru     rule->u.name.hash = nxt_http_field_hash_end(hash) & 0xFFFF;
7491059Sigor@sysoev.ru 
7501059Sigor@sysoev.ru     return rule;
7511059Sigor@sysoev.ru }
7521059Sigor@sysoev.ru 
7531059Sigor@sysoev.ru 
7541059Sigor@sysoev.ru static nxt_http_route_rule_t *
7551059Sigor@sysoev.ru nxt_http_route_rule_create(nxt_task_t *task, nxt_mp_t *mp,
756964Sigor@sysoev.ru     nxt_conf_value_t *cv, nxt_bool_t case_sensitive,
757964Sigor@sysoev.ru     nxt_http_route_pattern_case_t pattern_case)
758964Sigor@sysoev.ru {
759964Sigor@sysoev.ru     size_t                    size;
760964Sigor@sysoev.ru     uint32_t                  i, n;
761964Sigor@sysoev.ru     nxt_int_t                 ret;
762964Sigor@sysoev.ru     nxt_bool_t                string;
763964Sigor@sysoev.ru     nxt_conf_value_t          *value;
764964Sigor@sysoev.ru     nxt_http_route_rule_t     *rule;
765964Sigor@sysoev.ru     nxt_http_route_pattern_t  *pattern;
766964Sigor@sysoev.ru 
767964Sigor@sysoev.ru     string = (nxt_conf_type(cv) != NXT_CONF_ARRAY);
768964Sigor@sysoev.ru     n = string ? 1 : nxt_conf_array_elements_count(cv);
769964Sigor@sysoev.ru     size = sizeof(nxt_http_route_rule_t) + n * sizeof(nxt_http_route_pattern_t);
770964Sigor@sysoev.ru 
771964Sigor@sysoev.ru     rule = nxt_mp_alloc(mp, size);
772964Sigor@sysoev.ru     if (nxt_slow_path(rule == NULL)) {
773964Sigor@sysoev.ru         return NULL;
774964Sigor@sysoev.ru     }
775964Sigor@sysoev.ru 
776964Sigor@sysoev.ru     rule->items = n;
777964Sigor@sysoev.ru 
778964Sigor@sysoev.ru     pattern = &rule->pattern[0];
779964Sigor@sysoev.ru 
780964Sigor@sysoev.ru     if (string) {
781964Sigor@sysoev.ru         pattern[0].case_sensitive = case_sensitive;
782964Sigor@sysoev.ru         ret = nxt_http_route_pattern_create(task, mp, cv, &pattern[0],
783964Sigor@sysoev.ru                                             pattern_case);
784964Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
785964Sigor@sysoev.ru             return NULL;
786964Sigor@sysoev.ru         }
787964Sigor@sysoev.ru 
788964Sigor@sysoev.ru         return rule;
789964Sigor@sysoev.ru     }
790964Sigor@sysoev.ru 
791964Sigor@sysoev.ru     nxt_conf_array_qsort(cv, nxt_http_pattern_compare);
792964Sigor@sysoev.ru 
793964Sigor@sysoev.ru     for (i = 0; i < n; i++) {
794964Sigor@sysoev.ru         pattern[i].case_sensitive = case_sensitive;
795964Sigor@sysoev.ru         value = nxt_conf_get_array_element(cv, i);
796964Sigor@sysoev.ru 
797964Sigor@sysoev.ru         ret = nxt_http_route_pattern_create(task, mp, value, &pattern[i],
798964Sigor@sysoev.ru                                             pattern_case);
799964Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
800964Sigor@sysoev.ru             return NULL;
801964Sigor@sysoev.ru         }
802964Sigor@sysoev.ru     }
803964Sigor@sysoev.ru 
804964Sigor@sysoev.ru     return rule;
805964Sigor@sysoev.ru }
806964Sigor@sysoev.ru 
807964Sigor@sysoev.ru 
808*1324Saxel.duch@nginx.com static nxt_http_route_addr_rule_t *
809*1324Saxel.duch@nginx.com nxt_http_route_addr_rule_create(nxt_task_t *task, nxt_mp_t *mp,
810*1324Saxel.duch@nginx.com      nxt_conf_value_t *cv)
811*1324Saxel.duch@nginx.com {
812*1324Saxel.duch@nginx.com     size_t                         size;
813*1324Saxel.duch@nginx.com     uint32_t                       i, n;
814*1324Saxel.duch@nginx.com     nxt_bool_t                     array;
815*1324Saxel.duch@nginx.com     nxt_conf_value_t               *value;
816*1324Saxel.duch@nginx.com     nxt_http_route_addr_rule_t     *addr_rule;
817*1324Saxel.duch@nginx.com     nxt_http_route_addr_pattern_t  *pattern;
818*1324Saxel.duch@nginx.com 
819*1324Saxel.duch@nginx.com     array = (nxt_conf_type(cv) == NXT_CONF_ARRAY);
820*1324Saxel.duch@nginx.com     n = array ? nxt_conf_array_elements_count(cv) : 1;
821*1324Saxel.duch@nginx.com 
822*1324Saxel.duch@nginx.com     size = sizeof(nxt_http_route_addr_rule_t)
823*1324Saxel.duch@nginx.com            + n * sizeof(nxt_http_route_addr_pattern_t);
824*1324Saxel.duch@nginx.com 
825*1324Saxel.duch@nginx.com     addr_rule = nxt_mp_alloc(mp, size);
826*1324Saxel.duch@nginx.com     if (nxt_slow_path(addr_rule == NULL)) {
827*1324Saxel.duch@nginx.com         return NULL;
828*1324Saxel.duch@nginx.com     }
829*1324Saxel.duch@nginx.com 
830*1324Saxel.duch@nginx.com     addr_rule->items = n;
831*1324Saxel.duch@nginx.com 
832*1324Saxel.duch@nginx.com     if (!array) {
833*1324Saxel.duch@nginx.com         pattern = &addr_rule->addr_pattern[0];
834*1324Saxel.duch@nginx.com 
835*1324Saxel.duch@nginx.com         if (nxt_http_route_addr_pattern_parse(mp, pattern, cv) != NXT_OK) {
836*1324Saxel.duch@nginx.com             return NULL;
837*1324Saxel.duch@nginx.com         }
838*1324Saxel.duch@nginx.com 
839*1324Saxel.duch@nginx.com         return addr_rule;
840*1324Saxel.duch@nginx.com     }
841*1324Saxel.duch@nginx.com 
842*1324Saxel.duch@nginx.com     for (i = 0; i < n; i++) {
843*1324Saxel.duch@nginx.com         pattern = &addr_rule->addr_pattern[i];
844*1324Saxel.duch@nginx.com         value = nxt_conf_get_array_element(cv, i);
845*1324Saxel.duch@nginx.com 
846*1324Saxel.duch@nginx.com         if (nxt_http_route_addr_pattern_parse(mp, pattern, value) != NXT_OK) {
847*1324Saxel.duch@nginx.com             return NULL;
848*1324Saxel.duch@nginx.com         }
849*1324Saxel.duch@nginx.com     }
850*1324Saxel.duch@nginx.com 
851*1324Saxel.duch@nginx.com     return addr_rule;
852*1324Saxel.duch@nginx.com }
853*1324Saxel.duch@nginx.com 
854*1324Saxel.duch@nginx.com 
855964Sigor@sysoev.ru static int
856964Sigor@sysoev.ru nxt_http_pattern_compare(const void *one, const void *two)
857964Sigor@sysoev.ru {
858964Sigor@sysoev.ru     nxt_str_t         test;
859964Sigor@sysoev.ru     nxt_bool_t        negative1, negative2;
860964Sigor@sysoev.ru     nxt_conf_value_t  *value;
861964Sigor@sysoev.ru 
862964Sigor@sysoev.ru     value = (nxt_conf_value_t *) one;
863964Sigor@sysoev.ru     nxt_conf_get_string(value, &test);
864964Sigor@sysoev.ru     negative1 = (test.length != 0 && test.start[0] == '!');
865964Sigor@sysoev.ru 
866964Sigor@sysoev.ru     value = (nxt_conf_value_t *) two;
867964Sigor@sysoev.ru     nxt_conf_get_string(value, &test);
868964Sigor@sysoev.ru     negative2 = (test.length != 0 && test.start[0] == '!');
869964Sigor@sysoev.ru 
870964Sigor@sysoev.ru     return (negative2 - negative1);
871964Sigor@sysoev.ru }
872964Sigor@sysoev.ru 
873964Sigor@sysoev.ru 
874964Sigor@sysoev.ru static nxt_int_t
875964Sigor@sysoev.ru nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp,
876964Sigor@sysoev.ru     nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern,
877964Sigor@sysoev.ru     nxt_http_route_pattern_case_t pattern_case)
878964Sigor@sysoev.ru {
879964Sigor@sysoev.ru     u_char                         *start;
880964Sigor@sysoev.ru     nxt_str_t                      test;
8811032Sigor@sysoev.ru     nxt_uint_t                     n, length;
882964Sigor@sysoev.ru     nxt_http_route_pattern_type_t  type;
883964Sigor@sysoev.ru 
8841032Sigor@sysoev.ru     /* Suppress warning about uninitialized variable. */
8851032Sigor@sysoev.ru     length = 0;
8861032Sigor@sysoev.ru 
887964Sigor@sysoev.ru     type = NXT_HTTP_ROUTE_PATTERN_EXACT;
888964Sigor@sysoev.ru 
889964Sigor@sysoev.ru     nxt_conf_get_string(cv, &test);
890964Sigor@sysoev.ru 
891964Sigor@sysoev.ru     pattern->negative = 0;
892964Sigor@sysoev.ru     pattern->any = 1;
893964Sigor@sysoev.ru 
894964Sigor@sysoev.ru     if (test.length != 0) {
895964Sigor@sysoev.ru 
896964Sigor@sysoev.ru         if (test.start[0] == '!') {
897964Sigor@sysoev.ru             test.start++;
898964Sigor@sysoev.ru             test.length--;
899964Sigor@sysoev.ru 
900964Sigor@sysoev.ru             pattern->negative = 1;
901964Sigor@sysoev.ru             pattern->any = 0;
902964Sigor@sysoev.ru         }
903964Sigor@sysoev.ru 
904964Sigor@sysoev.ru         if (test.length != 0) {
905964Sigor@sysoev.ru 
906964Sigor@sysoev.ru             if (test.start[0] == '*') {
907964Sigor@sysoev.ru                 test.start++;
908964Sigor@sysoev.ru                 test.length--;
909964Sigor@sysoev.ru 
910964Sigor@sysoev.ru                 if (test.length != 0) {
911964Sigor@sysoev.ru                     if (test.start[test.length - 1] == '*') {
912964Sigor@sysoev.ru                         test.length--;
913964Sigor@sysoev.ru                         type = NXT_HTTP_ROUTE_PATTERN_SUBSTRING;
914964Sigor@sysoev.ru 
915964Sigor@sysoev.ru                     } else {
916964Sigor@sysoev.ru                         type = NXT_HTTP_ROUTE_PATTERN_END;
917964Sigor@sysoev.ru                     }
918964Sigor@sysoev.ru 
919964Sigor@sysoev.ru                 } else {
920964Sigor@sysoev.ru                     type = NXT_HTTP_ROUTE_PATTERN_BEGIN;
921964Sigor@sysoev.ru                 }
922964Sigor@sysoev.ru 
923964Sigor@sysoev.ru             } else if (test.start[test.length - 1] == '*') {
924964Sigor@sysoev.ru                 test.length--;
925964Sigor@sysoev.ru                 type = NXT_HTTP_ROUTE_PATTERN_BEGIN;
9261032Sigor@sysoev.ru 
9271032Sigor@sysoev.ru             } else {
9281032Sigor@sysoev.ru                 length = test.length - 1;
9291032Sigor@sysoev.ru 
9301032Sigor@sysoev.ru                 for (n = 1; n < length; n++) {
9311032Sigor@sysoev.ru                     if (test.start[n] == '*') {
9321032Sigor@sysoev.ru                         test.length = n;
9331032Sigor@sysoev.ru                         type = NXT_HTTP_ROUTE_PATTERN_MIDDLE;
9341032Sigor@sysoev.ru                         break;
9351032Sigor@sysoev.ru                     }
9361032Sigor@sysoev.ru                 }
937964Sigor@sysoev.ru             }
938964Sigor@sysoev.ru         }
939964Sigor@sysoev.ru     }
940964Sigor@sysoev.ru 
941964Sigor@sysoev.ru     pattern->type = type;
942964Sigor@sysoev.ru     pattern->min_length = test.length;
9431032Sigor@sysoev.ru     pattern->length1 = test.length;
944964Sigor@sysoev.ru 
9451032Sigor@sysoev.ru     start = nxt_http_route_pattern_copy(mp, &test, pattern_case);
946964Sigor@sysoev.ru     if (nxt_slow_path(start == NULL)) {
947964Sigor@sysoev.ru         return NXT_ERROR;
948964Sigor@sysoev.ru     }
949964Sigor@sysoev.ru 
9501032Sigor@sysoev.ru     pattern->start1 = start;
9511032Sigor@sysoev.ru 
9521032Sigor@sysoev.ru     if (type == NXT_HTTP_ROUTE_PATTERN_MIDDLE) {
9531032Sigor@sysoev.ru         length -= test.length;
9541032Sigor@sysoev.ru         pattern->length2 = length;
9551032Sigor@sysoev.ru         pattern->min_length += length;
9561032Sigor@sysoev.ru 
9571032Sigor@sysoev.ru         test.start = &test.start[test.length + 1];
9581032Sigor@sysoev.ru         test.length = length;
9591032Sigor@sysoev.ru 
9601032Sigor@sysoev.ru         start = nxt_http_route_pattern_copy(mp, &test, pattern_case);
9611032Sigor@sysoev.ru         if (nxt_slow_path(start == NULL)) {
9621032Sigor@sysoev.ru             return NXT_ERROR;
9631032Sigor@sysoev.ru         }
9641032Sigor@sysoev.ru 
9651032Sigor@sysoev.ru         pattern->start2 = start;
9661032Sigor@sysoev.ru     }
9671032Sigor@sysoev.ru 
9681032Sigor@sysoev.ru     return NXT_OK;
9691032Sigor@sysoev.ru }
9701032Sigor@sysoev.ru 
9711032Sigor@sysoev.ru 
9721032Sigor@sysoev.ru static u_char *
9731032Sigor@sysoev.ru nxt_http_route_pattern_copy(nxt_mp_t *mp, nxt_str_t *test,
9741032Sigor@sysoev.ru     nxt_http_route_pattern_case_t pattern_case)
9751032Sigor@sysoev.ru {
9761032Sigor@sysoev.ru     u_char  *start;
9771032Sigor@sysoev.ru 
9781032Sigor@sysoev.ru     start = nxt_mp_nget(mp, test->length);
9791032Sigor@sysoev.ru     if (nxt_slow_path(start == NULL)) {
9801032Sigor@sysoev.ru         return start;
9811032Sigor@sysoev.ru     }
982964Sigor@sysoev.ru 
983964Sigor@sysoev.ru     switch (pattern_case) {
984964Sigor@sysoev.ru 
985964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_UPCASE:
9861032Sigor@sysoev.ru         nxt_memcpy_upcase(start, test->start, test->length);
987964Sigor@sysoev.ru         break;
988964Sigor@sysoev.ru 
989964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_LOWCASE:
9901032Sigor@sysoev.ru         nxt_memcpy_lowcase(start, test->start, test->length);
991964Sigor@sysoev.ru         break;
992964Sigor@sysoev.ru 
993964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_NOCASE:
9941032Sigor@sysoev.ru         nxt_memcpy(start, test->start, test->length);
995964Sigor@sysoev.ru         break;
996964Sigor@sysoev.ru     }
997964Sigor@sysoev.ru 
9981032Sigor@sysoev.ru     return start;
999964Sigor@sysoev.ru }
1000964Sigor@sysoev.ru 
1001964Sigor@sysoev.ru 
1002964Sigor@sysoev.ru void
1003964Sigor@sysoev.ru nxt_http_routes_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
1004964Sigor@sysoev.ru {
10051033Svbart@nginx.com     nxt_http_route_t   **route, **end;
1006964Sigor@sysoev.ru     nxt_http_routes_t  *routes;
1007964Sigor@sysoev.ru 
1008964Sigor@sysoev.ru     routes = tmcf->router_conf->routes;
10091059Sigor@sysoev.ru 
1010964Sigor@sysoev.ru     if (routes != NULL) {
1011964Sigor@sysoev.ru         route = &routes->route[0];
10121033Svbart@nginx.com         end = route + routes->items;
1013964Sigor@sysoev.ru 
10141033Svbart@nginx.com         while (route < end) {
1015964Sigor@sysoev.ru             nxt_http_route_resolve(task, tmcf, *route);
1016964Sigor@sysoev.ru 
1017964Sigor@sysoev.ru             route++;
1018964Sigor@sysoev.ru         }
1019964Sigor@sysoev.ru     }
1020964Sigor@sysoev.ru }
1021964Sigor@sysoev.ru 
1022964Sigor@sysoev.ru 
1023964Sigor@sysoev.ru static void
1024964Sigor@sysoev.ru nxt_http_route_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1025964Sigor@sysoev.ru     nxt_http_route_t *route)
1026964Sigor@sysoev.ru {
10271264Sigor@sysoev.ru     nxt_http_action_t       *action;
10281033Svbart@nginx.com     nxt_http_route_match_t  **match, **end;
1029964Sigor@sysoev.ru 
1030964Sigor@sysoev.ru     match = &route->match[0];
10311033Svbart@nginx.com     end = match + route->items;
1032964Sigor@sysoev.ru 
10331033Svbart@nginx.com     while (match < end) {
10341264Sigor@sysoev.ru         action = &(*match)->action;
10351183Svbart@nginx.com 
10361264Sigor@sysoev.ru         if (action->handler == NULL) {
10371264Sigor@sysoev.ru             nxt_http_action_resolve(task, tmcf, &(*match)->action);
10381183Svbart@nginx.com         }
1039964Sigor@sysoev.ru 
1040964Sigor@sysoev.ru         match++;
1041964Sigor@sysoev.ru     }
1042964Sigor@sysoev.ru }
1043964Sigor@sysoev.ru 
1044964Sigor@sysoev.ru 
1045964Sigor@sysoev.ru static void
10461264Sigor@sysoev.ru nxt_http_action_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
10471264Sigor@sysoev.ru     nxt_http_action_t *action)
1048964Sigor@sysoev.ru {
1049964Sigor@sysoev.ru     nxt_str_t  name;
1050964Sigor@sysoev.ru 
10511264Sigor@sysoev.ru     name = action->name;
1052964Sigor@sysoev.ru 
1053964Sigor@sysoev.ru     if (nxt_str_start(&name, "applications/", 13)) {
1054964Sigor@sysoev.ru         name.length -= 13;
1055964Sigor@sysoev.ru         name.start += 13;
1056964Sigor@sysoev.ru 
10571264Sigor@sysoev.ru         action->u.application = nxt_router_listener_application(tmcf, &name);
10581264Sigor@sysoev.ru         nxt_router_app_use(task, action->u.application, 1);
1059964Sigor@sysoev.ru 
10601264Sigor@sysoev.ru         action->handler = nxt_http_application_handler;
1061964Sigor@sysoev.ru 
1062964Sigor@sysoev.ru     } else if (nxt_str_start(&name, "routes", 6)) {
1063964Sigor@sysoev.ru 
1064964Sigor@sysoev.ru         if (name.length == 6) {
1065964Sigor@sysoev.ru             name.length = 0;
1066964Sigor@sysoev.ru             name.start = NULL;
1067964Sigor@sysoev.ru 
1068964Sigor@sysoev.ru         } else if (name.start[6] == '/') {
1069964Sigor@sysoev.ru             name.length -= 7;
1070964Sigor@sysoev.ru             name.start += 7;
1071964Sigor@sysoev.ru         }
1072964Sigor@sysoev.ru 
10731264Sigor@sysoev.ru         action->u.route = nxt_http_route_find(tmcf->router_conf->routes, &name);
1074964Sigor@sysoev.ru 
10751264Sigor@sysoev.ru         action->handler = nxt_http_route_handler;
1076964Sigor@sysoev.ru     }
1077964Sigor@sysoev.ru }
1078964Sigor@sysoev.ru 
1079964Sigor@sysoev.ru 
1080964Sigor@sysoev.ru static nxt_http_route_t *
1081964Sigor@sysoev.ru nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name)
1082964Sigor@sysoev.ru {
10831033Svbart@nginx.com     nxt_http_route_t  **route, **end;
1084964Sigor@sysoev.ru 
1085964Sigor@sysoev.ru     route = &routes->route[0];
10861033Svbart@nginx.com     end = route + routes->items;
1087964Sigor@sysoev.ru 
10881058Sigor@sysoev.ru     while (route < end) {
1089964Sigor@sysoev.ru         if (nxt_strstr_eq(&(*route)->name, name)) {
1090964Sigor@sysoev.ru             return *route;
1091964Sigor@sysoev.ru         }
1092964Sigor@sysoev.ru 
1093964Sigor@sysoev.ru         route++;
10941058Sigor@sysoev.ru     }
1095964Sigor@sysoev.ru 
1096964Sigor@sysoev.ru     return NULL;
1097964Sigor@sysoev.ru }
1098964Sigor@sysoev.ru 
1099964Sigor@sysoev.ru 
11001264Sigor@sysoev.ru nxt_http_action_t *
11011264Sigor@sysoev.ru nxt_http_action_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1102964Sigor@sysoev.ru     nxt_str_t *name)
1103964Sigor@sysoev.ru {
11041264Sigor@sysoev.ru     nxt_http_action_t  *action;
1105964Sigor@sysoev.ru 
11061264Sigor@sysoev.ru     action = nxt_mp_alloc(tmcf->router_conf->mem_pool,
11071264Sigor@sysoev.ru                           sizeof(nxt_http_action_t));
11081264Sigor@sysoev.ru     if (nxt_slow_path(action == NULL)) {
1109964Sigor@sysoev.ru         return NULL;
1110964Sigor@sysoev.ru     }
1111964Sigor@sysoev.ru 
11121264Sigor@sysoev.ru     action->name = *name;
11131270Sigor@sysoev.ru     action->handler = NULL;
1114964Sigor@sysoev.ru 
11151264Sigor@sysoev.ru     nxt_http_action_resolve(task, tmcf, action);
1116964Sigor@sysoev.ru 
11171264Sigor@sysoev.ru     return action;
1118964Sigor@sysoev.ru }
1119964Sigor@sysoev.ru 
1120964Sigor@sysoev.ru 
1121964Sigor@sysoev.ru /* COMPATIBILITY: listener application. */
1122964Sigor@sysoev.ru 
11231264Sigor@sysoev.ru nxt_http_action_t *
1124964Sigor@sysoev.ru nxt_http_pass_application(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1125964Sigor@sysoev.ru     nxt_str_t *name)
1126964Sigor@sysoev.ru {
11271264Sigor@sysoev.ru     nxt_http_action_t  *action;
1128964Sigor@sysoev.ru 
11291264Sigor@sysoev.ru     action = nxt_mp_alloc(tmcf->router_conf->mem_pool,
11301264Sigor@sysoev.ru                           sizeof(nxt_http_action_t));
11311264Sigor@sysoev.ru     if (nxt_slow_path(action == NULL)) {
1132964Sigor@sysoev.ru         return NULL;
1133964Sigor@sysoev.ru     }
1134964Sigor@sysoev.ru 
11351264Sigor@sysoev.ru     action->name = *name;
1136964Sigor@sysoev.ru 
11371264Sigor@sysoev.ru     action->u.application = nxt_router_listener_application(tmcf, name);
11381264Sigor@sysoev.ru     nxt_router_app_use(task, action->u.application, 1);
1139964Sigor@sysoev.ru 
11401264Sigor@sysoev.ru     action->handler = nxt_http_application_handler;
1141964Sigor@sysoev.ru 
11421264Sigor@sysoev.ru     return action;
1143964Sigor@sysoev.ru }
1144964Sigor@sysoev.ru 
1145964Sigor@sysoev.ru 
1146964Sigor@sysoev.ru void
1147964Sigor@sysoev.ru nxt_http_routes_cleanup(nxt_task_t *task, nxt_http_routes_t *routes)
1148964Sigor@sysoev.ru {
11491033Svbart@nginx.com     nxt_http_route_t  **route, **end;
1150964Sigor@sysoev.ru 
1151964Sigor@sysoev.ru     if (routes != NULL) {
1152964Sigor@sysoev.ru         route = &routes->route[0];
11531033Svbart@nginx.com         end = route + routes->items;
1154964Sigor@sysoev.ru 
11551058Sigor@sysoev.ru         while (route < end) {
1156964Sigor@sysoev.ru             nxt_http_route_cleanup(task, *route);
1157964Sigor@sysoev.ru 
1158964Sigor@sysoev.ru             route++;
11591058Sigor@sysoev.ru         }
1160964Sigor@sysoev.ru     }
1161964Sigor@sysoev.ru }
1162964Sigor@sysoev.ru 
1163964Sigor@sysoev.ru 
1164964Sigor@sysoev.ru static void
1165964Sigor@sysoev.ru nxt_http_route_cleanup(nxt_task_t *task, nxt_http_route_t *route)
1166964Sigor@sysoev.ru {
11671033Svbart@nginx.com     nxt_http_route_match_t  **match, **end;
1168964Sigor@sysoev.ru 
1169964Sigor@sysoev.ru     match = &route->match[0];
11701033Svbart@nginx.com     end = match + route->items;
1171964Sigor@sysoev.ru 
11721058Sigor@sysoev.ru     while (match < end) {
11731264Sigor@sysoev.ru         nxt_http_action_cleanup(task, &(*match)->action);
1174964Sigor@sysoev.ru 
1175964Sigor@sysoev.ru         match++;
11761058Sigor@sysoev.ru     }
1177964Sigor@sysoev.ru }
1178964Sigor@sysoev.ru 
1179964Sigor@sysoev.ru 
1180964Sigor@sysoev.ru void
11811264Sigor@sysoev.ru nxt_http_action_cleanup(nxt_task_t *task, nxt_http_action_t *action)
1182964Sigor@sysoev.ru {
11831264Sigor@sysoev.ru     if (action->handler == nxt_http_application_handler) {
11841264Sigor@sysoev.ru         nxt_router_app_use(task, action->u.application, -1);
1185964Sigor@sysoev.ru     }
1186964Sigor@sysoev.ru }
1187964Sigor@sysoev.ru 
1188964Sigor@sysoev.ru 
11891264Sigor@sysoev.ru static nxt_http_action_t *
11901264Sigor@sysoev.ru nxt_http_route_handler(nxt_task_t *task, nxt_http_request_t *r,
11911264Sigor@sysoev.ru     nxt_http_action_t *start)
1192964Sigor@sysoev.ru {
1193964Sigor@sysoev.ru     nxt_http_route_t        *route;
11941264Sigor@sysoev.ru     nxt_http_action_t       *action;
11951033Svbart@nginx.com     nxt_http_route_match_t  **match, **end;
1196964Sigor@sysoev.ru 
1197964Sigor@sysoev.ru     route = start->u.route;
1198964Sigor@sysoev.ru     match = &route->match[0];
11991033Svbart@nginx.com     end = match + route->items;
1200964Sigor@sysoev.ru 
12011033Svbart@nginx.com     while (match < end) {
12021264Sigor@sysoev.ru         action = nxt_http_route_match(r, *match);
12031264Sigor@sysoev.ru         if (action != NULL) {
12041264Sigor@sysoev.ru             return action;
1205964Sigor@sysoev.ru         }
1206964Sigor@sysoev.ru 
1207964Sigor@sysoev.ru         match++;
1208964Sigor@sysoev.ru     }
1209964Sigor@sysoev.ru 
1210964Sigor@sysoev.ru     nxt_http_request_error(task, r, NXT_HTTP_NOT_FOUND);
1211964Sigor@sysoev.ru 
1212964Sigor@sysoev.ru     return NULL;
1213964Sigor@sysoev.ru }
1214964Sigor@sysoev.ru 
1215964Sigor@sysoev.ru 
12161264Sigor@sysoev.ru static nxt_http_action_t *
1217964Sigor@sysoev.ru nxt_http_route_match(nxt_http_request_t *r, nxt_http_route_match_t *match)
1218964Sigor@sysoev.ru {
12191060Sigor@sysoev.ru     nxt_int_t              ret;
12201059Sigor@sysoev.ru     nxt_http_route_test_t  *test, *end;
12211059Sigor@sysoev.ru 
12221059Sigor@sysoev.ru     test = &match->test[0];
12231059Sigor@sysoev.ru     end = test + match->items;
1224964Sigor@sysoev.ru 
12251059Sigor@sysoev.ru     while (test < end) {
1226*1324Saxel.duch@nginx.com         switch (test->rule->object) {
1227*1324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_TABLE:
1228*1324Saxel.duch@nginx.com             ret = nxt_http_route_table(r, test->table);
1229*1324Saxel.duch@nginx.com             break;
1230*1324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_SOURCE:
1231*1324Saxel.duch@nginx.com             ret = nxt_http_route_addr_rule(r, test->addr_rule, r->remote);
1232*1324Saxel.duch@nginx.com             break;
1233*1324Saxel.duch@nginx.com         default:
12341059Sigor@sysoev.ru             ret = nxt_http_route_rule(r, test->rule);
1235*1324Saxel.duch@nginx.com             break;
12361059Sigor@sysoev.ru         }
12371059Sigor@sysoev.ru 
12381060Sigor@sysoev.ru         if (ret <= 0) {
12391264Sigor@sysoev.ru             /* 0 => NULL, -1 => NXT_HTTP_ACTION_ERROR. */
12401264Sigor@sysoev.ru             return (nxt_http_action_t *) (intptr_t) ret;
1241964Sigor@sysoev.ru         }
1242964Sigor@sysoev.ru 
12431059Sigor@sysoev.ru         test++;
1244964Sigor@sysoev.ru     }
1245964Sigor@sysoev.ru 
12461264Sigor@sysoev.ru     return &match->action;
1247964Sigor@sysoev.ru }
1248964Sigor@sysoev.ru 
1249964Sigor@sysoev.ru 
12501060Sigor@sysoev.ru static nxt_int_t
12511059Sigor@sysoev.ru nxt_http_route_table(nxt_http_request_t *r, nxt_http_route_table_t *table)
1252964Sigor@sysoev.ru {
12531060Sigor@sysoev.ru     nxt_int_t                 ret;
12541059Sigor@sysoev.ru     nxt_http_route_ruleset_t  **ruleset, **end;
12551059Sigor@sysoev.ru 
12561059Sigor@sysoev.ru     ret = 1;
12571059Sigor@sysoev.ru     ruleset = &table->ruleset[0];
12581059Sigor@sysoev.ru     end = ruleset + table->items;
12591059Sigor@sysoev.ru 
12601059Sigor@sysoev.ru     while (ruleset < end) {
12611059Sigor@sysoev.ru         ret = nxt_http_route_ruleset(r, *ruleset);
12621059Sigor@sysoev.ru 
12631060Sigor@sysoev.ru         if (ret != 0) {
12641059Sigor@sysoev.ru             return ret;
12651059Sigor@sysoev.ru         }
1266964Sigor@sysoev.ru 
12671059Sigor@sysoev.ru         ruleset++;
12681059Sigor@sysoev.ru     }
12691059Sigor@sysoev.ru 
12701059Sigor@sysoev.ru     return ret;
12711059Sigor@sysoev.ru }
12721059Sigor@sysoev.ru 
1273964Sigor@sysoev.ru 
12741060Sigor@sysoev.ru static nxt_int_t
12751059Sigor@sysoev.ru nxt_http_route_ruleset(nxt_http_request_t *r, nxt_http_route_ruleset_t *ruleset)
12761059Sigor@sysoev.ru {
12771060Sigor@sysoev.ru     nxt_int_t              ret;
12781059Sigor@sysoev.ru     nxt_http_route_rule_t  **rule, **end;
1279964Sigor@sysoev.ru 
12801059Sigor@sysoev.ru     rule = &ruleset->rule[0];
12811059Sigor@sysoev.ru     end = rule + ruleset->items;
1282964Sigor@sysoev.ru 
12831059Sigor@sysoev.ru     while (rule < end) {
12841060Sigor@sysoev.ru         ret = nxt_http_route_rule(r, *rule);
12851060Sigor@sysoev.ru 
12861060Sigor@sysoev.ru         if (ret <= 0) {
12871060Sigor@sysoev.ru             return ret;
1288964Sigor@sysoev.ru         }
1289964Sigor@sysoev.ru 
12901059Sigor@sysoev.ru         rule++;
12911059Sigor@sysoev.ru     }
12921059Sigor@sysoev.ru 
12931059Sigor@sysoev.ru     return 1;
12941059Sigor@sysoev.ru }
12951059Sigor@sysoev.ru 
1296964Sigor@sysoev.ru 
12971060Sigor@sysoev.ru static nxt_int_t
12981059Sigor@sysoev.ru nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
12991059Sigor@sysoev.ru {
13001059Sigor@sysoev.ru     void       *p, **pp;
13011059Sigor@sysoev.ru     u_char     *start;
13021059Sigor@sysoev.ru     size_t     length;
13031059Sigor@sysoev.ru     nxt_str_t  *s;
13041059Sigor@sysoev.ru 
13051059Sigor@sysoev.ru     switch (rule->object) {
13061059Sigor@sysoev.ru 
13071059Sigor@sysoev.ru     case NXT_HTTP_ROUTE_HEADER:
13081059Sigor@sysoev.ru         return nxt_http_route_header(r, rule);
1309964Sigor@sysoev.ru 
13101059Sigor@sysoev.ru     case NXT_HTTP_ROUTE_ARGUMENT:
13111061Sigor@sysoev.ru         return nxt_http_route_arguments(r, rule);
1312964Sigor@sysoev.ru 
13131059Sigor@sysoev.ru     case NXT_HTTP_ROUTE_COOKIE:
13141062Sigor@sysoev.ru         return nxt_http_route_cookies(r, rule);
13151059Sigor@sysoev.ru 
13161110Saxel.duch@nginx.com     case NXT_HTTP_ROUTE_SCHEME:
13171110Saxel.duch@nginx.com         return nxt_http_route_scheme(r, rule);
13181110Saxel.duch@nginx.com 
13191059Sigor@sysoev.ru     default:
13201059Sigor@sysoev.ru         break;
13211059Sigor@sysoev.ru     }
1322964Sigor@sysoev.ru 
13231059Sigor@sysoev.ru     p = nxt_pointer_to(r, rule->u.offset);
13241059Sigor@sysoev.ru 
13251059Sigor@sysoev.ru     if (rule->object == NXT_HTTP_ROUTE_STRING) {
13261059Sigor@sysoev.ru         s = p;
1327964Sigor@sysoev.ru 
13281059Sigor@sysoev.ru     } else {
13291059Sigor@sysoev.ru         /* NXT_HTTP_ROUTE_STRING_PTR */
13301059Sigor@sysoev.ru         pp = p;
13311059Sigor@sysoev.ru         s = *pp;
1332964Sigor@sysoev.ru 
13331059Sigor@sysoev.ru         if (s == NULL) {
1334964Sigor@sysoev.ru             return 0;
1335964Sigor@sysoev.ru         }
1336964Sigor@sysoev.ru     }
1337964Sigor@sysoev.ru 
13381059Sigor@sysoev.ru     length = s->length;
13391059Sigor@sysoev.ru     start = s->start;
13401059Sigor@sysoev.ru 
13411059Sigor@sysoev.ru     return nxt_http_route_test_rule(r, rule, start, length);
13421059Sigor@sysoev.ru }
13431059Sigor@sysoev.ru 
13441059Sigor@sysoev.ru 
13451060Sigor@sysoev.ru static nxt_int_t
1346*1324Saxel.duch@nginx.com nxt_http_route_addr_pattern_match(nxt_http_route_addr_pattern_t *p,
1347*1324Saxel.duch@nginx.com     nxt_sockaddr_t *sa)
1348*1324Saxel.duch@nginx.com {
1349*1324Saxel.duch@nginx.com #if (NXT_INET6)
1350*1324Saxel.duch@nginx.com     uint32_t                    i;
1351*1324Saxel.duch@nginx.com #endif
1352*1324Saxel.duch@nginx.com     in_port_t                   in_port;
1353*1324Saxel.duch@nginx.com     nxt_int_t                   match;
1354*1324Saxel.duch@nginx.com     struct sockaddr_in          *sin;
1355*1324Saxel.duch@nginx.com #if (NXT_INET6)
1356*1324Saxel.duch@nginx.com     struct sockaddr_in6         *sin6;
1357*1324Saxel.duch@nginx.com #endif
1358*1324Saxel.duch@nginx.com     nxt_http_route_addr_base_t  *base;
1359*1324Saxel.duch@nginx.com 
1360*1324Saxel.duch@nginx.com     base = &p->base;
1361*1324Saxel.duch@nginx.com 
1362*1324Saxel.duch@nginx.com     switch (sa->u.sockaddr.sa_family) {
1363*1324Saxel.duch@nginx.com 
1364*1324Saxel.duch@nginx.com     case AF_INET:
1365*1324Saxel.duch@nginx.com 
1366*1324Saxel.duch@nginx.com         match = (base->addr_family == AF_INET
1367*1324Saxel.duch@nginx.com                  || base->addr_family == AF_UNSPEC);
1368*1324Saxel.duch@nginx.com         if (!match) {
1369*1324Saxel.duch@nginx.com             break;
1370*1324Saxel.duch@nginx.com         }
1371*1324Saxel.duch@nginx.com 
1372*1324Saxel.duch@nginx.com         sin = &sa->u.sockaddr_in;
1373*1324Saxel.duch@nginx.com         in_port = ntohs(sin->sin_port);
1374*1324Saxel.duch@nginx.com 
1375*1324Saxel.duch@nginx.com         match = (in_port >= base->port.start && in_port <= base->port.end);
1376*1324Saxel.duch@nginx.com         if (!match) {
1377*1324Saxel.duch@nginx.com             break;
1378*1324Saxel.duch@nginx.com         }
1379*1324Saxel.duch@nginx.com 
1380*1324Saxel.duch@nginx.com         switch (base->match_type) {
1381*1324Saxel.duch@nginx.com 
1382*1324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_ADDR_ANY:
1383*1324Saxel.duch@nginx.com             break;
1384*1324Saxel.duch@nginx.com 
1385*1324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_ADDR_EXACT:
1386*1324Saxel.duch@nginx.com             match = (nxt_memcmp(&sin->sin_addr, &p->addr.v4.start,
1387*1324Saxel.duch@nginx.com                                 sizeof(struct in_addr))
1388*1324Saxel.duch@nginx.com                      == 0);
1389*1324Saxel.duch@nginx.com             break;
1390*1324Saxel.duch@nginx.com 
1391*1324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_ADDR_RANGE:
1392*1324Saxel.duch@nginx.com             match = (nxt_memcmp(&sin->sin_addr, &p->addr.v4.start,
1393*1324Saxel.duch@nginx.com                                 sizeof(struct in_addr)) >= 0
1394*1324Saxel.duch@nginx.com                      && nxt_memcmp(&sin->sin_addr, &p->addr.v4.end,
1395*1324Saxel.duch@nginx.com                                    sizeof(struct in_addr)) <= 0);
1396*1324Saxel.duch@nginx.com             break;
1397*1324Saxel.duch@nginx.com 
1398*1324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_ADDR_CIDR:
1399*1324Saxel.duch@nginx.com             match = ((sin->sin_addr.s_addr & p->addr.v4.end)
1400*1324Saxel.duch@nginx.com                      == p->addr.v4.start);
1401*1324Saxel.duch@nginx.com             break;
1402*1324Saxel.duch@nginx.com 
1403*1324Saxel.duch@nginx.com         default:
1404*1324Saxel.duch@nginx.com             nxt_unreachable();
1405*1324Saxel.duch@nginx.com         }
1406*1324Saxel.duch@nginx.com 
1407*1324Saxel.duch@nginx.com         break;
1408*1324Saxel.duch@nginx.com 
1409*1324Saxel.duch@nginx.com #if (NXT_INET6)
1410*1324Saxel.duch@nginx.com     case AF_INET6:
1411*1324Saxel.duch@nginx.com 
1412*1324Saxel.duch@nginx.com         match = (base->addr_family == AF_INET6
1413*1324Saxel.duch@nginx.com                  || base->addr_family == AF_UNSPEC);
1414*1324Saxel.duch@nginx.com         if (!match) {
1415*1324Saxel.duch@nginx.com             break;
1416*1324Saxel.duch@nginx.com         }
1417*1324Saxel.duch@nginx.com 
1418*1324Saxel.duch@nginx.com         sin6 = &sa->u.sockaddr_in6;
1419*1324Saxel.duch@nginx.com         in_port = ntohs(sin6->sin6_port);
1420*1324Saxel.duch@nginx.com 
1421*1324Saxel.duch@nginx.com         match = (in_port >= base->port.start && in_port <= base->port.end);
1422*1324Saxel.duch@nginx.com         if (!match) {
1423*1324Saxel.duch@nginx.com             break;
1424*1324Saxel.duch@nginx.com         }
1425*1324Saxel.duch@nginx.com 
1426*1324Saxel.duch@nginx.com         switch (base->match_type) {
1427*1324Saxel.duch@nginx.com 
1428*1324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_ADDR_ANY:
1429*1324Saxel.duch@nginx.com             break;
1430*1324Saxel.duch@nginx.com 
1431*1324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_ADDR_EXACT:
1432*1324Saxel.duch@nginx.com             match = (nxt_memcmp(&sin6->sin6_addr, &p->addr.v6.start,
1433*1324Saxel.duch@nginx.com                                 sizeof(struct in6_addr))
1434*1324Saxel.duch@nginx.com                      == 0);
1435*1324Saxel.duch@nginx.com             break;
1436*1324Saxel.duch@nginx.com 
1437*1324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_ADDR_RANGE:
1438*1324Saxel.duch@nginx.com             match = (nxt_memcmp(&sin6->sin6_addr, &p->addr.v6.start,
1439*1324Saxel.duch@nginx.com                                 sizeof(struct in6_addr)) >= 0
1440*1324Saxel.duch@nginx.com                      && nxt_memcmp(&sin6->sin6_addr, &p->addr.v6.end,
1441*1324Saxel.duch@nginx.com                                    sizeof(struct in6_addr)) <= 0);
1442*1324Saxel.duch@nginx.com             break;
1443*1324Saxel.duch@nginx.com 
1444*1324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_ADDR_CIDR:
1445*1324Saxel.duch@nginx.com             for (i = 0; i < 16; i++) {
1446*1324Saxel.duch@nginx.com                 match = ((sin6->sin6_addr.s6_addr[i]
1447*1324Saxel.duch@nginx.com                           & p->addr.v6.end.s6_addr[i])
1448*1324Saxel.duch@nginx.com                          == p->addr.v6.start.s6_addr[i]);
1449*1324Saxel.duch@nginx.com 
1450*1324Saxel.duch@nginx.com                 if (!match) {
1451*1324Saxel.duch@nginx.com                     break;
1452*1324Saxel.duch@nginx.com                 }
1453*1324Saxel.duch@nginx.com             }
1454*1324Saxel.duch@nginx.com 
1455*1324Saxel.duch@nginx.com             break;
1456*1324Saxel.duch@nginx.com 
1457*1324Saxel.duch@nginx.com         default:
1458*1324Saxel.duch@nginx.com             nxt_unreachable();
1459*1324Saxel.duch@nginx.com         }
1460*1324Saxel.duch@nginx.com 
1461*1324Saxel.duch@nginx.com         break;
1462*1324Saxel.duch@nginx.com #endif
1463*1324Saxel.duch@nginx.com 
1464*1324Saxel.duch@nginx.com     default:
1465*1324Saxel.duch@nginx.com         match = 0;
1466*1324Saxel.duch@nginx.com         break;
1467*1324Saxel.duch@nginx.com     }
1468*1324Saxel.duch@nginx.com 
1469*1324Saxel.duch@nginx.com     return match ^ base->negative;
1470*1324Saxel.duch@nginx.com }
1471*1324Saxel.duch@nginx.com 
1472*1324Saxel.duch@nginx.com 
1473*1324Saxel.duch@nginx.com static nxt_int_t
1474*1324Saxel.duch@nginx.com nxt_http_route_addr_rule(nxt_http_request_t *r,
1475*1324Saxel.duch@nginx.com     nxt_http_route_addr_rule_t *addr_rule, nxt_sockaddr_t *sa)
1476*1324Saxel.duch@nginx.com {
1477*1324Saxel.duch@nginx.com     uint32_t                       i, n;
1478*1324Saxel.duch@nginx.com     nxt_http_route_addr_pattern_t  *p;
1479*1324Saxel.duch@nginx.com 
1480*1324Saxel.duch@nginx.com     n = addr_rule->items;
1481*1324Saxel.duch@nginx.com 
1482*1324Saxel.duch@nginx.com     for (i = 0; i < n; i++) {
1483*1324Saxel.duch@nginx.com         p = &addr_rule->addr_pattern[i];
1484*1324Saxel.duch@nginx.com         if (nxt_http_route_addr_pattern_match(p, sa)) {
1485*1324Saxel.duch@nginx.com             return 1;
1486*1324Saxel.duch@nginx.com         }
1487*1324Saxel.duch@nginx.com     }
1488*1324Saxel.duch@nginx.com 
1489*1324Saxel.duch@nginx.com     return 0;
1490*1324Saxel.duch@nginx.com }
1491*1324Saxel.duch@nginx.com 
1492*1324Saxel.duch@nginx.com 
1493*1324Saxel.duch@nginx.com static nxt_int_t
14941059Sigor@sysoev.ru nxt_http_route_header(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
14951059Sigor@sysoev.ru {
14961060Sigor@sysoev.ru     nxt_int_t         ret;
14971059Sigor@sysoev.ru     nxt_http_field_t  *f;
14981059Sigor@sysoev.ru 
14991059Sigor@sysoev.ru     ret = 0;
15001059Sigor@sysoev.ru 
15011059Sigor@sysoev.ru     nxt_list_each(f, r->fields) {
15021059Sigor@sysoev.ru 
15031059Sigor@sysoev.ru         if (rule->u.name.hash != f->hash
15041059Sigor@sysoev.ru             || rule->u.name.length != f->name_length
15051059Sigor@sysoev.ru             || nxt_strncasecmp(rule->u.name.start, f->name, f->name_length)
15061059Sigor@sysoev.ru                != 0)
15071059Sigor@sysoev.ru         {
15081059Sigor@sysoev.ru             continue;
15091059Sigor@sysoev.ru         }
15101059Sigor@sysoev.ru 
15111059Sigor@sysoev.ru         ret = nxt_http_route_test_rule(r, rule, f->value, f->value_length);
15121059Sigor@sysoev.ru 
15131060Sigor@sysoev.ru         if (ret == 0) {
15141059Sigor@sysoev.ru             return ret;
15151059Sigor@sysoev.ru         }
15161059Sigor@sysoev.ru 
15171059Sigor@sysoev.ru     } nxt_list_loop;
15181059Sigor@sysoev.ru 
15191059Sigor@sysoev.ru     return ret;
15201059Sigor@sysoev.ru }
15211059Sigor@sysoev.ru 
15221059Sigor@sysoev.ru 
15231060Sigor@sysoev.ru static nxt_int_t
15241061Sigor@sysoev.ru nxt_http_route_arguments(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
15251061Sigor@sysoev.ru {
15261061Sigor@sysoev.ru     nxt_array_t  *arguments;
15271061Sigor@sysoev.ru 
15281061Sigor@sysoev.ru     if (r->args == NULL) {
15291061Sigor@sysoev.ru         return 0;
15301061Sigor@sysoev.ru     }
15311061Sigor@sysoev.ru 
15321061Sigor@sysoev.ru     arguments = nxt_http_route_arguments_parse(r);
15331061Sigor@sysoev.ru     if (nxt_slow_path(arguments == NULL)) {
15341061Sigor@sysoev.ru         return -1;
15351061Sigor@sysoev.ru     }
15361061Sigor@sysoev.ru 
15371061Sigor@sysoev.ru     return nxt_http_route_test_argument(r, rule, arguments);
15381061Sigor@sysoev.ru }
15391061Sigor@sysoev.ru 
15401061Sigor@sysoev.ru 
15411061Sigor@sysoev.ru static nxt_array_t *
15421061Sigor@sysoev.ru nxt_http_route_arguments_parse(nxt_http_request_t *r)
15431061Sigor@sysoev.ru {
15441061Sigor@sysoev.ru     size_t                 name_length;
15451061Sigor@sysoev.ru     u_char                 c, *p, *start, *end, *name;
15461061Sigor@sysoev.ru     uint32_t               hash;
15471061Sigor@sysoev.ru     nxt_bool_t             valid;
15481061Sigor@sysoev.ru     nxt_array_t            *args;
15491061Sigor@sysoev.ru     nxt_http_name_value_t  *nv;
15501061Sigor@sysoev.ru 
15511061Sigor@sysoev.ru     if (r->arguments != NULL) {
15521061Sigor@sysoev.ru         return r->arguments;
15531061Sigor@sysoev.ru     }
15541061Sigor@sysoev.ru 
15551061Sigor@sysoev.ru     args = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t));
15561061Sigor@sysoev.ru     if (nxt_slow_path(args == NULL)) {
15571061Sigor@sysoev.ru         return NULL;
15581061Sigor@sysoev.ru     }
15591061Sigor@sysoev.ru 
15601061Sigor@sysoev.ru     hash = NXT_HTTP_FIELD_HASH_INIT;
15611061Sigor@sysoev.ru     valid = 1;
15621061Sigor@sysoev.ru     name = NULL;
15631061Sigor@sysoev.ru     name_length = 0;
15641061Sigor@sysoev.ru 
15651061Sigor@sysoev.ru     start = r->args->start;
15661061Sigor@sysoev.ru     end = start + r->args->length;
15671061Sigor@sysoev.ru 
15681061Sigor@sysoev.ru     for (p = start; p < end; p++) {
15691061Sigor@sysoev.ru         c = *p;
15701061Sigor@sysoev.ru 
15711061Sigor@sysoev.ru         if (c == '=') {
15721061Sigor@sysoev.ru             name_length = p - start;
15731061Sigor@sysoev.ru             name = start;
15741061Sigor@sysoev.ru             start = p + 1;
15751061Sigor@sysoev.ru             valid = (name_length != 0);
15761061Sigor@sysoev.ru 
15771061Sigor@sysoev.ru         } else if (c == '&') {
15781061Sigor@sysoev.ru             if (valid) {
15791061Sigor@sysoev.ru                 nv = nxt_http_route_argument(args, name, name_length, hash,
15801061Sigor@sysoev.ru                                              start, p);
15811061Sigor@sysoev.ru                 if (nxt_slow_path(nv == NULL)) {
15821061Sigor@sysoev.ru                     return NULL;
15831061Sigor@sysoev.ru                 }
15841061Sigor@sysoev.ru             }
15851061Sigor@sysoev.ru 
15861061Sigor@sysoev.ru             hash = NXT_HTTP_FIELD_HASH_INIT;
15871061Sigor@sysoev.ru             valid = 1;
15881061Sigor@sysoev.ru             name = NULL;
15891061Sigor@sysoev.ru             start = p + 1;
15901061Sigor@sysoev.ru 
15911061Sigor@sysoev.ru         } else if (name == NULL) {
15921061Sigor@sysoev.ru             hash = nxt_http_field_hash_char(hash, c);
15931061Sigor@sysoev.ru         }
15941061Sigor@sysoev.ru     }
15951061Sigor@sysoev.ru 
15961061Sigor@sysoev.ru     if (valid) {
15971061Sigor@sysoev.ru         nv = nxt_http_route_argument(args, name, name_length, hash, start, p);
15981061Sigor@sysoev.ru         if (nxt_slow_path(nv == NULL)) {
15991061Sigor@sysoev.ru             return NULL;
16001061Sigor@sysoev.ru         }
16011061Sigor@sysoev.ru     }
16021061Sigor@sysoev.ru 
16031061Sigor@sysoev.ru     r->arguments = args;
16041061Sigor@sysoev.ru 
16051061Sigor@sysoev.ru     return args;
16061061Sigor@sysoev.ru }
16071061Sigor@sysoev.ru 
16081061Sigor@sysoev.ru 
16091061Sigor@sysoev.ru static nxt_http_name_value_t *
16101061Sigor@sysoev.ru nxt_http_route_argument(nxt_array_t *array, u_char *name, size_t name_length,
16111061Sigor@sysoev.ru     uint32_t hash, u_char *start, u_char *end)
16121061Sigor@sysoev.ru {
16131061Sigor@sysoev.ru     size_t                 length;
16141061Sigor@sysoev.ru     nxt_http_name_value_t  *nv;
16151061Sigor@sysoev.ru 
16161061Sigor@sysoev.ru     nv = nxt_array_add(array);
16171061Sigor@sysoev.ru     if (nxt_slow_path(nv == NULL)) {
16181061Sigor@sysoev.ru         return NULL;
16191061Sigor@sysoev.ru     }
16201061Sigor@sysoev.ru 
16211061Sigor@sysoev.ru     nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF;
16221061Sigor@sysoev.ru 
16231061Sigor@sysoev.ru     length = end - start;
16241061Sigor@sysoev.ru 
16251061Sigor@sysoev.ru     if (name == NULL) {
16261061Sigor@sysoev.ru         name_length = length;
16271061Sigor@sysoev.ru         name = start;
16281061Sigor@sysoev.ru         length = 0;
16291061Sigor@sysoev.ru     }
16301061Sigor@sysoev.ru 
16311061Sigor@sysoev.ru     nv->name_length = name_length;
16321061Sigor@sysoev.ru     nv->value_length = length;
16331061Sigor@sysoev.ru     nv->name = name;
16341061Sigor@sysoev.ru     nv->value = start;
16351061Sigor@sysoev.ru 
16361061Sigor@sysoev.ru     return nv;
16371061Sigor@sysoev.ru }
16381061Sigor@sysoev.ru 
16391061Sigor@sysoev.ru 
16401061Sigor@sysoev.ru static nxt_int_t
16411061Sigor@sysoev.ru nxt_http_route_test_argument(nxt_http_request_t *r,
16421061Sigor@sysoev.ru     nxt_http_route_rule_t *rule, nxt_array_t *array)
16431061Sigor@sysoev.ru {
16441061Sigor@sysoev.ru     nxt_bool_t             ret;
16451061Sigor@sysoev.ru     nxt_http_name_value_t  *nv, *end;
16461061Sigor@sysoev.ru 
16471061Sigor@sysoev.ru     ret = 0;
16481061Sigor@sysoev.ru 
16491061Sigor@sysoev.ru     nv = array->elts;
16501061Sigor@sysoev.ru     end = nv + array->nelts;
16511061Sigor@sysoev.ru 
16521061Sigor@sysoev.ru     while (nv < end) {
16531061Sigor@sysoev.ru 
16541061Sigor@sysoev.ru         if (rule->u.name.hash == nv->hash
16551061Sigor@sysoev.ru             && rule->u.name.length == nv->name_length
16561061Sigor@sysoev.ru             && nxt_memcmp(rule->u.name.start, nv->name, nv->name_length) == 0)
16571061Sigor@sysoev.ru         {
16581061Sigor@sysoev.ru             ret = nxt_http_route_test_rule(r, rule, nv->value,
16591061Sigor@sysoev.ru                                            nv->value_length);
16601061Sigor@sysoev.ru             if (ret == 0) {
16611061Sigor@sysoev.ru                 break;
16621061Sigor@sysoev.ru             }
16631061Sigor@sysoev.ru         }
16641061Sigor@sysoev.ru 
16651061Sigor@sysoev.ru         nv++;
16661061Sigor@sysoev.ru     }
16671061Sigor@sysoev.ru 
16681061Sigor@sysoev.ru     return ret;
16691061Sigor@sysoev.ru }
16701061Sigor@sysoev.ru 
16711061Sigor@sysoev.ru 
16721061Sigor@sysoev.ru static nxt_int_t
16731110Saxel.duch@nginx.com nxt_http_route_scheme(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
16741110Saxel.duch@nginx.com {
16751110Saxel.duch@nginx.com     nxt_bool_t  tls, https;
16761110Saxel.duch@nginx.com 
16771110Saxel.duch@nginx.com     https = (rule->pattern[0].length1 == nxt_length("https"));
16781110Saxel.duch@nginx.com     tls = (r->tls != NULL);
16791110Saxel.duch@nginx.com 
16801110Saxel.duch@nginx.com     return (tls == https);
16811110Saxel.duch@nginx.com }
16821110Saxel.duch@nginx.com 
16831110Saxel.duch@nginx.com 
16841110Saxel.duch@nginx.com static nxt_int_t
16851062Sigor@sysoev.ru nxt_http_route_cookies(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
16861062Sigor@sysoev.ru {
16871062Sigor@sysoev.ru     nxt_array_t  *cookies;
16881062Sigor@sysoev.ru 
16891062Sigor@sysoev.ru     cookies = nxt_http_route_cookies_parse(r);
16901062Sigor@sysoev.ru     if (nxt_slow_path(cookies == NULL)) {
16911062Sigor@sysoev.ru         return -1;
16921062Sigor@sysoev.ru     }
16931062Sigor@sysoev.ru 
16941062Sigor@sysoev.ru     return nxt_http_route_test_cookie(r, rule, cookies);
16951062Sigor@sysoev.ru }
16961062Sigor@sysoev.ru 
16971062Sigor@sysoev.ru 
16981062Sigor@sysoev.ru static nxt_array_t *
16991062Sigor@sysoev.ru nxt_http_route_cookies_parse(nxt_http_request_t *r)
17001062Sigor@sysoev.ru {
17011062Sigor@sysoev.ru     nxt_int_t         ret;
17021062Sigor@sysoev.ru     nxt_array_t       *cookies;
17031062Sigor@sysoev.ru     nxt_http_field_t  *f;
17041062Sigor@sysoev.ru 
17051062Sigor@sysoev.ru     if (r->cookies != NULL) {
17061062Sigor@sysoev.ru         return r->cookies;
17071062Sigor@sysoev.ru     }
17081062Sigor@sysoev.ru 
17091062Sigor@sysoev.ru     cookies = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t));
17101062Sigor@sysoev.ru     if (nxt_slow_path(cookies == NULL)) {
17111062Sigor@sysoev.ru         return NULL;
17121062Sigor@sysoev.ru     }
17131062Sigor@sysoev.ru 
17141062Sigor@sysoev.ru     nxt_list_each(f, r->fields) {
17151062Sigor@sysoev.ru 
17161062Sigor@sysoev.ru         if (f->hash != NJS_COOKIE_HASH
17171062Sigor@sysoev.ru             || f->name_length != 6
17181062Sigor@sysoev.ru             || nxt_strncasecmp(f->name, (u_char *) "Cookie", 6) != 0)
17191062Sigor@sysoev.ru         {
17201062Sigor@sysoev.ru             continue;
17211062Sigor@sysoev.ru         }
17221062Sigor@sysoev.ru 
17231062Sigor@sysoev.ru         ret = nxt_http_route_cookie_parse(cookies, f->value,
17241062Sigor@sysoev.ru                                           f->value + f->value_length);
17251062Sigor@sysoev.ru         if (ret != NXT_OK) {
17261062Sigor@sysoev.ru             return NULL;
17271062Sigor@sysoev.ru         }
17281062Sigor@sysoev.ru 
17291062Sigor@sysoev.ru     } nxt_list_loop;
17301062Sigor@sysoev.ru 
17311062Sigor@sysoev.ru     r->cookies = cookies;
17321062Sigor@sysoev.ru 
17331062Sigor@sysoev.ru     return cookies;
17341062Sigor@sysoev.ru }
17351062Sigor@sysoev.ru 
17361062Sigor@sysoev.ru 
17371062Sigor@sysoev.ru static nxt_int_t
17381062Sigor@sysoev.ru nxt_http_route_cookie_parse(nxt_array_t *cookies, u_char *start, u_char *end)
17391062Sigor@sysoev.ru {
17401062Sigor@sysoev.ru     size_t                 name_length;
17411062Sigor@sysoev.ru     u_char                 c, *p, *name;
17421062Sigor@sysoev.ru     nxt_http_name_value_t  *nv;
17431062Sigor@sysoev.ru 
17441062Sigor@sysoev.ru     name = NULL;
17451062Sigor@sysoev.ru     name_length = 0;
17461062Sigor@sysoev.ru 
17471062Sigor@sysoev.ru     for (p = start; p < end; p++) {
17481062Sigor@sysoev.ru         c = *p;
17491062Sigor@sysoev.ru 
17501062Sigor@sysoev.ru         if (c == '=') {
17511062Sigor@sysoev.ru             while (start[0] == ' ') { start++; }
17521062Sigor@sysoev.ru 
17531062Sigor@sysoev.ru             name_length = p - start;
17541062Sigor@sysoev.ru 
17551062Sigor@sysoev.ru             if (name_length != 0) {
17561062Sigor@sysoev.ru                 name = start;
17571062Sigor@sysoev.ru             }
17581062Sigor@sysoev.ru 
17591062Sigor@sysoev.ru             start = p + 1;
17601062Sigor@sysoev.ru 
17611062Sigor@sysoev.ru         } else if (c == ';') {
17621062Sigor@sysoev.ru             if (name != NULL) {
17631062Sigor@sysoev.ru                 nv = nxt_http_route_cookie(cookies, name, name_length,
17641062Sigor@sysoev.ru                                            start, p);
17651062Sigor@sysoev.ru                 if (nxt_slow_path(nv == NULL)) {
17661062Sigor@sysoev.ru                     return NXT_ERROR;
17671062Sigor@sysoev.ru                 }
17681062Sigor@sysoev.ru             }
17691062Sigor@sysoev.ru 
17701062Sigor@sysoev.ru             name = NULL;
17711062Sigor@sysoev.ru             start = p + 1;
17721062Sigor@sysoev.ru          }
17731062Sigor@sysoev.ru     }
17741062Sigor@sysoev.ru 
17751062Sigor@sysoev.ru     if (name != NULL) {
17761062Sigor@sysoev.ru         nv = nxt_http_route_cookie(cookies, name, name_length, start, p);
17771062Sigor@sysoev.ru         if (nxt_slow_path(nv == NULL)) {
17781062Sigor@sysoev.ru             return NXT_ERROR;
17791062Sigor@sysoev.ru         }
17801062Sigor@sysoev.ru     }
17811062Sigor@sysoev.ru 
17821062Sigor@sysoev.ru     return NXT_OK;
17831062Sigor@sysoev.ru }
17841062Sigor@sysoev.ru 
17851062Sigor@sysoev.ru 
17861062Sigor@sysoev.ru static nxt_http_name_value_t *
17871062Sigor@sysoev.ru nxt_http_route_cookie(nxt_array_t *array, u_char *name, size_t name_length,
17881062Sigor@sysoev.ru     u_char *start, u_char *end)
17891062Sigor@sysoev.ru {
17901062Sigor@sysoev.ru     u_char                 c, *p;
17911062Sigor@sysoev.ru     uint32_t               hash;
17921062Sigor@sysoev.ru     nxt_http_name_value_t  *nv;
17931062Sigor@sysoev.ru 
17941062Sigor@sysoev.ru     nv = nxt_array_add(array);
17951062Sigor@sysoev.ru     if (nxt_slow_path(nv == NULL)) {
17961062Sigor@sysoev.ru         return NULL;
17971062Sigor@sysoev.ru     }
17981062Sigor@sysoev.ru 
17991062Sigor@sysoev.ru     nv->name_length = name_length;
18001062Sigor@sysoev.ru     nv->name = name;
18011062Sigor@sysoev.ru 
18021062Sigor@sysoev.ru     hash = NXT_HTTP_FIELD_HASH_INIT;
18031062Sigor@sysoev.ru 
18041062Sigor@sysoev.ru     for (p = name; p < name + name_length; p++) {
18051062Sigor@sysoev.ru         c = *p;
18061062Sigor@sysoev.ru         hash = nxt_http_field_hash_char(hash, c);
18071062Sigor@sysoev.ru     }
18081062Sigor@sysoev.ru 
18091062Sigor@sysoev.ru     nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF;
18101062Sigor@sysoev.ru 
18111062Sigor@sysoev.ru     while (start < end && end[-1] == ' ') { end--; }
18121062Sigor@sysoev.ru 
18131062Sigor@sysoev.ru     nv->value_length = end - start;
18141062Sigor@sysoev.ru     nv->value = start;
18151062Sigor@sysoev.ru 
18161062Sigor@sysoev.ru     return nv;
18171062Sigor@sysoev.ru }
18181062Sigor@sysoev.ru 
18191062Sigor@sysoev.ru 
18201062Sigor@sysoev.ru static nxt_int_t
18211062Sigor@sysoev.ru nxt_http_route_test_cookie(nxt_http_request_t *r,
18221062Sigor@sysoev.ru     nxt_http_route_rule_t *rule, nxt_array_t *array)
18231062Sigor@sysoev.ru {
18241062Sigor@sysoev.ru     nxt_bool_t             ret;
18251062Sigor@sysoev.ru     nxt_http_name_value_t  *nv, *end;
18261062Sigor@sysoev.ru 
18271062Sigor@sysoev.ru     ret = 0;
18281062Sigor@sysoev.ru 
18291062Sigor@sysoev.ru     nv = array->elts;
18301062Sigor@sysoev.ru     end = nv + array->nelts;
18311062Sigor@sysoev.ru 
18321062Sigor@sysoev.ru     while (nv < end) {
18331062Sigor@sysoev.ru 
18341062Sigor@sysoev.ru         if (rule->u.name.hash == nv->hash
18351062Sigor@sysoev.ru             && rule->u.name.length == nv->name_length
18361079Sigor@sysoev.ru             && nxt_memcmp(rule->u.name.start, nv->name, nv->name_length) == 0)
18371062Sigor@sysoev.ru         {
18381062Sigor@sysoev.ru             ret = nxt_http_route_test_rule(r, rule, nv->value,
18391062Sigor@sysoev.ru                                            nv->value_length);
18401062Sigor@sysoev.ru             if (ret == 0) {
18411062Sigor@sysoev.ru                 break;
18421062Sigor@sysoev.ru             }
18431062Sigor@sysoev.ru         }
18441062Sigor@sysoev.ru 
18451062Sigor@sysoev.ru         nv++;
18461062Sigor@sysoev.ru     }
18471062Sigor@sysoev.ru 
18481062Sigor@sysoev.ru     return ret;
18491062Sigor@sysoev.ru }
18501062Sigor@sysoev.ru 
18511062Sigor@sysoev.ru 
18521062Sigor@sysoev.ru static nxt_int_t
18531059Sigor@sysoev.ru nxt_http_route_test_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule,
18541059Sigor@sysoev.ru     u_char *start, size_t length)
18551059Sigor@sysoev.ru {
18561060Sigor@sysoev.ru     nxt_int_t                 ret;
18571059Sigor@sysoev.ru     nxt_http_route_pattern_t  *pattern, *end;
18581059Sigor@sysoev.ru 
18591057Sigor@sysoev.ru     ret = 1;
1860964Sigor@sysoev.ru     pattern = &rule->pattern[0];
18611033Svbart@nginx.com     end = pattern + rule->items;
1862964Sigor@sysoev.ru 
18631057Sigor@sysoev.ru     while (pattern < end) {
1864964Sigor@sysoev.ru         ret = nxt_http_route_pattern(r, pattern, start, length);
1865964Sigor@sysoev.ru 
18661060Sigor@sysoev.ru         /* nxt_http_route_pattern() returns either 1 or 0. */
1867964Sigor@sysoev.ru         ret ^= pattern->negative;
1868964Sigor@sysoev.ru 
1869964Sigor@sysoev.ru         if (pattern->any == ret) {
1870964Sigor@sysoev.ru             return ret;
1871964Sigor@sysoev.ru         }
1872964Sigor@sysoev.ru 
1873964Sigor@sysoev.ru         pattern++;
18741057Sigor@sysoev.ru     }
1875964Sigor@sysoev.ru 
1876964Sigor@sysoev.ru     return ret;
1877964Sigor@sysoev.ru }
1878964Sigor@sysoev.ru 
1879964Sigor@sysoev.ru 
18801060Sigor@sysoev.ru static nxt_int_t
1881964Sigor@sysoev.ru nxt_http_route_pattern(nxt_http_request_t *r, nxt_http_route_pattern_t *pattern,
1882964Sigor@sysoev.ru     u_char *start, size_t length)
1883964Sigor@sysoev.ru {
18841060Sigor@sysoev.ru     u_char     *p, *end, *test;
18851060Sigor@sysoev.ru     size_t     test_length;
18861060Sigor@sysoev.ru     nxt_int_t  ret;
1887964Sigor@sysoev.ru 
1888964Sigor@sysoev.ru     if (length < pattern->min_length) {
1889964Sigor@sysoev.ru         return 0;
1890964Sigor@sysoev.ru     }
1891964Sigor@sysoev.ru 
18921032Sigor@sysoev.ru     test = pattern->start1;
18931032Sigor@sysoev.ru     test_length = pattern->length1;
1894964Sigor@sysoev.ru 
1895964Sigor@sysoev.ru     switch (pattern->type) {
1896964Sigor@sysoev.ru 
1897964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_EXACT:
18981032Sigor@sysoev.ru         if (length != test_length) {
1899964Sigor@sysoev.ru             return 0;
1900964Sigor@sysoev.ru         }
1901964Sigor@sysoev.ru 
1902964Sigor@sysoev.ru         break;
1903964Sigor@sysoev.ru 
1904964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_BEGIN:
1905964Sigor@sysoev.ru         break;
1906964Sigor@sysoev.ru 
19071032Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_MIDDLE:
19081032Sigor@sysoev.ru         ret = nxt_http_route_memcmp(start, test, test_length,
19091032Sigor@sysoev.ru                                     pattern->case_sensitive);
19101032Sigor@sysoev.ru         if (!ret) {
19111032Sigor@sysoev.ru             return ret;
19121032Sigor@sysoev.ru         }
19131032Sigor@sysoev.ru 
19141032Sigor@sysoev.ru         test = pattern->start2;
19151032Sigor@sysoev.ru         test_length = pattern->length2;
19161032Sigor@sysoev.ru 
19171032Sigor@sysoev.ru         /* Fall through. */
19181032Sigor@sysoev.ru 
1919964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_END:
19201032Sigor@sysoev.ru         start += length - test_length;
1921964Sigor@sysoev.ru         break;
1922964Sigor@sysoev.ru 
1923964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_SUBSTRING:
19241032Sigor@sysoev.ru         end = start + length;
19251032Sigor@sysoev.ru 
1926964Sigor@sysoev.ru         if (pattern->case_sensitive) {
19271032Sigor@sysoev.ru             p = nxt_memstrn(start, end, (char *) test, test_length);
19281032Sigor@sysoev.ru 
19291032Sigor@sysoev.ru         } else {
19301032Sigor@sysoev.ru             p = nxt_memcasestrn(start, end, (char *) test, test_length);
1931964Sigor@sysoev.ru         }
1932964Sigor@sysoev.ru 
19331032Sigor@sysoev.ru         return (p != NULL);
1934964Sigor@sysoev.ru     }
1935964Sigor@sysoev.ru 
19361032Sigor@sysoev.ru     return nxt_http_route_memcmp(start, test, test_length,
19371032Sigor@sysoev.ru                                  pattern->case_sensitive);
19381032Sigor@sysoev.ru }
19391032Sigor@sysoev.ru 
19401032Sigor@sysoev.ru 
19411060Sigor@sysoev.ru static nxt_int_t
19421032Sigor@sysoev.ru nxt_http_route_memcmp(u_char *start, u_char *test, size_t test_length,
19431032Sigor@sysoev.ru     nxt_bool_t case_sensitive)
19441032Sigor@sysoev.ru {
19451032Sigor@sysoev.ru     nxt_int_t  n;
19461032Sigor@sysoev.ru 
19471032Sigor@sysoev.ru     if (case_sensitive) {
19481032Sigor@sysoev.ru         n = nxt_memcmp(start, test, test_length);
19491032Sigor@sysoev.ru 
19501032Sigor@sysoev.ru     } else {
19511032Sigor@sysoev.ru         n = nxt_memcasecmp(start, test, test_length);
1952964Sigor@sysoev.ru     }
1953964Sigor@sysoev.ru 
19541032Sigor@sysoev.ru     return (n == 0);
1955964Sigor@sysoev.ru }
1956