xref: /unit/src/nxt_http_route.c (revision 2133:46433e3cef45)
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>
91324Saxel.duch@nginx.com #include <nxt_sockaddr.h>
101324Saxel.duch@nginx.com #include <nxt_http_route_addr.h>
111721Saxel.duch@nginx.com #include <nxt_regex.h>
12964Sigor@sysoev.ru 
13964Sigor@sysoev.ru 
14964Sigor@sysoev.ru typedef enum {
151059Sigor@sysoev.ru     NXT_HTTP_ROUTE_TABLE = 0,
161059Sigor@sysoev.ru     NXT_HTTP_ROUTE_STRING,
17964Sigor@sysoev.ru     NXT_HTTP_ROUTE_STRING_PTR,
18964Sigor@sysoev.ru     NXT_HTTP_ROUTE_HEADER,
19964Sigor@sysoev.ru     NXT_HTTP_ROUTE_ARGUMENT,
20964Sigor@sysoev.ru     NXT_HTTP_ROUTE_COOKIE,
211110Saxel.duch@nginx.com     NXT_HTTP_ROUTE_SCHEME,
221991Sz.hong@f5.com     NXT_HTTP_ROUTE_QUERY,
231324Saxel.duch@nginx.com     NXT_HTTP_ROUTE_SOURCE,
241326Saxel.duch@nginx.com     NXT_HTTP_ROUTE_DESTINATION,
25964Sigor@sysoev.ru } nxt_http_route_object_t;
26964Sigor@sysoev.ru 
27964Sigor@sysoev.ru 
28964Sigor@sysoev.ru typedef enum {
29964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_EXACT = 0,
30964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_BEGIN,
31964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_END,
32964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_SUBSTRING,
33964Sigor@sysoev.ru } nxt_http_route_pattern_type_t;
34964Sigor@sysoev.ru 
35964Sigor@sysoev.ru 
36964Sigor@sysoev.ru typedef enum {
37964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_NOCASE = 0,
38964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_LOWCASE,
39964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_UPCASE,
40964Sigor@sysoev.ru } nxt_http_route_pattern_case_t;
41964Sigor@sysoev.ru 
42964Sigor@sysoev.ru 
43964Sigor@sysoev.ru typedef struct {
44964Sigor@sysoev.ru     nxt_conf_value_t               *host;
45964Sigor@sysoev.ru     nxt_conf_value_t               *uri;
46964Sigor@sysoev.ru     nxt_conf_value_t               *method;
471059Sigor@sysoev.ru     nxt_conf_value_t               *headers;
481061Sigor@sysoev.ru     nxt_conf_value_t               *arguments;
491062Sigor@sysoev.ru     nxt_conf_value_t               *cookies;
501110Saxel.duch@nginx.com     nxt_conf_value_t               *scheme;
511991Sz.hong@f5.com     nxt_conf_value_t               *query;
521324Saxel.duch@nginx.com     nxt_conf_value_t               *source;
531326Saxel.duch@nginx.com     nxt_conf_value_t               *destination;
54964Sigor@sysoev.ru } nxt_http_route_match_conf_t;
55964Sigor@sysoev.ru 
56964Sigor@sysoev.ru 
57964Sigor@sysoev.ru typedef struct {
581508Saxel.duch@nginx.com     u_char                         *start;
591508Saxel.duch@nginx.com     uint32_t                       length;
601508Saxel.duch@nginx.com     nxt_http_route_pattern_type_t  type:8;
611508Saxel.duch@nginx.com } nxt_http_route_pattern_slice_t;
621508Saxel.duch@nginx.com 
631508Saxel.duch@nginx.com 
641508Saxel.duch@nginx.com typedef struct {
651721Saxel.duch@nginx.com     union {
661721Saxel.duch@nginx.com         nxt_array_t                *pattern_slices;
671721Saxel.duch@nginx.com #if (NXT_HAVE_REGEX)
681721Saxel.duch@nginx.com         nxt_regex_t                *regex;
691721Saxel.duch@nginx.com #endif
701721Saxel.duch@nginx.com     } u;
71964Sigor@sysoev.ru     uint32_t                       min_length;
721508Saxel.duch@nginx.com 
73964Sigor@sysoev.ru     uint8_t                        case_sensitive;  /* 1 bit */
74964Sigor@sysoev.ru     uint8_t                        negative;        /* 1 bit */
75964Sigor@sysoev.ru     uint8_t                        any;             /* 1 bit */
761721Saxel.duch@nginx.com #if (NXT_HAVE_REGEX)
771721Saxel.duch@nginx.com     uint8_t                        regex;           /* 1 bit */
781721Saxel.duch@nginx.com #endif
79964Sigor@sysoev.ru } nxt_http_route_pattern_t;
80964Sigor@sysoev.ru 
81964Sigor@sysoev.ru 
82964Sigor@sysoev.ru typedef struct {
831061Sigor@sysoev.ru     uint16_t                       hash;
841061Sigor@sysoev.ru     uint16_t                       name_length;
851061Sigor@sysoev.ru     uint32_t                       value_length;
861061Sigor@sysoev.ru     u_char                         *name;
871061Sigor@sysoev.ru     u_char                         *value;
881062Sigor@sysoev.ru } nxt_http_cookie_t;
891062Sigor@sysoev.ru 
901062Sigor@sysoev.ru 
911859So.canty@f5.com struct nxt_http_route_rule_s {
921059Sigor@sysoev.ru     /* The object must be the first field. */
931059Sigor@sysoev.ru     nxt_http_route_object_t        object:8;
94964Sigor@sysoev.ru     uint32_t                       items;
951059Sigor@sysoev.ru 
961059Sigor@sysoev.ru     union {
971059Sigor@sysoev.ru         uintptr_t                  offset;
981059Sigor@sysoev.ru 
991059Sigor@sysoev.ru         struct {
1001059Sigor@sysoev.ru             u_char                 *start;
1011059Sigor@sysoev.ru             uint16_t               hash;
1021059Sigor@sysoev.ru             uint16_t               length;
1031059Sigor@sysoev.ru         } name;
1041059Sigor@sysoev.ru     } u;
1051059Sigor@sysoev.ru 
106964Sigor@sysoev.ru     nxt_http_route_pattern_t       pattern[0];
1071859So.canty@f5.com };
108964Sigor@sysoev.ru 
109964Sigor@sysoev.ru 
110964Sigor@sysoev.ru typedef struct {
111964Sigor@sysoev.ru     uint32_t                       items;
1121059Sigor@sysoev.ru     nxt_http_route_rule_t          *rule[0];
1131059Sigor@sysoev.ru } nxt_http_route_ruleset_t;
1141059Sigor@sysoev.ru 
1151059Sigor@sysoev.ru 
1161059Sigor@sysoev.ru typedef struct {
1171059Sigor@sysoev.ru     /* The object must be the first field. */
1181059Sigor@sysoev.ru     nxt_http_route_object_t        object:8;
1191059Sigor@sysoev.ru     uint32_t                       items;
1201059Sigor@sysoev.ru     nxt_http_route_ruleset_t       *ruleset[0];
1211059Sigor@sysoev.ru } nxt_http_route_table_t;
1221059Sigor@sysoev.ru 
1231059Sigor@sysoev.ru 
1241936So.canty@f5.com struct nxt_http_route_addr_rule_s {
1251324Saxel.duch@nginx.com     /* The object must be the first field. */
1261324Saxel.duch@nginx.com     nxt_http_route_object_t        object:8;
1271324Saxel.duch@nginx.com     uint32_t                       items;
1281324Saxel.duch@nginx.com     nxt_http_route_addr_pattern_t  addr_pattern[0];
1291936So.canty@f5.com };
1301324Saxel.duch@nginx.com 
1311324Saxel.duch@nginx.com 
1321059Sigor@sysoev.ru typedef union {
1331059Sigor@sysoev.ru     nxt_http_route_rule_t          *rule;
1341059Sigor@sysoev.ru     nxt_http_route_table_t         *table;
1351324Saxel.duch@nginx.com     nxt_http_route_addr_rule_t     *addr_rule;
1361059Sigor@sysoev.ru } nxt_http_route_test_t;
1371059Sigor@sysoev.ru 
1381059Sigor@sysoev.ru 
1391059Sigor@sysoev.ru typedef struct {
1401059Sigor@sysoev.ru     uint32_t                       items;
1411264Sigor@sysoev.ru     nxt_http_action_t              action;
1421059Sigor@sysoev.ru     nxt_http_route_test_t          test[0];
143964Sigor@sysoev.ru } nxt_http_route_match_t;
144964Sigor@sysoev.ru 
145964Sigor@sysoev.ru 
146964Sigor@sysoev.ru struct nxt_http_route_s {
147964Sigor@sysoev.ru     nxt_str_t                      name;
148964Sigor@sysoev.ru     uint32_t                       items;
149964Sigor@sysoev.ru     nxt_http_route_match_t         *match[0];
150964Sigor@sysoev.ru };
151964Sigor@sysoev.ru 
152964Sigor@sysoev.ru 
153964Sigor@sysoev.ru struct nxt_http_routes_s {
154964Sigor@sysoev.ru     uint32_t                       items;
155964Sigor@sysoev.ru     nxt_http_route_t               *route[0];
156964Sigor@sysoev.ru };
157964Sigor@sysoev.ru 
158964Sigor@sysoev.ru 
159964Sigor@sysoev.ru static nxt_http_route_t *nxt_http_route_create(nxt_task_t *task,
160964Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv);
161964Sigor@sysoev.ru static nxt_http_route_match_t *nxt_http_route_match_create(nxt_task_t *task,
162964Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv);
1631059Sigor@sysoev.ru static nxt_http_route_table_t *nxt_http_route_table_create(nxt_task_t *task,
1641061Sigor@sysoev.ru     nxt_mp_t *mp, nxt_conf_value_t *table_cv, nxt_http_route_object_t object,
1652123Sz.hong@f5.com     nxt_bool_t case_sensitive, nxt_http_uri_encoding_t encoding);
1661059Sigor@sysoev.ru static nxt_http_route_ruleset_t *nxt_http_route_ruleset_create(nxt_task_t *task,
1671061Sigor@sysoev.ru     nxt_mp_t *mp, nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object,
1682123Sz.hong@f5.com     nxt_bool_t case_sensitive, nxt_http_uri_encoding_t encoding);
1691061Sigor@sysoev.ru static nxt_http_route_rule_t *nxt_http_route_rule_name_create(nxt_task_t *task,
1701061Sigor@sysoev.ru     nxt_mp_t *mp, nxt_conf_value_t *rule_cv, nxt_str_t *name,
1712123Sz.hong@f5.com     nxt_bool_t case_sensitive, nxt_http_uri_encoding_t encoding);
172964Sigor@sysoev.ru static nxt_http_route_rule_t *nxt_http_route_rule_create(nxt_task_t *task,
1731059Sigor@sysoev.ru     nxt_mp_t *mp, nxt_conf_value_t *cv, nxt_bool_t case_sensitive,
1741474Saxel.duch@nginx.com     nxt_http_route_pattern_case_t pattern_case,
1752123Sz.hong@f5.com     nxt_http_uri_encoding_t encoding);
176964Sigor@sysoev.ru static int nxt_http_pattern_compare(const void *one, const void *two);
1771390Saxel.duch@nginx.com static int nxt_http_addr_pattern_compare(const void *one, const void *two);
178964Sigor@sysoev.ru static nxt_int_t nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp,
179964Sigor@sysoev.ru     nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern,
1801474Saxel.duch@nginx.com     nxt_http_route_pattern_case_t pattern_case,
1812123Sz.hong@f5.com     nxt_http_uri_encoding_t encoding);
1821474Saxel.duch@nginx.com static nxt_int_t nxt_http_route_decode_str(nxt_str_t *str,
1832123Sz.hong@f5.com     nxt_http_uri_encoding_t encoding);
1841508Saxel.duch@nginx.com static nxt_int_t nxt_http_route_pattern_slice(nxt_array_t *slices,
1851508Saxel.duch@nginx.com     nxt_str_t *test,
1861508Saxel.duch@nginx.com     nxt_http_route_pattern_type_t type,
1872123Sz.hong@f5.com     nxt_http_uri_encoding_t encoding,
1881032Sigor@sysoev.ru     nxt_http_route_pattern_case_t pattern_case);
189964Sigor@sysoev.ru 
1901472Svbart@nginx.com static nxt_int_t nxt_http_route_resolve(nxt_task_t *task,
191964Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_http_route_t *route);
1921472Svbart@nginx.com static nxt_int_t nxt_http_action_resolve(nxt_task_t *task,
1931264Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_http_action_t *action);
1941954Sz.hong@f5.com static nxt_http_action_t *nxt_http_pass_var(nxt_task_t *task,
1951563Svbart@nginx.com     nxt_http_request_t *r, nxt_http_action_t *action);
1961954Sz.hong@f5.com static void nxt_http_pass_var_ready(nxt_task_t *task, void *obj, void *data);
1971954Sz.hong@f5.com static void nxt_http_pass_var_error(nxt_task_t *task, void *obj, void *data);
1981954Sz.hong@f5.com static nxt_int_t nxt_http_pass_find(nxt_mp_t *mp, nxt_router_conf_t *rtcf,
1991954Sz.hong@f5.com     nxt_str_t *pass, nxt_http_action_t *action);
2001563Svbart@nginx.com static nxt_int_t nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name,
2011392Sigor@sysoev.ru     nxt_http_action_t *action);
202964Sigor@sysoev.ru 
2031264Sigor@sysoev.ru static nxt_http_action_t *nxt_http_route_handler(nxt_task_t *task,
2041264Sigor@sysoev.ru     nxt_http_request_t *r, nxt_http_action_t *start);
2051326Saxel.duch@nginx.com static nxt_http_action_t *nxt_http_route_match(nxt_task_t *task,
2061326Saxel.duch@nginx.com     nxt_http_request_t *r, nxt_http_route_match_t *match);
2071060Sigor@sysoev.ru static nxt_int_t nxt_http_route_table(nxt_http_request_t *r,
2081059Sigor@sysoev.ru     nxt_http_route_table_t *table);
2091060Sigor@sysoev.ru static nxt_int_t nxt_http_route_ruleset(nxt_http_request_t *r,
2101059Sigor@sysoev.ru     nxt_http_route_ruleset_t *ruleset);
2111060Sigor@sysoev.ru static nxt_int_t nxt_http_route_rule(nxt_http_request_t *r,
212964Sigor@sysoev.ru     nxt_http_route_rule_t *rule);
2131060Sigor@sysoev.ru static nxt_int_t nxt_http_route_header(nxt_http_request_t *r,
2141059Sigor@sysoev.ru     nxt_http_route_rule_t *rule);
2151061Sigor@sysoev.ru static nxt_int_t nxt_http_route_arguments(nxt_http_request_t *r,
2161061Sigor@sysoev.ru     nxt_http_route_rule_t *rule);
2171061Sigor@sysoev.ru static nxt_int_t nxt_http_route_test_argument(nxt_http_request_t *r,
2181061Sigor@sysoev.ru     nxt_http_route_rule_t *rule, nxt_array_t *array);
2191110Saxel.duch@nginx.com static nxt_int_t nxt_http_route_scheme(nxt_http_request_t *r,
2201110Saxel.duch@nginx.com     nxt_http_route_rule_t *rule);
2211991Sz.hong@f5.com static nxt_int_t nxt_http_route_query(nxt_http_request_t *r,
2221991Sz.hong@f5.com     nxt_http_route_rule_t *rule);
2231062Sigor@sysoev.ru static nxt_int_t nxt_http_route_cookies(nxt_http_request_t *r,
2241062Sigor@sysoev.ru     nxt_http_route_rule_t *rule);
2251062Sigor@sysoev.ru static nxt_int_t nxt_http_route_test_cookie(nxt_http_request_t *r,
2261062Sigor@sysoev.ru     nxt_http_route_rule_t *rule, nxt_array_t *array);
2271060Sigor@sysoev.ru static nxt_int_t nxt_http_route_pattern(nxt_http_request_t *r,
228964Sigor@sysoev.ru     nxt_http_route_pattern_t *pattern, u_char *start, size_t length);
2291060Sigor@sysoev.ru static nxt_int_t nxt_http_route_memcmp(u_char *start, u_char *test,
2301032Sigor@sysoev.ru     size_t length, nxt_bool_t case_sensitive);
231964Sigor@sysoev.ru 
232964Sigor@sysoev.ru 
233964Sigor@sysoev.ru nxt_http_routes_t *
nxt_http_routes_create(nxt_task_t * task,nxt_router_temp_conf_t * tmcf,nxt_conf_value_t * routes_conf)234964Sigor@sysoev.ru nxt_http_routes_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
235964Sigor@sysoev.ru     nxt_conf_value_t *routes_conf)
236964Sigor@sysoev.ru {
237964Sigor@sysoev.ru     size_t             size;
238964Sigor@sysoev.ru     uint32_t           i, n, next;
239964Sigor@sysoev.ru     nxt_mp_t           *mp;
240964Sigor@sysoev.ru     nxt_str_t          name, *string;
241964Sigor@sysoev.ru     nxt_bool_t         object;
242964Sigor@sysoev.ru     nxt_conf_value_t   *route_conf;
243964Sigor@sysoev.ru     nxt_http_route_t   *route;
244964Sigor@sysoev.ru     nxt_http_routes_t  *routes;
245964Sigor@sysoev.ru 
246964Sigor@sysoev.ru     object = (nxt_conf_type(routes_conf) == NXT_CONF_OBJECT);
247964Sigor@sysoev.ru     n = object ? nxt_conf_object_members_count(routes_conf) : 1;
248964Sigor@sysoev.ru     size = sizeof(nxt_http_routes_t) + n * sizeof(nxt_http_route_t *);
249964Sigor@sysoev.ru 
250964Sigor@sysoev.ru     mp = tmcf->router_conf->mem_pool;
251964Sigor@sysoev.ru 
252964Sigor@sysoev.ru     routes = nxt_mp_alloc(mp, size);
253964Sigor@sysoev.ru     if (nxt_slow_path(routes == NULL)) {
254964Sigor@sysoev.ru         return NULL;
255964Sigor@sysoev.ru     }
256964Sigor@sysoev.ru 
257964Sigor@sysoev.ru     routes->items = n;
258964Sigor@sysoev.ru 
259964Sigor@sysoev.ru     if (object) {
260964Sigor@sysoev.ru         next = 0;
261964Sigor@sysoev.ru 
262964Sigor@sysoev.ru         for (i = 0; i < n; i++) {
263964Sigor@sysoev.ru             route_conf = nxt_conf_next_object_member(routes_conf, &name, &next);
264964Sigor@sysoev.ru 
265964Sigor@sysoev.ru             route = nxt_http_route_create(task, tmcf, route_conf);
266964Sigor@sysoev.ru             if (nxt_slow_path(route == NULL)) {
267964Sigor@sysoev.ru                 return NULL;
268964Sigor@sysoev.ru             }
269964Sigor@sysoev.ru 
270964Sigor@sysoev.ru             routes->route[i] = route;
271964Sigor@sysoev.ru 
272964Sigor@sysoev.ru             string = nxt_str_dup(mp, &route->name, &name);
273964Sigor@sysoev.ru             if (nxt_slow_path(string == NULL)) {
274964Sigor@sysoev.ru                 return NULL;
275964Sigor@sysoev.ru             }
276964Sigor@sysoev.ru         }
277964Sigor@sysoev.ru 
278964Sigor@sysoev.ru     } else {
279964Sigor@sysoev.ru         route = nxt_http_route_create(task, tmcf, routes_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[0] = route;
285964Sigor@sysoev.ru 
286964Sigor@sysoev.ru         route->name.length = 0;
287964Sigor@sysoev.ru         route->name.start = NULL;
288964Sigor@sysoev.ru     }
289964Sigor@sysoev.ru 
290964Sigor@sysoev.ru     return routes;
291964Sigor@sysoev.ru }
292964Sigor@sysoev.ru 
293964Sigor@sysoev.ru 
294964Sigor@sysoev.ru static nxt_conf_map_t  nxt_http_route_match_conf[] = {
295964Sigor@sysoev.ru     {
2961110Saxel.duch@nginx.com         nxt_string("scheme"),
2971110Saxel.duch@nginx.com         NXT_CONF_MAP_PTR,
2981110Saxel.duch@nginx.com         offsetof(nxt_http_route_match_conf_t, scheme)
2991110Saxel.duch@nginx.com     },
3001110Saxel.duch@nginx.com     {
301964Sigor@sysoev.ru         nxt_string("host"),
302964Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
303964Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, host),
304964Sigor@sysoev.ru     },
305964Sigor@sysoev.ru 
306964Sigor@sysoev.ru     {
307964Sigor@sysoev.ru         nxt_string("uri"),
308964Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
309964Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, uri),
310964Sigor@sysoev.ru     },
311964Sigor@sysoev.ru 
312964Sigor@sysoev.ru     {
313964Sigor@sysoev.ru         nxt_string("method"),
314964Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
315964Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, method),
316964Sigor@sysoev.ru     },
3171059Sigor@sysoev.ru 
3181059Sigor@sysoev.ru     {
3191059Sigor@sysoev.ru         nxt_string("headers"),
3201059Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
3211059Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, headers),
3221059Sigor@sysoev.ru     },
3231061Sigor@sysoev.ru 
3241061Sigor@sysoev.ru     {
3251061Sigor@sysoev.ru         nxt_string("arguments"),
3261061Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
3271061Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, arguments),
3281061Sigor@sysoev.ru     },
3291062Sigor@sysoev.ru 
3301062Sigor@sysoev.ru     {
3311062Sigor@sysoev.ru         nxt_string("cookies"),
3321062Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
3331062Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, cookies),
3341062Sigor@sysoev.ru     },
3351324Saxel.duch@nginx.com 
3361324Saxel.duch@nginx.com     {
3371991Sz.hong@f5.com         nxt_string("query"),
3381991Sz.hong@f5.com         NXT_CONF_MAP_PTR,
3391991Sz.hong@f5.com         offsetof(nxt_http_route_match_conf_t, query),
3401991Sz.hong@f5.com     },
3411991Sz.hong@f5.com 
3421991Sz.hong@f5.com     {
3431324Saxel.duch@nginx.com         nxt_string("source"),
3441324Saxel.duch@nginx.com         NXT_CONF_MAP_PTR,
3451324Saxel.duch@nginx.com         offsetof(nxt_http_route_match_conf_t, source),
3461324Saxel.duch@nginx.com     },
3471326Saxel.duch@nginx.com 
3481326Saxel.duch@nginx.com     {
3491326Saxel.duch@nginx.com         nxt_string("destination"),
3501326Saxel.duch@nginx.com         NXT_CONF_MAP_PTR,
3511326Saxel.duch@nginx.com         offsetof(nxt_http_route_match_conf_t, destination),
3521326Saxel.duch@nginx.com     },
353964Sigor@sysoev.ru };
354964Sigor@sysoev.ru 
355964Sigor@sysoev.ru 
356964Sigor@sysoev.ru static nxt_http_route_t *
nxt_http_route_create(nxt_task_t * task,nxt_router_temp_conf_t * tmcf,nxt_conf_value_t * cv)357964Sigor@sysoev.ru nxt_http_route_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
358964Sigor@sysoev.ru     nxt_conf_value_t *cv)
359964Sigor@sysoev.ru {
360964Sigor@sysoev.ru     size_t                  size;
361964Sigor@sysoev.ru     uint32_t                i, n;
362964Sigor@sysoev.ru     nxt_conf_value_t        *value;
363964Sigor@sysoev.ru     nxt_http_route_t        *route;
364964Sigor@sysoev.ru     nxt_http_route_match_t  *match, **m;
365964Sigor@sysoev.ru 
366964Sigor@sysoev.ru     n = nxt_conf_array_elements_count(cv);
367964Sigor@sysoev.ru     size = sizeof(nxt_http_route_t) + n * sizeof(nxt_http_route_match_t *);
368964Sigor@sysoev.ru 
369964Sigor@sysoev.ru     route = nxt_mp_alloc(tmcf->router_conf->mem_pool, size);
370964Sigor@sysoev.ru     if (nxt_slow_path(route == NULL)) {
371964Sigor@sysoev.ru         return NULL;
372964Sigor@sysoev.ru     }
373964Sigor@sysoev.ru 
374964Sigor@sysoev.ru     route->items = n;
375964Sigor@sysoev.ru     m = &route->match[0];
376964Sigor@sysoev.ru 
377964Sigor@sysoev.ru     for (i = 0; i < n; i++) {
378964Sigor@sysoev.ru         value = nxt_conf_get_array_element(cv, i);
379964Sigor@sysoev.ru 
380964Sigor@sysoev.ru         match = nxt_http_route_match_create(task, tmcf, value);
381964Sigor@sysoev.ru         if (match == NULL) {
382964Sigor@sysoev.ru             return NULL;
383964Sigor@sysoev.ru         }
384964Sigor@sysoev.ru 
385964Sigor@sysoev.ru         *m++ = match;
386964Sigor@sysoev.ru     }
387964Sigor@sysoev.ru 
388964Sigor@sysoev.ru     return route;
389964Sigor@sysoev.ru }
390964Sigor@sysoev.ru 
391964Sigor@sysoev.ru 
392964Sigor@sysoev.ru static nxt_http_route_match_t *
nxt_http_route_match_create(nxt_task_t * task,nxt_router_temp_conf_t * tmcf,nxt_conf_value_t * cv)393964Sigor@sysoev.ru nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
394964Sigor@sysoev.ru     nxt_conf_value_t *cv)
395964Sigor@sysoev.ru {
396964Sigor@sysoev.ru     size_t                       size;
397964Sigor@sysoev.ru     uint32_t                     n;
3981059Sigor@sysoev.ru     nxt_mp_t                     *mp;
399964Sigor@sysoev.ru     nxt_int_t                    ret;
4001378Svbart@nginx.com     nxt_conf_value_t             *match_conf, *action_conf;
4011059Sigor@sysoev.ru     nxt_http_route_test_t        *test;
4021059Sigor@sysoev.ru     nxt_http_route_rule_t        *rule;
4031059Sigor@sysoev.ru     nxt_http_route_table_t       *table;
404964Sigor@sysoev.ru     nxt_http_route_match_t       *match;
4051324Saxel.duch@nginx.com     nxt_http_route_addr_rule_t   *addr_rule;
406964Sigor@sysoev.ru     nxt_http_route_match_conf_t  mtcf;
407964Sigor@sysoev.ru 
408964Sigor@sysoev.ru     static nxt_str_t  match_path = nxt_string("/match");
4091378Svbart@nginx.com     static nxt_str_t  action_path = nxt_string("/action");
410964Sigor@sysoev.ru 
411964Sigor@sysoev.ru     match_conf = nxt_conf_get_path(cv, &match_path);
412964Sigor@sysoev.ru 
413964Sigor@sysoev.ru     n = (match_conf != NULL) ? nxt_conf_object_members_count(match_conf) : 0;
4141859So.canty@f5.com     size = sizeof(nxt_http_route_match_t) + n * sizeof(nxt_http_route_test_t *);
415964Sigor@sysoev.ru 
4161059Sigor@sysoev.ru     mp = tmcf->router_conf->mem_pool;
4171059Sigor@sysoev.ru 
4181059Sigor@sysoev.ru     match = nxt_mp_alloc(mp, size);
419964Sigor@sysoev.ru     if (nxt_slow_path(match == NULL)) {
420964Sigor@sysoev.ru         return NULL;
421964Sigor@sysoev.ru     }
422964Sigor@sysoev.ru 
423964Sigor@sysoev.ru     match->items = n;
424964Sigor@sysoev.ru 
4251378Svbart@nginx.com     action_conf = nxt_conf_get_path(cv, &action_path);
4261378Svbart@nginx.com     if (nxt_slow_path(action_conf == NULL)) {
4271378Svbart@nginx.com         return NULL;
4281378Svbart@nginx.com     }
4291378Svbart@nginx.com 
4301903Sz.hong@f5.com     ret = nxt_http_action_init(task, tmcf, action_conf, &match->action);
4311264Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
432964Sigor@sysoev.ru         return NULL;
433964Sigor@sysoev.ru     }
434964Sigor@sysoev.ru 
435964Sigor@sysoev.ru     if (n == 0) {
436964Sigor@sysoev.ru         return match;
437964Sigor@sysoev.ru     }
438964Sigor@sysoev.ru 
439964Sigor@sysoev.ru     nxt_memzero(&mtcf, sizeof(mtcf));
440964Sigor@sysoev.ru 
441964Sigor@sysoev.ru     ret = nxt_conf_map_object(tmcf->mem_pool,
442964Sigor@sysoev.ru                               match_conf, nxt_http_route_match_conf,
443964Sigor@sysoev.ru                               nxt_nitems(nxt_http_route_match_conf), &mtcf);
444964Sigor@sysoev.ru     if (ret != NXT_OK) {
445964Sigor@sysoev.ru         return NULL;
446964Sigor@sysoev.ru     }
447964Sigor@sysoev.ru 
4481059Sigor@sysoev.ru     test = &match->test[0];
449964Sigor@sysoev.ru 
4501110Saxel.duch@nginx.com     if (mtcf.scheme != NULL) {
4511110Saxel.duch@nginx.com         rule = nxt_http_route_rule_create(task, mp, mtcf.scheme, 1,
4521474Saxel.duch@nginx.com                                           NXT_HTTP_ROUTE_PATTERN_NOCASE,
4532123Sz.hong@f5.com                                           NXT_HTTP_URI_ENCODING_NONE);
4541110Saxel.duch@nginx.com         if (rule == NULL) {
4551110Saxel.duch@nginx.com             return NULL;
4561110Saxel.duch@nginx.com         }
4571110Saxel.duch@nginx.com 
4581110Saxel.duch@nginx.com         rule->object = NXT_HTTP_ROUTE_SCHEME;
4591110Saxel.duch@nginx.com         test->rule = rule;
4601110Saxel.duch@nginx.com         test++;
4611110Saxel.duch@nginx.com     }
4621110Saxel.duch@nginx.com 
463964Sigor@sysoev.ru     if (mtcf.host != NULL) {
4641059Sigor@sysoev.ru         rule = nxt_http_route_rule_create(task, mp, mtcf.host, 1,
4651474Saxel.duch@nginx.com                                           NXT_HTTP_ROUTE_PATTERN_LOWCASE,
4662123Sz.hong@f5.com                                           NXT_HTTP_URI_ENCODING_NONE);
467964Sigor@sysoev.ru         if (rule == NULL) {
468964Sigor@sysoev.ru             return NULL;
469964Sigor@sysoev.ru         }
470964Sigor@sysoev.ru 
4711059Sigor@sysoev.ru         rule->u.offset = offsetof(nxt_http_request_t, host);
472964Sigor@sysoev.ru         rule->object = NXT_HTTP_ROUTE_STRING;
4731059Sigor@sysoev.ru         test->rule = rule;
4741059Sigor@sysoev.ru         test++;
475964Sigor@sysoev.ru     }
476964Sigor@sysoev.ru 
477964Sigor@sysoev.ru     if (mtcf.uri != NULL) {
4781059Sigor@sysoev.ru         rule = nxt_http_route_rule_create(task, mp, mtcf.uri, 1,
4791474Saxel.duch@nginx.com                                           NXT_HTTP_ROUTE_PATTERN_NOCASE,
4802123Sz.hong@f5.com                                           NXT_HTTP_URI_ENCODING);
481964Sigor@sysoev.ru         if (rule == NULL) {
482964Sigor@sysoev.ru             return NULL;
483964Sigor@sysoev.ru         }
484964Sigor@sysoev.ru 
4851059Sigor@sysoev.ru         rule->u.offset = offsetof(nxt_http_request_t, path);
486964Sigor@sysoev.ru         rule->object = NXT_HTTP_ROUTE_STRING_PTR;
4871059Sigor@sysoev.ru         test->rule = rule;
4881059Sigor@sysoev.ru         test++;
489964Sigor@sysoev.ru     }
490964Sigor@sysoev.ru 
491964Sigor@sysoev.ru     if (mtcf.method != NULL) {
4921059Sigor@sysoev.ru         rule = nxt_http_route_rule_create(task, mp, mtcf.method, 1,
4931474Saxel.duch@nginx.com                                           NXT_HTTP_ROUTE_PATTERN_UPCASE,
4942123Sz.hong@f5.com                                           NXT_HTTP_URI_ENCODING_NONE);
495964Sigor@sysoev.ru         if (rule == NULL) {
496964Sigor@sysoev.ru             return NULL;
497964Sigor@sysoev.ru         }
498964Sigor@sysoev.ru 
4991059Sigor@sysoev.ru         rule->u.offset = offsetof(nxt_http_request_t, method);
500964Sigor@sysoev.ru         rule->object = NXT_HTTP_ROUTE_STRING_PTR;
5011059Sigor@sysoev.ru         test->rule = rule;
5021059Sigor@sysoev.ru         test++;
5031059Sigor@sysoev.ru     }
5041059Sigor@sysoev.ru 
5051059Sigor@sysoev.ru     if (mtcf.headers != NULL) {
5061061Sigor@sysoev.ru         table = nxt_http_route_table_create(task, mp, mtcf.headers,
5071474Saxel.duch@nginx.com                                             NXT_HTTP_ROUTE_HEADER, 0,
5082123Sz.hong@f5.com                                             NXT_HTTP_URI_ENCODING_NONE);
5091061Sigor@sysoev.ru         if (table == NULL) {
5101061Sigor@sysoev.ru             return NULL;
5111061Sigor@sysoev.ru         }
5121061Sigor@sysoev.ru 
5131061Sigor@sysoev.ru         test->table = table;
5141061Sigor@sysoev.ru         test++;
5151061Sigor@sysoev.ru     }
5161061Sigor@sysoev.ru 
5171061Sigor@sysoev.ru     if (mtcf.arguments != NULL) {
5181061Sigor@sysoev.ru         table = nxt_http_route_table_create(task, mp, mtcf.arguments,
5191474Saxel.duch@nginx.com                                             NXT_HTTP_ROUTE_ARGUMENT, 1,
5202123Sz.hong@f5.com                                             NXT_HTTP_URI_ENCODING_PLUS);
5211059Sigor@sysoev.ru         if (table == NULL) {
5221059Sigor@sysoev.ru             return NULL;
5231059Sigor@sysoev.ru         }
5241059Sigor@sysoev.ru 
5251059Sigor@sysoev.ru         test->table = table;
5261059Sigor@sysoev.ru         test++;
527964Sigor@sysoev.ru     }
528964Sigor@sysoev.ru 
5291062Sigor@sysoev.ru     if (mtcf.cookies != NULL) {
5301062Sigor@sysoev.ru         table = nxt_http_route_table_create(task, mp, mtcf.cookies,
5311474Saxel.duch@nginx.com                                             NXT_HTTP_ROUTE_COOKIE, 1,
5322123Sz.hong@f5.com                                             NXT_HTTP_URI_ENCODING_NONE);
5331062Sigor@sysoev.ru         if (table == NULL) {
5341062Sigor@sysoev.ru             return NULL;
5351062Sigor@sysoev.ru         }
5361062Sigor@sysoev.ru 
5371062Sigor@sysoev.ru         test->table = table;
5381062Sigor@sysoev.ru         test++;
5391062Sigor@sysoev.ru     }
5401062Sigor@sysoev.ru 
5411991Sz.hong@f5.com     if (mtcf.query != NULL) {
5421991Sz.hong@f5.com         rule = nxt_http_route_rule_create(task, mp, mtcf.query, 1,
5431991Sz.hong@f5.com                                           NXT_HTTP_ROUTE_PATTERN_NOCASE,
5442123Sz.hong@f5.com                                           NXT_HTTP_URI_ENCODING_PLUS);
5451991Sz.hong@f5.com         if (rule == NULL) {
5461991Sz.hong@f5.com             return NULL;
5471991Sz.hong@f5.com         }
5481991Sz.hong@f5.com 
5491991Sz.hong@f5.com         rule->object = NXT_HTTP_ROUTE_QUERY;
5501991Sz.hong@f5.com         test->rule = rule;
5511991Sz.hong@f5.com         test++;
5521991Sz.hong@f5.com     }
5531991Sz.hong@f5.com 
5541324Saxel.duch@nginx.com     if (mtcf.source != NULL) {
5551324Saxel.duch@nginx.com         addr_rule = nxt_http_route_addr_rule_create(task, mp, mtcf.source);
5561324Saxel.duch@nginx.com         if (addr_rule == NULL) {
5571324Saxel.duch@nginx.com             return NULL;
5581324Saxel.duch@nginx.com         }
5591324Saxel.duch@nginx.com 
5601324Saxel.duch@nginx.com         addr_rule->object = NXT_HTTP_ROUTE_SOURCE;
5611324Saxel.duch@nginx.com         test->addr_rule = addr_rule;
5621324Saxel.duch@nginx.com         test++;
5631324Saxel.duch@nginx.com     }
5641324Saxel.duch@nginx.com 
5651326Saxel.duch@nginx.com     if (mtcf.destination != NULL) {
5661326Saxel.duch@nginx.com         addr_rule = nxt_http_route_addr_rule_create(task, mp, mtcf.destination);
5671326Saxel.duch@nginx.com         if (addr_rule == NULL) {
5681326Saxel.duch@nginx.com             return NULL;
5691326Saxel.duch@nginx.com         }
5701326Saxel.duch@nginx.com 
5711326Saxel.duch@nginx.com         addr_rule->object = NXT_HTTP_ROUTE_DESTINATION;
5721326Saxel.duch@nginx.com         test->addr_rule = addr_rule;
5731326Saxel.duch@nginx.com         test++;
5741326Saxel.duch@nginx.com     }
5751326Saxel.duch@nginx.com 
576964Sigor@sysoev.ru     return match;
577964Sigor@sysoev.ru }
578964Sigor@sysoev.ru 
579964Sigor@sysoev.ru 
5801264Sigor@sysoev.ru static nxt_conf_map_t  nxt_http_route_action_conf[] = {
5811264Sigor@sysoev.ru     {
5821264Sigor@sysoev.ru         nxt_string("pass"),
5831264Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
5841903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, pass)
5851264Sigor@sysoev.ru     },
5861264Sigor@sysoev.ru     {
5871429Svbart@nginx.com         nxt_string("return"),
5881429Svbart@nginx.com         NXT_CONF_MAP_PTR,
5891903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, ret)
5901429Svbart@nginx.com     },
5911429Svbart@nginx.com     {
5921432Svbart@nginx.com         nxt_string("location"),
5932098Salx.manpages@gmail.com         NXT_CONF_MAP_PTR,
5941903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, location)
5951432Svbart@nginx.com     },
5961432Svbart@nginx.com     {
5971854Sz.hong@f5.com         nxt_string("proxy"),
5981854Sz.hong@f5.com         NXT_CONF_MAP_PTR,
5991903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, proxy)
6001854Sz.hong@f5.com     },
6011854Sz.hong@f5.com     {
6021264Sigor@sysoev.ru         nxt_string("share"),
6031264Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
6041903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, share)
6051264Sigor@sysoev.ru     },
6061270Sigor@sysoev.ru     {
6072108Salx.manpages@gmail.com         nxt_string("index"),
6082108Salx.manpages@gmail.com         NXT_CONF_MAP_PTR,
6092108Salx.manpages@gmail.com         offsetof(nxt_http_action_conf_t, index)
6102108Salx.manpages@gmail.com     },
6112108Salx.manpages@gmail.com     {
6121855Sz.hong@f5.com         nxt_string("chroot"),
6131855Sz.hong@f5.com         NXT_CONF_MAP_STR,
6141903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, chroot)
6151855Sz.hong@f5.com     },
6161855Sz.hong@f5.com     {
6171855Sz.hong@f5.com         nxt_string("follow_symlinks"),
6181855Sz.hong@f5.com         NXT_CONF_MAP_PTR,
6191903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, follow_symlinks)
6201855Sz.hong@f5.com     },
6211855Sz.hong@f5.com     {
6221855Sz.hong@f5.com         nxt_string("traverse_mounts"),
6231855Sz.hong@f5.com         NXT_CONF_MAP_PTR,
6241903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, traverse_mounts)
6251855Sz.hong@f5.com     },
6261855Sz.hong@f5.com     {
6271859So.canty@f5.com         nxt_string("types"),
6281859So.canty@f5.com         NXT_CONF_MAP_PTR,
6291903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, types)
6301859So.canty@f5.com     },
6311859So.canty@f5.com     {
6321378Svbart@nginx.com         nxt_string("fallback"),
6331378Svbart@nginx.com         NXT_CONF_MAP_PTR,
6341903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, fallback)
6351378Svbart@nginx.com     },
6361264Sigor@sysoev.ru };
6371264Sigor@sysoev.ru 
6381264Sigor@sysoev.ru 
6391923Sz.hong@f5.com nxt_int_t
nxt_http_action_init(nxt_task_t * task,nxt_router_temp_conf_t * tmcf,nxt_conf_value_t * cv,nxt_http_action_t * action)6401903Sz.hong@f5.com nxt_http_action_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
6411859So.canty@f5.com     nxt_conf_value_t *cv, nxt_http_action_t *action)
6421264Sigor@sysoev.ru {
6431903Sz.hong@f5.com     nxt_mp_t                *mp;
6441903Sz.hong@f5.com     nxt_int_t               ret;
6451954Sz.hong@f5.com     nxt_str_t               pass;
6461903Sz.hong@f5.com     nxt_http_action_conf_t  acf;
6471903Sz.hong@f5.com 
6481903Sz.hong@f5.com     nxt_memzero(&acf, sizeof(acf));
6491264Sigor@sysoev.ru 
6501378Svbart@nginx.com     ret = nxt_conf_map_object(tmcf->mem_pool, cv, nxt_http_route_action_conf,
6511903Sz.hong@f5.com                               nxt_nitems(nxt_http_route_action_conf), &acf);
6521264Sigor@sysoev.ru     if (ret != NXT_OK) {
6531264Sigor@sysoev.ru         return ret;
6541264Sigor@sysoev.ru     }
6551264Sigor@sysoev.ru 
6561428Svbart@nginx.com     nxt_memzero(action, sizeof(nxt_http_action_t));
6571428Svbart@nginx.com 
6581432Svbart@nginx.com     mp = tmcf->router_conf->mem_pool;
6591432Svbart@nginx.com 
6601903Sz.hong@f5.com     if (acf.ret != NULL) {
6611903Sz.hong@f5.com         return nxt_http_return_init(mp, action, &acf);
6621429Svbart@nginx.com     }
6631429Svbart@nginx.com 
6641903Sz.hong@f5.com     if (acf.share != NULL) {
6651923Sz.hong@f5.com         return nxt_http_static_init(task, tmcf, action, &acf);
6661923Sz.hong@f5.com     }
6671923Sz.hong@f5.com 
6681923Sz.hong@f5.com     if (acf.proxy != NULL) {
6691924Sz.hong@f5.com         return nxt_http_proxy_init(mp, action, &acf);
6701264Sigor@sysoev.ru     }
6711264Sigor@sysoev.ru 
6721954Sz.hong@f5.com     nxt_conf_get_string(acf.pass, &pass);
6731954Sz.hong@f5.com 
6741959Sz.hong@f5.com     action->u.var = nxt_var_compile(&pass, mp, 0);
6751954Sz.hong@f5.com     if (nxt_slow_path(action->u.var == NULL)) {
6761264Sigor@sysoev.ru         return NXT_ERROR;
6771264Sigor@sysoev.ru     }
6781264Sigor@sysoev.ru 
6791264Sigor@sysoev.ru     return NXT_OK;
6801264Sigor@sysoev.ru }
6811264Sigor@sysoev.ru 
6821264Sigor@sysoev.ru 
6831059Sigor@sysoev.ru static nxt_http_route_table_t *
nxt_http_route_table_create(nxt_task_t * task,nxt_mp_t * mp,nxt_conf_value_t * table_cv,nxt_http_route_object_t object,nxt_bool_t case_sensitive,nxt_http_uri_encoding_t encoding)6841059Sigor@sysoev.ru nxt_http_route_table_create(nxt_task_t *task, nxt_mp_t *mp,
6851061Sigor@sysoev.ru     nxt_conf_value_t *table_cv, nxt_http_route_object_t object,
6862123Sz.hong@f5.com     nxt_bool_t case_sensitive, nxt_http_uri_encoding_t encoding)
6871059Sigor@sysoev.ru {
6881059Sigor@sysoev.ru     size_t                    size;
6891059Sigor@sysoev.ru     uint32_t                  i, n;
6901059Sigor@sysoev.ru     nxt_conf_value_t          *ruleset_cv;
6911059Sigor@sysoev.ru     nxt_http_route_table_t    *table;
6921059Sigor@sysoev.ru     nxt_http_route_ruleset_t  *ruleset;
6931059Sigor@sysoev.ru 
6942077Salx.manpages@gmail.com     n = nxt_conf_array_elements_count_or_1(table_cv);
6951059Sigor@sysoev.ru     size = sizeof(nxt_http_route_table_t)
6961059Sigor@sysoev.ru            + n * sizeof(nxt_http_route_ruleset_t *);
6971059Sigor@sysoev.ru 
6981059Sigor@sysoev.ru     table = nxt_mp_alloc(mp, size);
6991059Sigor@sysoev.ru     if (nxt_slow_path(table == NULL)) {
7001059Sigor@sysoev.ru         return NULL;
7011059Sigor@sysoev.ru     }
7021059Sigor@sysoev.ru 
7031059Sigor@sysoev.ru     table->items = n;
7041059Sigor@sysoev.ru     table->object = NXT_HTTP_ROUTE_TABLE;
7051059Sigor@sysoev.ru 
7061059Sigor@sysoev.ru     for (i = 0; i < n; i++) {
7072077Salx.manpages@gmail.com         ruleset_cv = nxt_conf_get_array_element_or_itself(table_cv, i);
7081059Sigor@sysoev.ru 
7091474Saxel.duch@nginx.com         ruleset = nxt_http_route_ruleset_create(task, mp, ruleset_cv, object,
7101474Saxel.duch@nginx.com                                                 case_sensitive, encoding);
7111059Sigor@sysoev.ru         if (nxt_slow_path(ruleset == NULL)) {
7121059Sigor@sysoev.ru             return NULL;
7131059Sigor@sysoev.ru         }
7141059Sigor@sysoev.ru 
7151059Sigor@sysoev.ru         table->ruleset[i] = ruleset;
7161059Sigor@sysoev.ru     }
7171059Sigor@sysoev.ru 
7181059Sigor@sysoev.ru     return table;
7191059Sigor@sysoev.ru }
7201059Sigor@sysoev.ru 
7211059Sigor@sysoev.ru 
7221059Sigor@sysoev.ru static nxt_http_route_ruleset_t *
nxt_http_route_ruleset_create(nxt_task_t * task,nxt_mp_t * mp,nxt_conf_value_t * ruleset_cv,nxt_http_route_object_t object,nxt_bool_t case_sensitive,nxt_http_uri_encoding_t encoding)7231059Sigor@sysoev.ru nxt_http_route_ruleset_create(nxt_task_t *task, nxt_mp_t *mp,
7241061Sigor@sysoev.ru     nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object,
7252123Sz.hong@f5.com     nxt_bool_t case_sensitive, nxt_http_uri_encoding_t encoding)
7261059Sigor@sysoev.ru {
7271059Sigor@sysoev.ru     size_t                    size;
7281059Sigor@sysoev.ru     uint32_t                  i, n, next;
7291059Sigor@sysoev.ru     nxt_str_t                 name;
7301059Sigor@sysoev.ru     nxt_conf_value_t          *rule_cv;
7311059Sigor@sysoev.ru     nxt_http_route_rule_t     *rule;
7321059Sigor@sysoev.ru     nxt_http_route_ruleset_t  *ruleset;
7331059Sigor@sysoev.ru 
7341059Sigor@sysoev.ru     n = nxt_conf_object_members_count(ruleset_cv);
7351059Sigor@sysoev.ru     size = sizeof(nxt_http_route_ruleset_t)
7361059Sigor@sysoev.ru            + n * sizeof(nxt_http_route_rule_t *);
7371059Sigor@sysoev.ru 
7381059Sigor@sysoev.ru     ruleset = nxt_mp_alloc(mp, size);
7391059Sigor@sysoev.ru     if (nxt_slow_path(ruleset == NULL)) {
7401059Sigor@sysoev.ru         return NULL;
7411059Sigor@sysoev.ru     }
7421059Sigor@sysoev.ru 
7431059Sigor@sysoev.ru     ruleset->items = n;
7441059Sigor@sysoev.ru 
7451059Sigor@sysoev.ru     next = 0;
7461059Sigor@sysoev.ru 
7471785Svbart@nginx.com     /*
7481785Svbart@nginx.com      * A workaround for GCC 10 with -flto -O2 flags that warns about "name"
7491785Svbart@nginx.com      * may be uninitialized in nxt_http_route_rule_name_create().
7501785Svbart@nginx.com      */
7511785Svbart@nginx.com     nxt_str_null(&name);
7521785Svbart@nginx.com 
7531059Sigor@sysoev.ru     for (i = 0; i < n; i++) {
7541059Sigor@sysoev.ru         rule_cv = nxt_conf_next_object_member(ruleset_cv, &name, &next);
7551059Sigor@sysoev.ru 
7561061Sigor@sysoev.ru         rule = nxt_http_route_rule_name_create(task, mp, rule_cv, &name,
7571474Saxel.duch@nginx.com                                                case_sensitive, encoding);
7581059Sigor@sysoev.ru         if (nxt_slow_path(rule == NULL)) {
7591059Sigor@sysoev.ru             return NULL;
7601059Sigor@sysoev.ru         }
7611059Sigor@sysoev.ru 
7621061Sigor@sysoev.ru         rule->object = object;
7631059Sigor@sysoev.ru         ruleset->rule[i] = rule;
7641059Sigor@sysoev.ru     }
7651059Sigor@sysoev.ru 
7661059Sigor@sysoev.ru     return ruleset;
7671059Sigor@sysoev.ru }
7681059Sigor@sysoev.ru 
7691059Sigor@sysoev.ru 
770964Sigor@sysoev.ru static nxt_http_route_rule_t *
nxt_http_route_rule_name_create(nxt_task_t * task,nxt_mp_t * mp,nxt_conf_value_t * rule_cv,nxt_str_t * name,nxt_bool_t case_sensitive,nxt_http_uri_encoding_t encoding)7711061Sigor@sysoev.ru nxt_http_route_rule_name_create(nxt_task_t *task, nxt_mp_t *mp,
7721474Saxel.duch@nginx.com     nxt_conf_value_t *rule_cv, nxt_str_t *name, nxt_bool_t case_sensitive,
7732123Sz.hong@f5.com     nxt_http_uri_encoding_t encoding)
7741059Sigor@sysoev.ru {
7752123Sz.hong@f5.com     int64_t                hash;
7761059Sigor@sysoev.ru     nxt_http_route_rule_t  *rule;
7771059Sigor@sysoev.ru 
7781061Sigor@sysoev.ru     rule = nxt_http_route_rule_create(task, mp, rule_cv, case_sensitive,
7791474Saxel.duch@nginx.com                                       NXT_HTTP_ROUTE_PATTERN_NOCASE,
7801474Saxel.duch@nginx.com                                       encoding);
7811059Sigor@sysoev.ru     if (nxt_slow_path(rule == NULL)) {
7821059Sigor@sysoev.ru         return NULL;
7831059Sigor@sysoev.ru     }
7841059Sigor@sysoev.ru 
7852123Sz.hong@f5.com     hash = nxt_http_field_hash(mp, name, case_sensitive, encoding);
7862123Sz.hong@f5.com     if (nxt_slow_path(hash == -1)) {
7871059Sigor@sysoev.ru         return NULL;
7881059Sigor@sysoev.ru     }
7891059Sigor@sysoev.ru 
7902123Sz.hong@f5.com     rule->u.name.hash = hash;
7912123Sz.hong@f5.com     rule->u.name.start = name->start;
7922123Sz.hong@f5.com     rule->u.name.length = name->length;
7931059Sigor@sysoev.ru 
7941059Sigor@sysoev.ru     return rule;
7951059Sigor@sysoev.ru }
7961059Sigor@sysoev.ru 
7971059Sigor@sysoev.ru 
7981059Sigor@sysoev.ru static nxt_http_route_rule_t *
nxt_http_route_rule_create(nxt_task_t * task,nxt_mp_t * mp,nxt_conf_value_t * cv,nxt_bool_t case_sensitive,nxt_http_route_pattern_case_t pattern_case,nxt_http_uri_encoding_t encoding)7991059Sigor@sysoev.ru nxt_http_route_rule_create(nxt_task_t *task, nxt_mp_t *mp,
800964Sigor@sysoev.ru     nxt_conf_value_t *cv, nxt_bool_t case_sensitive,
8011474Saxel.duch@nginx.com     nxt_http_route_pattern_case_t pattern_case,
8022123Sz.hong@f5.com     nxt_http_uri_encoding_t encoding)
803964Sigor@sysoev.ru {
804964Sigor@sysoev.ru     size_t                    size;
805964Sigor@sysoev.ru     uint32_t                  i, n;
806964Sigor@sysoev.ru     nxt_int_t                 ret;
807964Sigor@sysoev.ru     nxt_conf_value_t          *value;
808964Sigor@sysoev.ru     nxt_http_route_rule_t     *rule;
809964Sigor@sysoev.ru     nxt_http_route_pattern_t  *pattern;
810964Sigor@sysoev.ru 
8112077Salx.manpages@gmail.com     n = nxt_conf_array_elements_count_or_1(cv);
812964Sigor@sysoev.ru     size = sizeof(nxt_http_route_rule_t) + n * sizeof(nxt_http_route_pattern_t);
813964Sigor@sysoev.ru 
814964Sigor@sysoev.ru     rule = nxt_mp_alloc(mp, size);
815964Sigor@sysoev.ru     if (nxt_slow_path(rule == NULL)) {
816964Sigor@sysoev.ru         return NULL;
817964Sigor@sysoev.ru     }
818964Sigor@sysoev.ru 
819964Sigor@sysoev.ru     rule->items = n;
820964Sigor@sysoev.ru 
821964Sigor@sysoev.ru     pattern = &rule->pattern[0];
822964Sigor@sysoev.ru 
823964Sigor@sysoev.ru     nxt_conf_array_qsort(cv, nxt_http_pattern_compare);
824964Sigor@sysoev.ru 
825964Sigor@sysoev.ru     for (i = 0; i < n; i++) {
826964Sigor@sysoev.ru         pattern[i].case_sensitive = case_sensitive;
8272077Salx.manpages@gmail.com         value = nxt_conf_get_array_element_or_itself(cv, i);
828964Sigor@sysoev.ru 
829964Sigor@sysoev.ru         ret = nxt_http_route_pattern_create(task, mp, value, &pattern[i],
8301474Saxel.duch@nginx.com                                             pattern_case, encoding);
831964Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
832964Sigor@sysoev.ru             return NULL;
833964Sigor@sysoev.ru         }
834964Sigor@sysoev.ru     }
835964Sigor@sysoev.ru 
836964Sigor@sysoev.ru     return rule;
837964Sigor@sysoev.ru }
838964Sigor@sysoev.ru 
839964Sigor@sysoev.ru 
8401936So.canty@f5.com nxt_http_route_addr_rule_t *
nxt_http_route_addr_rule_create(nxt_task_t * task,nxt_mp_t * mp,nxt_conf_value_t * cv)8411324Saxel.duch@nginx.com nxt_http_route_addr_rule_create(nxt_task_t *task, nxt_mp_t *mp,
8422078Salx.manpages@gmail.com     nxt_conf_value_t *cv)
8431324Saxel.duch@nginx.com {
8441324Saxel.duch@nginx.com     size_t                         size;
8451324Saxel.duch@nginx.com     uint32_t                       i, n;
8461324Saxel.duch@nginx.com     nxt_conf_value_t               *value;
8471324Saxel.duch@nginx.com     nxt_http_route_addr_rule_t     *addr_rule;
8481324Saxel.duch@nginx.com     nxt_http_route_addr_pattern_t  *pattern;
8491324Saxel.duch@nginx.com 
8502077Salx.manpages@gmail.com     n = nxt_conf_array_elements_count_or_1(cv);
8511324Saxel.duch@nginx.com 
8521324Saxel.duch@nginx.com     size = sizeof(nxt_http_route_addr_rule_t)
8531324Saxel.duch@nginx.com            + n * sizeof(nxt_http_route_addr_pattern_t);
8541324Saxel.duch@nginx.com 
8551324Saxel.duch@nginx.com     addr_rule = nxt_mp_alloc(mp, size);
8561324Saxel.duch@nginx.com     if (nxt_slow_path(addr_rule == NULL)) {
8571324Saxel.duch@nginx.com         return NULL;
8581324Saxel.duch@nginx.com     }
8591324Saxel.duch@nginx.com 
8601324Saxel.duch@nginx.com     addr_rule->items = n;
8611324Saxel.duch@nginx.com 
8621324Saxel.duch@nginx.com     for (i = 0; i < n; i++) {
8631324Saxel.duch@nginx.com         pattern = &addr_rule->addr_pattern[i];
8642077Salx.manpages@gmail.com         value = nxt_conf_get_array_element_or_itself(cv, i);
8651324Saxel.duch@nginx.com 
8661324Saxel.duch@nginx.com         if (nxt_http_route_addr_pattern_parse(mp, pattern, value) != NXT_OK) {
8671324Saxel.duch@nginx.com             return NULL;
8681324Saxel.duch@nginx.com         }
8691324Saxel.duch@nginx.com     }
8701324Saxel.duch@nginx.com 
8711390Saxel.duch@nginx.com     if (n > 1) {
8721390Saxel.duch@nginx.com         nxt_qsort(addr_rule->addr_pattern, addr_rule->items,
8731390Saxel.duch@nginx.com             sizeof(nxt_http_route_addr_pattern_t),
8741390Saxel.duch@nginx.com             nxt_http_addr_pattern_compare);
8751390Saxel.duch@nginx.com     }
8761390Saxel.duch@nginx.com 
8771324Saxel.duch@nginx.com     return addr_rule;
8781324Saxel.duch@nginx.com }
8791324Saxel.duch@nginx.com 
8801324Saxel.duch@nginx.com 
8811923Sz.hong@f5.com nxt_http_route_rule_t *
nxt_http_route_types_rule_create(nxt_task_t * task,nxt_mp_t * mp,nxt_conf_value_t * types)8821923Sz.hong@f5.com nxt_http_route_types_rule_create(nxt_task_t *task, nxt_mp_t *mp,
8831923Sz.hong@f5.com     nxt_conf_value_t *types)
8841923Sz.hong@f5.com {
8851923Sz.hong@f5.com     return nxt_http_route_rule_create(task, mp, types, 0,
8861923Sz.hong@f5.com                                       NXT_HTTP_ROUTE_PATTERN_LOWCASE,
8872123Sz.hong@f5.com                                       NXT_HTTP_URI_ENCODING_NONE);
8881923Sz.hong@f5.com }
8891923Sz.hong@f5.com 
8901923Sz.hong@f5.com 
891964Sigor@sysoev.ru static int
nxt_http_pattern_compare(const void * one,const void * two)892964Sigor@sysoev.ru nxt_http_pattern_compare(const void *one, const void *two)
893964Sigor@sysoev.ru {
894964Sigor@sysoev.ru     nxt_str_t         test;
895964Sigor@sysoev.ru     nxt_bool_t        negative1, negative2;
896964Sigor@sysoev.ru     nxt_conf_value_t  *value;
897964Sigor@sysoev.ru 
898964Sigor@sysoev.ru     value = (nxt_conf_value_t *) one;
899964Sigor@sysoev.ru     nxt_conf_get_string(value, &test);
900964Sigor@sysoev.ru     negative1 = (test.length != 0 && test.start[0] == '!');
901964Sigor@sysoev.ru 
902964Sigor@sysoev.ru     value = (nxt_conf_value_t *) two;
903964Sigor@sysoev.ru     nxt_conf_get_string(value, &test);
904964Sigor@sysoev.ru     negative2 = (test.length != 0 && test.start[0] == '!');
905964Sigor@sysoev.ru 
906964Sigor@sysoev.ru     return (negative2 - negative1);
907964Sigor@sysoev.ru }
908964Sigor@sysoev.ru 
909964Sigor@sysoev.ru 
9101390Saxel.duch@nginx.com static int
nxt_http_addr_pattern_compare(const void * one,const void * two)9111390Saxel.duch@nginx.com nxt_http_addr_pattern_compare(const void *one, const void *two)
9121390Saxel.duch@nginx.com {
9131390Saxel.duch@nginx.com     const nxt_http_route_addr_pattern_t  *p1, *p2;
9141390Saxel.duch@nginx.com 
9151390Saxel.duch@nginx.com     p1 = one;
9161390Saxel.duch@nginx.com     p2 = two;
9171390Saxel.duch@nginx.com 
9181390Saxel.duch@nginx.com     return (p2->base.negative - p1->base.negative);
9191390Saxel.duch@nginx.com }
9201390Saxel.duch@nginx.com 
9211390Saxel.duch@nginx.com 
922964Sigor@sysoev.ru static nxt_int_t
nxt_http_route_pattern_create(nxt_task_t * task,nxt_mp_t * mp,nxt_conf_value_t * cv,nxt_http_route_pattern_t * pattern,nxt_http_route_pattern_case_t pattern_case,nxt_http_uri_encoding_t encoding)923964Sigor@sysoev.ru nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp,
924964Sigor@sysoev.ru     nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern,
9251474Saxel.duch@nginx.com     nxt_http_route_pattern_case_t pattern_case,
9262123Sz.hong@f5.com     nxt_http_uri_encoding_t encoding)
927964Sigor@sysoev.ru {
9281508Saxel.duch@nginx.com     u_char                          c, *p, *end;
9291508Saxel.duch@nginx.com     nxt_str_t                       test, tmp;
9301508Saxel.duch@nginx.com     nxt_int_t                       ret;
9311508Saxel.duch@nginx.com     nxt_array_t                     *slices;
9321721Saxel.duch@nginx.com #if (NXT_HAVE_REGEX)
9331721Saxel.duch@nginx.com     nxt_regex_t                     *re;
9341721Saxel.duch@nginx.com     nxt_regex_err_t                 err;
9351721Saxel.duch@nginx.com #endif
9361508Saxel.duch@nginx.com     nxt_http_route_pattern_type_t   type;
9371508Saxel.duch@nginx.com     nxt_http_route_pattern_slice_t  *slice;
938964Sigor@sysoev.ru 
939964Sigor@sysoev.ru     type = NXT_HTTP_ROUTE_PATTERN_EXACT;
940964Sigor@sysoev.ru 
941964Sigor@sysoev.ru     nxt_conf_get_string(cv, &test);
942964Sigor@sysoev.ru 
9431721Saxel.duch@nginx.com     pattern->u.pattern_slices = NULL;
944964Sigor@sysoev.ru     pattern->negative = 0;
945964Sigor@sysoev.ru     pattern->any = 1;
9461474Saxel.duch@nginx.com     pattern->min_length = 0;
9471721Saxel.duch@nginx.com #if (NXT_HAVE_REGEX)
9481721Saxel.duch@nginx.com     pattern->regex = 0;
9491721Saxel.duch@nginx.com #endif
950964Sigor@sysoev.ru 
9511508Saxel.duch@nginx.com     if (test.length != 0 && test.start[0] == '!') {
9521508Saxel.duch@nginx.com         test.start++;
9531508Saxel.duch@nginx.com         test.length--;
9541508Saxel.duch@nginx.com 
9551508Saxel.duch@nginx.com         pattern->negative = 1;
9561508Saxel.duch@nginx.com         pattern->any = 0;
9571508Saxel.duch@nginx.com     }
9581508Saxel.duch@nginx.com 
9591721Saxel.duch@nginx.com     if (test.length > 0 && test.start[0] == '~') {
9601721Saxel.duch@nginx.com #if (NXT_HAVE_REGEX)
9611721Saxel.duch@nginx.com         test.start++;
9621721Saxel.duch@nginx.com         test.length--;
9631721Saxel.duch@nginx.com 
9641721Saxel.duch@nginx.com         re = nxt_regex_compile(mp, &test, &err);
9651721Saxel.duch@nginx.com         if (nxt_slow_path(re == NULL)) {
9661721Saxel.duch@nginx.com             if (err.offset < test.length) {
9671721Saxel.duch@nginx.com                 nxt_alert(task, "nxt_regex_compile(%V) failed: %s at offset %d",
9681721Saxel.duch@nginx.com                           &test, err.msg, (int) err.offset);
9691721Saxel.duch@nginx.com                 return NXT_ERROR;
9701721Saxel.duch@nginx.com             }
9711721Saxel.duch@nginx.com 
9721721Saxel.duch@nginx.com             nxt_alert(task, "nxt_regex_compile(%V) failed %s", &test, err.msg);
9731721Saxel.duch@nginx.com 
9741721Saxel.duch@nginx.com             return NXT_ERROR;
9751721Saxel.duch@nginx.com         }
9761721Saxel.duch@nginx.com 
9771721Saxel.duch@nginx.com         pattern->u.regex = re;
9781721Saxel.duch@nginx.com         pattern->regex = 1;
9791721Saxel.duch@nginx.com 
9801721Saxel.duch@nginx.com         return NXT_OK;
9811721Saxel.duch@nginx.com 
9821721Saxel.duch@nginx.com #else
9831721Saxel.duch@nginx.com         return NXT_ERROR;
9841721Saxel.duch@nginx.com #endif
9851721Saxel.duch@nginx.com     }
9861721Saxel.duch@nginx.com 
9871721Saxel.duch@nginx.com     slices = nxt_array_create(mp, 1, sizeof(nxt_http_route_pattern_slice_t));
9881721Saxel.duch@nginx.com     if (nxt_slow_path(slices == NULL)) {
9891721Saxel.duch@nginx.com         return NXT_ERROR;
9901721Saxel.duch@nginx.com     }
9911721Saxel.duch@nginx.com 
9921721Saxel.duch@nginx.com     pattern->u.pattern_slices = slices;
9931721Saxel.duch@nginx.com 
9941508Saxel.duch@nginx.com     if (test.length == 0) {
9951508Saxel.duch@nginx.com         slice = nxt_array_add(slices);
9961508Saxel.duch@nginx.com         if (nxt_slow_path(slice == NULL)) {
9971508Saxel.duch@nginx.com             return NXT_ERROR;
998964Sigor@sysoev.ru         }
999964Sigor@sysoev.ru 
10001508Saxel.duch@nginx.com         slice->type = NXT_HTTP_ROUTE_PATTERN_EXACT;
10011508Saxel.duch@nginx.com         slice->start = NULL;
10021508Saxel.duch@nginx.com         slice->length = 0;
10031508Saxel.duch@nginx.com 
10041508Saxel.duch@nginx.com         return NXT_OK;
10051508Saxel.duch@nginx.com     }
10061508Saxel.duch@nginx.com 
10071508Saxel.duch@nginx.com     if (test.start[0] == '*') {
10081508Saxel.duch@nginx.com         /* 'type' is no longer 'EXACT', assume 'END'. */
10091508Saxel.duch@nginx.com         type = NXT_HTTP_ROUTE_PATTERN_END;
10101508