xref: /unit/src/nxt_http_route.c (revision 1903)
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,
221324Saxel.duch@nginx.com     NXT_HTTP_ROUTE_SOURCE,
231326Saxel.duch@nginx.com     NXT_HTTP_ROUTE_DESTINATION,
24964Sigor@sysoev.ru } nxt_http_route_object_t;
25964Sigor@sysoev.ru 
26964Sigor@sysoev.ru 
27964Sigor@sysoev.ru typedef enum {
28964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_EXACT = 0,
29964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_BEGIN,
30964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_END,
31964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_SUBSTRING,
32964Sigor@sysoev.ru } nxt_http_route_pattern_type_t;
33964Sigor@sysoev.ru 
34964Sigor@sysoev.ru 
35964Sigor@sysoev.ru typedef enum {
36964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_NOCASE = 0,
37964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_LOWCASE,
38964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_UPCASE,
39964Sigor@sysoev.ru } nxt_http_route_pattern_case_t;
40964Sigor@sysoev.ru 
41964Sigor@sysoev.ru 
421474Saxel.duch@nginx.com typedef enum {
431474Saxel.duch@nginx.com     NXT_HTTP_ROUTE_ENCODING_NONE = 0,
441474Saxel.duch@nginx.com     NXT_HTTP_ROUTE_ENCODING_URI,
451474Saxel.duch@nginx.com     NXT_HTTP_ROUTE_ENCODING_URI_PLUS
461474Saxel.duch@nginx.com } nxt_http_route_encoding_t;
471474Saxel.duch@nginx.com 
481474Saxel.duch@nginx.com 
49964Sigor@sysoev.ru typedef struct {
50964Sigor@sysoev.ru     nxt_conf_value_t               *host;
51964Sigor@sysoev.ru     nxt_conf_value_t               *uri;
52964Sigor@sysoev.ru     nxt_conf_value_t               *method;
531059Sigor@sysoev.ru     nxt_conf_value_t               *headers;
541061Sigor@sysoev.ru     nxt_conf_value_t               *arguments;
551062Sigor@sysoev.ru     nxt_conf_value_t               *cookies;
561110Saxel.duch@nginx.com     nxt_conf_value_t               *scheme;
571324Saxel.duch@nginx.com     nxt_conf_value_t               *source;
581326Saxel.duch@nginx.com     nxt_conf_value_t               *destination;
59964Sigor@sysoev.ru } nxt_http_route_match_conf_t;
60964Sigor@sysoev.ru 
61964Sigor@sysoev.ru 
62964Sigor@sysoev.ru typedef struct {
631508Saxel.duch@nginx.com     u_char                         *start;
641508Saxel.duch@nginx.com     uint32_t                       length;
651508Saxel.duch@nginx.com     nxt_http_route_pattern_type_t  type:8;
661508Saxel.duch@nginx.com } nxt_http_route_pattern_slice_t;
671508Saxel.duch@nginx.com 
681508Saxel.duch@nginx.com 
691508Saxel.duch@nginx.com typedef struct {
701721Saxel.duch@nginx.com     union {
711721Saxel.duch@nginx.com         nxt_array_t                *pattern_slices;
721721Saxel.duch@nginx.com #if (NXT_HAVE_REGEX)
731721Saxel.duch@nginx.com         nxt_regex_t                *regex;
741721Saxel.duch@nginx.com #endif
751721Saxel.duch@nginx.com     } u;
76964Sigor@sysoev.ru     uint32_t                       min_length;
771508Saxel.duch@nginx.com 
78964Sigor@sysoev.ru     uint8_t                        case_sensitive;  /* 1 bit */
79964Sigor@sysoev.ru     uint8_t                        negative;        /* 1 bit */
80964Sigor@sysoev.ru     uint8_t                        any;             /* 1 bit */
811721Saxel.duch@nginx.com #if (NXT_HAVE_REGEX)
821721Saxel.duch@nginx.com     uint8_t                        regex;           /* 1 bit */
831721Saxel.duch@nginx.com #endif
84964Sigor@sysoev.ru } nxt_http_route_pattern_t;
85964Sigor@sysoev.ru 
86964Sigor@sysoev.ru 
87964Sigor@sysoev.ru typedef struct {
881061Sigor@sysoev.ru     uint16_t                       hash;
891061Sigor@sysoev.ru     uint16_t                       name_length;
901061Sigor@sysoev.ru     uint32_t                       value_length;
911061Sigor@sysoev.ru     u_char                         *name;
921061Sigor@sysoev.ru     u_char                         *value;
931061Sigor@sysoev.ru } nxt_http_name_value_t;
941061Sigor@sysoev.ru 
951061Sigor@sysoev.ru 
961061Sigor@sysoev.ru typedef struct {
971062Sigor@sysoev.ru     uint16_t                       hash;
981062Sigor@sysoev.ru     uint16_t                       name_length;
991062Sigor@sysoev.ru     uint32_t                       value_length;
1001062Sigor@sysoev.ru     u_char                         *name;
1011062Sigor@sysoev.ru     u_char                         *value;
1021062Sigor@sysoev.ru } nxt_http_cookie_t;
1031062Sigor@sysoev.ru 
1041062Sigor@sysoev.ru 
1051859So.canty@f5.com struct nxt_http_route_rule_s {
1061059Sigor@sysoev.ru     /* The object must be the first field. */
1071059Sigor@sysoev.ru     nxt_http_route_object_t        object:8;
108964Sigor@sysoev.ru     uint32_t                       items;
1091059Sigor@sysoev.ru 
1101059Sigor@sysoev.ru     union {
1111059Sigor@sysoev.ru         uintptr_t                  offset;
1121059Sigor@sysoev.ru 
1131059Sigor@sysoev.ru         struct {
1141059Sigor@sysoev.ru             u_char                 *start;
1151059Sigor@sysoev.ru             uint16_t               hash;
1161059Sigor@sysoev.ru             uint16_t               length;
1171059Sigor@sysoev.ru         } name;
1181059Sigor@sysoev.ru     } u;
1191059Sigor@sysoev.ru 
120964Sigor@sysoev.ru     nxt_http_route_pattern_t       pattern[0];
1211859So.canty@f5.com };
122964Sigor@sysoev.ru 
123964Sigor@sysoev.ru 
124964Sigor@sysoev.ru typedef struct {
125964Sigor@sysoev.ru     uint32_t                       items;
1261059Sigor@sysoev.ru     nxt_http_route_rule_t          *rule[0];
1271059Sigor@sysoev.ru } nxt_http_route_ruleset_t;
1281059Sigor@sysoev.ru 
1291059Sigor@sysoev.ru 
1301059Sigor@sysoev.ru typedef struct {
1311059Sigor@sysoev.ru     /* The object must be the first field. */
1321059Sigor@sysoev.ru     nxt_http_route_object_t        object:8;
1331059Sigor@sysoev.ru     uint32_t                       items;
1341059Sigor@sysoev.ru     nxt_http_route_ruleset_t       *ruleset[0];
1351059Sigor@sysoev.ru } nxt_http_route_table_t;
1361059Sigor@sysoev.ru 
1371059Sigor@sysoev.ru 
1381324Saxel.duch@nginx.com typedef struct {
1391324Saxel.duch@nginx.com     /* The object must be the first field. */
1401324Saxel.duch@nginx.com     nxt_http_route_object_t        object:8;
1411324Saxel.duch@nginx.com     uint32_t                       items;
1421324Saxel.duch@nginx.com     nxt_http_route_addr_pattern_t  addr_pattern[0];
1431324Saxel.duch@nginx.com } nxt_http_route_addr_rule_t;
1441324Saxel.duch@nginx.com 
1451324Saxel.duch@nginx.com 
1461059Sigor@sysoev.ru typedef union {
1471059Sigor@sysoev.ru     nxt_http_route_rule_t          *rule;
1481059Sigor@sysoev.ru     nxt_http_route_table_t         *table;
1491324Saxel.duch@nginx.com     nxt_http_route_addr_rule_t     *addr_rule;
1501059Sigor@sysoev.ru } nxt_http_route_test_t;
1511059Sigor@sysoev.ru 
1521059Sigor@sysoev.ru 
1531059Sigor@sysoev.ru typedef struct {
1541059Sigor@sysoev.ru     uint32_t                       items;
1551264Sigor@sysoev.ru     nxt_http_action_t              action;
1561059Sigor@sysoev.ru     nxt_http_route_test_t          test[0];
157964Sigor@sysoev.ru } nxt_http_route_match_t;
158964Sigor@sysoev.ru 
159964Sigor@sysoev.ru 
160964Sigor@sysoev.ru struct nxt_http_route_s {
161964Sigor@sysoev.ru     nxt_str_t                      name;
162964Sigor@sysoev.ru     uint32_t                       items;
163964Sigor@sysoev.ru     nxt_http_route_match_t         *match[0];
164964Sigor@sysoev.ru };
165964Sigor@sysoev.ru 
166964Sigor@sysoev.ru 
167964Sigor@sysoev.ru struct nxt_http_routes_s {
168964Sigor@sysoev.ru     uint32_t                       items;
169964Sigor@sysoev.ru     nxt_http_route_t               *route[0];
170964Sigor@sysoev.ru };
171964Sigor@sysoev.ru 
172964Sigor@sysoev.ru 
1731522Saxel.duch@nginx.com #define NXT_COOKIE_HASH                                                       \
1741062Sigor@sysoev.ru     (nxt_http_field_hash_end(                                                 \
1751062Sigor@sysoev.ru      nxt_http_field_hash_char(                                                \
1761062Sigor@sysoev.ru      nxt_http_field_hash_char(                                                \
1771062Sigor@sysoev.ru      nxt_http_field_hash_char(                                                \
1781062Sigor@sysoev.ru      nxt_http_field_hash_char(                                                \
1791062Sigor@sysoev.ru      nxt_http_field_hash_char(                                                \
1801062Sigor@sysoev.ru      nxt_http_field_hash_char(NXT_HTTP_FIELD_HASH_INIT,                       \
1811062Sigor@sysoev.ru         'c'), 'o'), 'o'), 'k'), 'i'), 'e')) & 0xFFFF)
1821062Sigor@sysoev.ru 
1831062Sigor@sysoev.ru 
184964Sigor@sysoev.ru static nxt_http_route_t *nxt_http_route_create(nxt_task_t *task,
185964Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv);
186964Sigor@sysoev.ru static nxt_http_route_match_t *nxt_http_route_match_create(nxt_task_t *task,
187964Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv);
188*1903Sz.hong@f5.com static nxt_int_t nxt_http_action_init(nxt_task_t *task,
1891859So.canty@f5.com     nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv,
1901859So.canty@f5.com     nxt_http_action_t *action);
1911059Sigor@sysoev.ru static nxt_http_route_table_t *nxt_http_route_table_create(nxt_task_t *task,
1921061Sigor@sysoev.ru     nxt_mp_t *mp, nxt_conf_value_t *table_cv, nxt_http_route_object_t object,
1931474Saxel.duch@nginx.com     nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding);
1941059Sigor@sysoev.ru static nxt_http_route_ruleset_t *nxt_http_route_ruleset_create(nxt_task_t *task,
1951061Sigor@sysoev.ru     nxt_mp_t *mp, nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object,
1961474Saxel.duch@nginx.com     nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding);
1971061Sigor@sysoev.ru static nxt_http_route_rule_t *nxt_http_route_rule_name_create(nxt_task_t *task,
1981061Sigor@sysoev.ru     nxt_mp_t *mp, nxt_conf_value_t *rule_cv, nxt_str_t *name,
1991474Saxel.duch@nginx.com     nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding);
2001324Saxel.duch@nginx.com static nxt_http_route_addr_rule_t *nxt_http_route_addr_rule_create(
2011324Saxel.duch@nginx.com     nxt_task_t *task, nxt_mp_t *mp, nxt_conf_value_t *cv);
202964Sigor@sysoev.ru static nxt_http_route_rule_t *nxt_http_route_rule_create(nxt_task_t *task,
2031059Sigor@sysoev.ru     nxt_mp_t *mp, nxt_conf_value_t *cv, nxt_bool_t case_sensitive,
2041474Saxel.duch@nginx.com     nxt_http_route_pattern_case_t pattern_case,
2051474Saxel.duch@nginx.com     nxt_http_route_encoding_t encoding);
206964Sigor@sysoev.ru static int nxt_http_pattern_compare(const void *one, const void *two);
2071390Saxel.duch@nginx.com static int nxt_http_addr_pattern_compare(const void *one, const void *two);
208964Sigor@sysoev.ru static nxt_int_t nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp,
209964Sigor@sysoev.ru     nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern,
2101474Saxel.duch@nginx.com     nxt_http_route_pattern_case_t pattern_case,
2111474Saxel.duch@nginx.com     nxt_http_route_encoding_t encoding);
2121474Saxel.duch@nginx.com static nxt_int_t nxt_http_route_decode_str(nxt_str_t *str,
2131474Saxel.duch@nginx.com     nxt_http_route_encoding_t encoding);
2141508Saxel.duch@nginx.com static nxt_int_t nxt_http_route_pattern_slice(nxt_array_t *slices,
2151508Saxel.duch@nginx.com     nxt_str_t *test,
2161508Saxel.duch@nginx.com     nxt_http_route_pattern_type_t type,
2171508Saxel.duch@nginx.com     nxt_http_route_encoding_t encoding,
2181032Sigor@sysoev.ru     nxt_http_route_pattern_case_t pattern_case);
219964Sigor@sysoev.ru 
2201472Svbart@nginx.com static nxt_int_t nxt_http_route_resolve(nxt_task_t *task,
221964Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_http_route_t *route);
2221472Svbart@nginx.com static nxt_int_t nxt_http_action_resolve(nxt_task_t *task,
2231264Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_http_action_t *action);
2241563Svbart@nginx.com static nxt_http_action_t *nxt_http_action_pass_var(nxt_task_t *task,
2251563Svbart@nginx.com     nxt_http_request_t *r, nxt_http_action_t *action);
2261563Svbart@nginx.com static void nxt_http_action_pass_var_ready(nxt_task_t *task, void *obj,
2271563Svbart@nginx.com     void *data);
2281563Svbart@nginx.com static void nxt_http_action_pass_var_error(nxt_task_t *task, void *obj,
2291563Svbart@nginx.com     void *data);
2301563Svbart@nginx.com static nxt_int_t nxt_http_pass_find(nxt_task_t *task, nxt_mp_t *mp,
2311563Svbart@nginx.com     nxt_router_conf_t *rtcf, nxt_http_action_t *action);
2321563Svbart@nginx.com static nxt_int_t nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name,
2331392Sigor@sysoev.ru     nxt_http_action_t *action);
234964Sigor@sysoev.ru 
2351264Sigor@sysoev.ru static nxt_http_action_t *nxt_http_route_handler(nxt_task_t *task,
2361264Sigor@sysoev.ru     nxt_http_request_t *r, nxt_http_action_t *start);
2371326Saxel.duch@nginx.com static nxt_http_action_t *nxt_http_route_match(nxt_task_t *task,
2381326Saxel.duch@nginx.com     nxt_http_request_t *r, nxt_http_route_match_t *match);
2391060Sigor@sysoev.ru static nxt_int_t nxt_http_route_table(nxt_http_request_t *r,
2401059Sigor@sysoev.ru     nxt_http_route_table_t *table);
2411060Sigor@sysoev.ru static nxt_int_t nxt_http_route_ruleset(nxt_http_request_t *r,
2421059Sigor@sysoev.ru     nxt_http_route_ruleset_t *ruleset);
2431324Saxel.duch@nginx.com static nxt_int_t nxt_http_route_addr_rule(nxt_http_request_t *r,
2441324Saxel.duch@nginx.com     nxt_http_route_addr_rule_t *addr_rule, nxt_sockaddr_t *sockaddr);
2451060Sigor@sysoev.ru static nxt_int_t nxt_http_route_rule(nxt_http_request_t *r,
246964Sigor@sysoev.ru     nxt_http_route_rule_t *rule);
2471060Sigor@sysoev.ru static nxt_int_t nxt_http_route_header(nxt_http_request_t *r,
2481059Sigor@sysoev.ru     nxt_http_route_rule_t *rule);
2491061Sigor@sysoev.ru static nxt_int_t nxt_http_route_arguments(nxt_http_request_t *r,
2501061Sigor@sysoev.ru     nxt_http_route_rule_t *rule);
2511061Sigor@sysoev.ru static nxt_array_t *nxt_http_route_arguments_parse(nxt_http_request_t *r);
2521061Sigor@sysoev.ru static nxt_http_name_value_t *nxt_http_route_argument(nxt_array_t *array,
2531061Sigor@sysoev.ru     u_char *name, size_t name_length, uint32_t hash, u_char *start,
2541061Sigor@sysoev.ru     u_char *end);
2551061Sigor@sysoev.ru static nxt_int_t nxt_http_route_test_argument(nxt_http_request_t *r,
2561061Sigor@sysoev.ru     nxt_http_route_rule_t *rule, nxt_array_t *array);
2571110Saxel.duch@nginx.com static nxt_int_t nxt_http_route_scheme(nxt_http_request_t *r,
2581110Saxel.duch@nginx.com     nxt_http_route_rule_t *rule);
2591062Sigor@sysoev.ru static nxt_int_t nxt_http_route_cookies(nxt_http_request_t *r,
2601062Sigor@sysoev.ru     nxt_http_route_rule_t *rule);
2611062Sigor@sysoev.ru static nxt_array_t *nxt_http_route_cookies_parse(nxt_http_request_t *r);
2621062Sigor@sysoev.ru static nxt_int_t nxt_http_route_cookie_parse(nxt_array_t *cookies,
2631062Sigor@sysoev.ru     u_char *start, u_char *end);
2641062Sigor@sysoev.ru static nxt_http_name_value_t *nxt_http_route_cookie(nxt_array_t *array,
2651062Sigor@sysoev.ru     u_char *name, size_t name_length, u_char *start, u_char *end);
2661062Sigor@sysoev.ru static nxt_int_t nxt_http_route_test_cookie(nxt_http_request_t *r,
2671062Sigor@sysoev.ru     nxt_http_route_rule_t *rule, nxt_array_t *array);
2681060Sigor@sysoev.ru static nxt_int_t nxt_http_route_pattern(nxt_http_request_t *r,
269964Sigor@sysoev.ru     nxt_http_route_pattern_t *pattern, u_char *start, size_t length);
2701060Sigor@sysoev.ru static nxt_int_t nxt_http_route_memcmp(u_char *start, u_char *test,
2711032Sigor@sysoev.ru     size_t length, nxt_bool_t case_sensitive);
272964Sigor@sysoev.ru 
273964Sigor@sysoev.ru 
274964Sigor@sysoev.ru nxt_http_routes_t *
275964Sigor@sysoev.ru nxt_http_routes_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
276964Sigor@sysoev.ru     nxt_conf_value_t *routes_conf)
277964Sigor@sysoev.ru {
278964Sigor@sysoev.ru     size_t             size;
279964Sigor@sysoev.ru     uint32_t           i, n, next;
280964Sigor@sysoev.ru     nxt_mp_t           *mp;
281964Sigor@sysoev.ru     nxt_str_t          name, *string;
282964Sigor@sysoev.ru     nxt_bool_t         object;
283964Sigor@sysoev.ru     nxt_conf_value_t   *route_conf;
284964Sigor@sysoev.ru     nxt_http_route_t   *route;
285964Sigor@sysoev.ru     nxt_http_routes_t  *routes;
286964Sigor@sysoev.ru 
287964Sigor@sysoev.ru     object = (nxt_conf_type(routes_conf) == NXT_CONF_OBJECT);
288964Sigor@sysoev.ru     n = object ? nxt_conf_object_members_count(routes_conf) : 1;
289964Sigor@sysoev.ru     size = sizeof(nxt_http_routes_t) + n * sizeof(nxt_http_route_t *);
290964Sigor@sysoev.ru 
291964Sigor@sysoev.ru     mp = tmcf->router_conf->mem_pool;
292964Sigor@sysoev.ru 
293964Sigor@sysoev.ru     routes = nxt_mp_alloc(mp, size);
294964Sigor@sysoev.ru     if (nxt_slow_path(routes == NULL)) {
295964Sigor@sysoev.ru         return NULL;
296964Sigor@sysoev.ru     }
297964Sigor@sysoev.ru 
298964Sigor@sysoev.ru     routes->items = n;
299964Sigor@sysoev.ru 
300964Sigor@sysoev.ru     if (object) {
301964Sigor@sysoev.ru         next = 0;
302964Sigor@sysoev.ru 
303964Sigor@sysoev.ru         for (i = 0; i < n; i++) {
304964Sigor@sysoev.ru             route_conf = nxt_conf_next_object_member(routes_conf, &name, &next);
305964Sigor@sysoev.ru 
306964Sigor@sysoev.ru             route = nxt_http_route_create(task, tmcf, route_conf);
307964Sigor@sysoev.ru             if (nxt_slow_path(route == NULL)) {
308964Sigor@sysoev.ru                 return NULL;
309964Sigor@sysoev.ru             }
310964Sigor@sysoev.ru 
311964Sigor@sysoev.ru             routes->route[i] = route;
312964Sigor@sysoev.ru 
313964Sigor@sysoev.ru             string = nxt_str_dup(mp, &route->name, &name);
314964Sigor@sysoev.ru             if (nxt_slow_path(string == NULL)) {
315964Sigor@sysoev.ru                 return NULL;
316964Sigor@sysoev.ru             }
317964Sigor@sysoev.ru         }
318964Sigor@sysoev.ru 
319964Sigor@sysoev.ru     } else {
320964Sigor@sysoev.ru         route = nxt_http_route_create(task, tmcf, routes_conf);
321964Sigor@sysoev.ru         if (nxt_slow_path(route == NULL)) {
322964Sigor@sysoev.ru             return NULL;
323964Sigor@sysoev.ru         }
324964Sigor@sysoev.ru 
325964Sigor@sysoev.ru         routes->route[0] = route;
326964Sigor@sysoev.ru 
327964Sigor@sysoev.ru         route->name.length = 0;
328964Sigor@sysoev.ru         route->name.start = NULL;
329964Sigor@sysoev.ru     }
330964Sigor@sysoev.ru 
331964Sigor@sysoev.ru     return routes;
332964Sigor@sysoev.ru }
333964Sigor@sysoev.ru 
334964Sigor@sysoev.ru 
335964Sigor@sysoev.ru static nxt_conf_map_t  nxt_http_route_match_conf[] = {
336964Sigor@sysoev.ru     {
3371110Saxel.duch@nginx.com         nxt_string("scheme"),
3381110Saxel.duch@nginx.com         NXT_CONF_MAP_PTR,
3391110Saxel.duch@nginx.com         offsetof(nxt_http_route_match_conf_t, scheme)
3401110Saxel.duch@nginx.com     },
3411110Saxel.duch@nginx.com     {
342964Sigor@sysoev.ru         nxt_string("host"),
343964Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
344964Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, host),
345964Sigor@sysoev.ru     },
346964Sigor@sysoev.ru 
347964Sigor@sysoev.ru     {
348964Sigor@sysoev.ru         nxt_string("uri"),
349964Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
350964Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, uri),
351964Sigor@sysoev.ru     },
352964Sigor@sysoev.ru 
353964Sigor@sysoev.ru     {
354964Sigor@sysoev.ru         nxt_string("method"),
355964Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
356964Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, method),
357964Sigor@sysoev.ru     },
3581059Sigor@sysoev.ru 
3591059Sigor@sysoev.ru     {
3601059Sigor@sysoev.ru         nxt_string("headers"),
3611059Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
3621059Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, headers),
3631059Sigor@sysoev.ru     },
3641061Sigor@sysoev.ru 
3651061Sigor@sysoev.ru     {
3661061Sigor@sysoev.ru         nxt_string("arguments"),
3671061Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
3681061Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, arguments),
3691061Sigor@sysoev.ru     },
3701062Sigor@sysoev.ru 
3711062Sigor@sysoev.ru     {
3721062Sigor@sysoev.ru         nxt_string("cookies"),
3731062Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
3741062Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, cookies),
3751062Sigor@sysoev.ru     },
3761324Saxel.duch@nginx.com 
3771324Saxel.duch@nginx.com     {
3781324Saxel.duch@nginx.com         nxt_string("source"),
3791324Saxel.duch@nginx.com         NXT_CONF_MAP_PTR,
3801324Saxel.duch@nginx.com         offsetof(nxt_http_route_match_conf_t, source),
3811324Saxel.duch@nginx.com     },
3821326Saxel.duch@nginx.com 
3831326Saxel.duch@nginx.com     {
3841326Saxel.duch@nginx.com         nxt_string("destination"),
3851326Saxel.duch@nginx.com         NXT_CONF_MAP_PTR,
3861326Saxel.duch@nginx.com         offsetof(nxt_http_route_match_conf_t, destination),
3871326Saxel.duch@nginx.com     },
388964Sigor@sysoev.ru };
389964Sigor@sysoev.ru 
390964Sigor@sysoev.ru 
391964Sigor@sysoev.ru static nxt_http_route_t *
392964Sigor@sysoev.ru nxt_http_route_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
393964Sigor@sysoev.ru     nxt_conf_value_t *cv)
394964Sigor@sysoev.ru {
395964Sigor@sysoev.ru     size_t                  size;
396964Sigor@sysoev.ru     uint32_t                i, n;
397964Sigor@sysoev.ru     nxt_conf_value_t        *value;
398964Sigor@sysoev.ru     nxt_http_route_t        *route;
399964Sigor@sysoev.ru     nxt_http_route_match_t  *match, **m;
400964Sigor@sysoev.ru 
401964Sigor@sysoev.ru     n = nxt_conf_array_elements_count(cv);
402964Sigor@sysoev.ru     size = sizeof(nxt_http_route_t) + n * sizeof(nxt_http_route_match_t *);
403964Sigor@sysoev.ru 
404964Sigor@sysoev.ru     route = nxt_mp_alloc(tmcf->router_conf->mem_pool, size);
405964Sigor@sysoev.ru     if (nxt_slow_path(route == NULL)) {
406964Sigor@sysoev.ru         return NULL;
407964Sigor@sysoev.ru     }
408964Sigor@sysoev.ru 
409964Sigor@sysoev.ru     route->items = n;
410964Sigor@sysoev.ru     m = &route->match[0];
411964Sigor@sysoev.ru 
412964Sigor@sysoev.ru     for (i = 0; i < n; i++) {
413964Sigor@sysoev.ru         value = nxt_conf_get_array_element(cv, i);
414964Sigor@sysoev.ru 
415964Sigor@sysoev.ru         match = nxt_http_route_match_create(task, tmcf, value);
416964Sigor@sysoev.ru         if (match == NULL) {
417964Sigor@sysoev.ru             return NULL;
418964Sigor@sysoev.ru         }
419964Sigor@sysoev.ru 
420964Sigor@sysoev.ru         *m++ = match;
421964Sigor@sysoev.ru     }
422964Sigor@sysoev.ru 
423964Sigor@sysoev.ru     return route;
424964Sigor@sysoev.ru }
425964Sigor@sysoev.ru 
426964Sigor@sysoev.ru 
427964Sigor@sysoev.ru static nxt_http_route_match_t *
428964Sigor@sysoev.ru nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
429964Sigor@sysoev.ru     nxt_conf_value_t *cv)
430964Sigor@sysoev.ru {
431964Sigor@sysoev.ru     size_t                       size;
432964Sigor@sysoev.ru     uint32_t                     n;
4331059Sigor@sysoev.ru     nxt_mp_t                     *mp;
434964Sigor@sysoev.ru     nxt_int_t                    ret;
4351378Svbart@nginx.com     nxt_conf_value_t             *match_conf, *action_conf;
4361059Sigor@sysoev.ru     nxt_http_route_test_t        *test;
4371059Sigor@sysoev.ru     nxt_http_route_rule_t        *rule;
4381059Sigor@sysoev.ru     nxt_http_route_table_t       *table;
439964Sigor@sysoev.ru     nxt_http_route_match_t       *match;
4401324Saxel.duch@nginx.com     nxt_http_route_addr_rule_t   *addr_rule;
441964Sigor@sysoev.ru     nxt_http_route_match_conf_t  mtcf;
442964Sigor@sysoev.ru 
443964Sigor@sysoev.ru     static nxt_str_t  match_path = nxt_string("/match");
4441378Svbart@nginx.com     static nxt_str_t  action_path = nxt_string("/action");
445964Sigor@sysoev.ru 
446964Sigor@sysoev.ru     match_conf = nxt_conf_get_path(cv, &match_path);
447964Sigor@sysoev.ru 
448964Sigor@sysoev.ru     n = (match_conf != NULL) ? nxt_conf_object_members_count(match_conf) : 0;
4491859So.canty@f5.com     size = sizeof(nxt_http_route_match_t) + n * sizeof(nxt_http_route_test_t *);
450964Sigor@sysoev.ru 
4511059Sigor@sysoev.ru     mp = tmcf->router_conf->mem_pool;
4521059Sigor@sysoev.ru 
4531059Sigor@sysoev.ru     match = nxt_mp_alloc(mp, size);
454964Sigor@sysoev.ru     if (nxt_slow_path(match == NULL)) {
455964Sigor@sysoev.ru         return NULL;
456964Sigor@sysoev.ru     }
457964Sigor@sysoev.ru 
458964Sigor@sysoev.ru     match->items = n;
459964Sigor@sysoev.ru 
4601378Svbart@nginx.com     action_conf = nxt_conf_get_path(cv, &action_path);
4611378Svbart@nginx.com     if (nxt_slow_path(action_conf == NULL)) {
4621378Svbart@nginx.com         return NULL;
4631378Svbart@nginx.com     }
4641378Svbart@nginx.com 
465*1903Sz.hong@f5.com     ret = nxt_http_action_init(task, tmcf, action_conf, &match->action);
4661264Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
467964Sigor@sysoev.ru         return NULL;
468964Sigor@sysoev.ru     }
469964Sigor@sysoev.ru 
470964Sigor@sysoev.ru     if (n == 0) {
471964Sigor@sysoev.ru         return match;
472964Sigor@sysoev.ru     }
473964Sigor@sysoev.ru 
474964Sigor@sysoev.ru     nxt_memzero(&mtcf, sizeof(mtcf));
475964Sigor@sysoev.ru 
476964Sigor@sysoev.ru     ret = nxt_conf_map_object(tmcf->mem_pool,
477964Sigor@sysoev.ru                               match_conf, nxt_http_route_match_conf,
478964Sigor@sysoev.ru                               nxt_nitems(nxt_http_route_match_conf), &mtcf);
479964Sigor@sysoev.ru     if (ret != NXT_OK) {
480964Sigor@sysoev.ru         return NULL;
481964Sigor@sysoev.ru     }
482964Sigor@sysoev.ru 
4831059Sigor@sysoev.ru     test = &match->test[0];
484964Sigor@sysoev.ru 
4851110Saxel.duch@nginx.com     if (mtcf.scheme != NULL) {
4861110Saxel.duch@nginx.com         rule = nxt_http_route_rule_create(task, mp, mtcf.scheme, 1,
4871474Saxel.duch@nginx.com                                           NXT_HTTP_ROUTE_PATTERN_NOCASE,
4881474Saxel.duch@nginx.com                                           NXT_HTTP_ROUTE_ENCODING_NONE);
4891110Saxel.duch@nginx.com         if (rule == NULL) {
4901110Saxel.duch@nginx.com             return NULL;
4911110Saxel.duch@nginx.com         }
4921110Saxel.duch@nginx.com 
4931110Saxel.duch@nginx.com         rule->object = NXT_HTTP_ROUTE_SCHEME;
4941110Saxel.duch@nginx.com         test->rule = rule;
4951110Saxel.duch@nginx.com         test++;
4961110Saxel.duch@nginx.com     }
4971110Saxel.duch@nginx.com 
498964Sigor@sysoev.ru     if (mtcf.host != NULL) {
4991059Sigor@sysoev.ru         rule = nxt_http_route_rule_create(task, mp, mtcf.host, 1,
5001474Saxel.duch@nginx.com                                           NXT_HTTP_ROUTE_PATTERN_LOWCASE,
5011474Saxel.duch@nginx.com                                           NXT_HTTP_ROUTE_ENCODING_NONE);
502964Sigor@sysoev.ru         if (rule == NULL) {
503964Sigor@sysoev.ru             return NULL;
504964Sigor@sysoev.ru         }
505964Sigor@sysoev.ru 
5061059Sigor@sysoev.ru         rule->u.offset = offsetof(nxt_http_request_t, host);
507964Sigor@sysoev.ru         rule->object = NXT_HTTP_ROUTE_STRING;
5081059Sigor@sysoev.ru         test->rule = rule;
5091059Sigor@sysoev.ru         test++;
510964Sigor@sysoev.ru     }
511964Sigor@sysoev.ru 
512964Sigor@sysoev.ru     if (mtcf.uri != NULL) {
5131059Sigor@sysoev.ru         rule = nxt_http_route_rule_create(task, mp, mtcf.uri, 1,
5141474Saxel.duch@nginx.com                                           NXT_HTTP_ROUTE_PATTERN_NOCASE,
5151474Saxel.duch@nginx.com                                           NXT_HTTP_ROUTE_ENCODING_URI);
516964Sigor@sysoev.ru         if (rule == NULL) {
517964Sigor@sysoev.ru             return NULL;
518964Sigor@sysoev.ru         }
519964Sigor@sysoev.ru 
5201059Sigor@sysoev.ru         rule->u.offset = offsetof(nxt_http_request_t, path);
521964Sigor@sysoev.ru         rule->object = NXT_HTTP_ROUTE_STRING_PTR;
5221059Sigor@sysoev.ru         test->rule = rule;
5231059Sigor@sysoev.ru         test++;
524964Sigor@sysoev.ru     }
525964Sigor@sysoev.ru 
526964Sigor@sysoev.ru     if (mtcf.method != NULL) {
5271059Sigor@sysoev.ru         rule = nxt_http_route_rule_create(task, mp, mtcf.method, 1,
5281474Saxel.duch@nginx.com                                           NXT_HTTP_ROUTE_PATTERN_UPCASE,
5291474Saxel.duch@nginx.com                                           NXT_HTTP_ROUTE_ENCODING_NONE);
530964Sigor@sysoev.ru         if (rule == NULL) {
531964Sigor@sysoev.ru             return NULL;
532964Sigor@sysoev.ru         }
533964Sigor@sysoev.ru 
5341059Sigor@sysoev.ru         rule->u.offset = offsetof(nxt_http_request_t, method);
535964Sigor@sysoev.ru         rule->object = NXT_HTTP_ROUTE_STRING_PTR;
5361059Sigor@sysoev.ru         test->rule = rule;
5371059Sigor@sysoev.ru         test++;
5381059Sigor@sysoev.ru     }
5391059Sigor@sysoev.ru 
5401059Sigor@sysoev.ru     if (mtcf.headers != NULL) {
5411061Sigor@sysoev.ru         table = nxt_http_route_table_create(task, mp, mtcf.headers,
5421474Saxel.duch@nginx.com                                             NXT_HTTP_ROUTE_HEADER, 0,
5431474Saxel.duch@nginx.com                                             NXT_HTTP_ROUTE_ENCODING_NONE);
5441061Sigor@sysoev.ru         if (table == NULL) {
5451061Sigor@sysoev.ru             return NULL;
5461061Sigor@sysoev.ru         }
5471061Sigor@sysoev.ru 
5481061Sigor@sysoev.ru         test->table = table;
5491061Sigor@sysoev.ru         test++;
5501061Sigor@sysoev.ru     }
5511061Sigor@sysoev.ru 
5521061Sigor@sysoev.ru     if (mtcf.arguments != NULL) {
5531061Sigor@sysoev.ru         table = nxt_http_route_table_create(task, mp, mtcf.arguments,
5541474Saxel.duch@nginx.com                                             NXT_HTTP_ROUTE_ARGUMENT, 1,
5551474Saxel.duch@nginx.com                                             NXT_HTTP_ROUTE_ENCODING_URI_PLUS);
5561059Sigor@sysoev.ru         if (table == NULL) {
5571059Sigor@sysoev.ru             return NULL;
5581059Sigor@sysoev.ru         }
5591059Sigor@sysoev.ru 
5601059Sigor@sysoev.ru         test->table = table;
5611059Sigor@sysoev.ru         test++;
562964Sigor@sysoev.ru     }
563964Sigor@sysoev.ru 
5641062Sigor@sysoev.ru     if (mtcf.cookies != NULL) {
5651062Sigor@sysoev.ru         table = nxt_http_route_table_create(task, mp, mtcf.cookies,
5661474Saxel.duch@nginx.com                                             NXT_HTTP_ROUTE_COOKIE, 1,
5671474Saxel.duch@nginx.com                                             NXT_HTTP_ROUTE_ENCODING_NONE);
5681062Sigor@sysoev.ru         if (table == NULL) {
5691062Sigor@sysoev.ru             return NULL;
5701062Sigor@sysoev.ru         }
5711062Sigor@sysoev.ru 
5721062Sigor@sysoev.ru         test->table = table;
5731062Sigor@sysoev.ru         test++;
5741062Sigor@sysoev.ru     }
5751062Sigor@sysoev.ru 
5761324Saxel.duch@nginx.com     if (mtcf.source != NULL) {
5771324Saxel.duch@nginx.com         addr_rule = nxt_http_route_addr_rule_create(task, mp, mtcf.source);
5781324Saxel.duch@nginx.com         if (addr_rule == NULL) {
5791324Saxel.duch@nginx.com             return NULL;
5801324Saxel.duch@nginx.com         }
5811324Saxel.duch@nginx.com 
5821324Saxel.duch@nginx.com         addr_rule->object = NXT_HTTP_ROUTE_SOURCE;
5831324Saxel.duch@nginx.com         test->addr_rule = addr_rule;
5841324Saxel.duch@nginx.com         test++;
5851324Saxel.duch@nginx.com     }
5861324Saxel.duch@nginx.com 
5871326Saxel.duch@nginx.com     if (mtcf.destination != NULL) {
5881326Saxel.duch@nginx.com         addr_rule = nxt_http_route_addr_rule_create(task, mp, mtcf.destination);
5891326Saxel.duch@nginx.com         if (addr_rule == NULL) {
5901326Saxel.duch@nginx.com             return NULL;
5911326Saxel.duch@nginx.com         }
5921326Saxel.duch@nginx.com 
5931326Saxel.duch@nginx.com         addr_rule->object = NXT_HTTP_ROUTE_DESTINATION;
5941326Saxel.duch@nginx.com         test->addr_rule = addr_rule;
5951326Saxel.duch@nginx.com         test++;
5961326Saxel.duch@nginx.com     }
5971326Saxel.duch@nginx.com 
598964Sigor@sysoev.ru     return match;
599964Sigor@sysoev.ru }
600964Sigor@sysoev.ru 
601964Sigor@sysoev.ru 
6021264Sigor@sysoev.ru static nxt_conf_map_t  nxt_http_route_action_conf[] = {
6031264Sigor@sysoev.ru     {
6041264Sigor@sysoev.ru         nxt_string("pass"),
6051264Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
606*1903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, pass)
6071264Sigor@sysoev.ru     },
6081264Sigor@sysoev.ru     {
6091429Svbart@nginx.com         nxt_string("return"),
6101429Svbart@nginx.com         NXT_CONF_MAP_PTR,
611*1903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, ret)
6121429Svbart@nginx.com     },
6131429Svbart@nginx.com     {
6141432Svbart@nginx.com         nxt_string("location"),
6151432Svbart@nginx.com         NXT_CONF_MAP_STR,
616*1903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, location)
6171432Svbart@nginx.com     },
6181432Svbart@nginx.com     {
6191854Sz.hong@f5.com         nxt_string("proxy"),
6201854Sz.hong@f5.com         NXT_CONF_MAP_PTR,
621*1903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, proxy)
6221854Sz.hong@f5.com     },
6231854Sz.hong@f5.com     {
6241264Sigor@sysoev.ru         nxt_string("share"),
6251264Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
626*1903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, share)
6271264Sigor@sysoev.ru     },
6281270Sigor@sysoev.ru     {
6291855Sz.hong@f5.com         nxt_string("chroot"),
6301855Sz.hong@f5.com         NXT_CONF_MAP_STR,
631*1903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, chroot)
6321855Sz.hong@f5.com     },
6331855Sz.hong@f5.com     {
6341855Sz.hong@f5.com         nxt_string("follow_symlinks"),
6351855Sz.hong@f5.com         NXT_CONF_MAP_PTR,
636*1903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, follow_symlinks)
6371855Sz.hong@f5.com     },
6381855Sz.hong@f5.com     {
6391855Sz.hong@f5.com         nxt_string("traverse_mounts"),
6401855Sz.hong@f5.com         NXT_CONF_MAP_PTR,
641*1903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, traverse_mounts)
6421855Sz.hong@f5.com     },
6431855Sz.hong@f5.com     {
6441859So.canty@f5.com         nxt_string("types"),
6451859So.canty@f5.com         NXT_CONF_MAP_PTR,
646*1903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, types)
6471859So.canty@f5.com     },
6481859So.canty@f5.com     {
6491378Svbart@nginx.com         nxt_string("fallback"),
6501378Svbart@nginx.com         NXT_CONF_MAP_PTR,
651*1903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, fallback)
6521378Svbart@nginx.com     },
6531264Sigor@sysoev.ru };
6541264Sigor@sysoev.ru 
6551264Sigor@sysoev.ru 
6561264Sigor@sysoev.ru static nxt_int_t
657*1903Sz.hong@f5.com nxt_http_action_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
6581859So.canty@f5.com     nxt_conf_value_t *cv, nxt_http_action_t *action)
6591264Sigor@sysoev.ru {
6601855Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
661*1903Sz.hong@f5.com     u_char                  *p;
662*1903Sz.hong@f5.com     uint8_t                 slash;
663*1903Sz.hong@f5.com     nxt_str_t               *chroot;
6641855Sz.hong@f5.com #endif
665*1903Sz.hong@f5.com     nxt_mp_t                *mp;
666*1903Sz.hong@f5.com     nxt_int_t               ret;
667*1903Sz.hong@f5.com     nxt_str_t               name, *string;
668*1903Sz.hong@f5.com     nxt_conf_value_t        *conf;
669*1903Sz.hong@f5.com     nxt_http_route_rule_t   *rule;
670*1903Sz.hong@f5.com     nxt_http_action_conf_t  acf;
671*1903Sz.hong@f5.com 
672*1903Sz.hong@f5.com     nxt_memzero(&acf, sizeof(acf));
6731264Sigor@sysoev.ru 
6741378Svbart@nginx.com     ret = nxt_conf_map_object(tmcf->mem_pool, cv, nxt_http_route_action_conf,
675*1903Sz.hong@f5.com                               nxt_nitems(nxt_http_route_action_conf), &acf);
6761264Sigor@sysoev.ru     if (ret != NXT_OK) {
6771264Sigor@sysoev.ru         return ret;
6781264Sigor@sysoev.ru     }
6791264Sigor@sysoev.ru 
6801428Svbart@nginx.com     nxt_memzero(action, sizeof(nxt_http_action_t));
6811428Svbart@nginx.com 
6821432Svbart@nginx.com     mp = tmcf->router_conf->mem_pool;
6831432Svbart@nginx.com 
684*1903Sz.hong@f5.com     if (acf.ret != NULL) {
685*1903Sz.hong@f5.com         return nxt_http_return_init(mp, action, &acf);
6861429Svbart@nginx.com     }
6871429Svbart@nginx.com 
688*1903Sz.hong@f5.com     if (acf.share != NULL) {
689*1903Sz.hong@f5.com         conf = acf.share;
690*1903Sz.hong@f5.com 
691*1903Sz.hong@f5.com     } else if (acf.proxy != NULL) {
692*1903Sz.hong@f5.com         conf = acf.proxy;
6931854Sz.hong@f5.com 
6941854Sz.hong@f5.com     } else {
695*1903Sz.hong@f5.com         conf = acf.pass;
6961264Sigor@sysoev.ru     }
6971264Sigor@sysoev.ru 
6981264Sigor@sysoev.ru     nxt_conf_get_string(conf, &name);
6991264Sigor@sysoev.ru 
7001378Svbart@nginx.com     string = nxt_str_dup(mp, &action->name, &name);
7011264Sigor@sysoev.ru     if (nxt_slow_path(string == NULL)) {
7021264Sigor@sysoev.ru         return NXT_ERROR;
7031264Sigor@sysoev.ru     }
7041264Sigor@sysoev.ru 
705*1903Sz.hong@f5.com     if (acf.share != NULL) {
7061854Sz.hong@f5.com         action->handler = nxt_http_static_handler;
7071854Sz.hong@f5.com 
7081855Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
709*1903Sz.hong@f5.com         string = &acf.chroot;
7101855Sz.hong@f5.com         chroot = &action->u.share.chroot;
7111855Sz.hong@f5.com 
7121855Sz.hong@f5.com         if (string->length > 0) {
7131855Sz.hong@f5.com             action->u.share.resolve |= RESOLVE_IN_ROOT;
7141855Sz.hong@f5.com 
7151855Sz.hong@f5.com             slash = (string->start[string->length - 1] != '/');
7161855Sz.hong@f5.com 
7171855Sz.hong@f5.com             chroot->length = string->length + (slash ? 1 : 0);
7181855Sz.hong@f5.com 
7191855Sz.hong@f5.com             chroot->start = nxt_mp_alloc(mp, chroot->length + 1);
7201855Sz.hong@f5.com             if (nxt_slow_path(chroot->start == NULL)) {
7211855Sz.hong@f5.com                 return NXT_ERROR;
7221855Sz.hong@f5.com             }
7231855Sz.hong@f5.com 
7241855Sz.hong@f5.com             p = nxt_cpymem(chroot->start, string->start, string->length);
7251855Sz.hong@f5.com 
7261855Sz.hong@f5.com             if (slash) {
7271855Sz.hong@f5.com                 *p++ = '/';
7281855Sz.hong@f5.com             }
7291855Sz.hong@f5.com 
7301855Sz.hong@f5.com             *p = '\0';
7311855Sz.hong@f5.com         }
7321855Sz.hong@f5.com 
733*1903Sz.hong@f5.com         if (acf.follow_symlinks != NULL
734*1903Sz.hong@f5.com             && !nxt_conf_get_boolean(acf.follow_symlinks))
7351855Sz.hong@f5.com         {
7361855Sz.hong@f5.com             action->u.share.resolve |= RESOLVE_NO_SYMLINKS;
7371855Sz.hong@f5.com         }
7381855Sz.hong@f5.com 
739*1903Sz.hong@f5.com         if (acf.traverse_mounts != NULL
740*1903Sz.hong@f5.com             && !nxt_conf_get_boolean(acf.traverse_mounts))
7411855Sz.hong@f5.com         {
7421855Sz.hong@f5.com             action->u.share.resolve |= RESOLVE_NO_XDEV;
7431855Sz.hong@f5.com         }
7441855Sz.hong@f5.com #endif
7451855Sz.hong@f5.com 
746*1903Sz.hong@f5.com         if (acf.types != NULL) {
747*1903Sz.hong@f5.com             rule = nxt_http_route_rule_create(task, mp, acf.types, 0,
7481859So.canty@f5.com                                               NXT_HTTP_ROUTE_PATTERN_LOWCASE,
7491859So.canty@f5.com                                               NXT_HTTP_ROUTE_ENCODING_NONE);
7501859So.canty@f5.com             if (nxt_slow_path(rule == NULL)) {
7511859So.canty@f5.com                 return NXT_ERROR;
7521859So.canty@f5.com             }
7531859So.canty@f5.com 
7541859So.canty@f5.com             action->u.share.types = rule;
7551859So.canty@f5.com         }
7561859So.canty@f5.com 
757*1903Sz.hong@f5.com         if (acf.fallback != NULL) {
7581854Sz.hong@f5.com             action->u.share.fallback = nxt_mp_alloc(mp,
7591854Sz.hong@f5.com                                                     sizeof(nxt_http_action_t));
7601854Sz.hong@f5.com             if (nxt_slow_path(action->u.share.fallback == NULL)) {
7611854Sz.hong@f5.com                 return NXT_ERROR;
7621854Sz.hong@f5.com             }
7631854Sz.hong@f5.com 
764*1903Sz.hong@f5.com             return nxt_http_action_init(task, tmcf, acf.fallback,
765*1903Sz.hong@f5.com                                         action->u.share.fallback);
7661378Svbart@nginx.com         }
7671378Svbart@nginx.com 
7681854Sz.hong@f5.com         return NXT_OK;
7691378Svbart@nginx.com     }
7701378Svbart@nginx.com 
771*1903Sz.hong@f5.com     if (acf.proxy != NULL) {
7721378Svbart@nginx.com         return nxt_http_proxy_create(mp, action);
7731270Sigor@sysoev.ru     }
7741270Sigor@sysoev.ru 
7751264Sigor@sysoev.ru     return NXT_OK;
7761264Sigor@sysoev.ru }
7771264Sigor@sysoev.ru 
7781264Sigor@sysoev.ru 
7791059Sigor@sysoev.ru static nxt_http_route_table_t *
7801059Sigor@sysoev.ru nxt_http_route_table_create(nxt_task_t *task, nxt_mp_t *mp,
7811061Sigor@sysoev.ru     nxt_conf_value_t *table_cv, nxt_http_route_object_t object,
7821474Saxel.duch@nginx.com     nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding)
7831059Sigor@sysoev.ru {
7841059Sigor@sysoev.ru     size_t                    size;
7851059Sigor@sysoev.ru     uint32_t                  i, n;
7861059Sigor@sysoev.ru     nxt_bool_t                array;
7871059Sigor@sysoev.ru     nxt_conf_value_t          *ruleset_cv;
7881059Sigor@sysoev.ru     nxt_http_route_table_t    *table;
7891059Sigor@sysoev.ru     nxt_http_route_ruleset_t  *ruleset;
7901059Sigor@sysoev.ru 
7911059Sigor@sysoev.ru     array = (nxt_conf_type(table_cv) == NXT_CONF_ARRAY);
7921059Sigor@sysoev.ru     n = array ? nxt_conf_array_elements_count(table_cv) : 1;
7931059Sigor@sysoev.ru     size = sizeof(nxt_http_route_table_t)
7941059Sigor@sysoev.ru            + n * sizeof(nxt_http_route_ruleset_t *);
7951059Sigor@sysoev.ru 
7961059Sigor@sysoev.ru     table = nxt_mp_alloc(mp, size);
7971059Sigor@sysoev.ru     if (nxt_slow_path(table == NULL)) {
7981059Sigor@sysoev.ru         return NULL;
7991059Sigor@sysoev.ru     }
8001059Sigor@sysoev.ru 
8011059Sigor@sysoev.ru     table->items = n;
8021059Sigor@sysoev.ru     table->object = NXT_HTTP_ROUTE_TABLE;
8031059Sigor@sysoev.ru 
8041059Sigor@sysoev.ru     if (!array) {
8051474Saxel.duch@nginx.com         ruleset = nxt_http_route_ruleset_create(task, mp, table_cv, object,
8061474Saxel.duch@nginx.com                                                 case_sensitive, encoding);
8071059Sigor@sysoev.ru         if (nxt_slow_path(ruleset == NULL)) {
8081059Sigor@sysoev.ru             return NULL;
8091059Sigor@sysoev.ru         }
8101059Sigor@sysoev.ru 
8111059Sigor@sysoev.ru         table->ruleset[0] = ruleset;
8121059Sigor@sysoev.ru 
8131059Sigor@sysoev.ru         return table;
8141059Sigor@sysoev.ru     }
8151059Sigor@sysoev.ru 
8161059Sigor@sysoev.ru     for (i = 0; i < n; i++) {
8171059Sigor@sysoev.ru         ruleset_cv = nxt_conf_get_array_element(table_cv, i);
8181059Sigor@sysoev.ru 
8191474Saxel.duch@nginx.com         ruleset = nxt_http_route_ruleset_create(task, mp, ruleset_cv, object,
8201474Saxel.duch@nginx.com                                                 case_sensitive, encoding);
8211059Sigor@sysoev.ru         if (nxt_slow_path(ruleset == NULL)) {
8221059Sigor@sysoev.ru             return NULL;
8231059Sigor@sysoev.ru         }
8241059Sigor@sysoev.ru 
8251059Sigor@sysoev.ru         table->ruleset[i] = ruleset;
8261059Sigor@sysoev.ru     }
8271059Sigor@sysoev.ru 
8281059Sigor@sysoev.ru     return table;
8291059Sigor@sysoev.ru }
8301059Sigor@sysoev.ru 
8311059Sigor@sysoev.ru 
8321059Sigor@sysoev.ru static nxt_http_route_ruleset_t *
8331059Sigor@sysoev.ru nxt_http_route_ruleset_create(nxt_task_t *task, nxt_mp_t *mp,
8341061Sigor@sysoev.ru     nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object,
8351474Saxel.duch@nginx.com     nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding)
8361059Sigor@sysoev.ru {
8371059Sigor@sysoev.ru     size_t                    size;
8381059Sigor@sysoev.ru     uint32_t                  i, n, next;
8391059Sigor@sysoev.ru     nxt_str_t                 name;
8401059Sigor@sysoev.ru     nxt_conf_value_t          *rule_cv;
8411059Sigor@sysoev.ru     nxt_http_route_rule_t     *rule;
8421059Sigor@sysoev.ru     nxt_http_route_ruleset_t  *ruleset;
8431059Sigor@sysoev.ru 
8441059Sigor@sysoev.ru     n = nxt_conf_object_members_count(ruleset_cv);
8451059Sigor@sysoev.ru     size = sizeof(nxt_http_route_ruleset_t)
8461059Sigor@sysoev.ru            + n * sizeof(nxt_http_route_rule_t *);
8471059Sigor@sysoev.ru 
8481059Sigor@sysoev.ru     ruleset = nxt_mp_alloc(mp, size);
8491059Sigor@sysoev.ru     if (nxt_slow_path(ruleset == NULL)) {
8501059Sigor@sysoev.ru         return NULL;
8511059Sigor@sysoev.ru     }
8521059Sigor@sysoev.ru 
8531059Sigor@sysoev.ru     ruleset->items = n;
8541059Sigor@sysoev.ru 
8551059Sigor@sysoev.ru     next = 0;
8561059Sigor@sysoev.ru 
8571785Svbart@nginx.com     /*
8581785Svbart@nginx.com      * A workaround for GCC 10 with -flto -O2 flags that warns about "name"
8591785Svbart@nginx.com      * may be uninitialized in nxt_http_route_rule_name_create().
8601785Svbart@nginx.com      */
8611785Svbart@nginx.com     nxt_str_null(&name);
8621785Svbart@nginx.com 
8631059Sigor@sysoev.ru     for (i = 0; i < n; i++) {
8641059Sigor@sysoev.ru         rule_cv = nxt_conf_next_object_member(ruleset_cv, &name, &next);
8651059Sigor@sysoev.ru 
8661061Sigor@sysoev.ru         rule = nxt_http_route_rule_name_create(task, mp, rule_cv, &name,
8671474Saxel.duch@nginx.com                                                case_sensitive, encoding);
8681059Sigor@sysoev.ru         if (nxt_slow_path(rule == NULL)) {
8691059Sigor@sysoev.ru             return NULL;
8701059Sigor@sysoev.ru         }
8711059Sigor@sysoev.ru 
8721061Sigor@sysoev.ru         rule->object = object;
8731059Sigor@sysoev.ru         ruleset->rule[i] = rule;
8741059Sigor@sysoev.ru     }
8751059Sigor@sysoev.ru 
8761059Sigor@sysoev.ru     return ruleset;
8771059Sigor@sysoev.ru }
8781059Sigor@sysoev.ru 
8791059Sigor@sysoev.ru 
880964Sigor@sysoev.ru static nxt_http_route_rule_t *
8811061Sigor@sysoev.ru nxt_http_route_rule_name_create(nxt_task_t *task, nxt_mp_t *mp,
8821474Saxel.duch@nginx.com     nxt_conf_value_t *rule_cv, nxt_str_t *name, nxt_bool_t case_sensitive,
8831474Saxel.duch@nginx.com     nxt_http_route_encoding_t encoding)
8841059Sigor@sysoev.ru {
8851474Saxel.duch@nginx.com     u_char                 c, *p, *src, *start, *end, plus;
8861474Saxel.duch@nginx.com     uint8_t                d0, d1;
8871059Sigor@sysoev.ru     uint32_t               hash;
8881059Sigor@sysoev.ru     nxt_uint_t             i;
8891059Sigor@sysoev.ru     nxt_http_route_rule_t  *rule;
8901059Sigor@sysoev.ru 
8911061Sigor@sysoev.ru     rule = nxt_http_route_rule_create(task, mp, rule_cv, case_sensitive,
8921474Saxel.duch@nginx.com                                       NXT_HTTP_ROUTE_PATTERN_NOCASE,
8931474Saxel.duch@nginx.com                                       encoding);
8941059Sigor@sysoev.ru     if (nxt_slow_path(rule == NULL)) {
8951059Sigor@sysoev.ru         return NULL;
8961059Sigor@sysoev.ru     }
8971059Sigor@sysoev.ru 
8981059Sigor@sysoev.ru     rule->u.name.length = name->length;
8991059Sigor@sysoev.ru 
9001059Sigor@sysoev.ru     p = nxt_mp_nget(mp, name->length);
9011059Sigor@sysoev.ru     if (nxt_slow_path(p == NULL)) {
9021059Sigor@sysoev.ru         return NULL;
9031059Sigor@sysoev.ru     }
9041059Sigor@sysoev.ru 
9051474Saxel.duch@nginx.com     hash = NXT_HTTP_FIELD_HASH_INIT;
9061059Sigor@sysoev.ru     rule->u.name.start = p;
9071059Sigor@sysoev.ru 
9081474Saxel.duch@nginx.com     if (encoding == NXT_HTTP_ROUTE_ENCODING_NONE) {
9091474Saxel.duch@nginx.com         for (i = 0; i < name->length; i++) {
9101474Saxel.duch@nginx.com             c = name->start[i];
9111474Saxel.duch@nginx.com             *p++ = c;
9121474Saxel.duch@nginx.com 
9131474Saxel.duch@nginx.com             c = case_sensitive ? c : nxt_lowcase(c);
9141474Saxel.duch@nginx.com             hash = nxt_http_field_hash_char(hash, c);
9151474Saxel.duch@nginx.com         }
9161474Saxel.duch@nginx.com 
9171474Saxel.duch@nginx.com         goto end;
9181474Saxel.duch@nginx.com     }
9191474Saxel.duch@nginx.com 
9201474Saxel.duch@nginx.com     plus = (encoding == NXT_HTTP_ROUTE_ENCODING_URI_PLUS) ? ' ' : '+';
9211474Saxel.duch@nginx.com 
9221474Saxel.duch@nginx.com     start = name->start;
9231474Saxel.duch@nginx.com     end = start + name->length;
9241474Saxel.duch@nginx.com 
9251474Saxel.duch@nginx.com     for (src = start; src < end; src++) {
9261474Saxel.duch@nginx.com         c = *src;
9271474Saxel.duch@nginx.com 
9281474Saxel.duch@nginx.com         switch (c) {
9291474Saxel.duch@nginx.com         case '%':
9301474Saxel.duch@nginx.com             if (nxt_slow_path(end - src <= 2)) {
9311474Saxel.duch@nginx.com                 return NULL;
9321474Saxel.duch@nginx.com             }
9331474Saxel.duch@nginx.com 
9341474Saxel.duch@nginx.com             d0 = nxt_hex2int[src[1]];
9351474Saxel.duch@nginx.com             d1 = nxt_hex2int[src[2]];
9361474Saxel.duch@nginx.com             src += 2;
9371474Saxel.duch@nginx.com 
9381474Saxel.duch@nginx.com             if (nxt_slow_path((d0 | d1) >= 16)) {
9391474Saxel.duch@nginx.com                 return NULL;
9401474Saxel.duch@nginx.com             }
9411474Saxel.duch@nginx.com 
9421474Saxel.duch@nginx.com             c = (d0 << 4) + d1;
9431474Saxel.duch@nginx.com             *p++ = c;
9441474Saxel.duch@nginx.com             break;
9451474Saxel.duch@nginx.com 
9461474Saxel.duch@nginx.com         case '+':
9471474Saxel.duch@nginx.com             c = plus;
9481474Saxel.duch@nginx.com             *p++ = c;
9491474Saxel.duch@nginx.com             break;
9501474Saxel.duch@nginx.com 
9511474Saxel.duch@nginx.com         default:
9521474Saxel.duch@nginx.com             *p++ = c;
9531474Saxel.duch@nginx.com             break;
9541474Saxel.duch@nginx.com         }
9551059Sigor@sysoev.ru 
9561079Sigor@sysoev.ru         c = case_sensitive ? c : nxt_lowcase(c);
9571059Sigor@sysoev.ru         hash = nxt_http_field_hash_char(hash, c);
9581059Sigor@sysoev.ru     }
9591059Sigor@sysoev.ru 
9601474Saxel.duch@nginx.com     rule->u.name.length = p - rule->u.name.start;
9611474Saxel.duch@nginx.com 
9621474Saxel.duch@nginx.com end:
9631474Saxel.duch@nginx.com 
9641059Sigor@sysoev.ru     rule->u.name.hash = nxt_http_field_hash_end(hash) & 0xFFFF;
9651059Sigor@sysoev.ru 
9661059Sigor@sysoev.ru     return rule;
9671059Sigor@sysoev.ru }
9681059Sigor@sysoev.ru 
9691059Sigor@sysoev.ru 
9701059Sigor@sysoev.ru static nxt_http_route_rule_t *
9711059Sigor@sysoev.ru nxt_http_route_rule_create(nxt_task_t *task, nxt_mp_t *mp,
972964Sigor@sysoev.ru     nxt_conf_value_t *cv, nxt_bool_t case_sensitive,
9731474Saxel.duch@nginx.com     nxt_http_route_pattern_case_t pattern_case,
9741474Saxel.duch@nginx.com     nxt_http_route_encoding_t encoding)
975964Sigor@sysoev.ru {
976964Sigor@sysoev.ru     size_t                    size;
977964Sigor@sysoev.ru     uint32_t                  i, n;
978964Sigor@sysoev.ru     nxt_int_t                 ret;
979964Sigor@sysoev.ru     nxt_bool_t                string;
980964Sigor@sysoev.ru     nxt_conf_value_t          *value;
981964Sigor@sysoev.ru     nxt_http_route_rule_t     *rule;
982964Sigor@sysoev.ru     nxt_http_route_pattern_t  *pattern;
983964Sigor@sysoev.ru 
984964Sigor@sysoev.ru     string = (nxt_conf_type(cv) != NXT_CONF_ARRAY);
985964Sigor@sysoev.ru     n = string ? 1 : nxt_conf_array_elements_count(cv);
986964Sigor@sysoev.ru     size = sizeof(nxt_http_route_rule_t) + n * sizeof(nxt_http_route_pattern_t);
987964Sigor@sysoev.ru 
988964Sigor@sysoev.ru     rule = nxt_mp_alloc(mp, size);
989964Sigor@sysoev.ru     if (nxt_slow_path(rule == NULL)) {
990964Sigor@sysoev.ru         return NULL;
991964Sigor@sysoev.ru     }
992964Sigor@sysoev.ru 
993964Sigor@sysoev.ru     rule->items = n;
994964Sigor@sysoev.ru 
995964Sigor@sysoev.ru     pattern = &rule->pattern[0];
996964Sigor@sysoev.ru 
997964Sigor@sysoev.ru     if (string) {
998964Sigor@sysoev.ru         pattern[0].case_sensitive = case_sensitive;
999964Sigor@sysoev.ru         ret = nxt_http_route_pattern_create(task, mp, cv, &pattern[0],
10001474Saxel.duch@nginx.com                                             pattern_case, encoding);
1001964Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
1002964Sigor@sysoev.ru             return NULL;
1003964Sigor@sysoev.ru         }
1004964Sigor@sysoev.ru 
1005964Sigor@sysoev.ru         return rule;
1006964Sigor@sysoev.ru     }
1007964Sigor@sysoev.ru 
1008964Sigor@sysoev.ru     nxt_conf_array_qsort(cv, nxt_http_pattern_compare);
1009964Sigor@sysoev.ru 
1010964Sigor@sysoev.ru     for (i = 0; i < n; i++) {
1011964Sigor@sysoev.ru         pattern[i].case_sensitive = case_sensitive;
1012964Sigor@sysoev.ru         value = nxt_conf_get_array_element(cv, i);
1013964Sigor@sysoev.ru 
1014964Sigor@sysoev.ru         ret = nxt_http_route_pattern_create(task, mp, value, &pattern[i],
10151474Saxel.duch@nginx.com                                             pattern_case, encoding);
1016964Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
1017964Sigor@sysoev.ru             return NULL;
1018964Sigor@sysoev.ru         }
1019964Sigor@sysoev.ru     }
1020964Sigor@sysoev.ru 
1021964Sigor@sysoev.ru     return rule;
1022964Sigor@sysoev.ru }
1023964Sigor@sysoev.ru 
1024964Sigor@sysoev.ru 
10251324Saxel.duch@nginx.com static nxt_http_route_addr_rule_t *
10261324Saxel.duch@nginx.com nxt_http_route_addr_rule_create(nxt_task_t *task, nxt_mp_t *mp,
10271324Saxel.duch@nginx.com      nxt_conf_value_t *cv)
10281324Saxel.duch@nginx.com {
10291324Saxel.duch@nginx.com     size_t                         size;
10301324Saxel.duch@nginx.com     uint32_t                       i, n;
10311324Saxel.duch@nginx.com     nxt_bool_t                     array;
10321324Saxel.duch@nginx.com     nxt_conf_value_t               *value;
10331324Saxel.duch@nginx.com     nxt_http_route_addr_rule_t     *addr_rule;
10341324Saxel.duch@nginx.com     nxt_http_route_addr_pattern_t  *pattern;
10351324Saxel.duch@nginx.com 
10361324Saxel.duch@nginx.com     array = (nxt_conf_type(cv) == NXT_CONF_ARRAY);
10371324Saxel.duch@nginx.com     n = array ? nxt_conf_array_elements_count(cv) : 1;
10381324Saxel.duch@nginx.com 
10391324Saxel.duch@nginx.com     size = sizeof(nxt_http_route_addr_rule_t)
10401324Saxel.duch@nginx.com            + n * sizeof(nxt_http_route_addr_pattern_t);
10411324Saxel.duch@nginx.com 
10421324Saxel.duch@nginx.com     addr_rule = nxt_mp_alloc(mp, size);
10431324Saxel.duch@nginx.com     if (nxt_slow_path(addr_rule == NULL)) {
10441324Saxel.duch@nginx.com         return NULL;
10451324Saxel.duch@nginx.com     }
10461324Saxel.duch@nginx.com 
10471324Saxel.duch@nginx.com     addr_rule->items = n;
10481324Saxel.duch@nginx.com 
10491324Saxel.duch@nginx.com     if (!array) {
10501324Saxel.duch@nginx.com         pattern = &addr_rule->addr_pattern[0];
10511324Saxel.duch@nginx.com 
10521324Saxel.duch@nginx.com         if (nxt_http_route_addr_pattern_parse(mp, pattern, cv) != NXT_OK) {
10531324Saxel.duch@nginx.com             return NULL;
10541324Saxel.duch@nginx.com         }
10551324Saxel.duch@nginx.com 
10561324Saxel.duch@nginx.com         return addr_rule;
10571324Saxel.duch@nginx.com     }
10581324Saxel.duch@nginx.com 
10591324Saxel.duch@nginx.com     for (i = 0; i < n; i++) {
10601324Saxel.duch@nginx.com         pattern = &addr_rule->addr_pattern[i];
10611324Saxel.duch@nginx.com         value = nxt_conf_get_array_element(cv, i);
10621324Saxel.duch@nginx.com 
10631324Saxel.duch@nginx.com         if (nxt_http_route_addr_pattern_parse(mp, pattern, value) != NXT_OK) {
10641324Saxel.duch@nginx.com             return NULL;
10651324Saxel.duch@nginx.com         }
10661324Saxel.duch@nginx.com     }
10671324Saxel.duch@nginx.com 
10681390Saxel.duch@nginx.com     if (n > 1) {
10691390Saxel.duch@nginx.com         nxt_qsort(addr_rule->addr_pattern, addr_rule->items,
10701390Saxel.duch@nginx.com             sizeof(nxt_http_route_addr_pattern_t),
10711390Saxel.duch@nginx.com             nxt_http_addr_pattern_compare);
10721390Saxel.duch@nginx.com     }
10731390Saxel.duch@nginx.com 
10741324Saxel.duch@nginx.com     return addr_rule;
10751324Saxel.duch@nginx.com }
10761324Saxel.duch@nginx.com 
10771324Saxel.duch@nginx.com 
1078964Sigor@sysoev.ru static int
1079964Sigor@sysoev.ru nxt_http_pattern_compare(const void *one, const void *two)
1080964Sigor@sysoev.ru {
1081964Sigor@sysoev.ru     nxt_str_t         test;
1082964Sigor@sysoev.ru     nxt_bool_t        negative1, negative2;
1083964Sigor@sysoev.ru     nxt_conf_value_t  *value;
1084964Sigor@sysoev.ru 
1085964Sigor@sysoev.ru     value = (nxt_conf_value_t *) one;
1086964Sigor@sysoev.ru     nxt_conf_get_string(value, &test);
1087964Sigor@sysoev.ru     negative1 = (test.length != 0 && test.start[0] == '!');
1088964Sigor@sysoev.ru 
1089964Sigor@sysoev.ru     value = (nxt_conf_value_t *) two;
1090964Sigor@sysoev.ru     nxt_conf_get_string(value, &test);
1091964Sigor@sysoev.ru     negative2 = (test.length != 0 && test.start[0] == '!');
1092964Sigor@sysoev.ru 
1093964Sigor@sysoev.ru     return (negative2 - negative1);
1094964Sigor@sysoev.ru }
1095964Sigor@sysoev.ru 
1096964Sigor@sysoev.ru 
10971390Saxel.duch@nginx.com static int
10981390Saxel.duch@nginx.com nxt_http_addr_pattern_compare(const void *one, const void *two)
10991390Saxel.duch@nginx.com {
11001390Saxel.duch@nginx.com     const nxt_http_route_addr_pattern_t  *p1, *p2;
11011390Saxel.duch@nginx.com 
11021390Saxel.duch@nginx.com     p1 = one;
11031390Saxel.duch@nginx.com     p2 = two;
11041390Saxel.duch@nginx.com 
11051390Saxel.duch@nginx.com     return (p2->base.negative - p1->base.negative);
11061390Saxel.duch@nginx.com }
11071390Saxel.duch@nginx.com 
11081390Saxel.duch@nginx.com 
1109964Sigor@sysoev.ru static nxt_int_t
1110964Sigor@sysoev.ru nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp,
1111964Sigor@sysoev.ru     nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern,
11121474Saxel.duch@nginx.com     nxt_http_route_pattern_case_t pattern_case,
11131474Saxel.duch@nginx.com     nxt_http_route_encoding_t encoding)
1114964Sigor@sysoev.ru {
11151508Saxel.duch@nginx.com     u_char                          c, *p, *end;
11161508Saxel.duch@nginx.com     nxt_str_t                       test, tmp;
11171508Saxel.duch@nginx.com     nxt_int_t                       ret;
11181508Saxel.duch@nginx.com     nxt_array_t                     *slices;
11191721Saxel.duch@nginx.com #if (NXT_HAVE_REGEX)
11201721Saxel.duch@nginx.com     nxt_regex_t                     *re;
11211721Saxel.duch@nginx.com     nxt_regex_err_t                 err;
11221721Saxel.duch@nginx.com #endif
11231508Saxel.duch@nginx.com     nxt_http_route_pattern_type_t   type;
11241508Saxel.duch@nginx.com     nxt_http_route_pattern_slice_t  *slice;
1125964Sigor@sysoev.ru 
1126964Sigor@sysoev.ru     type = NXT_HTTP_ROUTE_PATTERN_EXACT;
1127964Sigor@sysoev.ru 
1128964Sigor@sysoev.ru     nxt_conf_get_string(cv, &test);
1129964Sigor@sysoev.ru 
11301721Saxel.duch@nginx.com     pattern->u.pattern_slices = NULL;
1131964Sigor@sysoev.ru     pattern->negative = 0;
1132964Sigor@sysoev.ru     pattern->any = 1;
11331474Saxel.duch@nginx.com     pattern->min_length = 0;
11341721Saxel.duch@nginx.com #if (NXT_HAVE_REGEX)
11351721Saxel.duch@nginx.com     pattern->regex = 0;
11361721Saxel.duch@nginx.com #endif
1137964Sigor@sysoev.ru 
11381508Saxel.duch@nginx.com     if (test.length != 0 && test.start[0] == '!') {
11391508Saxel.duch@nginx.com         test.start++;
11401508Saxel.duch@nginx.com         test.length--;
11411508Saxel.duch@nginx.com 
11421508Saxel.duch@nginx.com         pattern->negative = 1;
11431508Saxel.duch@nginx.com         pattern->any = 0;
11441508Saxel.duch@nginx.com     }
11451508Saxel.duch@nginx.com 
11461721Saxel.duch@nginx.com     if (test.length > 0 && test.start[0] == '~') {
11471721Saxel.duch@nginx.com #if (NXT_HAVE_REGEX)
11481721Saxel.duch@nginx.com         test.start++;
11491721Saxel.duch@nginx.com         test.length--;
11501721Saxel.duch@nginx.com 
11511721Saxel.duch@nginx.com         re = nxt_regex_compile(mp, &test, &err);
11521721Saxel.duch@nginx.com         if (nxt_slow_path(re == NULL)) {
11531721Saxel.duch@nginx.com             if (err.offset < test.length) {
11541721Saxel.duch@nginx.com                 nxt_alert(task, "nxt_regex_compile(%V) failed: %s at offset %d",
11551721Saxel.duch@nginx.com                           &test, err.msg, (int) err.offset);
11561721Saxel.duch@nginx.com                 return NXT_ERROR;
11571721Saxel.duch@nginx.com             }
11581721Saxel.duch@nginx.com 
11591721Saxel.duch@nginx.com             nxt_alert(task, "nxt_regex_compile(%V) failed %s", &test, err.msg);
11601721Saxel.duch@nginx.com 
11611721Saxel.duch@nginx.com             return NXT_ERROR;
11621721Saxel.duch@nginx.com         }
11631721Saxel.duch@nginx.com 
11641721Saxel.duch@nginx.com         pattern->u.regex = re;
11651721Saxel.duch@nginx.com         pattern->regex = 1;
11661721Saxel.duch@nginx.com 
11671721Saxel.duch@nginx.com         return NXT_OK;
11681721Saxel.duch@nginx.com 
11691721Saxel.duch@nginx.com #else
11701721Saxel.duch@nginx.com         return NXT_ERROR;
11711721Saxel.duch@nginx.com #endif
11721721Saxel.duch@nginx.com     }
11731721Saxel.duch@nginx.com 
11741721Saxel.duch@nginx.com     slices = nxt_array_create(mp, 1, sizeof(nxt_http_route_pattern_slice_t));
11751721Saxel.duch@nginx.com     if (nxt_slow_path(slices == NULL)) {
11761721Saxel.duch@nginx.com         return NXT_ERROR;
11771721Saxel.duch@nginx.com     }
11781721Saxel.duch@nginx.com 
11791721Saxel.duch@nginx.com     pattern->u.pattern_slices = slices;
11801721Saxel.duch@nginx.com 
11811508Saxel.duch@nginx.com     if (test.length == 0) {
11821508Saxel.duch@nginx.com         slice = nxt_array_add(slices);
11831508Saxel.duch@nginx.com         if (nxt_slow_path(slice == NULL)) {
11841508Saxel.duch@nginx.com             return NXT_ERROR;
1185964Sigor@sysoev.ru         }
1186964Sigor@sysoev.ru 
11871508Saxel.duch@nginx.com         slice->type = NXT_HTTP_ROUTE_PATTERN_EXACT;
11881508Saxel.duch@nginx.com         slice->start = NULL;
11891508Saxel.duch@nginx.com         slice->length = 0;
11901508Saxel.duch@nginx.com 
11911508Saxel.duch@nginx.com         return NXT_OK;
11921508Saxel.duch@nginx.com     }
11931508Saxel.duch@nginx.com 
11941508Saxel.duch@nginx.com     if (test.start[0] == '*') {
11951508Saxel.duch@nginx.com         /* 'type' is no longer 'EXACT', assume 'END'. */
11961508Saxel.duch@nginx.com         type = NXT_HTTP_ROUTE_PATTERN_END;
11971508Saxel.duch@nginx.com         test.start++;
11981508Saxel.duch@nginx.com         test.length--;
11991508Saxel.duch@nginx.com     }
12001508Saxel.duch@nginx.com 
12011522Saxel.duch@nginx.com     if (type == NXT_HTTP_ROUTE_PATTERN_EXACT) {
12021508Saxel.duch@nginx.com         tmp.start = test.start;
12031508Saxel.duch@nginx.com 
12041508Saxel.duch@nginx.com         p = nxt_memchr(test.start, '*', test.length);
12051508Saxel.duch@nginx.com 
12061508Saxel.duch@nginx.com         if (p == NULL) {
12071508Saxel.duch@nginx.com             /* No '*' found - EXACT pattern. */
12081508Saxel.duch@nginx.com             tmp.length = test.length;
12091508Saxel.duch@nginx.com             type = NXT_HTTP_ROUTE_PATTERN_EXACT;
12101508Saxel.duch@nginx.com 
12111508Saxel.duch@nginx.com             test.start += test.length;
12121508Saxel.duch@nginx.com             test.length = 0;
12131508Saxel.duch@nginx.com 
12141508Saxel.duch@nginx.com         } else {
12151508Saxel.duch@nginx.com             /* '*' found - BEGIN pattern. */
12161508Saxel.duch@nginx.com             tmp.length = p - test.start;
12171508Saxel.duch@nginx.com             type = NXT_HTTP_ROUTE_PATTERN_BEGIN;
12181508Saxel.duch@nginx.com 
12191508Saxel.duch@nginx.com             test.start = p + 1;
12201508Saxel.duch@nginx.com             test.length -= tmp.length + 1;
12211508Saxel.duch@nginx.com         }
12221508Saxel.duch@nginx.com 
12231508Saxel.duch@nginx.com         ret = nxt_http_route_pattern_slice(slices, &tmp, type, encoding,
12241508Saxel.duch@nginx.com                                            pattern_case);
12251508Saxel.duch@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
12261508Saxel.duch@nginx.com             return ret;
12271508Saxel.duch@nginx.com         }
12281508Saxel.duch@nginx.com 
12291508Saxel.duch@nginx.com         pattern->min_length += tmp.length;
12301508Saxel.duch@nginx.com     }
12311508Saxel.duch@nginx.com 
12321508Saxel.duch@nginx.com     end = test.start + test.length;
12331508Saxel.duch@nginx.com 
12341508Saxel.duch@nginx.com     if (test.length != 0 && end[-1] != '*') {
12351508Saxel.duch@nginx.com         p = end - 1;
12361508Saxel.duch@nginx.com 
12371508Saxel.duch@nginx.com         while (p != test.start) {
12381508Saxel.duch@nginx.com             c = *p--;
12391508Saxel.duch@nginx.com 
12401508Saxel.duch@nginx.com             if (c == '*') {
12411508Saxel.duch@nginx.com                 p += 2;
12421508Saxel.duch@nginx.com                 break;
12431474Saxel.duch@nginx.com             }
1244964Sigor@sysoev.ru         }
12451508Saxel.duch@nginx.com 
12461508Saxel.duch@nginx.com         tmp.start = p;
12471508Saxel.duch@nginx.com         tmp.length = end - p;
12481508Saxel.duch@nginx.com 
12491508Saxel.duch@nginx.com         test.length -= tmp.length;
12501508Saxel.duch@nginx.com         end = p;
12511508Saxel.duch@nginx.com 
12521508Saxel.duch@nginx.com         ret = nxt_http_route_pattern_slice(slices, &tmp,
12531508Saxel.duch@nginx.com                                            NXT_HTTP_ROUTE_PATTERN_END,
12541508Saxel.duch@nginx.com                                            encoding, pattern_case);
12551508Saxel.duch@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
12561508Saxel.duch@nginx.com             return ret;
12571508Saxel.duch@nginx.com         }
12581508Saxel.duch@nginx.com 
12591508Saxel.duch@nginx.com         pattern->min_length += tmp.length;
1260964Sigor@sysoev.ru     }
1261964Sigor@sysoev.ru 
12621508Saxel.duch@nginx.com     tmp.start = test.start;
12631508Saxel.duch@nginx.com     tmp.length = 0;
12641508Saxel.duch@nginx.com 
12651508Saxel.duch@nginx.com     p = tmp.start;
12661508Saxel.duch@nginx.com 
12671508Saxel.duch@nginx.com     while (p != end) {
12681508Saxel.duch@nginx.com         c = *p++;
12691508Saxel.duch@nginx.com 
12701508Saxel.duch@nginx.com         if (c != '*') {
12711508Saxel.duch@nginx.com             tmp.length++;
12721508Saxel.duch@nginx.com             continue;
12731508Saxel.duch@nginx.com         }
12741508Saxel.duch@nginx.com 
12751508Saxel.duch@nginx.com         if (tmp.length == 0) {
12761508Saxel.duch@nginx.com             tmp.start = p;
12771508Saxel.duch@nginx.com             continue;
12781508Saxel.duch@nginx.com         }
12791508Saxel.duch@nginx.com 
12801508Saxel.duch@nginx.com         ret = nxt_http_route_pattern_slice(slices, &tmp,
12811508Saxel.duch@nginx.com                                            NXT_HTTP_ROUTE_PATTERN_SUBSTRING,
12821508Saxel.duch@nginx.com                                            encoding, pattern_case);
12831508Saxel.duch@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
12841508Saxel.duch@nginx.com             return ret;
12851508Saxel.duch@nginx.com         }
12861508Saxel.duch@nginx.com 
12871508Saxel.duch@nginx.com         pattern->min_length += tmp.length;
12881508Saxel.duch@nginx.com 
12891508Saxel.duch@nginx.com         tmp.start = p;
12901508Saxel.duch@nginx.com         tmp.length = 0;
1291964Sigor@sysoev.ru     }
1292964Sigor@sysoev.ru 
12931508Saxel.duch@nginx.com     if (tmp.length != 0) {
12941508Saxel.duch@nginx.com         ret = nxt_http_route_pattern_slice(slices, &tmp,
12951508Saxel.duch@nginx.com                                            NXT_HTTP_ROUTE_PATTERN_SUBSTRING,
12961508Saxel.duch@nginx.com                                            encoding, pattern_case);
12971508Saxel.duch@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
12981508Saxel.duch@nginx.com             return ret;
12991508Saxel.duch@nginx.com         }
13001508Saxel.duch@nginx.com 
13011508Saxel.duch@nginx.com         pattern->min_length += tmp.length;
13021508Saxel.duch@nginx.com     }
13031032Sigor@sysoev.ru 
13041474Saxel.duch@nginx.com     return NXT_OK;
13051474Saxel.duch@nginx.com }
13061474Saxel.duch@nginx.com 
13071474Saxel.duch@nginx.com 
13081474Saxel.duch@nginx.com static nxt_int_t
13091474Saxel.duch@nginx.com nxt_http_route_decode_str(nxt_str_t *str, nxt_http_route_encoding_t encoding)
13101474Saxel.duch@nginx.com {
13111474Saxel.duch@nginx.com     u_char  *start, *end;
13121474Saxel.duch@nginx.com 
13131474Saxel.duch@nginx.com     switch (encoding) {
13141474Saxel.duch@nginx.com     case NXT_HTTP_ROUTE_ENCODING_NONE:
13151474Saxel.duch@nginx.com         break;
13161474Saxel.duch@nginx.com 
13171474Saxel.duch@nginx.com     case NXT_HTTP_ROUTE_ENCODING_URI:
13181474Saxel.duch@nginx.com         start = str->start;
13191474Saxel.duch@nginx.com 
13201474Saxel.duch@nginx.com         end = nxt_decode_uri(start, start, str->length);
13211474Saxel.duch@nginx.com         if (nxt_slow_path(end == NULL)) {
13221032Sigor@sysoev.ru             return NXT_ERROR;
13231032Sigor@sysoev.ru         }
13241032Sigor@sysoev.ru 
13251474Saxel.duch@nginx.com         str->length = end - start;
13261474Saxel.duch@nginx.com         break;
13271474Saxel.duch@nginx.com 
13281474Saxel.duch@nginx.com     case NXT_HTTP_ROUTE_ENCODING_URI_PLUS:
13291474Saxel.duch@nginx.com         start = str->start;
13301474Saxel.duch@nginx.com 
13311474Saxel.duch@nginx.com         end = nxt_decode_uri_plus(start, start, str->length);
13321474Saxel.duch@nginx.com         if (nxt_slow_path(end == NULL)) {
13331474Saxel.duch@nginx.com             return NXT_ERROR;
13341474Saxel.duch@nginx.com         }
13351474Saxel.duch@nginx.com 
13361474Saxel.duch@nginx.com         str->length = end - start;
13371474Saxel.duch@nginx.com         break;
13381474Saxel.duch@nginx.com 
13391474Saxel.duch@nginx.com     default:
13401474Saxel.duch@nginx.com         nxt_unreachable();
13411032Sigor@sysoev.ru     }
13421032Sigor@sysoev.ru 
13431032Sigor@sysoev.ru     return NXT_OK;
13441032Sigor@sysoev.ru }
13451032Sigor@sysoev.ru 
13461032Sigor@sysoev.ru 
13471508Saxel.duch@nginx.com static nxt_int_t
13481508Saxel.duch@nginx.com nxt_http_route_pattern_slice(nxt_array_t *slices,
13491508Saxel.duch@nginx.com     nxt_str_t *test,
13501508Saxel.duch@nginx.com     nxt_http_route_pattern_type_t type,
13511508Saxel.duch@nginx.com     nxt_http_route_encoding_t encoding,
13521032Sigor@sysoev.ru     nxt_http_route_pattern_case_t pattern_case)
13531032Sigor@sysoev.ru {
13541508Saxel.duch@nginx.com     u_char                          *start;
13551508Saxel.duch@nginx.com     nxt_int_t                       ret;
13561508Saxel.duch@nginx.com     nxt_http_route_pattern_slice_t  *slice;
13571508Saxel.duch@nginx.com 
13581508Saxel.duch@nginx.com     ret = nxt_http_route_decode_str(test, encoding);
13591508Saxel.duch@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
13601508Saxel.duch@nginx.com         return ret;
13611508Saxel.duch@nginx.com     }
13621508Saxel.duch@nginx.com 
13631508Saxel.duch@nginx.com     start = nxt_mp_nget(slices->mem_pool, test->length);
13641032Sigor@sysoev.ru     if (nxt_slow_path(start == NULL)) {
13651508Saxel.duch@nginx.com         return NXT_ERROR;
13661032Sigor@sysoev.ru     }
1367964Sigor@sysoev.ru 
1368964Sigor@sysoev.ru     switch (pattern_case) {
1369964Sigor@sysoev.ru 
1370964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_UPCASE:
13711032Sigor@sysoev.ru         nxt_memcpy_upcase(start, test->start, test->length);
1372964Sigor@sysoev.ru         break;
1373964Sigor@sysoev.ru 
1374964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_LOWCASE:
13751032Sigor@sysoev.ru         nxt_memcpy_lowcase(start, test->start, test->length);
1376964Sigor@sysoev.ru         break;
1377964Sigor@sysoev.ru 
1378964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_NOCASE:
13791032Sigor@sysoev.ru         nxt_memcpy(start, test->start, test->length);
1380964Sigor@sysoev.ru         break;
1381964Sigor@sysoev.ru     }
1382964Sigor@sysoev.ru 
13831508Saxel.duch@nginx.com     slice = nxt_array_add(slices);
13841564Svbart@nginx.com     if (nxt_slow_path(slice == NULL)) {
13851508Saxel.duch@nginx.com         return NXT_ERROR;
13861508Saxel.duch@nginx.com     }
13871508Saxel.duch@nginx.com 
13881508Saxel.duch@nginx.com     slice->type = type;
13891508Saxel.duch@nginx.com     slice->start = start;
13901508Saxel.duch@nginx.com     slice->length = test->length;
13911508Saxel.duch@nginx.com 
13921508Saxel.duch@nginx.com     return NXT_OK;
1393964Sigor@sysoev.ru }
1394964Sigor@sysoev.ru 
1395964Sigor@sysoev.ru 
13961472Svbart@nginx.com nxt_int_t
1397964Sigor@sysoev.ru nxt_http_routes_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
1398964Sigor@sysoev.ru {
13991472Svbart@nginx.com     nxt_int_t          ret;
14001033Svbart@nginx.com     nxt_http_route_t   **route, **end;
1401964Sigor@sysoev.ru     nxt_http_routes_t  *routes;
1402964Sigor@sysoev.ru 
1403964Sigor@sysoev.ru     routes = tmcf->router_conf->routes;
14041059Sigor@sysoev.ru 
1405964Sigor@sysoev.ru     if (routes != NULL) {
1406964Sigor@sysoev.ru         route = &routes->route[0];
14071033Svbart@nginx.com         end = route + routes->items;
1408964Sigor@sysoev.ru 
14091033Svbart@nginx.com         while (route < end) {
14101472Svbart@nginx.com             ret = nxt_http_route_resolve(task, tmcf, *route);
14111472Svbart@nginx.com             if (nxt_slow_path(ret != NXT_OK)) {
14121472Svbart@nginx.com                 return NXT_ERROR;
14131472Svbart@nginx.com             }
1414964Sigor@sysoev.ru 
1415964Sigor@sysoev.ru             route++;
1416964Sigor@sysoev.ru         }
1417964Sigor@sysoev.ru     }
14181472Svbart@nginx.com 
14191472Svbart@nginx.com     return NXT_OK;
1420964Sigor@sysoev.ru }
1421964Sigor@sysoev.ru 
1422964Sigor@sysoev.ru 
14231472Svbart@nginx.com static nxt_int_t
1424964Sigor@sysoev.ru nxt_http_route_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1425964Sigor@sysoev.ru     nxt_http_route_t *route)
1426964Sigor@sysoev.ru {
14271472Svbart@nginx.com     nxt_int_t               ret;
14281033Svbart@nginx.com     nxt_http_route_match_t  **match, **end;
1429964Sigor@sysoev.ru 
1430964Sigor@sysoev.ru     match = &route->match[0];
14311033Svbart@nginx.com     end = match + route->items;
1432964Sigor@sysoev.ru 
14331033Svbart@nginx.com     while (match < end) {
14341472Svbart@nginx.com         ret = nxt_http_action_resolve(task, tmcf, &(*match)->action);
14351472Svbart@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
14361472Svbart@nginx.com             return NXT_ERROR;
14371472Svbart@nginx.com         }
1438964Sigor@sysoev.ru 
1439964Sigor@sysoev.ru         match++;
1440964Sigor@sysoev.ru     }
14411472Svbart@nginx.com 
14421472Svbart@nginx.com     return NXT_OK;
1443964Sigor@sysoev.ru }
1444964Sigor@sysoev.ru 
1445964Sigor@sysoev.ru 
14461472Svbart@nginx.com static nxt_int_t
14471264Sigor@sysoev.ru nxt_http_action_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
14481264Sigor@sysoev.ru     nxt_http_action_t *action)
1449964Sigor@sysoev.ru {
14501563Svbart@nginx.com     nxt_var_t  *var;
14511563Svbart@nginx.com     nxt_int_t  ret;
1452964Sigor@sysoev.ru 
14531378Svbart@nginx.com     if (action->handler != NULL) {
14541378Svbart@nginx.com         if (action->handler == nxt_http_static_handler
14551854Sz.hong@f5.com             && action->u.share.fallback != NULL)
14561378Svbart@nginx.com         {
14571854Sz.hong@f5.com             return nxt_http_action_resolve(task, tmcf,
14581854Sz.hong@f5.com                                            action->u.share.fallback);
14591378Svbart@nginx.com         }
14601378Svbart@nginx.com 
14611472Svbart@nginx.com         return NXT_OK;
14621378Svbart@nginx.com     }
14631378Svbart@nginx.com 
14641563Svbart@nginx.com     if (nxt_is_var(&action->name)) {
14651563Svbart@nginx.com         var = nxt_var_compile(&action->name, tmcf->router_conf->mem_pool);
14661563Svbart@nginx.com         if (nxt_slow_path(var == NULL)) {
14671563Svbart@nginx.com             return NXT_ERROR;
14681563Svbart@nginx.com         }
14691563Svbart@nginx.com 
14701563Svbart@nginx.com         action->u.var = var;
14711563Svbart@nginx.com         action->handler = nxt_http_action_pass_var;
14721563Svbart@nginx.com         return NXT_OK;
14731563Svbart@nginx.com     }
14741563Svbart@nginx.com 
14751563Svbart@nginx.com     ret = nxt_http_pass_find(task, tmcf->mem_pool, tmcf->router_conf, action);
14761472Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
14771472Svbart@nginx.com         return NXT_ERROR;
14781472Svbart@nginx.com     }
14791472Svbart@nginx.com 
14801563Svbart@nginx.com     return NXT_OK;
14811563Svbart@nginx.com }
14821563Svbart@nginx.com 
14831563Svbart@nginx.com 
14841563Svbart@nginx.com static nxt_http_action_t *
14851563Svbart@nginx.com nxt_http_action_pass_var(nxt_task_t *task, nxt_http_request_t *r,
14861563Svbart@nginx.com     nxt_http_action_t *action)
14871563Svbart@nginx.com {
14881563Svbart@nginx.com     nxt_var_t  *var;
14891563Svbart@nginx.com     nxt_int_t  ret;
14901563Svbart@nginx.com 
14911563Svbart@nginx.com     ret = nxt_var_query_init(&r->var_query, r, r->mem_pool);
14921563Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
14931563Svbart@nginx.com         goto fail;
14941563Svbart@nginx.com     }
14951563Svbart@nginx.com 
14961563Svbart@nginx.com     var = action->u.var;
14971563Svbart@nginx.com 
14981563Svbart@nginx.com     action = nxt_mp_get(r->mem_pool, sizeof(nxt_http_action_t));
14991563Svbart@nginx.com     if (nxt_slow_path(action == NULL)) {
15001563Svbart@nginx.com         goto fail;
15011563Svbart@nginx.com     }
15021563Svbart@nginx.com 
15031563Svbart@nginx.com     nxt_var_query(task, r->var_query, var, &action->name);
15041563Svbart@nginx.com     nxt_var_query_resolve(task, r->var_query, action,
15051563Svbart@nginx.com                           nxt_http_action_pass_var_ready,
15061563Svbart@nginx.com                           nxt_http_action_pass_var_error);
15071563Svbart@nginx.com     return NULL;
15081563Svbart@nginx.com 
15091563Svbart@nginx.com fail:
15101563Svbart@nginx.com 
15111563Svbart@nginx.com     nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
15121563Svbart@nginx.com     return NULL;
15131563Svbart@nginx.com }
15141563Svbart@nginx.com 
15151563Svbart@nginx.com 
15161563Svbart@nginx.com static void
15171563Svbart@nginx.com nxt_http_action_pass_var_ready(nxt_task_t *task, void *obj, void *data)
15181563Svbart@nginx.com {
15191563Svbart@nginx.com     nxt_int_t           ret;
15201563Svbart@nginx.com     nxt_router_conf_t   *rtcf;
15211563Svbart@nginx.com     nxt_http_action_t   *action;
15221563Svbart@nginx.com     nxt_http_status_t   status;
15231563Svbart@nginx.com     nxt_http_request_t  *r;
15241563Svbart@nginx.com 
15251563Svbart@nginx.com     r = obj;
15261563Svbart@nginx.com     action = data;
15271563Svbart@nginx.com     rtcf = r->conf->socket_conf->router_conf;
15281563Svbart@nginx.com 
15291563Svbart@nginx.com     nxt_debug(task, "http pass lookup: %V", &action->name);
15301563Svbart@nginx.com 
15311563Svbart@nginx.com     ret = nxt_http_pass_find(task, r->mem_pool, rtcf, action);
15321563Svbart@nginx.com 
15331563Svbart@nginx.com     if (ret != NXT_OK) {
15341563Svbart@nginx.com         status = (ret == NXT_DECLINED) ? NXT_HTTP_NOT_FOUND
15351563Svbart@nginx.com                                        : NXT_HTTP_INTERNAL_SERVER_ERROR;
15361563Svbart@nginx.com 
15371563Svbart@nginx.com         nxt_http_request_error(task, r, status);
15381563Svbart@nginx.com         return;
15391563Svbart@nginx.com     }
15401563Svbart@nginx.com 
15411563Svbart@nginx.com     nxt_http_request_action(task, r, action);
15421563Svbart@nginx.com }
15431563Svbart@nginx.com 
15441563Svbart@nginx.com 
15451563Svbart@nginx.com static void
15461563Svbart@nginx.com nxt_http_action_pass_var_error(nxt_task_t *task, void *obj, void *data)
15471563Svbart@nginx.com {
15481563Svbart@nginx.com     nxt_http_request_t  *r;
15491563Svbart@nginx.com 
15501563Svbart@nginx.com     r = obj;
15511563Svbart@nginx.com 
15521563Svbart@nginx.com     nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
15531563Svbart@nginx.com }
15541563Svbart@nginx.com 
15551563Svbart@nginx.com 
15561563Svbart@nginx.com static nxt_int_t
15571563Svbart@nginx.com nxt_http_pass_find(nxt_task_t *task, nxt_mp_t *mp, nxt_router_conf_t *rtcf,
15581563Svbart@nginx.com     nxt_http_action_t *action)
15591563Svbart@nginx.com {
15601563Svbart@nginx.com     nxt_str_t   *targets;
15611563Svbart@nginx.com     nxt_int_t   ret;
15621563Svbart@nginx.com     nxt_uint_t  i;
15631563Svbart@nginx.com     nxt_str_t   segments[3];
15641563Svbart@nginx.com 
15651563Svbart@nginx.com     ret = nxt_http_pass_segments(mp, &action->name, segments, 3);
15661563Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
15671563Svbart@nginx.com         return ret;
15681563Svbart@nginx.com     }
15691563Svbart@nginx.com 
15701472Svbart@nginx.com     if (nxt_str_eq(&segments[0], "applications", 12)) {
15711563Svbart@nginx.com         ret = nxt_router_listener_application(rtcf, &segments[1], action);
15721563Svbart@nginx.com 
15731563Svbart@nginx.com         if (ret != NXT_OK) {
15741563Svbart@nginx.com             return ret;
15751563Svbart@nginx.com         }
1576964Sigor@sysoev.ru 
15771473Svbart@nginx.com         if (segments[2].length != 0) {
15781854Sz.hong@f5.com             targets = action->u.app.application->targets;
15791473Svbart@nginx.com 
15801473Svbart@nginx.com             for (i = 0; !nxt_strstr_eq(&segments[2], &targets[i]); i++);
15811473Svbart@nginx.com 
15821854Sz.hong@f5.com             action->u.app.target = i;
15831473Svbart@nginx.com 
15841473Svbart@nginx.com         } else {
15851854Sz.hong@f5.com             action->u.app.target = 0;
15861473Svbart@nginx.com         }
15871473Svbart@nginx.com 
15881563Svbart@nginx.com         return NXT_OK;
15891472Svbart@nginx.com     }
15901472Svbart@nginx.com 
15911563Svbart@nginx.com     if (segments[2].length == 0) {
15921563Svbart@nginx.com         if (nxt_str_eq(&segments[0], "upstreams", 9)) {
15931563Svbart@nginx.com             return nxt_upstream_find(rtcf->upstreams, &segments[1], action);
15941563Svbart@nginx.com         }
15951563Svbart@nginx.com 
15961563Svbart@nginx.com         if (nxt_str_eq(&segments[0], "routes", 6)) {
15971563Svbart@nginx.com             return nxt_http_route_find(rtcf->routes, &segments[1], action);
15981563Svbart@nginx.com         }
15991563Svbart@nginx.com     }
16001563Svbart@nginx.com 
16011563Svbart@nginx.com     return NXT_DECLINED;
16021472Svbart@nginx.com }
16031472Svbart@nginx.com 
16041472Svbart@nginx.com 
16051472Svbart@nginx.com nxt_int_t
16061472Svbart@nginx.com nxt_http_pass_segments(nxt_mp_t *mp, nxt_str_t *pass, nxt_str_t *segments,
16071472Svbart@nginx.com     nxt_uint_t n)
16081472Svbart@nginx.com {
16091472Svbart@nginx.com     u_char     *p;
16101472Svbart@nginx.com     nxt_str_t  rest;
16111472Svbart@nginx.com 
16121472Svbart@nginx.com     if (nxt_slow_path(nxt_str_dup(mp, &rest, pass) == NULL)) {
16131472Svbart@nginx.com         return NXT_ERROR;
16141472Svbart@nginx.com     }
16151472Svbart@nginx.com 
16161472Svbart@nginx.com     nxt_memzero(segments, n * sizeof(nxt_str_t));
16171472Svbart@nginx.com 
16181472Svbart@nginx.com     do {
16191472Svbart@nginx.com         p = nxt_memchr(rest.start, '/', rest.length);
16201472Svbart@nginx.com 
16211472Svbart@nginx.com         if (p != NULL) {
16221472Svbart@nginx.com             n--;
16231472Svbart@nginx.com 
16241472Svbart@nginx.com             if (n == 0) {
16251472Svbart@nginx.com                 return NXT_DECLINED;
16261472Svbart@nginx.com             }
16271472Svbart@nginx.com 
16281472Svbart@nginx.com             segments->length = p - rest.start;
16291472Svbart@nginx.com             segments->start = rest.start;
16301472Svbart@nginx.com 
16311472Svbart@nginx.com             rest.length -= segments->length + 1;
16321472Svbart@nginx.com             rest.start = p + 1;
16331472Svbart@nginx.com 
16341472Svbart@nginx.com         } else {
16351472Svbart@nginx.com             n = 0;
16361472Svbart@nginx.com             *segments = rest;
1637964Sigor@sysoev.ru         }
1638964Sigor@sysoev.ru 
16391472Svbart@nginx.com         if (segments->length == 0) {
16401472Svbart@nginx.com             return NXT_DECLINED;
16411472Svbart@nginx.com         }
16421472Svbart@nginx.com 
16431472Svbart@nginx.com         p = nxt_decode_uri(segments->start, segments->start, segments->length);
16441472Svbart@nginx.com         if (p == NULL) {
16451472Svbart@nginx.com             return NXT_DECLINED;
16461472Svbart@nginx.com         }
16471472Svbart@nginx.com 
16481472Svbart@nginx.com         segments->length = p - segments->start;
16491472Svbart@nginx.com         segments++;
16501472Svbart@nginx.com 
16511472Svbart@nginx.com     } while (n);
16521472Svbart@nginx.com 
16531472Svbart@nginx.com     return NXT_OK;
1654964Sigor@sysoev.ru }
1655964Sigor@sysoev.ru 
1656964Sigor@sysoev.ru 
16571563Svbart@nginx.com static nxt_int_t
16581392Sigor@sysoev.ru nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name,
16591392Sigor@sysoev.ru     nxt_http_action_t *action)
1660964Sigor@sysoev.ru {
16611033Svbart@nginx.com     nxt_http_route_t  **route, **end;
1662964Sigor@sysoev.ru 
1663964Sigor@sysoev.ru     route = &routes->route[0];
16641033Svbart@nginx.com     end = route + routes->items;
1665964Sigor@sysoev.ru 
16661058Sigor@sysoev.ru     while (route < end) {
1667964Sigor@sysoev.ru         if (nxt_strstr_eq(&(*route)->name, name)) {
16681392Sigor@sysoev.ru             action->u.route = *route;
16691392Sigor@sysoev.ru             action->handler = nxt_http_route_handler;
16701392Sigor@sysoev.ru 
16711563Svbart@nginx.com             return NXT_OK;
1672964Sigor@sysoev.ru         }
1673964Sigor@sysoev.ru 
1674964Sigor@sysoev.ru         route++;
16751058Sigor@sysoev.ru     }
16761563Svbart@nginx.com 
16771563Svbart@nginx.com     return NXT_DECLINED;
1678964Sigor@sysoev.ru }
1679964Sigor@sysoev.ru 
1680964Sigor@sysoev.ru 
16811264Sigor@sysoev.ru nxt_http_action_t *
16821264Sigor@sysoev.ru nxt_http_action_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1683964Sigor@sysoev.ru     nxt_str_t *name)
1684964Sigor@sysoev.ru {
16851597Shongzhidao@gmail.com     nxt_int_t          ret;
16861264Sigor@sysoev.ru     nxt_http_action_t  *action;
1687964Sigor@sysoev.ru 
16881264Sigor@sysoev.ru     action = nxt_mp_alloc(tmcf->router_conf->mem_pool,
16891264Sigor@sysoev.ru                           sizeof(nxt_http_action_t));
16901264Sigor@sysoev.ru     if (nxt_slow_path(action == NULL)) {
1691964Sigor@sysoev.ru         return NULL;
1692964Sigor@sysoev.ru     }
1693964Sigor@sysoev.ru 
16941264Sigor@sysoev.ru     action->name = *name;
16951270Sigor@sysoev.ru     action->handler = NULL;
1696964Sigor@sysoev.ru 
16971597Shongzhidao@gmail.com     ret = nxt_http_action_resolve(task, tmcf, action);
16981597Shongzhidao@gmail.com     if (nxt_slow_path(ret != NXT_OK)) {
16991597Shongzhidao@gmail.com         return NULL;
17001597Shongzhidao@gmail.com     }
1701964Sigor@sysoev.ru 
17021264Sigor@sysoev.ru     return action;
1703964Sigor@sysoev.ru }
1704964Sigor@sysoev.ru 
1705964Sigor@sysoev.ru 
1706964Sigor@sysoev.ru /* COMPATIBILITY: listener application. */
1707964Sigor@sysoev.ru 
17081264Sigor@sysoev.ru nxt_http_action_t *
17091563Svbart@nginx.com nxt_http_pass_application(nxt_task_t *task, nxt_router_conf_t *rtcf,
1710964Sigor@sysoev.ru     nxt_str_t *name)
1711964Sigor@sysoev.ru {
17121264Sigor@sysoev.ru     nxt_http_action_t  *action;
1713964Sigor@sysoev.ru 
17141563Svbart@nginx.com     action = nxt_mp_alloc(rtcf->mem_pool, sizeof(nxt_http_action_t));
17151264Sigor@sysoev.ru     if (nxt_slow_path(action == NULL)) {
1716964Sigor@sysoev.ru         return NULL;
1717964Sigor@sysoev.ru     }
1718964Sigor@sysoev.ru 
17191264Sigor@sysoev.ru     action->name = *name;
1720964Sigor@sysoev.ru 
17211563Svbart@nginx.com     (void) nxt_router_listener_application(rtcf, name, action);
1722964Sigor@sysoev.ru 
17231854Sz.hong@f5.com     action->u.app.target = 0;
17241473Svbart@nginx.com 
17251264Sigor@sysoev.ru     return action;
1726964Sigor@sysoev.ru }
1727964Sigor@sysoev.ru 
1728964Sigor@sysoev.ru 
17291264Sigor@sysoev.ru static nxt_http_action_t *
17301264Sigor@sysoev.ru nxt_http_route_handler(nxt_task_t *task, nxt_http_request_t *r,
17311264Sigor@sysoev.ru     nxt_http_action_t *start)
1732964Sigor@sysoev.ru {
1733964Sigor@sysoev.ru     nxt_http_route_t        *route;
17341264Sigor@sysoev.ru     nxt_http_action_t       *action;
17351033Svbart@nginx.com     nxt_http_route_match_t  **match, **end;
1736964Sigor@sysoev.ru 
1737964Sigor@sysoev.ru     route = start->u.route;
1738964Sigor@sysoev.ru     match = &route->match[0];
17391033Svbart@nginx.com     end = match + route->items;
1740964Sigor@sysoev.ru 
17411033Svbart@nginx.com     while (match < end) {
17421326Saxel.duch@nginx.com         action = nxt_http_route_match(task, r, *match);
17431264Sigor@sysoev.ru         if (action != NULL) {
17441264Sigor@sysoev.ru             return action;
1745964Sigor@sysoev.ru         }
1746964Sigor@sysoev.ru 
1747964Sigor@sysoev.ru         match++;
1748964Sigor@sysoev.ru     }
1749964Sigor@sysoev.ru 
1750964Sigor@sysoev.ru     nxt_http_request_error(task, r, NXT_HTTP_NOT_FOUND);
1751964Sigor@sysoev.ru 
1752964Sigor@sysoev.ru     return NULL;
1753964Sigor@sysoev.ru }
1754964Sigor@sysoev.ru 
1755964Sigor@sysoev.ru 
17561264Sigor@sysoev.ru static nxt_http_action_t *
17571326Saxel.duch@nginx.com nxt_http_route_match(nxt_task_t *task, nxt_http_request_t *r,
17581326Saxel.duch@nginx.com     nxt_http_route_match_t *match)
1759964Sigor@sysoev.ru {
17601060Sigor@sysoev.ru     nxt_int_t              ret;
17611059Sigor@sysoev.ru     nxt_http_route_test_t  *test, *end;
17621059Sigor@sysoev.ru 
17631059Sigor@sysoev.ru     test = &match->test[0];
17641059Sigor@sysoev.ru     end = test + match->items;
1765964Sigor@sysoev.ru 
17661059Sigor@sysoev.ru     while (test < end) {
17671324Saxel.duch@nginx.com         switch (test->rule->object) {
17681324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_TABLE:
17691324Saxel.duch@nginx.com             ret = nxt_http_route_table(r, test->table);
17701324Saxel.duch@nginx.com             break;
17711324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_SOURCE:
17721324Saxel.duch@nginx.com             ret = nxt_http_route_addr_rule(r, test->addr_rule, r->remote);
17731324Saxel.duch@nginx.com             break;
17741326Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_DESTINATION:
17751326Saxel.duch@nginx.com             if (r->local == NULL && nxt_fast_path(r->proto.any != NULL)) {
17761326Saxel.duch@nginx.com                 nxt_http_proto[r->protocol].local_addr(task, r);
17771326Saxel.duch@nginx.com             }
17781326Saxel.duch@nginx.com 
17791326Saxel.duch@nginx.com             ret = nxt_http_route_addr_rule(r, test->addr_rule, r->local);
17801326Saxel.duch@nginx.com             break;
17811324Saxel.duch@nginx.com         default:
17821059Sigor@sysoev.ru             ret = nxt_http_route_rule(r, test->rule);
17831324Saxel.duch@nginx.com             break;
17841059Sigor@sysoev.ru         }
17851059Sigor@sysoev.ru 
17861060Sigor@sysoev.ru         if (ret <= 0) {
17871264Sigor@sysoev.ru             /* 0 => NULL, -1 => NXT_HTTP_ACTION_ERROR. */
17881264Sigor@sysoev.ru             return (nxt_http_action_t *) (intptr_t) ret;
1789964Sigor@sysoev.ru         }
1790964Sigor@sysoev.ru 
17911059Sigor@sysoev.ru         test++;
1792964Sigor@sysoev.ru     }
1793964Sigor@sysoev.ru 
17941264Sigor@sysoev.ru     return &match->action;
1795964Sigor@sysoev.ru }
1796964Sigor@sysoev.ru 
1797964Sigor@sysoev.ru 
17981060Sigor@sysoev.ru static nxt_int_t
17991059Sigor@sysoev.ru nxt_http_route_table(nxt_http_request_t *r, nxt_http_route_table_t *table)
1800964Sigor@sysoev.ru {
18011060Sigor@sysoev.ru     nxt_int_t                 ret;
18021059Sigor@sysoev.ru     nxt_http_route_ruleset_t  **ruleset, **end;
18031059Sigor@sysoev.ru 
18041059Sigor@sysoev.ru     ret = 1;
18051059Sigor@sysoev.ru     ruleset = &table->ruleset[0];
18061059Sigor@sysoev.ru     end = ruleset + table->items;
18071059Sigor@sysoev.ru 
18081059Sigor@sysoev.ru     while (ruleset < end) {
18091059Sigor@sysoev.ru         ret = nxt_http_route_ruleset(r, *ruleset);
18101059Sigor@sysoev.ru 
18111060Sigor@sysoev.ru         if (ret != 0) {
18121059Sigor@sysoev.ru             return ret;
18131059Sigor@sysoev.ru         }
1814964Sigor@sysoev.ru 
18151059Sigor@sysoev.ru         ruleset++;
18161059Sigor@sysoev.ru     }
18171059Sigor@sysoev.ru 
18181059Sigor@sysoev.ru     return ret;
18191059Sigor@sysoev.ru }
18201059Sigor@sysoev.ru 
1821964Sigor@sysoev.ru 
18221060Sigor@sysoev.ru static nxt_int_t
18231059Sigor@sysoev.ru nxt_http_route_ruleset(nxt_http_request_t *r, nxt_http_route_ruleset_t *ruleset)
18241059Sigor@sysoev.ru {
18251060Sigor@sysoev.ru     nxt_int_t              ret;
18261059Sigor@sysoev.ru     nxt_http_route_rule_t  **rule, **end;
1827964Sigor@sysoev.ru 
18281059Sigor@sysoev.ru     rule = &ruleset->rule[0];
18291059Sigor@sysoev.ru     end = rule + ruleset->items;
1830964Sigor@sysoev.ru 
18311059Sigor@sysoev.ru     while (rule < end) {
18321060Sigor@sysoev.ru         ret = nxt_http_route_rule(r, *rule);
18331060Sigor@sysoev.ru 
18341060Sigor@sysoev.ru         if (ret <= 0) {
18351060Sigor@sysoev.ru             return ret;
1836964Sigor@sysoev.ru         }
1837964Sigor@sysoev.ru 
18381059Sigor@sysoev.ru         rule++;
18391059Sigor@sysoev.ru     }
18401059Sigor@sysoev.ru 
18411059Sigor@sysoev.ru     return 1;
18421059Sigor@sysoev.ru }
18431059Sigor@sysoev.ru 
1844964Sigor@sysoev.ru 
18451060Sigor@sysoev.ru static nxt_int_t
18461059Sigor@sysoev.ru nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
18471059Sigor@sysoev.ru {
18481059Sigor@sysoev.ru     void       *p, **pp;
18491059Sigor@sysoev.ru     u_char     *start;
18501059Sigor@sysoev.ru     size_t     length;
18511059Sigor@sysoev.ru     nxt_str_t  *s;
18521059Sigor@sysoev.ru 
18531059Sigor@sysoev.ru     switch (rule->object) {
18541059Sigor@sysoev.ru 
18551059Sigor@sysoev.ru     case NXT_HTTP_ROUTE_HEADER:
18561059Sigor@sysoev.ru         return nxt_http_route_header(r, rule);
1857964Sigor@sysoev.ru 
18581059Sigor@sysoev.ru     case NXT_HTTP_ROUTE_ARGUMENT:
18591061Sigor@sysoev.ru         return nxt_http_route_arguments(r, rule);
1860964Sigor@sysoev.ru 
18611059Sigor@sysoev.ru     case NXT_HTTP_ROUTE_COOKIE:
18621062Sigor@sysoev.ru         return nxt_http_route_cookies(r, rule);
18631059Sigor@sysoev.ru 
18641110Saxel.duch@nginx.com     case NXT_HTTP_ROUTE_SCHEME:
18651110Saxel.duch@nginx.com         return nxt_http_route_scheme(r, rule);
18661110Saxel.duch@nginx.com 
18671059Sigor@sysoev.ru     default:
18681059Sigor@sysoev.ru         break;
18691059Sigor@sysoev.ru     }
1870964Sigor@sysoev.ru 
18711059Sigor@sysoev.ru     p = nxt_pointer_to(r, rule->u.offset);
18721059Sigor@sysoev.ru 
18731059Sigor@sysoev.ru     if (rule->object == NXT_HTTP_ROUTE_STRING) {
18741059Sigor@sysoev.ru         s = p;
1875964Sigor@sysoev.ru 
18761059Sigor@sysoev.ru     } else {
18771059Sigor@sysoev.ru         /* NXT_HTTP_ROUTE_STRING_PTR */
18781059Sigor@sysoev.ru         pp = p;
18791059Sigor@sysoev.ru         s = *pp;
1880964Sigor@sysoev.ru 
18811059Sigor@sysoev.ru         if (s == NULL) {
1882964Sigor@sysoev.ru             return 0;
1883964Sigor@sysoev.ru         }
1884964Sigor@sysoev.ru     }
1885964Sigor@sysoev.ru 
18861059Sigor@sysoev.ru     length = s->length;
18871059Sigor@sysoev.ru     start = s->start;
18881059Sigor@sysoev.ru 
18891059Sigor@sysoev.ru     return nxt_http_route_test_rule(r, rule, start, length);
18901059Sigor@sysoev.ru }
18911059Sigor@sysoev.ru 
18921059Sigor@sysoev.ru 
18931060Sigor@sysoev.ru static nxt_int_t
18941324Saxel.duch@nginx.com nxt_http_route_addr_pattern_match(nxt_http_route_addr_pattern_t *p,
18951324Saxel.duch@nginx.com     nxt_sockaddr_t *sa)
18961324Saxel.duch@nginx.com {
18971324Saxel.duch@nginx.com #if (NXT_INET6)
18981324Saxel.duch@nginx.com     uint32_t                    i;
18991324Saxel.duch@nginx.com #endif
19001324Saxel.duch@nginx.com     in_port_t                   in_port;
19011324Saxel.duch@nginx.com     nxt_int_t                   match;
19021324Saxel.duch@nginx.com     struct sockaddr_in          *sin;
19031324Saxel.duch@nginx.com #if (NXT_INET6)
19041324Saxel.duch@nginx.com     struct sockaddr_in6         *sin6;
19051324Saxel.duch@nginx.com #endif
19061324Saxel.duch@nginx.com     nxt_http_route_addr_base_t  *base;
19071324Saxel.duch@nginx.com 
19081324Saxel.duch@nginx.com     base = &p->base;
19091324Saxel.duch@nginx.com 
19101324Saxel.duch@nginx.com     switch (sa->u.sockaddr.sa_family) {
19111324Saxel.duch@nginx.com 
19121324Saxel.duch@nginx.com     case AF_INET:
19131324Saxel.duch@nginx.com 
19141324Saxel.duch@nginx.com         match = (base->addr_family == AF_INET
19151324Saxel.duch@nginx.com                  || base->addr_family == AF_UNSPEC);
19161324Saxel.duch@nginx.com         if (!match) {
19171324Saxel.duch@nginx.com             break;
19181324Saxel.duch@nginx.com         }
19191324Saxel.duch@nginx.com 
19201324Saxel.duch@nginx.com         sin = &sa->u.sockaddr_in;
19211324Saxel.duch@nginx.com         in_port = ntohs(sin->sin_port);
19221324Saxel.duch@nginx.com 
19231324Saxel.duch@nginx.com         match = (in_port >= base->port.start && in_port <= base->port.end);
19241324Saxel.duch@nginx.com         if (!match) {
19251324Saxel.duch@nginx.com             break;
19261324Saxel.duch@nginx.com         }
19271324Saxel.duch@nginx.com 
19281324Saxel.duch@nginx.com         switch (base->match_type) {
19291324Saxel.duch@nginx.com 
19301324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_ADDR_ANY:
19311324Saxel.duch@nginx.com             break;
19321324Saxel.duch@nginx.com 
19331324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_ADDR_EXACT:
19341324Saxel.duch@nginx.com             match = (nxt_memcmp(&sin->sin_addr, &p->addr.v4.start,
19351324Saxel.duch@nginx.com                                 sizeof(struct in_addr))
19361324Saxel.duch@nginx.com                      == 0);
19371324Saxel.duch@nginx.com             break;
19381324Saxel.duch@nginx.com 
19391324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_ADDR_RANGE:
19401324Saxel.duch@nginx.com             match = (nxt_memcmp(&sin->sin_addr, &p->addr.v4.start,
19411324Saxel.duch@nginx.com                                 sizeof(struct in_addr)) >= 0
19421324Saxel.duch@nginx.com                      && nxt_memcmp(&sin->sin_addr, &p->addr.v4.end,
19431324Saxel.duch@nginx.com                                    sizeof(struct in_addr)) <= 0);
19441324Saxel.duch@nginx.com             break;
19451324Saxel.duch@nginx.com 
19461324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_ADDR_CIDR:
19471324Saxel.duch@nginx.com             match = ((sin->sin_addr.s_addr & p->addr.v4.end)
19481324Saxel.duch@nginx.com                      == p->addr.v4.start);
19491324Saxel.duch@nginx.com             break;
19501324Saxel.duch@nginx.com 
19511324Saxel.duch@nginx.com         default:
19521324Saxel.duch@nginx.com             nxt_unreachable();
19531324Saxel.duch@nginx.com         }
19541324Saxel.duch@nginx.com 
19551324Saxel.duch@nginx.com         break;
19561324Saxel.duch@nginx.com 
19571324Saxel.duch@nginx.com #if (NXT_INET6)
19581324Saxel.duch@nginx.com     case AF_INET6:
19591324Saxel.duch@nginx.com 
19601324Saxel.duch@nginx.com         match = (base->addr_family == AF_INET6
19611324Saxel.duch@nginx.com                  || base->addr_family == AF_UNSPEC);
19621324Saxel.duch@nginx.com         if (!match) {
19631324Saxel.duch@nginx.com             break;
19641324Saxel.duch@nginx.com         }
19651324Saxel.duch@nginx.com 
19661324Saxel.duch@nginx.com         sin6 = &sa->u.sockaddr_in6;
19671324Saxel.duch@nginx.com         in_port = ntohs(sin6->sin6_port);
19681324Saxel.duch@nginx.com 
19691324Saxel.duch@nginx.com         match = (in_port >= base->port.start && in_port <= base->port.end);
19701324Saxel.duch@nginx.com         if (!match) {
19711324Saxel.duch@nginx.com             break;
19721324Saxel.duch@nginx.com         }
19731324Saxel.duch@nginx.com 
19741324Saxel.duch@nginx.com         switch (base->match_type) {
19751324Saxel.duch@nginx.com 
19761324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_ADDR_ANY:
19771324Saxel.duch@nginx.com             break;
19781324Saxel.duch@nginx.com 
19791324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_ADDR_EXACT:
19801324Saxel.duch@nginx.com             match = (nxt_memcmp(&sin6->sin6_addr, &p->addr.v6.start,
19811324Saxel.duch@nginx.com                                 sizeof(struct in6_addr))
19821324Saxel.duch@nginx.com                      == 0);
19831324Saxel.duch@nginx.com             break;
19841324Saxel.duch@nginx.com 
19851324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_ADDR_RANGE:
19861324Saxel.duch@nginx.com             match = (nxt_memcmp(&sin6->sin6_addr, &p->addr.v6.start,
19871324Saxel.duch@nginx.com                                 sizeof(struct in6_addr)) >= 0
19881324Saxel.duch@nginx.com                      && nxt_memcmp(&sin6->sin6_addr, &p->addr.v6.end,
19891324Saxel.duch@nginx.com                                    sizeof(struct in6_addr)) <= 0);
19901324Saxel.duch@nginx.com             break;
19911324Saxel.duch@nginx.com 
19921324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_ADDR_CIDR:
19931324Saxel.duch@nginx.com             for (i = 0; i < 16; i++) {
19941324Saxel.duch@nginx.com                 match = ((sin6->sin6_addr.s6_addr[i]
19951324Saxel.duch@nginx.com                           & p->addr.v6.end.s6_addr[i])
19961324Saxel.duch@nginx.com                          == p->addr.v6.start.s6_addr[i]);
19971324Saxel.duch@nginx.com 
19981324Saxel.duch@nginx.com                 if (!match) {
19991324Saxel.duch@nginx.com                     break;
20001324Saxel.duch@nginx.com                 }
20011324Saxel.duch@nginx.com             }
20021324Saxel.duch@nginx.com 
20031324Saxel.duch@nginx.com             break;
20041324Saxel.duch@nginx.com 
20051324Saxel.duch@nginx.com         default:
20061324Saxel.duch@nginx.com             nxt_unreachable();
20071324Saxel.duch@nginx.com         }
20081324Saxel.duch@nginx.com 
20091324Saxel.duch@nginx.com         break;
20101324Saxel.duch@nginx.com #endif
20111324Saxel.duch@nginx.com 
20121324Saxel.duch@nginx.com     default:
20131324Saxel.duch@nginx.com         match = 0;
20141324Saxel.duch@nginx.com         break;
20151324Saxel.duch@nginx.com     }
20161324Saxel.duch@nginx.com 
20171324Saxel.duch@nginx.com     return match ^ base->negative;
20181324Saxel.duch@nginx.com }
20191324Saxel.duch@nginx.com 
20201324Saxel.duch@nginx.com 
20211324Saxel.duch@nginx.com static nxt_int_t
20221324Saxel.duch@nginx.com nxt_http_route_addr_rule(nxt_http_request_t *r,
20231324Saxel.duch@nginx.com     nxt_http_route_addr_rule_t *addr_rule, nxt_sockaddr_t *sa)
20241324Saxel.duch@nginx.com {
20251390Saxel.duch@nginx.com     uint32_t                       n;
20261390Saxel.duch@nginx.com     nxt_bool_t                     matches;
20271324Saxel.duch@nginx.com     nxt_http_route_addr_pattern_t  *p;
20281324Saxel.duch@nginx.com 
20291324Saxel.duch@nginx.com     n = addr_rule->items;
20301390Saxel.duch@nginx.com     p = &addr_rule->addr_pattern[0] - 1;
20311324Saxel.duch@nginx.com 
20321390Saxel.duch@nginx.com     do {
20331390Saxel.duch@nginx.com         p++;
20341390Saxel.duch@nginx.com         n--;
20351390Saxel.duch@nginx.com 
20361390Saxel.duch@nginx.com         matches = nxt_http_route_addr_pattern_match(p, sa);
20371390Saxel.duch@nginx.com 
20381390Saxel.duch@nginx.com         if (p->base.negative) {
20391390Saxel.duch@nginx.com             if (matches) {
20401390Saxel.duch@nginx.com                 continue;
20411390Saxel.duch@nginx.com             }
20421390Saxel.duch@nginx.com 
20431390Saxel.duch@nginx.com             return 0;
20441390Saxel.duch@nginx.com         }
20451390Saxel.duch@nginx.com 
20461390Saxel.duch@nginx.com         if (matches) {
20471324Saxel.duch@nginx.com             return 1;
20481324Saxel.duch@nginx.com         }
20491324Saxel.duch@nginx.com 
20501390Saxel.duch@nginx.com     } while (n > 0);
20511390Saxel.duch@nginx.com 
20521390Saxel.duch@nginx.com     return p->base.negative;
20531324Saxel.duch@nginx.com }
20541324Saxel.duch@nginx.com 
20551324Saxel.duch@nginx.com 
20561324Saxel.duch@nginx.com static nxt_int_t
20571059Sigor@sysoev.ru nxt_http_route_header(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
20581059Sigor@sysoev.ru {
20591060Sigor@sysoev.ru     nxt_int_t         ret;
20601059Sigor@sysoev.ru     nxt_http_field_t  *f;
20611059Sigor@sysoev.ru 
20621059Sigor@sysoev.ru     ret = 0;
20631059Sigor@sysoev.ru 
20641059Sigor@sysoev.ru     nxt_list_each(f, r->fields) {
20651059Sigor@sysoev.ru 
20661059Sigor@sysoev.ru         if (rule->u.name.hash != f->hash
20671059Sigor@sysoev.ru             || rule->u.name.length != f->name_length
20681059Sigor@sysoev.ru             || nxt_strncasecmp(rule->u.name.start, f->name, f->name_length)
20691059Sigor@sysoev.ru                != 0)
20701059Sigor@sysoev.ru         {
20711059Sigor@sysoev.ru             continue;
20721059Sigor@sysoev.ru         }
20731059Sigor@sysoev.ru 
20741059Sigor@sysoev.ru         ret = nxt_http_route_test_rule(r, rule, f->value, f->value_length);
20751721Saxel.duch@nginx.com         if (nxt_slow_path(ret == NXT_ERROR)) {
20761721Saxel.duch@nginx.com             return NXT_ERROR;
20771721Saxel.duch@nginx.com         }
20781059Sigor@sysoev.ru 
20791060Sigor@sysoev.ru         if (ret == 0) {
20801059Sigor@sysoev.ru             return ret;
20811059Sigor@sysoev.ru         }
20821059Sigor@sysoev.ru 
20831059Sigor@sysoev.ru     } nxt_list_loop;
20841059Sigor@sysoev.ru 
20851059Sigor@sysoev.ru     return ret;
20861059Sigor@sysoev.ru }
20871059Sigor@sysoev.ru 
20881059Sigor@sysoev.ru 
20891060Sigor@sysoev.ru static nxt_int_t
20901061Sigor@sysoev.ru nxt_http_route_arguments(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
20911061Sigor@sysoev.ru {
20921061Sigor@sysoev.ru     nxt_array_t  *arguments;
20931061Sigor@sysoev.ru 
20941061Sigor@sysoev.ru     if (r->args == NULL) {
20951061Sigor@sysoev.ru         return 0;
20961061Sigor@sysoev.ru     }
20971061Sigor@sysoev.ru 
20981061Sigor@sysoev.ru     arguments = nxt_http_route_arguments_parse(r);
20991061Sigor@sysoev.ru     if (nxt_slow_path(arguments == NULL)) {
21001061Sigor@sysoev.ru         return -1;
21011061Sigor@sysoev.ru     }
21021061Sigor@sysoev.ru 
21031061Sigor@sysoev.ru     return nxt_http_route_test_argument(r, rule, arguments);
21041061Sigor@sysoev.ru }
21051061Sigor@sysoev.ru 
21061061Sigor@sysoev.ru 
21071061Sigor@sysoev.ru static nxt_array_t *
21081061Sigor@sysoev.ru nxt_http_route_arguments_parse(nxt_http_request_t *r)
21091061Sigor@sysoev.ru {
21101061Sigor@sysoev.ru     size_t                 name_length;
21111474Saxel.duch@nginx.com     u_char                 c, *p, *dst, *dst_start, *start, *end, *name;
21121474Saxel.duch@nginx.com     uint8_t                d0, d1;
21131061Sigor@sysoev.ru     uint32_t               hash;
21141061Sigor@sysoev.ru     nxt_bool_t             valid;
21151061Sigor@sysoev.ru     nxt_array_t            *args;
21161061Sigor@sysoev.ru     nxt_http_name_value_t  *nv;
21171061Sigor@sysoev.ru 
21181061Sigor@sysoev.ru     if (r->arguments != NULL) {
21191061Sigor@sysoev.ru         return r->arguments;
21201061Sigor@sysoev.ru     }
21211061Sigor@sysoev.ru 
21221061Sigor@sysoev.ru     args = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t));
21231061Sigor@sysoev.ru     if (nxt_slow_path(args == NULL)) {
21241061Sigor@sysoev.ru         return NULL;
21251061Sigor@sysoev.ru     }
21261061Sigor@sysoev.ru 
21271061Sigor@sysoev.ru     hash = NXT_HTTP_FIELD_HASH_INIT;
21281061Sigor@sysoev.ru     valid = 1;
21291061Sigor@sysoev.ru     name = NULL;
21301061Sigor@sysoev.ru     name_length = 0;
21311061Sigor@sysoev.ru 
21321474Saxel.duch@nginx.com     dst_start = nxt_mp_nget(r->mem_pool, r->args->length);
21331474Saxel.duch@nginx.com     if (nxt_slow_path(dst_start == NULL)) {
21341474Saxel.duch@nginx.com         return NULL;
21351474Saxel.duch@nginx.com     }
21361474Saxel.duch@nginx.com 
21371061Sigor@sysoev.ru     start = r->args->start;
21381061Sigor@sysoev.ru     end = start + r->args->length;
21391061Sigor@sysoev.ru 
21401474Saxel.duch@nginx.com     for (p = start, dst = dst_start; p < end; p++, dst++) {
21411061Sigor@sysoev.ru         c = *p;
21421474Saxel.duch@nginx.com         *dst = c;
21431474Saxel.duch@nginx.com 
21441474Saxel.duch@nginx.com         switch (c) {
21451474Saxel.duch@nginx.com         case '=':
21461474Saxel.duch@nginx.com             if (name != NULL) {
21471474Saxel.duch@nginx.com                 break;
21481474Saxel.duch@nginx.com             }
21491474Saxel.duch@nginx.com 
21501474Saxel.duch@nginx.com             name_length = dst - dst_start;
21511061Sigor@sysoev.ru             valid = (name_length != 0);
21521474Saxel.duch@nginx.com             name = dst_start;
21531474Saxel.duch@nginx.com             dst_start = dst + 1;
21541474Saxel.duch@nginx.com 
21551474Saxel.duch@nginx.com             continue;
21561474Saxel.duch@nginx.com 
21571474Saxel.duch@nginx.com         case '&':
21581061Sigor@sysoev.ru             if (valid) {
21591061Sigor@sysoev.ru                 nv = nxt_http_route_argument(args, name, name_length, hash,
21601474Saxel.duch@nginx.com                                              dst_start, dst);
21611061Sigor@sysoev.ru                 if (nxt_slow_path(nv == NULL)) {
21621061Sigor@sysoev.ru                     return NULL;
21631061Sigor@sysoev.ru                 }
21641061Sigor@sysoev.ru             }
21651061Sigor@sysoev.ru 
21661061Sigor@sysoev.ru             hash = NXT_HTTP_FIELD_HASH_INIT;
21671474Saxel.duch@nginx.com             name_length = 0;
21681061Sigor@sysoev.ru             valid = 1;
21691061Sigor@sysoev.ru             name = NULL;
21701474Saxel.duch@nginx.com             dst_start = dst + 1;
21711474Saxel.duch@nginx.com 
21721474Saxel.duch@nginx.com             continue;
21731474Saxel.duch@nginx.com 
21741474Saxel.duch@nginx.com         case '+':
21751474Saxel.duch@nginx.com             c = ' ';
21761474Saxel.duch@nginx.com             *dst = ' ';
21771474Saxel.duch@nginx.com 
21781474Saxel.duch@nginx.com             break;
21791474Saxel.duch@nginx.com 
21801474Saxel.duch@nginx.com         case '%':
21811474Saxel.duch@nginx.com             if (nxt_slow_path(end - p <= 2)) {
21821474Saxel.duch@nginx.com                 break;
21831474Saxel.duch@nginx.com             }
21841474Saxel.duch@nginx.com 
21851474Saxel.duch@nginx.com             d0 = nxt_hex2int[p[1]];
21861474Saxel.duch@nginx.com             d1 = nxt_hex2int[p[2]];
21871474Saxel.duch@nginx.com 
21881474Saxel.duch@nginx.com             if (nxt_slow_path((d0 | d1) >= 16)) {
21891474Saxel.duch@nginx.com                 break;
21901474Saxel.duch@nginx.com             }
21911474Saxel.duch@nginx.com 
21921474Saxel.duch@nginx.com             p += 2;
21931474Saxel.duch@nginx.com             c = (d0 << 4) + d1;
21941474Saxel.duch@nginx.com             *dst = c;
21951474Saxel.duch@nginx.com 
21961474Saxel.duch@nginx.com             break;
21971474Saxel.duch@nginx.com         }
21981474Saxel.duch@nginx.com 
21991474Saxel.duch@nginx.com         if (name == NULL) {
22001061Sigor@sysoev.ru             hash = nxt_http_field_hash_char(hash, c);
22011061Sigor@sysoev.ru         }
22021061Sigor@sysoev.ru     }
22031061Sigor@sysoev.ru 
22041061Sigor@sysoev.ru     if (valid) {
22051474Saxel.duch@nginx.com         nv = nxt_http_route_argument(args, name, name_length, hash, dst_start,
22061474Saxel.duch@nginx.com                                      dst);
22071061Sigor@sysoev.ru         if (nxt_slow_path(nv == NULL)) {
22081061Sigor@sysoev.ru             return NULL;
22091061Sigor@sysoev.ru         }
22101061Sigor@sysoev.ru     }
22111061Sigor@sysoev.ru 
22121061Sigor@sysoev.ru     r->arguments = args;
22131061Sigor@sysoev.ru 
22141061Sigor@sysoev.ru     return args;
22151061Sigor@sysoev.ru }
22161061Sigor@sysoev.ru 
22171061Sigor@sysoev.ru 
22181061Sigor@sysoev.ru static nxt_http_name_value_t *
22191061Sigor@sysoev.ru nxt_http_route_argument(nxt_array_t *array, u_char *name, size_t name_length,
22201061Sigor@sysoev.ru     uint32_t hash, u_char *start, u_char *end)
22211061Sigor@sysoev.ru {
22221061Sigor@sysoev.ru     size_t                 length;
22231061Sigor@sysoev.ru     nxt_http_name_value_t  *nv;
22241061Sigor@sysoev.ru 
22251061Sigor@sysoev.ru     nv = nxt_array_add(array);
22261061Sigor@sysoev.ru     if (nxt_slow_path(nv == NULL)) {
22271061Sigor@sysoev.ru         return NULL;
22281061Sigor@sysoev.ru     }
22291061Sigor@sysoev.ru 
22301061Sigor@sysoev.ru     nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF;
22311061Sigor@sysoev.ru 
22321061Sigor@sysoev.ru     length = end - start;
22331061Sigor@sysoev.ru 
22341061Sigor@sysoev.ru     if (name == NULL) {
22351061Sigor@sysoev.ru         name_length = length;
22361061Sigor@sysoev.ru         name = start;
22371061Sigor@sysoev.ru         length = 0;
22381061Sigor@sysoev.ru     }
22391061Sigor@sysoev.ru 
22401061Sigor@sysoev.ru     nv->name_length = name_length;
22411061Sigor@sysoev.ru     nv->value_length = length;
22421061Sigor@sysoev.ru     nv->name = name;
22431061Sigor@sysoev.ru     nv->value = start;
22441061Sigor@sysoev.ru 
22451061Sigor@sysoev.ru     return nv;
22461061Sigor@sysoev.ru }
22471061Sigor@sysoev.ru 
22481061Sigor@sysoev.ru 
22491061Sigor@sysoev.ru static nxt_int_t
22501061Sigor@sysoev.ru nxt_http_route_test_argument(nxt_http_request_t *r,
22511061Sigor@sysoev.ru     nxt_http_route_rule_t *rule, nxt_array_t *array)
22521061Sigor@sysoev.ru {
22531721Saxel.duch@nginx.com     nxt_int_t              ret;
22541061Sigor@sysoev.ru     nxt_http_name_value_t  *nv, *end;
22551061Sigor@sysoev.ru 
22561061Sigor@sysoev.ru     ret = 0;
22571061Sigor@sysoev.ru 
22581061Sigor@sysoev.ru     nv = array->elts;
22591061Sigor@sysoev.ru     end = nv + array->nelts;
22601061Sigor@sysoev.ru 
22611061Sigor@sysoev.ru     while (nv < end) {
22621061Sigor@sysoev.ru 
22631061Sigor@sysoev.ru         if (rule->u.name.hash == nv->hash
22641061Sigor@sysoev.ru             && rule->u.name.length == nv->name_length
22651061Sigor@sysoev.ru             && nxt_memcmp(rule->u.name.start, nv->name, nv->name_length) == 0)
22661061Sigor@sysoev.ru         {
22671061Sigor@sysoev.ru             ret = nxt_http_route_test_rule(r, rule, nv->value,
22681061Sigor@sysoev.ru                                            nv->value_length);
22691721Saxel.duch@nginx.com             if (nxt_slow_path(ret == NXT_ERROR)) {
22701721Saxel.duch@nginx.com                 return NXT_ERROR;
22711721Saxel.duch@nginx.com             }
22721721Saxel.duch@nginx.com 
22731061Sigor@sysoev.ru             if (ret == 0) {
22741061Sigor@sysoev.ru                 break;
22751061Sigor@sysoev.ru             }
22761061Sigor@sysoev.ru         }
22771061Sigor@sysoev.ru 
22781061Sigor@sysoev.ru         nv++;
22791061Sigor@sysoev.ru     }
22801061Sigor@sysoev.ru 
22811061Sigor@sysoev.ru     return ret;
22821061Sigor@sysoev.ru }
22831061Sigor@sysoev.ru 
22841061Sigor@sysoev.ru 
22851061Sigor@sysoev.ru static nxt_int_t
22861110Saxel.duch@nginx.com nxt_http_route_scheme(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
22871110Saxel.duch@nginx.com {
22881508Saxel.duch@nginx.com     nxt_bool_t                      tls, https;
22891508Saxel.duch@nginx.com     nxt_http_route_pattern_slice_t  *pattern_slice;
22901508Saxel.duch@nginx.com 
22911721Saxel.duch@nginx.com     pattern_slice = rule->pattern[0].u.pattern_slices->elts;
22921508Saxel.duch@nginx.com     https = (pattern_slice->length == nxt_length("https"));
22931110Saxel.duch@nginx.com     tls = (r->tls != NULL);
22941110Saxel.duch@nginx.com 
22951110Saxel.duch@nginx.com     return (tls == https);
22961110Saxel.duch@nginx.com }
22971110Saxel.duch@nginx.com 
22981110Saxel.duch@nginx.com 
22991110Saxel.duch@nginx.com static nxt_int_t
23001062Sigor@sysoev.ru nxt_http_route_cookies(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
23011062Sigor@sysoev.ru {
23021062Sigor@sysoev.ru     nxt_array_t  *cookies;
23031062Sigor@sysoev.ru 
23041062Sigor@sysoev.ru     cookies = nxt_http_route_cookies_parse(r);
23051062Sigor@sysoev.ru     if (nxt_slow_path(cookies == NULL)) {
23061062Sigor@sysoev.ru         return -1;
23071062Sigor@sysoev.ru     }
23081062Sigor@sysoev.ru 
23091062Sigor@sysoev.ru     return nxt_http_route_test_cookie(r, rule, cookies);
23101062Sigor@sysoev.ru }
23111062Sigor@sysoev.ru 
23121062Sigor@sysoev.ru 
23131062Sigor@sysoev.ru static nxt_array_t *
23141062Sigor@sysoev.ru nxt_http_route_cookies_parse(nxt_http_request_t *r)
23151062Sigor@sysoev.ru {
23161062Sigor@sysoev.ru     nxt_int_t         ret;
23171062Sigor@sysoev.ru     nxt_array_t       *cookies;
23181062Sigor@sysoev.ru     nxt_http_field_t  *f;
23191062Sigor@sysoev.ru 
23201062Sigor@sysoev.ru     if (r->cookies != NULL) {
23211062Sigor@sysoev.ru         return r->cookies;
23221062Sigor@sysoev.ru     }
23231062Sigor@sysoev.ru 
23241062Sigor@sysoev.ru     cookies = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t));
23251062Sigor@sysoev.ru     if (nxt_slow_path(cookies == NULL)) {
23261062Sigor@sysoev.ru         return NULL;
23271062Sigor@sysoev.ru     }
23281062Sigor@sysoev.ru 
23291062Sigor@sysoev.ru     nxt_list_each(f, r->fields) {
23301062Sigor@sysoev.ru 
23311522Saxel.duch@nginx.com         if (f->hash != NXT_COOKIE_HASH
23321062Sigor@sysoev.ru             || f->name_length != 6
23331062Sigor@sysoev.ru             || nxt_strncasecmp(f->name, (u_char *) "Cookie", 6) != 0)
23341062Sigor@sysoev.ru         {
23351062Sigor@sysoev.ru             continue;
23361062Sigor@sysoev.ru         }
23371062Sigor@sysoev.ru 
23381062Sigor@sysoev.ru         ret = nxt_http_route_cookie_parse(cookies, f->value,
23391062Sigor@sysoev.ru                                           f->value + f->value_length);
23401062Sigor@sysoev.ru         if (ret != NXT_OK) {
23411062Sigor@sysoev.ru             return NULL;
23421062Sigor@sysoev.ru         }
23431062Sigor@sysoev.ru 
23441062Sigor@sysoev.ru     } nxt_list_loop;
23451062Sigor@sysoev.ru 
23461062Sigor@sysoev.ru     r->cookies = cookies;
23471062Sigor@sysoev.ru 
23481062Sigor@sysoev.ru     return cookies;
23491062Sigor@sysoev.ru }
23501062Sigor@sysoev.ru 
23511062Sigor@sysoev.ru 
23521062Sigor@sysoev.ru static nxt_int_t
23531062Sigor@sysoev.ru nxt_http_route_cookie_parse(nxt_array_t *cookies, u_char *start, u_char *end)
23541062Sigor@sysoev.ru {
23551062Sigor@sysoev.ru     size_t                 name_length;
23561062Sigor@sysoev.ru     u_char                 c, *p, *name;
23571062Sigor@sysoev.ru     nxt_http_name_value_t  *nv;
23581062Sigor@sysoev.ru 
23591062Sigor@sysoev.ru     name = NULL;
23601062Sigor@sysoev.ru     name_length = 0;
23611062Sigor@sysoev.ru 
23621062Sigor@sysoev.ru     for (p = start; p < end; p++) {
23631062Sigor@sysoev.ru         c = *p;
23641062Sigor@sysoev.ru 
23651062Sigor@sysoev.ru         if (c == '=') {
23661062Sigor@sysoev.ru             while (start[0] == ' ') { start++; }
23671062Sigor@sysoev.ru 
23681062Sigor@sysoev.ru             name_length = p - start;
23691062Sigor@sysoev.ru 
23701062Sigor@sysoev.ru             if (name_length != 0) {
23711062Sigor@sysoev.ru                 name = start;
23721062Sigor@sysoev.ru             }
23731062Sigor@sysoev.ru 
23741062Sigor@sysoev.ru             start = p + 1;
23751062Sigor@sysoev.ru 
23761062Sigor@sysoev.ru         } else if (c == ';') {
23771062Sigor@sysoev.ru             if (name != NULL) {
23781062Sigor@sysoev.ru                 nv = nxt_http_route_cookie(cookies, name, name_length,
23791062Sigor@sysoev.ru                                            start, p);
23801062Sigor@sysoev.ru                 if (nxt_slow_path(nv == NULL)) {
23811062Sigor@sysoev.ru                     return NXT_ERROR;
23821062Sigor@sysoev.ru                 }
23831062Sigor@sysoev.ru             }
23841062Sigor@sysoev.ru 
23851062Sigor@sysoev.ru             name = NULL;
23861062Sigor@sysoev.ru             start = p + 1;
23871062Sigor@sysoev.ru          }
23881062Sigor@sysoev.ru     }
23891062Sigor@sysoev.ru 
23901062Sigor@sysoev.ru     if (name != NULL) {
23911062Sigor@sysoev.ru         nv = nxt_http_route_cookie(cookies, name, name_length, start, p);
23921062Sigor@sysoev.ru         if (nxt_slow_path(nv == NULL)) {
23931062Sigor@sysoev.ru             return NXT_ERROR;
23941062Sigor@sysoev.ru         }
23951062Sigor@sysoev.ru     }
23961062Sigor@sysoev.ru 
23971062Sigor@sysoev.ru     return NXT_OK;
23981062Sigor@sysoev.ru }
23991062Sigor@sysoev.ru 
24001062Sigor@sysoev.ru 
24011062Sigor@sysoev.ru static nxt_http_name_value_t *
24021062Sigor@sysoev.ru nxt_http_route_cookie(nxt_array_t *array, u_char *name, size_t name_length,
24031062Sigor@sysoev.ru     u_char *start, u_char *end)
24041062Sigor@sysoev.ru {
24051062Sigor@sysoev.ru     u_char                 c, *p;
24061062Sigor@sysoev.ru     uint32_t               hash;
24071062Sigor@sysoev.ru     nxt_http_name_value_t  *nv;
24081062Sigor@sysoev.ru 
24091062Sigor@sysoev.ru     nv = nxt_array_add(array);
24101062Sigor@sysoev.ru     if (nxt_slow_path(nv == NULL)) {
24111062Sigor@sysoev.ru         return NULL;
24121062Sigor@sysoev.ru     }
24131062Sigor@sysoev.ru 
24141062Sigor@sysoev.ru     nv->name_length = name_length;
24151062Sigor@sysoev.ru     nv->name = name;
24161062Sigor@sysoev.ru 
24171062Sigor@sysoev.ru     hash = NXT_HTTP_FIELD_HASH_INIT;
24181062Sigor@sysoev.ru 
24191062Sigor@sysoev.ru     for (p = name; p < name + name_length; p++) {
24201062Sigor@sysoev.ru         c = *p;
24211062Sigor@sysoev.ru         hash = nxt_http_field_hash_char(hash, c);
24221062Sigor@sysoev.ru     }
24231062Sigor@sysoev.ru 
24241062Sigor@sysoev.ru     nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF;
24251062Sigor@sysoev.ru 
24261062Sigor@sysoev.ru     while (start < end && end[-1] == ' ') { end--; }
24271062Sigor@sysoev.ru 
24281062Sigor@sysoev.ru     nv->value_length = end - start;
24291062Sigor@sysoev.ru     nv->value = start;
24301062Sigor@sysoev.ru 
24311062Sigor@sysoev.ru     return nv;
24321062Sigor@sysoev.ru }
24331062Sigor@sysoev.ru 
24341062Sigor@sysoev.ru 
24351062Sigor@sysoev.ru static nxt_int_t
24361062Sigor@sysoev.ru nxt_http_route_test_cookie(nxt_http_request_t *r,
24371062Sigor@sysoev.ru     nxt_http_route_rule_t *rule, nxt_array_t *array)
24381062Sigor@sysoev.ru {
24391721Saxel.duch@nginx.com     nxt_int_t              ret;
24401062Sigor@sysoev.ru     nxt_http_name_value_t  *nv, *end;
24411062Sigor@sysoev.ru 
24421062Sigor@sysoev.ru     ret = 0;
24431062Sigor@sysoev.ru 
24441062Sigor@sysoev.ru     nv = array->elts;
24451062Sigor@sysoev.ru     end = nv + array->nelts;
24461062Sigor@sysoev.ru 
24471062Sigor@sysoev.ru     while (nv < end) {
24481062Sigor@sysoev.ru 
24491062Sigor@sysoev.ru         if (rule->u.name.hash == nv->hash
24501062Sigor@sysoev.ru             && rule->u.name.length == nv->name_length
24511079Sigor@sysoev.ru             && nxt_memcmp(rule->u.name.start, nv->name, nv->name_length) == 0)
24521062Sigor@sysoev.ru         {
24531062Sigor@sysoev.ru             ret = nxt_http_route_test_rule(r, rule, nv->value,
24541062Sigor@sysoev.ru                                            nv->value_length);
24551721Saxel.duch@nginx.com             if (nxt_slow_path(ret == NXT_ERROR)) {
24561721Saxel.duch@nginx.com                 return NXT_ERROR;
24571721Saxel.duch@nginx.com             }
24581721Saxel.duch@nginx.com 
24591062Sigor@sysoev.ru             if (ret == 0) {
24601062Sigor@sysoev.ru                 break;
24611062Sigor@sysoev.ru             }
24621062Sigor@sysoev.ru         }
24631062Sigor@sysoev.ru 
24641062Sigor@sysoev.ru         nv++;
24651062Sigor@sysoev.ru     }
24661062Sigor@sysoev.ru 
24671062Sigor@sysoev.ru     return ret;
24681062Sigor@sysoev.ru }
24691062Sigor@sysoev.ru 
24701062Sigor@sysoev.ru 
24711859So.canty@f5.com nxt_int_t
24721059Sigor@sysoev.ru nxt_http_route_test_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule,
24731059Sigor@sysoev.ru     u_char *start, size_t length)
24741059Sigor@sysoev.ru {
24751060Sigor@sysoev.ru     nxt_int_t                 ret;
24761059Sigor@sysoev.ru     nxt_http_route_pattern_t  *pattern, *end;
24771059Sigor@sysoev.ru 
24781057Sigor@sysoev.ru     ret = 1;
2479964Sigor@sysoev.ru     pattern = &rule->pattern[0];
24801033Svbart@nginx.com     end = pattern + rule->items;
2481964Sigor@sysoev.ru 
24821057Sigor@sysoev.ru     while (pattern < end) {
2483964Sigor@sysoev.ru         ret = nxt_http_route_pattern(r, pattern, start, length);
24841721Saxel.duch@nginx.com         if (nxt_slow_path(ret == NXT_ERROR)) {
24851721Saxel.duch@nginx.com             return NXT_ERROR;
24861721Saxel.duch@nginx.com         }
2487964Sigor@sysoev.ru 
24881060Sigor@sysoev.ru         /* nxt_http_route_pattern() returns either 1 or 0. */
2489964Sigor@sysoev.ru         ret ^= pattern->negative;
2490964Sigor@sysoev.ru 
2491964Sigor@sysoev.ru         if (pattern->any == ret) {
2492964Sigor@sysoev.ru             return ret;
2493964Sigor@sysoev.ru         }
2494964Sigor@sysoev.ru 
2495964Sigor@sysoev.ru         pattern++;
24961057Sigor@sysoev.ru     }
2497964Sigor@sysoev.ru 
2498964Sigor@sysoev.ru     return ret;
2499964Sigor@sysoev.ru }
2500964Sigor@sysoev.ru 
2501964Sigor@sysoev.ru 
25021060Sigor@sysoev.ru static nxt_int_t
2503964Sigor@sysoev.ru nxt_http_route_pattern(nxt_http_request_t *r, nxt_http_route_pattern_t *pattern,
2504964Sigor@sysoev.ru     u_char *start, size_t length)
2505964Sigor@sysoev.ru {
25061508Saxel.duch@nginx.com     u_char                          *p, *end, *test;
25071508Saxel.duch@nginx.com     size_t                          test_length;
25081508Saxel.duch@nginx.com     uint32_t                        i;
25091508Saxel.duch@nginx.com     nxt_array_t                     *pattern_slices;
25101508Saxel.duch@nginx.com     nxt_http_route_pattern_slice_t  *pattern_slice;
2511964Sigor@sysoev.ru 
25121721Saxel.duch@nginx.com #if (NXT_HAVE_REGEX)
25131721Saxel.duch@nginx.com     if (pattern->regex) {
25141721Saxel.duch@nginx.com         if (r->regex_match == NULL) {
25151721Saxel.duch@nginx.com             r->regex_match = nxt_regex_match_create(r->mem_pool, 0);
25161721Saxel.duch@nginx.com             if (nxt_slow_path(r->regex_match == NULL)) {
25171721Saxel.duch@nginx.com                 return NXT_ERROR;
25181721Saxel.duch@nginx.com             }
25191721Saxel.duch@nginx.com         }
25201721Saxel.duch@nginx.com 
25211721Saxel.duch@nginx.com         return nxt_regex_match(pattern->u.regex, start, length, r->regex_match);
25221721Saxel.duch@nginx.com     }
25231721Saxel.duch@nginx.com #endif
25241721Saxel.duch@nginx.com 
2525964Sigor@sysoev.ru     if (length < pattern->min_length) {
2526964Sigor@sysoev.ru         return 0;
2527964Sigor@sysoev.ru     }
2528964Sigor@sysoev.ru 
25291721Saxel.duch@nginx.com     nxt_assert(pattern->u.pattern_slices != NULL);
25301721Saxel.duch@nginx.com 
25311721Saxel.duch@nginx.com     pattern_slices = pattern->u.pattern_slices;
25321508Saxel.duch@nginx.com     pattern_slice = pattern_slices->elts;
25331510Saxel.duch@nginx.com     end = start + length;
25341508Saxel.duch@nginx.com 
25351508Saxel.duch@nginx.com     for (i = 0; i < pattern_slices->nelts; i++, pattern_slice++) {
25361508Saxel.duch@nginx.com         test = pattern_slice->start;
25371508Saxel.duch@nginx.com         test_length = pattern_slice->length;
25381508Saxel.duch@nginx.com 
25391508Saxel.duch@nginx.com         switch (pattern_slice->type) {
25401508Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_PATTERN_EXACT:
25411508Saxel.duch@nginx.com             return ((length == pattern->min_length) &&
25421508Saxel.duch@nginx.com                     nxt_http_route_memcmp(start, test, test_length,
25431508Saxel.duch@nginx.com                                           pattern->case_sensitive));
25441508Saxel.duch@nginx.com 
25451508Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_PATTERN_BEGIN:
25461508Saxel.duch@nginx.com             if (nxt_http_route_memcmp(start, test, test_length,
25471508Saxel.duch@nginx.com                                       pattern->case_sensitive))
25481508Saxel.duch@nginx.com             {
25491510Saxel.duch@nginx.com                 start += test_length;
25501508Saxel.duch@nginx.com                 break;
25511508Saxel.duch@nginx.com             }
25521508Saxel.duch@nginx.com 
2553964Sigor@sysoev.ru             return 0;
25541508Saxel.duch@nginx.com 
25551508Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_PATTERN_END:
25561510Saxel.duch@nginx.com             p = end - test_length;
25571508Saxel.duch@nginx.com 
25581508Saxel.duch@nginx.com             if (nxt_http_route_memcmp(p, test, test_length,
25591508Saxel.duch@nginx.com                                       pattern->case_sensitive))
25601508Saxel.duch@nginx.com             {
25611510Saxel.duch@nginx.com                 end = p;
25621508Saxel.duch@nginx.com                 break;
25631508Saxel.duch@nginx.com             }
25641508Saxel.duch@nginx.com 
25651508Saxel.duch@nginx.com             return 0;
25661508Saxel.duch@nginx.com 
25671508Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_PATTERN_SUBSTRING:
25681508Saxel.duch@nginx.com             if (pattern->case_sensitive) {
25691508Saxel.duch@nginx.com                 p = nxt_memstrn(start, end, (char *) test, test_length);
25701508Saxel.duch@nginx.com 
25711508Saxel.duch@nginx.com             } else {
25721508Saxel.duch@nginx.com                 p = nxt_memcasestrn(start, end, (char *) test, test_length);
25731508Saxel.duch@nginx.com             }
25741508Saxel.duch@nginx.com 
25751508Saxel.duch@nginx.com             if (p == NULL) {
25761508Saxel.duch@nginx.com                 return 0;
25771508Saxel.duch@nginx.com             }
25781510Saxel.duch@nginx.com 
25791510Saxel.duch@nginx.com             start = p + test_length;
25801032Sigor@sysoev.ru         }
2581964Sigor@sysoev.ru     }
2582964Sigor@sysoev.ru 
25831508Saxel.duch@nginx.com     return 1;
25841032Sigor@sysoev.ru }
25851032Sigor@sysoev.ru 
25861032Sigor@sysoev.ru 
25871060Sigor@sysoev.ru static nxt_int_t
25881032Sigor@sysoev.ru nxt_http_route_memcmp(u_char *start, u_char *test, size_t test_length,
25891032Sigor@sysoev.ru     nxt_bool_t case_sensitive)
25901032Sigor@sysoev.ru {
25911032Sigor@sysoev.ru     nxt_int_t  n;
25921032Sigor@sysoev.ru 
25931032Sigor@sysoev.ru     if (case_sensitive) {
25941032Sigor@sysoev.ru         n = nxt_memcmp(start, test, test_length);
25951032Sigor@sysoev.ru 
25961032Sigor@sysoev.ru     } else {
25971032Sigor@sysoev.ru         n = nxt_memcasecmp(start, test, test_length);
2598964Sigor@sysoev.ru     }
2599964Sigor@sysoev.ru 
26001032Sigor@sysoev.ru     return (n == 0);
2601964Sigor@sysoev.ru }
2602