xref: /unit/src/nxt_http_route.c (revision 2098)
1964Sigor@sysoev.ru 
2964Sigor@sysoev.ru /*
3964Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
4964Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
5964Sigor@sysoev.ru  */
6964Sigor@sysoev.ru 
7964Sigor@sysoev.ru #include <nxt_router.h>
8964Sigor@sysoev.ru #include <nxt_http.h>
91324Saxel.duch@nginx.com #include <nxt_sockaddr.h>
101324Saxel.duch@nginx.com #include <nxt_http_route_addr.h>
111721Saxel.duch@nginx.com #include <nxt_regex.h>
12964Sigor@sysoev.ru 
13964Sigor@sysoev.ru 
14964Sigor@sysoev.ru typedef enum {
151059Sigor@sysoev.ru     NXT_HTTP_ROUTE_TABLE = 0,
161059Sigor@sysoev.ru     NXT_HTTP_ROUTE_STRING,
17964Sigor@sysoev.ru     NXT_HTTP_ROUTE_STRING_PTR,
18964Sigor@sysoev.ru     NXT_HTTP_ROUTE_HEADER,
19964Sigor@sysoev.ru     NXT_HTTP_ROUTE_ARGUMENT,
20964Sigor@sysoev.ru     NXT_HTTP_ROUTE_COOKIE,
211110Saxel.duch@nginx.com     NXT_HTTP_ROUTE_SCHEME,
221991Sz.hong@f5.com     NXT_HTTP_ROUTE_QUERY,
231324Saxel.duch@nginx.com     NXT_HTTP_ROUTE_SOURCE,
241326Saxel.duch@nginx.com     NXT_HTTP_ROUTE_DESTINATION,
25964Sigor@sysoev.ru } nxt_http_route_object_t;
26964Sigor@sysoev.ru 
27964Sigor@sysoev.ru 
28964Sigor@sysoev.ru typedef enum {
29964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_EXACT = 0,
30964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_BEGIN,
31964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_END,
32964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_SUBSTRING,
33964Sigor@sysoev.ru } nxt_http_route_pattern_type_t;
34964Sigor@sysoev.ru 
35964Sigor@sysoev.ru 
36964Sigor@sysoev.ru typedef enum {
37964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_NOCASE = 0,
38964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_LOWCASE,
39964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_UPCASE,
40964Sigor@sysoev.ru } nxt_http_route_pattern_case_t;
41964Sigor@sysoev.ru 
42964Sigor@sysoev.ru 
431474Saxel.duch@nginx.com typedef enum {
441474Saxel.duch@nginx.com     NXT_HTTP_ROUTE_ENCODING_NONE = 0,
451474Saxel.duch@nginx.com     NXT_HTTP_ROUTE_ENCODING_URI,
461474Saxel.duch@nginx.com     NXT_HTTP_ROUTE_ENCODING_URI_PLUS
471474Saxel.duch@nginx.com } nxt_http_route_encoding_t;
481474Saxel.duch@nginx.com 
491474Saxel.duch@nginx.com 
50964Sigor@sysoev.ru typedef struct {
51964Sigor@sysoev.ru     nxt_conf_value_t               *host;
52964Sigor@sysoev.ru     nxt_conf_value_t               *uri;
53964Sigor@sysoev.ru     nxt_conf_value_t               *method;
541059Sigor@sysoev.ru     nxt_conf_value_t               *headers;
551061Sigor@sysoev.ru     nxt_conf_value_t               *arguments;
561062Sigor@sysoev.ru     nxt_conf_value_t               *cookies;
571110Saxel.duch@nginx.com     nxt_conf_value_t               *scheme;
581991Sz.hong@f5.com     nxt_conf_value_t               *query;
591324Saxel.duch@nginx.com     nxt_conf_value_t               *source;
601326Saxel.duch@nginx.com     nxt_conf_value_t               *destination;
61964Sigor@sysoev.ru } nxt_http_route_match_conf_t;
62964Sigor@sysoev.ru 
63964Sigor@sysoev.ru 
64964Sigor@sysoev.ru typedef struct {
651508Saxel.duch@nginx.com     u_char                         *start;
661508Saxel.duch@nginx.com     uint32_t                       length;
671508Saxel.duch@nginx.com     nxt_http_route_pattern_type_t  type:8;
681508Saxel.duch@nginx.com } nxt_http_route_pattern_slice_t;
691508Saxel.duch@nginx.com 
701508Saxel.duch@nginx.com 
711508Saxel.duch@nginx.com typedef struct {
721721Saxel.duch@nginx.com     union {
731721Saxel.duch@nginx.com         nxt_array_t                *pattern_slices;
741721Saxel.duch@nginx.com #if (NXT_HAVE_REGEX)
751721Saxel.duch@nginx.com         nxt_regex_t                *regex;
761721Saxel.duch@nginx.com #endif
771721Saxel.duch@nginx.com     } u;
78964Sigor@sysoev.ru     uint32_t                       min_length;
791508Saxel.duch@nginx.com 
80964Sigor@sysoev.ru     uint8_t                        case_sensitive;  /* 1 bit */
81964Sigor@sysoev.ru     uint8_t                        negative;        /* 1 bit */
82964Sigor@sysoev.ru     uint8_t                        any;             /* 1 bit */
831721Saxel.duch@nginx.com #if (NXT_HAVE_REGEX)
841721Saxel.duch@nginx.com     uint8_t                        regex;           /* 1 bit */
851721Saxel.duch@nginx.com #endif
86964Sigor@sysoev.ru } nxt_http_route_pattern_t;
87964Sigor@sysoev.ru 
88964Sigor@sysoev.ru 
89964Sigor@sysoev.ru typedef struct {
901061Sigor@sysoev.ru     uint16_t                       hash;
911061Sigor@sysoev.ru     uint16_t                       name_length;
921061Sigor@sysoev.ru     uint32_t                       value_length;
931061Sigor@sysoev.ru     u_char                         *name;
941061Sigor@sysoev.ru     u_char                         *value;
951061Sigor@sysoev.ru } nxt_http_name_value_t;
961061Sigor@sysoev.ru 
971061Sigor@sysoev.ru 
981061Sigor@sysoev.ru typedef struct {
991062Sigor@sysoev.ru     uint16_t                       hash;
1001062Sigor@sysoev.ru     uint16_t                       name_length;
1011062Sigor@sysoev.ru     uint32_t                       value_length;
1021062Sigor@sysoev.ru     u_char                         *name;
1031062Sigor@sysoev.ru     u_char                         *value;
1041062Sigor@sysoev.ru } nxt_http_cookie_t;
1051062Sigor@sysoev.ru 
1061062Sigor@sysoev.ru 
1071859So.canty@f5.com struct nxt_http_route_rule_s {
1081059Sigor@sysoev.ru     /* The object must be the first field. */
1091059Sigor@sysoev.ru     nxt_http_route_object_t        object:8;
110964Sigor@sysoev.ru     uint32_t                       items;
1111059Sigor@sysoev.ru 
1121059Sigor@sysoev.ru     union {
1131059Sigor@sysoev.ru         uintptr_t                  offset;
1141059Sigor@sysoev.ru 
1151059Sigor@sysoev.ru         struct {
1161059Sigor@sysoev.ru             u_char                 *start;
1171059Sigor@sysoev.ru             uint16_t               hash;
1181059Sigor@sysoev.ru             uint16_t               length;
1191059Sigor@sysoev.ru         } name;
1201059Sigor@sysoev.ru     } u;
1211059Sigor@sysoev.ru 
122964Sigor@sysoev.ru     nxt_http_route_pattern_t       pattern[0];
1231859So.canty@f5.com };
124964Sigor@sysoev.ru 
125964Sigor@sysoev.ru 
126964Sigor@sysoev.ru typedef struct {
127964Sigor@sysoev.ru     uint32_t                       items;
1281059Sigor@sysoev.ru     nxt_http_route_rule_t          *rule[0];
1291059Sigor@sysoev.ru } nxt_http_route_ruleset_t;
1301059Sigor@sysoev.ru 
1311059Sigor@sysoev.ru 
1321059Sigor@sysoev.ru typedef struct {
1331059Sigor@sysoev.ru     /* The object must be the first field. */
1341059Sigor@sysoev.ru     nxt_http_route_object_t        object:8;
1351059Sigor@sysoev.ru     uint32_t                       items;
1361059Sigor@sysoev.ru     nxt_http_route_ruleset_t       *ruleset[0];
1371059Sigor@sysoev.ru } nxt_http_route_table_t;
1381059Sigor@sysoev.ru 
1391059Sigor@sysoev.ru 
1401936So.canty@f5.com struct nxt_http_route_addr_rule_s {
1411324Saxel.duch@nginx.com     /* The object must be the first field. */
1421324Saxel.duch@nginx.com     nxt_http_route_object_t        object:8;
1431324Saxel.duch@nginx.com     uint32_t                       items;
1441324Saxel.duch@nginx.com     nxt_http_route_addr_pattern_t  addr_pattern[0];
1451936So.canty@f5.com };
1461324Saxel.duch@nginx.com 
1471324Saxel.duch@nginx.com 
1481059Sigor@sysoev.ru typedef union {
1491059Sigor@sysoev.ru     nxt_http_route_rule_t          *rule;
1501059Sigor@sysoev.ru     nxt_http_route_table_t         *table;
1511324Saxel.duch@nginx.com     nxt_http_route_addr_rule_t     *addr_rule;
1521059Sigor@sysoev.ru } nxt_http_route_test_t;
1531059Sigor@sysoev.ru 
1541059Sigor@sysoev.ru 
1551059Sigor@sysoev.ru typedef struct {
1561059Sigor@sysoev.ru     uint32_t                       items;
1571264Sigor@sysoev.ru     nxt_http_action_t              action;
1581059Sigor@sysoev.ru     nxt_http_route_test_t          test[0];
159964Sigor@sysoev.ru } nxt_http_route_match_t;
160964Sigor@sysoev.ru 
161964Sigor@sysoev.ru 
162964Sigor@sysoev.ru struct nxt_http_route_s {
163964Sigor@sysoev.ru     nxt_str_t                      name;
164964Sigor@sysoev.ru     uint32_t                       items;
165964Sigor@sysoev.ru     nxt_http_route_match_t         *match[0];
166964Sigor@sysoev.ru };
167964Sigor@sysoev.ru 
168964Sigor@sysoev.ru 
169964Sigor@sysoev.ru struct nxt_http_routes_s {
170964Sigor@sysoev.ru     uint32_t                       items;
171964Sigor@sysoev.ru     nxt_http_route_t               *route[0];
172964Sigor@sysoev.ru };
173964Sigor@sysoev.ru 
174964Sigor@sysoev.ru 
1751522Saxel.duch@nginx.com #define NXT_COOKIE_HASH                                                       \
1761062Sigor@sysoev.ru     (nxt_http_field_hash_end(                                                 \
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(                                                \
1811062Sigor@sysoev.ru      nxt_http_field_hash_char(                                                \
1821062Sigor@sysoev.ru      nxt_http_field_hash_char(NXT_HTTP_FIELD_HASH_INIT,                       \
1831062Sigor@sysoev.ru         'c'), 'o'), 'o'), 'k'), 'i'), 'e')) & 0xFFFF)
1841062Sigor@sysoev.ru 
1851062Sigor@sysoev.ru 
186964Sigor@sysoev.ru static nxt_http_route_t *nxt_http_route_create(nxt_task_t *task,
187964Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv);
188964Sigor@sysoev.ru static nxt_http_route_match_t *nxt_http_route_match_create(nxt_task_t *task,
189964Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv);
1901059Sigor@sysoev.ru static nxt_http_route_table_t *nxt_http_route_table_create(nxt_task_t *task,
1911061Sigor@sysoev.ru     nxt_mp_t *mp, nxt_conf_value_t *table_cv, nxt_http_route_object_t object,
1921474Saxel.duch@nginx.com     nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding);
1931059Sigor@sysoev.ru static nxt_http_route_ruleset_t *nxt_http_route_ruleset_create(nxt_task_t *task,
1941061Sigor@sysoev.ru     nxt_mp_t *mp, nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object,
1951474Saxel.duch@nginx.com     nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding);
1961061Sigor@sysoev.ru static nxt_http_route_rule_t *nxt_http_route_rule_name_create(nxt_task_t *task,
1971061Sigor@sysoev.ru     nxt_mp_t *mp, nxt_conf_value_t *rule_cv, nxt_str_t *name,
1981474Saxel.duch@nginx.com     nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding);
199964Sigor@sysoev.ru static nxt_http_route_rule_t *nxt_http_route_rule_create(nxt_task_t *task,
2001059Sigor@sysoev.ru     nxt_mp_t *mp, nxt_conf_value_t *cv, nxt_bool_t case_sensitive,
2011474Saxel.duch@nginx.com     nxt_http_route_pattern_case_t pattern_case,
2021474Saxel.duch@nginx.com     nxt_http_route_encoding_t encoding);
203964Sigor@sysoev.ru static int nxt_http_pattern_compare(const void *one, const void *two);
2041390Saxel.duch@nginx.com static int nxt_http_addr_pattern_compare(const void *one, const void *two);
205964Sigor@sysoev.ru static nxt_int_t nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp,
206964Sigor@sysoev.ru     nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern,
2071474Saxel.duch@nginx.com     nxt_http_route_pattern_case_t pattern_case,
2081474Saxel.duch@nginx.com     nxt_http_route_encoding_t encoding);
2091474Saxel.duch@nginx.com static nxt_int_t nxt_http_route_decode_str(nxt_str_t *str,
2101474Saxel.duch@nginx.com     nxt_http_route_encoding_t encoding);
2111508Saxel.duch@nginx.com static nxt_int_t nxt_http_route_pattern_slice(nxt_array_t *slices,
2121508Saxel.duch@nginx.com     nxt_str_t *test,
2131508Saxel.duch@nginx.com     nxt_http_route_pattern_type_t type,
2141508Saxel.duch@nginx.com     nxt_http_route_encoding_t encoding,
2151032Sigor@sysoev.ru     nxt_http_route_pattern_case_t pattern_case);
216964Sigor@sysoev.ru 
2171472Svbart@nginx.com static nxt_int_t nxt_http_route_resolve(nxt_task_t *task,
218964Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_http_route_t *route);
2191472Svbart@nginx.com static nxt_int_t nxt_http_action_resolve(nxt_task_t *task,
2201264Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_http_action_t *action);
2211954Sz.hong@f5.com static nxt_http_action_t *nxt_http_pass_var(nxt_task_t *task,
2221563Svbart@nginx.com     nxt_http_request_t *r, nxt_http_action_t *action);
2231954Sz.hong@f5.com static void nxt_http_pass_var_ready(nxt_task_t *task, void *obj, void *data);
2241954Sz.hong@f5.com static void nxt_http_pass_var_error(nxt_task_t *task, void *obj, void *data);
2251954Sz.hong@f5.com static nxt_int_t nxt_http_pass_find(nxt_mp_t *mp, nxt_router_conf_t *rtcf,
2261954Sz.hong@f5.com     nxt_str_t *pass, nxt_http_action_t *action);
2271563Svbart@nginx.com static nxt_int_t nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name,
2281392Sigor@sysoev.ru     nxt_http_action_t *action);
229964Sigor@sysoev.ru 
2301264Sigor@sysoev.ru static nxt_http_action_t *nxt_http_route_handler(nxt_task_t *task,
2311264Sigor@sysoev.ru     nxt_http_request_t *r, nxt_http_action_t *start);
2321326Saxel.duch@nginx.com static nxt_http_action_t *nxt_http_route_match(nxt_task_t *task,
2331326Saxel.duch@nginx.com     nxt_http_request_t *r, nxt_http_route_match_t *match);
2341060Sigor@sysoev.ru static nxt_int_t nxt_http_route_table(nxt_http_request_t *r,
2351059Sigor@sysoev.ru     nxt_http_route_table_t *table);
2361060Sigor@sysoev.ru static nxt_int_t nxt_http_route_ruleset(nxt_http_request_t *r,
2371059Sigor@sysoev.ru     nxt_http_route_ruleset_t *ruleset);
2381060Sigor@sysoev.ru static nxt_int_t nxt_http_route_rule(nxt_http_request_t *r,
239964Sigor@sysoev.ru     nxt_http_route_rule_t *rule);
2401060Sigor@sysoev.ru static nxt_int_t nxt_http_route_header(nxt_http_request_t *r,
2411059Sigor@sysoev.ru     nxt_http_route_rule_t *rule);
2421061Sigor@sysoev.ru static nxt_int_t nxt_http_route_arguments(nxt_http_request_t *r,
2431061Sigor@sysoev.ru     nxt_http_route_rule_t *rule);
2441061Sigor@sysoev.ru static nxt_array_t *nxt_http_route_arguments_parse(nxt_http_request_t *r);
2451061Sigor@sysoev.ru static nxt_http_name_value_t *nxt_http_route_argument(nxt_array_t *array,
2461061Sigor@sysoev.ru     u_char *name, size_t name_length, uint32_t hash, u_char *start,
2471061Sigor@sysoev.ru     u_char *end);
2481061Sigor@sysoev.ru static nxt_int_t nxt_http_route_test_argument(nxt_http_request_t *r,
2491061Sigor@sysoev.ru     nxt_http_route_rule_t *rule, nxt_array_t *array);
2501110Saxel.duch@nginx.com static nxt_int_t nxt_http_route_scheme(nxt_http_request_t *r,
2511110Saxel.duch@nginx.com     nxt_http_route_rule_t *rule);
2521991Sz.hong@f5.com static nxt_int_t nxt_http_route_query(nxt_http_request_t *r,
2531991Sz.hong@f5.com     nxt_http_route_rule_t *rule);
2541062Sigor@sysoev.ru static nxt_int_t nxt_http_route_cookies(nxt_http_request_t *r,
2551062Sigor@sysoev.ru     nxt_http_route_rule_t *rule);
2561062Sigor@sysoev.ru static nxt_array_t *nxt_http_route_cookies_parse(nxt_http_request_t *r);
2571062Sigor@sysoev.ru static nxt_int_t nxt_http_route_cookie_parse(nxt_array_t *cookies,
2581062Sigor@sysoev.ru     u_char *start, u_char *end);
2591062Sigor@sysoev.ru static nxt_http_name_value_t *nxt_http_route_cookie(nxt_array_t *array,
2601062Sigor@sysoev.ru     u_char *name, size_t name_length, u_char *start, u_char *end);
2611062Sigor@sysoev.ru static nxt_int_t nxt_http_route_test_cookie(nxt_http_request_t *r,
2621062Sigor@sysoev.ru     nxt_http_route_rule_t *rule, nxt_array_t *array);
2631060Sigor@sysoev.ru static nxt_int_t nxt_http_route_pattern(nxt_http_request_t *r,
264964Sigor@sysoev.ru     nxt_http_route_pattern_t *pattern, u_char *start, size_t length);
2651060Sigor@sysoev.ru static nxt_int_t nxt_http_route_memcmp(u_char *start, u_char *test,
2661032Sigor@sysoev.ru     size_t length, nxt_bool_t case_sensitive);
267964Sigor@sysoev.ru 
268964Sigor@sysoev.ru 
269964Sigor@sysoev.ru nxt_http_routes_t *
270964Sigor@sysoev.ru nxt_http_routes_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
271964Sigor@sysoev.ru     nxt_conf_value_t *routes_conf)
272964Sigor@sysoev.ru {
273964Sigor@sysoev.ru     size_t             size;
274964Sigor@sysoev.ru     uint32_t           i, n, next;
275964Sigor@sysoev.ru     nxt_mp_t           *mp;
276964Sigor@sysoev.ru     nxt_str_t          name, *string;
277964Sigor@sysoev.ru     nxt_bool_t         object;
278964Sigor@sysoev.ru     nxt_conf_value_t   *route_conf;
279964Sigor@sysoev.ru     nxt_http_route_t   *route;
280964Sigor@sysoev.ru     nxt_http_routes_t  *routes;
281964Sigor@sysoev.ru 
282964Sigor@sysoev.ru     object = (nxt_conf_type(routes_conf) == NXT_CONF_OBJECT);
283964Sigor@sysoev.ru     n = object ? nxt_conf_object_members_count(routes_conf) : 1;
284964Sigor@sysoev.ru     size = sizeof(nxt_http_routes_t) + n * sizeof(nxt_http_route_t *);
285964Sigor@sysoev.ru 
286964Sigor@sysoev.ru     mp = tmcf->router_conf->mem_pool;
287964Sigor@sysoev.ru 
288964Sigor@sysoev.ru     routes = nxt_mp_alloc(mp, size);
289964Sigor@sysoev.ru     if (nxt_slow_path(routes == NULL)) {
290964Sigor@sysoev.ru         return NULL;
291964Sigor@sysoev.ru     }
292964Sigor@sysoev.ru 
293964Sigor@sysoev.ru     routes->items = n;
294964Sigor@sysoev.ru 
295964Sigor@sysoev.ru     if (object) {
296964Sigor@sysoev.ru         next = 0;
297964Sigor@sysoev.ru 
298964Sigor@sysoev.ru         for (i = 0; i < n; i++) {
299964Sigor@sysoev.ru             route_conf = nxt_conf_next_object_member(routes_conf, &name, &next);
300964Sigor@sysoev.ru 
301964Sigor@sysoev.ru             route = nxt_http_route_create(task, tmcf, route_conf);
302964Sigor@sysoev.ru             if (nxt_slow_path(route == NULL)) {
303964Sigor@sysoev.ru                 return NULL;
304964Sigor@sysoev.ru             }
305964Sigor@sysoev.ru 
306964Sigor@sysoev.ru             routes->route[i] = route;
307964Sigor@sysoev.ru 
308964Sigor@sysoev.ru             string = nxt_str_dup(mp, &route->name, &name);
309964Sigor@sysoev.ru             if (nxt_slow_path(string == NULL)) {
310964Sigor@sysoev.ru                 return NULL;
311964Sigor@sysoev.ru             }
312964Sigor@sysoev.ru         }
313964Sigor@sysoev.ru 
314964Sigor@sysoev.ru     } else {
315964Sigor@sysoev.ru         route = nxt_http_route_create(task, tmcf, routes_conf);
316964Sigor@sysoev.ru         if (nxt_slow_path(route == NULL)) {
317964Sigor@sysoev.ru             return NULL;
318964Sigor@sysoev.ru         }
319964Sigor@sysoev.ru 
320964Sigor@sysoev.ru         routes->route[0] = route;
321964Sigor@sysoev.ru 
322964Sigor@sysoev.ru         route->name.length = 0;
323964Sigor@sysoev.ru         route->name.start = NULL;
324964Sigor@sysoev.ru     }
325964Sigor@sysoev.ru 
326964Sigor@sysoev.ru     return routes;
327964Sigor@sysoev.ru }
328964Sigor@sysoev.ru 
329964Sigor@sysoev.ru 
330964Sigor@sysoev.ru static nxt_conf_map_t  nxt_http_route_match_conf[] = {
331964Sigor@sysoev.ru     {
3321110Saxel.duch@nginx.com         nxt_string("scheme"),
3331110Saxel.duch@nginx.com         NXT_CONF_MAP_PTR,
3341110Saxel.duch@nginx.com         offsetof(nxt_http_route_match_conf_t, scheme)
3351110Saxel.duch@nginx.com     },
3361110Saxel.duch@nginx.com     {
337964Sigor@sysoev.ru         nxt_string("host"),
338964Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
339964Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, host),
340964Sigor@sysoev.ru     },
341964Sigor@sysoev.ru 
342964Sigor@sysoev.ru     {
343964Sigor@sysoev.ru         nxt_string("uri"),
344964Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
345964Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, uri),
346964Sigor@sysoev.ru     },
347964Sigor@sysoev.ru 
348964Sigor@sysoev.ru     {
349964Sigor@sysoev.ru         nxt_string("method"),
350964Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
351964Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, method),
352964Sigor@sysoev.ru     },
3531059Sigor@sysoev.ru 
3541059Sigor@sysoev.ru     {
3551059Sigor@sysoev.ru         nxt_string("headers"),
3561059Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
3571059Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, headers),
3581059Sigor@sysoev.ru     },
3591061Sigor@sysoev.ru 
3601061Sigor@sysoev.ru     {
3611061Sigor@sysoev.ru         nxt_string("arguments"),
3621061Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
3631061Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, arguments),
3641061Sigor@sysoev.ru     },
3651062Sigor@sysoev.ru 
3661062Sigor@sysoev.ru     {
3671062Sigor@sysoev.ru         nxt_string("cookies"),
3681062Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
3691062Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, cookies),
3701062Sigor@sysoev.ru     },
3711324Saxel.duch@nginx.com 
3721324Saxel.duch@nginx.com     {
3731991Sz.hong@f5.com         nxt_string("query"),
3741991Sz.hong@f5.com         NXT_CONF_MAP_PTR,
3751991Sz.hong@f5.com         offsetof(nxt_http_route_match_conf_t, query),
3761991Sz.hong@f5.com     },
3771991Sz.hong@f5.com 
3781991Sz.hong@f5.com     {
3791324Saxel.duch@nginx.com         nxt_string("source"),
3801324Saxel.duch@nginx.com         NXT_CONF_MAP_PTR,
3811324Saxel.duch@nginx.com         offsetof(nxt_http_route_match_conf_t, source),
3821324Saxel.duch@nginx.com     },
3831326Saxel.duch@nginx.com 
3841326Saxel.duch@nginx.com     {
3851326Saxel.duch@nginx.com         nxt_string("destination"),
3861326Saxel.duch@nginx.com         NXT_CONF_MAP_PTR,
3871326Saxel.duch@nginx.com         offsetof(nxt_http_route_match_conf_t, destination),
3881326Saxel.duch@nginx.com     },
389964Sigor@sysoev.ru };
390964Sigor@sysoev.ru 
391964Sigor@sysoev.ru 
392964Sigor@sysoev.ru static nxt_http_route_t *
393964Sigor@sysoev.ru nxt_http_route_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
394964Sigor@sysoev.ru     nxt_conf_value_t *cv)
395964Sigor@sysoev.ru {
396964Sigor@sysoev.ru     size_t                  size;
397964Sigor@sysoev.ru     uint32_t                i, n;
398964Sigor@sysoev.ru     nxt_conf_value_t        *value;
399964Sigor@sysoev.ru     nxt_http_route_t        *route;
400964Sigor@sysoev.ru     nxt_http_route_match_t  *match, **m;
401964Sigor@sysoev.ru 
402964Sigor@sysoev.ru     n = nxt_conf_array_elements_count(cv);
403964Sigor@sysoev.ru     size = sizeof(nxt_http_route_t) + n * sizeof(nxt_http_route_match_t *);
404964Sigor@sysoev.ru 
405964Sigor@sysoev.ru     route = nxt_mp_alloc(tmcf->router_conf->mem_pool, size);
406964Sigor@sysoev.ru     if (nxt_slow_path(route == NULL)) {
407964Sigor@sysoev.ru         return NULL;
408964Sigor@sysoev.ru     }
409964Sigor@sysoev.ru 
410964Sigor@sysoev.ru     route->items = n;
411964Sigor@sysoev.ru     m = &route->match[0];
412964Sigor@sysoev.ru 
413964Sigor@sysoev.ru     for (i = 0; i < n; i++) {
414964Sigor@sysoev.ru         value = nxt_conf_get_array_element(cv, i);
415964Sigor@sysoev.ru 
416964Sigor@sysoev.ru         match = nxt_http_route_match_create(task, tmcf, value);
417964Sigor@sysoev.ru         if (match == NULL) {
418964Sigor@sysoev.ru             return NULL;
419964Sigor@sysoev.ru         }
420964Sigor@sysoev.ru 
421964Sigor@sysoev.ru         *m++ = match;
422964Sigor@sysoev.ru     }
423964Sigor@sysoev.ru 
424964Sigor@sysoev.ru     return route;
425964Sigor@sysoev.ru }
426964Sigor@sysoev.ru 
427964Sigor@sysoev.ru 
428964Sigor@sysoev.ru static nxt_http_route_match_t *
429964Sigor@sysoev.ru nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
430964Sigor@sysoev.ru     nxt_conf_value_t *cv)
431964Sigor@sysoev.ru {
432964Sigor@sysoev.ru     size_t                       size;
433964Sigor@sysoev.ru     uint32_t                     n;
4341059Sigor@sysoev.ru     nxt_mp_t                     *mp;
435964Sigor@sysoev.ru     nxt_int_t                    ret;
4361378Svbart@nginx.com     nxt_conf_value_t             *match_conf, *action_conf;
4371059Sigor@sysoev.ru     nxt_http_route_test_t        *test;
4381059Sigor@sysoev.ru     nxt_http_route_rule_t        *rule;
4391059Sigor@sysoev.ru     nxt_http_route_table_t       *table;
440964Sigor@sysoev.ru     nxt_http_route_match_t       *match;
4411324Saxel.duch@nginx.com     nxt_http_route_addr_rule_t   *addr_rule;
442964Sigor@sysoev.ru     nxt_http_route_match_conf_t  mtcf;
443964Sigor@sysoev.ru 
444964Sigor@sysoev.ru     static nxt_str_t  match_path = nxt_string("/match");
4451378Svbart@nginx.com     static nxt_str_t  action_path = nxt_string("/action");
446964Sigor@sysoev.ru 
447964Sigor@sysoev.ru     match_conf = nxt_conf_get_path(cv, &match_path);
448964Sigor@sysoev.ru 
449964Sigor@sysoev.ru     n = (match_conf != NULL) ? nxt_conf_object_members_count(match_conf) : 0;
4501859So.canty@f5.com     size = sizeof(nxt_http_route_match_t) + n * sizeof(nxt_http_route_test_t *);
451964Sigor@sysoev.ru 
4521059Sigor@sysoev.ru     mp = tmcf->router_conf->mem_pool;
4531059Sigor@sysoev.ru 
4541059Sigor@sysoev.ru     match = nxt_mp_alloc(mp, size);
455964Sigor@sysoev.ru     if (nxt_slow_path(match == NULL)) {
456964Sigor@sysoev.ru         return NULL;
457964Sigor@sysoev.ru     }
458964Sigor@sysoev.ru 
459964Sigor@sysoev.ru     match->items = n;
460964Sigor@sysoev.ru 
4611378Svbart@nginx.com     action_conf = nxt_conf_get_path(cv, &action_path);
4621378Svbart@nginx.com     if (nxt_slow_path(action_conf == NULL)) {
4631378Svbart@nginx.com         return NULL;
4641378Svbart@nginx.com     }
4651378Svbart@nginx.com 
4661903Sz.hong@f5.com     ret = nxt_http_action_init(task, tmcf, action_conf, &match->action);
4671264Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
468964Sigor@sysoev.ru         return NULL;
469964Sigor@sysoev.ru     }
470964Sigor@sysoev.ru 
471964Sigor@sysoev.ru     if (n == 0) {
472964Sigor@sysoev.ru         return match;
473964Sigor@sysoev.ru     }
474964Sigor@sysoev.ru 
475964Sigor@sysoev.ru     nxt_memzero(&mtcf, sizeof(mtcf));
476964Sigor@sysoev.ru 
477964Sigor@sysoev.ru     ret = nxt_conf_map_object(tmcf->mem_pool,
478964Sigor@sysoev.ru                               match_conf, nxt_http_route_match_conf,
479964Sigor@sysoev.ru                               nxt_nitems(nxt_http_route_match_conf), &mtcf);
480964Sigor@sysoev.ru     if (ret != NXT_OK) {
481964Sigor@sysoev.ru         return NULL;
482964Sigor@sysoev.ru     }
483964Sigor@sysoev.ru 
4841059Sigor@sysoev.ru     test = &match->test[0];
485964Sigor@sysoev.ru 
4861110Saxel.duch@nginx.com     if (mtcf.scheme != NULL) {
4871110Saxel.duch@nginx.com         rule = nxt_http_route_rule_create(task, mp, mtcf.scheme, 1,
4881474Saxel.duch@nginx.com                                           NXT_HTTP_ROUTE_PATTERN_NOCASE,
4891474Saxel.duch@nginx.com                                           NXT_HTTP_ROUTE_ENCODING_NONE);
4901110Saxel.duch@nginx.com         if (rule == NULL) {
4911110Saxel.duch@nginx.com             return NULL;
4921110Saxel.duch@nginx.com         }
4931110Saxel.duch@nginx.com 
4941110Saxel.duch@nginx.com         rule->object = NXT_HTTP_ROUTE_SCHEME;
4951110Saxel.duch@nginx.com         test->rule = rule;
4961110Saxel.duch@nginx.com         test++;
4971110Saxel.duch@nginx.com     }
4981110Saxel.duch@nginx.com 
499964Sigor@sysoev.ru     if (mtcf.host != NULL) {
5001059Sigor@sysoev.ru         rule = nxt_http_route_rule_create(task, mp, mtcf.host, 1,
5011474Saxel.duch@nginx.com                                           NXT_HTTP_ROUTE_PATTERN_LOWCASE,
5021474Saxel.duch@nginx.com                                           NXT_HTTP_ROUTE_ENCODING_NONE);
503964Sigor@sysoev.ru         if (rule == NULL) {
504964Sigor@sysoev.ru             return NULL;
505964Sigor@sysoev.ru         }
506964Sigor@sysoev.ru 
5071059Sigor@sysoev.ru         rule->u.offset = offsetof(nxt_http_request_t, host);
508964Sigor@sysoev.ru         rule->object = NXT_HTTP_ROUTE_STRING;
5091059Sigor@sysoev.ru         test->rule = rule;
5101059Sigor@sysoev.ru         test++;
511964Sigor@sysoev.ru     }
512964Sigor@sysoev.ru 
513964Sigor@sysoev.ru     if (mtcf.uri != NULL) {
5141059Sigor@sysoev.ru         rule = nxt_http_route_rule_create(task, mp, mtcf.uri, 1,
5151474Saxel.duch@nginx.com                                           NXT_HTTP_ROUTE_PATTERN_NOCASE,
5161474Saxel.duch@nginx.com                                           NXT_HTTP_ROUTE_ENCODING_URI);
517964Sigor@sysoev.ru         if (rule == NULL) {
518964Sigor@sysoev.ru             return NULL;
519964Sigor@sysoev.ru         }
520964Sigor@sysoev.ru 
5211059Sigor@sysoev.ru         rule->u.offset = offsetof(nxt_http_request_t, path);
522964Sigor@sysoev.ru         rule->object = NXT_HTTP_ROUTE_STRING_PTR;
5231059Sigor@sysoev.ru         test->rule = rule;
5241059Sigor@sysoev.ru         test++;
525964Sigor@sysoev.ru     }
526964Sigor@sysoev.ru 
527964Sigor@sysoev.ru     if (mtcf.method != NULL) {
5281059Sigor@sysoev.ru         rule = nxt_http_route_rule_create(task, mp, mtcf.method, 1,
5291474Saxel.duch@nginx.com                                           NXT_HTTP_ROUTE_PATTERN_UPCASE,
5301474Saxel.duch@nginx.com                                           NXT_HTTP_ROUTE_ENCODING_NONE);
531964Sigor@sysoev.ru         if (rule == NULL) {
532964Sigor@sysoev.ru             return NULL;
533964Sigor@sysoev.ru         }
534964Sigor@sysoev.ru 
5351059Sigor@sysoev.ru         rule->u.offset = offsetof(nxt_http_request_t, method);
536964Sigor@sysoev.ru         rule->object = NXT_HTTP_ROUTE_STRING_PTR;
5371059Sigor@sysoev.ru         test->rule = rule;
5381059Sigor@sysoev.ru         test++;
5391059Sigor@sysoev.ru     }
5401059Sigor@sysoev.ru 
5411059Sigor@sysoev.ru     if (mtcf.headers != NULL) {
5421061Sigor@sysoev.ru         table = nxt_http_route_table_create(task, mp, mtcf.headers,
5431474Saxel.duch@nginx.com                                             NXT_HTTP_ROUTE_HEADER, 0,
5441474Saxel.duch@nginx.com                                             NXT_HTTP_ROUTE_ENCODING_NONE);
5451061Sigor@sysoev.ru         if (table == NULL) {
5461061Sigor@sysoev.ru             return NULL;
5471061Sigor@sysoev.ru         }
5481061Sigor@sysoev.ru 
5491061Sigor@sysoev.ru         test->table = table;
5501061Sigor@sysoev.ru         test++;
5511061Sigor@sysoev.ru     }
5521061Sigor@sysoev.ru 
5531061Sigor@sysoev.ru     if (mtcf.arguments != NULL) {
5541061Sigor@sysoev.ru         table = nxt_http_route_table_create(task, mp, mtcf.arguments,
5551474Saxel.duch@nginx.com                                             NXT_HTTP_ROUTE_ARGUMENT, 1,
5561474Saxel.duch@nginx.com                                             NXT_HTTP_ROUTE_ENCODING_URI_PLUS);
5571059Sigor@sysoev.ru         if (table == NULL) {
5581059Sigor@sysoev.ru             return NULL;
5591059Sigor@sysoev.ru         }
5601059Sigor@sysoev.ru 
5611059Sigor@sysoev.ru         test->table = table;
5621059Sigor@sysoev.ru         test++;
563964Sigor@sysoev.ru     }
564964Sigor@sysoev.ru 
5651062Sigor@sysoev.ru     if (mtcf.cookies != NULL) {
5661062Sigor@sysoev.ru         table = nxt_http_route_table_create(task, mp, mtcf.cookies,
5671474Saxel.duch@nginx.com                                             NXT_HTTP_ROUTE_COOKIE, 1,
5681474Saxel.duch@nginx.com                                             NXT_HTTP_ROUTE_ENCODING_NONE);
5691062Sigor@sysoev.ru         if (table == NULL) {
5701062Sigor@sysoev.ru             return NULL;
5711062Sigor@sysoev.ru         }
5721062Sigor@sysoev.ru 
5731062Sigor@sysoev.ru         test->table = table;
5741062Sigor@sysoev.ru         test++;
5751062Sigor@sysoev.ru     }
5761062Sigor@sysoev.ru 
5771991Sz.hong@f5.com     if (mtcf.query != NULL) {
5781991Sz.hong@f5.com         rule = nxt_http_route_rule_create(task, mp, mtcf.query, 1,
5791991Sz.hong@f5.com                                           NXT_HTTP_ROUTE_PATTERN_NOCASE,
5801991Sz.hong@f5.com                                           NXT_HTTP_ROUTE_ENCODING_URI_PLUS);
5811991Sz.hong@f5.com         if (rule == NULL) {
5821991Sz.hong@f5.com             return NULL;
5831991Sz.hong@f5.com         }
5841991Sz.hong@f5.com 
5851991Sz.hong@f5.com         rule->object = NXT_HTTP_ROUTE_QUERY;
5861991Sz.hong@f5.com         test->rule = rule;
5871991Sz.hong@f5.com         test++;
5881991Sz.hong@f5.com     }
5891991Sz.hong@f5.com 
5901324Saxel.duch@nginx.com     if (mtcf.source != NULL) {
5911324Saxel.duch@nginx.com         addr_rule = nxt_http_route_addr_rule_create(task, mp, mtcf.source);
5921324Saxel.duch@nginx.com         if (addr_rule == NULL) {
5931324Saxel.duch@nginx.com             return NULL;
5941324Saxel.duch@nginx.com         }
5951324Saxel.duch@nginx.com 
5961324Saxel.duch@nginx.com         addr_rule->object = NXT_HTTP_ROUTE_SOURCE;
5971324Saxel.duch@nginx.com         test->addr_rule = addr_rule;
5981324Saxel.duch@nginx.com         test++;
5991324Saxel.duch@nginx.com     }
6001324Saxel.duch@nginx.com 
6011326Saxel.duch@nginx.com     if (mtcf.destination != NULL) {
6021326Saxel.duch@nginx.com         addr_rule = nxt_http_route_addr_rule_create(task, mp, mtcf.destination);
6031326Saxel.duch@nginx.com         if (addr_rule == NULL) {
6041326Saxel.duch@nginx.com             return NULL;
6051326Saxel.duch@nginx.com         }
6061326Saxel.duch@nginx.com 
6071326Saxel.duch@nginx.com         addr_rule->object = NXT_HTTP_ROUTE_DESTINATION;
6081326Saxel.duch@nginx.com         test->addr_rule = addr_rule;
6091326Saxel.duch@nginx.com         test++;
6101326Saxel.duch@nginx.com     }
6111326Saxel.duch@nginx.com 
612964Sigor@sysoev.ru     return match;
613964Sigor@sysoev.ru }
614964Sigor@sysoev.ru 
615964Sigor@sysoev.ru 
6161264Sigor@sysoev.ru static nxt_conf_map_t  nxt_http_route_action_conf[] = {
6171264Sigor@sysoev.ru     {
6181264Sigor@sysoev.ru         nxt_string("pass"),
6191264Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
6201903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, pass)
6211264Sigor@sysoev.ru     },
6221264Sigor@sysoev.ru     {
6231429Svbart@nginx.com         nxt_string("return"),
6241429Svbart@nginx.com         NXT_CONF_MAP_PTR,
6251903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, ret)
6261429Svbart@nginx.com     },
6271429Svbart@nginx.com     {
6281432Svbart@nginx.com         nxt_string("location"),
629*2098Salx.manpages@gmail.com         NXT_CONF_MAP_PTR,
6301903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, location)
6311432Svbart@nginx.com     },
6321432Svbart@nginx.com     {
6331854Sz.hong@f5.com         nxt_string("proxy"),
6341854Sz.hong@f5.com         NXT_CONF_MAP_PTR,
6351903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, proxy)
6361854Sz.hong@f5.com     },
6371854Sz.hong@f5.com     {
6381264Sigor@sysoev.ru         nxt_string("share"),
6391264Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
6401903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, share)
6411264Sigor@sysoev.ru     },
6421270Sigor@sysoev.ru     {
6431855Sz.hong@f5.com         nxt_string("chroot"),
6441855Sz.hong@f5.com         NXT_CONF_MAP_STR,
6451903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, chroot)
6461855Sz.hong@f5.com     },
6471855Sz.hong@f5.com     {
6481855Sz.hong@f5.com         nxt_string("follow_symlinks"),
6491855Sz.hong@f5.com         NXT_CONF_MAP_PTR,
6501903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, follow_symlinks)
6511855Sz.hong@f5.com     },
6521855Sz.hong@f5.com     {
6531855Sz.hong@f5.com         nxt_string("traverse_mounts"),
6541855Sz.hong@f5.com         NXT_CONF_MAP_PTR,
6551903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, traverse_mounts)
6561855Sz.hong@f5.com     },
6571855Sz.hong@f5.com     {
6581859So.canty@f5.com         nxt_string("types"),
6591859So.canty@f5.com         NXT_CONF_MAP_PTR,
6601903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, types)
6611859So.canty@f5.com     },
6621859So.canty@f5.com     {
6631378Svbart@nginx.com         nxt_string("fallback"),
6641378Svbart@nginx.com         NXT_CONF_MAP_PTR,
6651903Sz.hong@f5.com         offsetof(nxt_http_action_conf_t, fallback)
6661378Svbart@nginx.com     },
6671264Sigor@sysoev.ru };
6681264Sigor@sysoev.ru 
6691264Sigor@sysoev.ru 
6701923Sz.hong@f5.com nxt_int_t
6711903Sz.hong@f5.com nxt_http_action_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
6721859So.canty@f5.com     nxt_conf_value_t *cv, nxt_http_action_t *action)
6731264Sigor@sysoev.ru {
6741903Sz.hong@f5.com     nxt_mp_t                *mp;
6751903Sz.hong@f5.com     nxt_int_t               ret;
6761954Sz.hong@f5.com     nxt_str_t               pass;
6771903Sz.hong@f5.com     nxt_http_action_conf_t  acf;
6781903Sz.hong@f5.com 
6791903Sz.hong@f5.com     nxt_memzero(&acf, sizeof(acf));
6801264Sigor@sysoev.ru 
6811378Svbart@nginx.com     ret = nxt_conf_map_object(tmcf->mem_pool, cv, nxt_http_route_action_conf,
6821903Sz.hong@f5.com                               nxt_nitems(nxt_http_route_action_conf), &acf);
6831264Sigor@sysoev.ru     if (ret != NXT_OK) {
6841264Sigor@sysoev.ru         return ret;
6851264Sigor@sysoev.ru     }
6861264Sigor@sysoev.ru 
6871428Svbart@nginx.com     nxt_memzero(action, sizeof(nxt_http_action_t));
6881428Svbart@nginx.com 
6891432Svbart@nginx.com     mp = tmcf->router_conf->mem_pool;
6901432Svbart@nginx.com 
6911903Sz.hong@f5.com     if (acf.ret != NULL) {
6921903Sz.hong@f5.com         return nxt_http_return_init(mp, action, &acf);
6931429Svbart@nginx.com     }
6941429Svbart@nginx.com 
6951903Sz.hong@f5.com     if (acf.share != NULL) {
6961923Sz.hong@f5.com         return nxt_http_static_init(task, tmcf, action, &acf);
6971923Sz.hong@f5.com     }
6981923Sz.hong@f5.com 
6991923Sz.hong@f5.com     if (acf.proxy != NULL) {
7001924Sz.hong@f5.com         return nxt_http_proxy_init(mp, action, &acf);
7011264Sigor@sysoev.ru     }
7021264Sigor@sysoev.ru 
7031954Sz.hong@f5.com     nxt_conf_get_string(acf.pass, &pass);
7041954Sz.hong@f5.com 
7051959Sz.hong@f5.com     action->u.var = nxt_var_compile(&pass, mp, 0);
7061954Sz.hong@f5.com     if (nxt_slow_path(action->u.var == NULL)) {
7071264Sigor@sysoev.ru         return NXT_ERROR;
7081264Sigor@sysoev.ru     }
7091264Sigor@sysoev.ru 
7101264Sigor@sysoev.ru     return NXT_OK;
7111264Sigor@sysoev.ru }
7121264Sigor@sysoev.ru 
7131264Sigor@sysoev.ru 
7141059Sigor@sysoev.ru static nxt_http_route_table_t *
7151059Sigor@sysoev.ru nxt_http_route_table_create(nxt_task_t *task, nxt_mp_t *mp,
7161061Sigor@sysoev.ru     nxt_conf_value_t *table_cv, nxt_http_route_object_t object,
7171474Saxel.duch@nginx.com     nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding)
7181059Sigor@sysoev.ru {
7191059Sigor@sysoev.ru     size_t                    size;
7201059Sigor@sysoev.ru     uint32_t                  i, n;
7211059Sigor@sysoev.ru     nxt_conf_value_t          *ruleset_cv;
7221059Sigor@sysoev.ru     nxt_http_route_table_t    *table;
7231059Sigor@sysoev.ru     nxt_http_route_ruleset_t  *ruleset;
7241059Sigor@sysoev.ru 
7252077Salx.manpages@gmail.com     n = nxt_conf_array_elements_count_or_1(table_cv);
7261059Sigor@sysoev.ru     size = sizeof(nxt_http_route_table_t)
7271059Sigor@sysoev.ru            + n * sizeof(nxt_http_route_ruleset_t *);
7281059Sigor@sysoev.ru 
7291059Sigor@sysoev.ru     table = nxt_mp_alloc(mp, size);
7301059Sigor@sysoev.ru     if (nxt_slow_path(table == NULL)) {
7311059Sigor@sysoev.ru         return NULL;
7321059Sigor@sysoev.ru     }
7331059Sigor@sysoev.ru 
7341059Sigor@sysoev.ru     table->items = n;
7351059Sigor@sysoev.ru     table->object = NXT_HTTP_ROUTE_TABLE;
7361059Sigor@sysoev.ru 
7371059Sigor@sysoev.ru     for (i = 0; i < n; i++) {
7382077Salx.manpages@gmail.com         ruleset_cv = nxt_conf_get_array_element_or_itself(table_cv, i);
7391059Sigor@sysoev.ru 
7401474Saxel.duch@nginx.com         ruleset = nxt_http_route_ruleset_create(task, mp, ruleset_cv, object,
7411474Saxel.duch@nginx.com                                                 case_sensitive, encoding);
7421059Sigor@sysoev.ru         if (nxt_slow_path(ruleset == NULL)) {
7431059Sigor@sysoev.ru             return NULL;
7441059Sigor@sysoev.ru         }
7451059Sigor@sysoev.ru 
7461059Sigor@sysoev.ru         table->ruleset[i] = ruleset;
7471059Sigor@sysoev.ru     }
7481059Sigor@sysoev.ru 
7491059Sigor@sysoev.ru     return table;
7501059Sigor@sysoev.ru }
7511059Sigor@sysoev.ru 
7521059Sigor@sysoev.ru 
7531059Sigor@sysoev.ru static nxt_http_route_ruleset_t *
7541059Sigor@sysoev.ru nxt_http_route_ruleset_create(nxt_task_t *task, nxt_mp_t *mp,
7551061Sigor@sysoev.ru     nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object,
7561474Saxel.duch@nginx.com     nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding)
7571059Sigor@sysoev.ru {
7581059Sigor@sysoev.ru     size_t                    size;
7591059Sigor@sysoev.ru     uint32_t                  i, n, next;
7601059Sigor@sysoev.ru     nxt_str_t                 name;
7611059Sigor@sysoev.ru     nxt_conf_value_t          *rule_cv;
7621059Sigor@sysoev.ru     nxt_http_route_rule_t     *rule;
7631059Sigor@sysoev.ru     nxt_http_route_ruleset_t  *ruleset;
7641059Sigor@sysoev.ru 
7651059Sigor@sysoev.ru     n = nxt_conf_object_members_count(ruleset_cv);
7661059Sigor@sysoev.ru     size = sizeof(nxt_http_route_ruleset_t)
7671059Sigor@sysoev.ru            + n * sizeof(nxt_http_route_rule_t *);
7681059Sigor@sysoev.ru 
7691059Sigor@sysoev.ru     ruleset = nxt_mp_alloc(mp, size);
7701059Sigor@sysoev.ru     if (nxt_slow_path(ruleset == NULL)) {
7711059Sigor@sysoev.ru         return NULL;
7721059Sigor@sysoev.ru     }
7731059Sigor@sysoev.ru 
7741059Sigor@sysoev.ru     ruleset->items = n;
7751059Sigor@sysoev.ru 
7761059Sigor@sysoev.ru     next = 0;
7771059Sigor@sysoev.ru 
7781785Svbart@nginx.com     /*
7791785Svbart@nginx.com      * A workaround for GCC 10 with -flto -O2 flags that warns about "name"
7801785Svbart@nginx.com      * may be uninitialized in nxt_http_route_rule_name_create().
7811785Svbart@nginx.com      */
7821785Svbart@nginx.com     nxt_str_null(&name);
7831785Svbart@nginx.com 
7841059Sigor@sysoev.ru     for (i = 0; i < n; i++) {
7851059Sigor@sysoev.ru         rule_cv = nxt_conf_next_object_member(ruleset_cv, &name, &next);
7861059Sigor@sysoev.ru 
7871061Sigor@sysoev.ru         rule = nxt_http_route_rule_name_create(task, mp, rule_cv, &name,
7881474Saxel.duch@nginx.com                                                case_sensitive, encoding);
7891059Sigor@sysoev.ru         if (nxt_slow_path(rule == NULL)) {
7901059Sigor@sysoev.ru             return NULL;
7911059Sigor@sysoev.ru         }
7921059Sigor@sysoev.ru 
7931061Sigor@sysoev.ru         rule->object = object;
7941059Sigor@sysoev.ru         ruleset->rule[i] = rule;
7951059Sigor@sysoev.ru     }
7961059Sigor@sysoev.ru 
7971059Sigor@sysoev.ru     return ruleset;
7981059Sigor@sysoev.ru }
7991059Sigor@sysoev.ru 
8001059Sigor@sysoev.ru 
801964Sigor@sysoev.ru static nxt_http_route_rule_t *
8021061Sigor@sysoev.ru nxt_http_route_rule_name_create(nxt_task_t *task, nxt_mp_t *mp,
8031474Saxel.duch@nginx.com     nxt_conf_value_t *rule_cv, nxt_str_t *name, nxt_bool_t case_sensitive,
8041474Saxel.duch@nginx.com     nxt_http_route_encoding_t encoding)
8051059Sigor@sysoev.ru {
8061474Saxel.duch@nginx.com     u_char                 c, *p, *src, *start, *end, plus;
8071474Saxel.duch@nginx.com     uint8_t                d0, d1;
8081059Sigor@sysoev.ru     uint32_t               hash;
8091059Sigor@sysoev.ru     nxt_uint_t             i;
8101059Sigor@sysoev.ru     nxt_http_route_rule_t  *rule;
8111059Sigor@sysoev.ru 
8121061Sigor@sysoev.ru     rule = nxt_http_route_rule_create(task, mp, rule_cv, case_sensitive,
8131474Saxel.duch@nginx.com                                       NXT_HTTP_ROUTE_PATTERN_NOCASE,
8141474Saxel.duch@nginx.com                                       encoding);
8151059Sigor@sysoev.ru     if (nxt_slow_path(rule == NULL)) {
8161059Sigor@sysoev.ru         return NULL;
8171059Sigor@sysoev.ru     }
8181059Sigor@sysoev.ru 
8191059Sigor@sysoev.ru     rule->u.name.length = name->length;
8201059Sigor@sysoev.ru 
8211059Sigor@sysoev.ru     p = nxt_mp_nget(mp, name->length);
8221059Sigor@sysoev.ru     if (nxt_slow_path(p == NULL)) {
8231059Sigor@sysoev.ru         return NULL;
8241059Sigor@sysoev.ru     }
8251059Sigor@sysoev.ru 
8261474Saxel.duch@nginx.com     hash = NXT_HTTP_FIELD_HASH_INIT;
8271059Sigor@sysoev.ru     rule->u.name.start = p;
8281059Sigor@sysoev.ru 
8291474Saxel.duch@nginx.com     if (encoding == NXT_HTTP_ROUTE_ENCODING_NONE) {
8301474Saxel.duch@nginx.com         for (i = 0; i < name->length; i++) {
8311474Saxel.duch@nginx.com             c = name->start[i];
8321474Saxel.duch@nginx.com             *p++ = c;
8331474Saxel.duch@nginx.com 
8341474Saxel.duch@nginx.com             c = case_sensitive ? c : nxt_lowcase(c);
8351474Saxel.duch@nginx.com             hash = nxt_http_field_hash_char(hash, c);
8361474Saxel.duch@nginx.com         }
8371474Saxel.duch@nginx.com 
8381474Saxel.duch@nginx.com         goto end;
8391474Saxel.duch@nginx.com     }
8401474Saxel.duch@nginx.com 
8411474Saxel.duch@nginx.com     plus = (encoding == NXT_HTTP_ROUTE_ENCODING_URI_PLUS) ? ' ' : '+';
8421474Saxel.duch@nginx.com 
8431474Saxel.duch@nginx.com     start = name->start;
8441474Saxel.duch@nginx.com     end = start + name->length;
8451474Saxel.duch@nginx.com 
8461474Saxel.duch@nginx.com     for (src = start; src < end; src++) {
8471474Saxel.duch@nginx.com         c = *src;
8481474Saxel.duch@nginx.com 
8491474Saxel.duch@nginx.com         switch (c) {
8501474Saxel.duch@nginx.com         case '%':
8511474Saxel.duch@nginx.com             if (nxt_slow_path(end - src <= 2)) {
8521474Saxel.duch@nginx.com                 return NULL;
8531474Saxel.duch@nginx.com             }
8541474Saxel.duch@nginx.com 
8551474Saxel.duch@nginx.com             d0 = nxt_hex2int[src[1]];
8561474Saxel.duch@nginx.com             d1 = nxt_hex2int[src[2]];
8571474Saxel.duch@nginx.com             src += 2;
8581474Saxel.duch@nginx.com 
8591474Saxel.duch@nginx.com             if (nxt_slow_path((d0 | d1) >= 16)) {
8601474Saxel.duch@nginx.com                 return NULL;
8611474Saxel.duch@nginx.com             }
8621474Saxel.duch@nginx.com 
8631474Saxel.duch@nginx.com             c = (d0 << 4) + d1;
8641474Saxel.duch@nginx.com             *p++ = c;
8651474Saxel.duch@nginx.com             break;
8661474Saxel.duch@nginx.com 
8671474Saxel.duch@nginx.com         case '+':
8681474Saxel.duch@nginx.com             c = plus;
8691474Saxel.duch@nginx.com             *p++ = c;
8701474Saxel.duch@nginx.com             break;
8711474Saxel.duch@nginx.com 
8721474Saxel.duch@nginx.com         default:
8731474Saxel.duch@nginx.com             *p++ = c;
8741474Saxel.duch@nginx.com             break;
8751474Saxel.duch@nginx.com         }
8761059Sigor@sysoev.ru 
8771079Sigor@sysoev.ru         c = case_sensitive ? c : nxt_lowcase(c);
8781059Sigor@sysoev.ru         hash = nxt_http_field_hash_char(hash, c);
8791059Sigor@sysoev.ru     }
8801059Sigor@sysoev.ru 
8811474Saxel.duch@nginx.com     rule->u.name.length = p - rule->u.name.start;
8821474Saxel.duch@nginx.com 
8831474Saxel.duch@nginx.com end:
8841474Saxel.duch@nginx.com 
8851059Sigor@sysoev.ru     rule->u.name.hash = nxt_http_field_hash_end(hash) & 0xFFFF;
8861059Sigor@sysoev.ru 
8871059Sigor@sysoev.ru     return rule;
8881059Sigor@sysoev.ru }
8891059Sigor@sysoev.ru 
8901059Sigor@sysoev.ru 
8911059Sigor@sysoev.ru static nxt_http_route_rule_t *
8921059Sigor@sysoev.ru nxt_http_route_rule_create(nxt_task_t *task, nxt_mp_t *mp,
893964Sigor@sysoev.ru     nxt_conf_value_t *cv, nxt_bool_t case_sensitive,
8941474Saxel.duch@nginx.com     nxt_http_route_pattern_case_t pattern_case,
8951474Saxel.duch@nginx.com     nxt_http_route_encoding_t encoding)
896964Sigor@sysoev.ru {
897964Sigor@sysoev.ru     size_t                    size;
898964Sigor@sysoev.ru     uint32_t                  i, n;
899964Sigor@sysoev.ru     nxt_int_t                 ret;
900964Sigor@sysoev.ru     nxt_conf_value_t          *value;
901964Sigor@sysoev.ru     nxt_http_route_rule_t     *rule;
902964Sigor@sysoev.ru     nxt_http_route_pattern_t  *pattern;
903964Sigor@sysoev.ru 
9042077Salx.manpages@gmail.com     n = nxt_conf_array_elements_count_or_1(cv);
905964Sigor@sysoev.ru     size = sizeof(nxt_http_route_rule_t) + n * sizeof(nxt_http_route_pattern_t);
906964Sigor@sysoev.ru 
907964Sigor@sysoev.ru     rule = nxt_mp_alloc(mp, size);
908964Sigor@sysoev.ru     if (nxt_slow_path(rule == NULL)) {
909964Sigor@sysoev.ru         return NULL;
910964Sigor@sysoev.ru     }
911964Sigor@sysoev.ru 
912964Sigor@sysoev.ru     rule->items = n;
913964Sigor@sysoev.ru 
914964Sigor@sysoev.ru     pattern = &rule->pattern[0];
915964Sigor@sysoev.ru 
916964Sigor@sysoev.ru     nxt_conf_array_qsort(cv, nxt_http_pattern_compare);
917964Sigor@sysoev.ru 
918964Sigor@sysoev.ru     for (i = 0; i < n; i++) {
919964Sigor@sysoev.ru         pattern[i].case_sensitive = case_sensitive;
9202077Salx.manpages@gmail.com         value = nxt_conf_get_array_element_or_itself(cv, i);
921964Sigor@sysoev.ru 
922964Sigor@sysoev.ru         ret = nxt_http_route_pattern_create(task, mp, value, &pattern[i],
9231474Saxel.duch@nginx.com                                             pattern_case, encoding);
924964Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
925964Sigor@sysoev.ru             return NULL;
926964Sigor@sysoev.ru         }
927964Sigor@sysoev.ru     }
928964Sigor@sysoev.ru 
929964Sigor@sysoev.ru     return rule;
930964Sigor@sysoev.ru }
931964Sigor@sysoev.ru 
932964Sigor@sysoev.ru 
9331936So.canty@f5.com nxt_http_route_addr_rule_t *
9341324Saxel.duch@nginx.com nxt_http_route_addr_rule_create(nxt_task_t *task, nxt_mp_t *mp,
9352078Salx.manpages@gmail.com     nxt_conf_value_t *cv)
9361324Saxel.duch@nginx.com {
9371324Saxel.duch@nginx.com     size_t                         size;
9381324Saxel.duch@nginx.com     uint32_t                       i, n;
9391324Saxel.duch@nginx.com     nxt_conf_value_t               *value;
9401324Saxel.duch@nginx.com     nxt_http_route_addr_rule_t     *addr_rule;
9411324Saxel.duch@nginx.com     nxt_http_route_addr_pattern_t  *pattern;
9421324Saxel.duch@nginx.com 
9432077Salx.manpages@gmail.com     n = nxt_conf_array_elements_count_or_1(cv);
9441324Saxel.duch@nginx.com 
9451324Saxel.duch@nginx.com     size = sizeof(nxt_http_route_addr_rule_t)
9461324Saxel.duch@nginx.com            + n * sizeof(nxt_http_route_addr_pattern_t);
9471324Saxel.duch@nginx.com 
9481324Saxel.duch@nginx.com     addr_rule = nxt_mp_alloc(mp, size);
9491324Saxel.duch@nginx.com     if (nxt_slow_path(addr_rule == NULL)) {
9501324Saxel.duch@nginx.com         return NULL;
9511324Saxel.duch@nginx.com     }
9521324Saxel.duch@nginx.com 
9531324Saxel.duch@nginx.com     addr_rule->items = n;
9541324Saxel.duch@nginx.com 
9551324Saxel.duch@nginx.com     for (i = 0; i < n; i++) {
9561324Saxel.duch@nginx.com         pattern = &addr_rule->addr_pattern[i];
9572077Salx.manpages@gmail.com         value = nxt_conf_get_array_element_or_itself(cv, i);
9581324Saxel.duch@nginx.com 
9591324Saxel.duch@nginx.com         if (nxt_http_route_addr_pattern_parse(mp, pattern, value) != NXT_OK) {
9601324Saxel.duch@nginx.com             return NULL;
9611324Saxel.duch@nginx.com         }
9621324Saxel.duch@nginx.com     }
9631324Saxel.duch@nginx.com 
9641390Saxel.duch@nginx.com     if (n > 1) {
9651390Saxel.duch@nginx.com         nxt_qsort(addr_rule->addr_pattern, addr_rule->items,
9661390Saxel.duch@nginx.com             sizeof(nxt_http_route_addr_pattern_t),
9671390Saxel.duch@nginx.com             nxt_http_addr_pattern_compare);
9681390Saxel.duch@nginx.com     }
9691390Saxel.duch@nginx.com 
9701324Saxel.duch@nginx.com     return addr_rule;
9711324Saxel.duch@nginx.com }
9721324Saxel.duch@nginx.com 
9731324Saxel.duch@nginx.com 
9741923Sz.hong@f5.com nxt_http_route_rule_t *
9751923Sz.hong@f5.com nxt_http_route_types_rule_create(nxt_task_t *task, nxt_mp_t *mp,
9761923Sz.hong@f5.com     nxt_conf_value_t *types)
9771923Sz.hong@f5.com {
9781923Sz.hong@f5.com     return nxt_http_route_rule_create(task, mp, types, 0,
9791923Sz.hong@f5.com                                       NXT_HTTP_ROUTE_PATTERN_LOWCASE,
9801923Sz.hong@f5.com                                       NXT_HTTP_ROUTE_ENCODING_NONE);
9811923Sz.hong@f5.com }
9821923Sz.hong@f5.com 
9831923Sz.hong@f5.com 
984964Sigor@sysoev.ru static int
985964Sigor@sysoev.ru nxt_http_pattern_compare(const void *one, const void *two)
986964Sigor@sysoev.ru {
987964Sigor@sysoev.ru     nxt_str_t         test;
988964Sigor@sysoev.ru     nxt_bool_t        negative1, negative2;
989964Sigor@sysoev.ru     nxt_conf_value_t  *value;
990964Sigor@sysoev.ru 
991964Sigor@sysoev.ru     value = (nxt_conf_value_t *) one;
992964Sigor@sysoev.ru     nxt_conf_get_string(value, &test);
993964Sigor@sysoev.ru     negative1 = (test.length != 0 && test.start[0] == '!');
994964Sigor@sysoev.ru 
995964Sigor@sysoev.ru     value = (nxt_conf_value_t *) two;
996964Sigor@sysoev.ru     nxt_conf_get_string(value, &test);
997964Sigor@sysoev.ru     negative2 = (test.length != 0 && test.start[0] == '!');
998964Sigor@sysoev.ru 
999964Sigor@sysoev.ru     return (negative2 - negative1);
1000964Sigor@sysoev.ru }
1001964Sigor@sysoev.ru 
1002964Sigor@sysoev.ru 
10031390Saxel.duch@nginx.com static int
10041390Saxel.duch@nginx.com nxt_http_addr_pattern_compare(const void *one, const void *two)
10051390Saxel.duch@nginx.com {
10061390Saxel.duch@nginx.com     const nxt_http_route_addr_pattern_t  *p1, *p2;
10071390Saxel.duch@nginx.com 
10081390Saxel.duch@nginx.com     p1 = one;
10091390Saxel.duch@nginx.com     p2 = two;
10101390Saxel.duch@nginx.com 
10111390Saxel.duch@nginx.com     return (p2->base.negative - p1->base.negative);
10121390Saxel.duch@nginx.com }
10131390Saxel.duch@nginx.com 
10141390Saxel.duch@nginx.com 
1015964Sigor@sysoev.ru static nxt_int_t
1016964Sigor@sysoev.ru nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp,
1017964Sigor@sysoev.ru     nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern,
10181474Saxel.duch@nginx.com     nxt_http_route_pattern_case_t pattern_case,
10191474Saxel.duch@nginx.com     nxt_http_route_encoding_t encoding)
1020964Sigor@sysoev.ru {
10211508Saxel.duch@nginx.com     u_char                          c, *p, *end;
10221508Saxel.duch@nginx.com     nxt_str_t                       test, tmp;
10231508Saxel.duch@nginx.com     nxt_int_t                       ret;
10241508Saxel.duch@nginx.com     nxt_array_t                     *slices;
10251721Saxel.duch@nginx.com #if (NXT_HAVE_REGEX)
10261721Saxel.duch@nginx.com     nxt_regex_t                     *re;
10271721Saxel.duch@nginx.com     nxt_regex_err_t                 err;
10281721Saxel.duch@nginx.com #endif
10291508Saxel.duch@nginx.com     nxt_http_route_pattern_type_t   type;
10301508Saxel.duch@nginx.com     nxt_http_route_pattern_slice_t  *slice;
1031964Sigor@sysoev.ru 
1032964Sigor@sysoev.ru     type = NXT_HTTP_ROUTE_PATTERN_EXACT;
1033964Sigor@sysoev.ru 
1034964Sigor@sysoev.ru     nxt_conf_get_string(cv, &test);
1035964Sigor@sysoev.ru 
10361721Saxel.duch@nginx.com     pattern->u.pattern_slices = NULL;
1037964Sigor@sysoev.ru     pattern->negative = 0;
1038964Sigor@sysoev.ru     pattern->any = 1;
10391474Saxel.duch@nginx.com     pattern->min_length = 0;
10401721Saxel.duch@nginx.com #if (NXT_HAVE_REGEX)
10411721Saxel.duch@nginx.com     pattern->regex = 0;
10421721Saxel.duch@nginx.com #endif
1043964Sigor@sysoev.ru 
10441508Saxel.duch@nginx.com     if (test.length != 0 && test.start[0] == '!') {
10451508Saxel.duch@nginx.com         test.start++;
10461508Saxel.duch@nginx.com         test.length--;
10471508Saxel.duch@nginx.com 
10481508Saxel.duch@nginx.com         pattern->negative = 1;
10491508Saxel.duch@nginx.com         pattern->any = 0;
10501508Saxel.duch@nginx.com     }
10511508Saxel.duch@nginx.com 
10521721Saxel.duch@nginx.com     if (test.length > 0 && test.start[0] == '~') {
10531721Saxel.duch@nginx.com #if (NXT_HAVE_REGEX)
10541721Saxel.duch@nginx.com         test.start++;
10551721Saxel.duch@nginx.com         test.length--;
10561721Saxel.duch@nginx.com 
10571721Saxel.duch@nginx.com         re = nxt_regex_compile(mp, &test, &err);
10581721Saxel.duch@nginx.com         if (nxt_slow_path(re == NULL)) {
10591721Saxel.duch@nginx.com             if (err.offset < test.length) {
10601721Saxel.duch@nginx.com                 nxt_alert(task, "nxt_regex_compile(%V) failed: %s at offset %d",
10611721Saxel.duch@nginx.com                           &test, err.msg, (int) err.offset);
10621721Saxel.duch@nginx.com                 return NXT_ERROR;
10631721Saxel.duch@nginx.com             }
10641721Saxel.duch@nginx.com 
10651721Saxel.duch@nginx.com             nxt_alert(task, "nxt_regex_compile(%V) failed %s", &test, err.msg);
10661721Saxel.duch@nginx.com 
10671721Saxel.duch@nginx.com             return NXT_ERROR;
10681721Saxel.duch@nginx.com         }
10691721Saxel.duch@nginx.com 
10701721Saxel.duch@nginx.com         pattern->u.regex = re;
10711721Saxel.duch@nginx.com         pattern->regex = 1;
10721721Saxel.duch@nginx.com 
10731721Saxel.duch@nginx.com         return NXT_OK;
10741721Saxel.duch@nginx.com 
10751721Saxel.duch@nginx.com #else
10761721Saxel.duch@nginx.com         return NXT_ERROR;
10771721Saxel.duch@nginx.com #endif
10781721Saxel.duch@nginx.com     }
10791721Saxel.duch@nginx.com 
10801721Saxel.duch@nginx.com     slices = nxt_array_create(mp, 1, sizeof(nxt_http_route_pattern_slice_t));
10811721Saxel.duch@nginx.com     if (nxt_slow_path(slices == NULL)) {
10821721Saxel.duch@nginx.com         return NXT_ERROR;
10831721Saxel.duch@nginx.com     }
10841721Saxel.duch@nginx.com 
10851721Saxel.duch@nginx.com     pattern->u.pattern_slices = slices;
10861721Saxel.duch@nginx.com 
10871508Saxel.duch@nginx.com     if (test.length == 0) {
10881508Saxel.duch@nginx.com         slice = nxt_array_add(slices);
10891508Saxel.duch@nginx.com         if (nxt_slow_path(slice == NULL)) {
10901508Saxel.duch@nginx.com             return NXT_ERROR;
1091964Sigor@sysoev.ru         }
1092964Sigor@sysoev.ru 
10931508Saxel.duch@nginx.com         slice->type = NXT_HTTP_ROUTE_PATTERN_EXACT;
10941508Saxel.duch@nginx.com         slice->start = NULL;
10951508Saxel.duch@nginx.com         slice->length = 0;
10961508Saxel.duch@nginx.com 
10971508Saxel.duch@nginx.com         return NXT_OK;
10981508Saxel.duch@nginx.com     }
10991508Saxel.duch@nginx.com 
11001508Saxel.duch@nginx.com     if (test.start[0] == '*') {
11011508Saxel.duch@nginx.com         /* 'type' is no longer 'EXACT', assume 'END'. */
11021508Saxel.duch@nginx.com         type = NXT_HTTP_ROUTE_PATTERN_END;
11031508Saxel.duch@nginx.com         test.start++;
11041508Saxel.duch@nginx.com         test.length--;
11051508Saxel.duch@nginx.com     }
11061508Saxel.duch@nginx.com 
11071522Saxel.duch@nginx.com     if (type == NXT_HTTP_ROUTE_PATTERN_EXACT) {
11081508Saxel.duch@nginx.com         tmp.start = test.start;
11091508Saxel.duch@nginx.com 
11101508Saxel.duch@nginx.com         p = nxt_memchr(test.start, '*', test.length);
11111508Saxel.duch@nginx.com 
11121508Saxel.duch@nginx.com         if (p == NULL) {
11131508Saxel.duch@nginx.com             /* No '*' found - EXACT pattern. */
11141508Saxel.duch@nginx.com             tmp.length = test.length;
11151508Saxel.duch@nginx.com             type = NXT_HTTP_ROUTE_PATTERN_EXACT;
11161508Saxel.duch@nginx.com 
11171508Saxel.duch@nginx.com             test.start += test.length;
11181508Saxel.duch@nginx.com             test.length = 0;
11191508Saxel.duch@nginx.com 
11201508Saxel.duch@nginx.com         } else {
11211508Saxel.duch@nginx.com             /* '*' found - BEGIN pattern. */
11221508Saxel.duch@nginx.com             tmp.length = p - test.start;
11231508Saxel.duch@nginx.com             type = NXT_HTTP_ROUTE_PATTERN_BEGIN;
11241508Saxel.duch@nginx.com 
11251508Saxel.duch@nginx.com             test.start = p + 1;
11261508Saxel.duch@nginx.com             test.length -= tmp.length + 1;
11271508Saxel.duch@nginx.com         }
11281508Saxel.duch@nginx.com 
11291508Saxel.duch@nginx.com         ret = nxt_http_route_pattern_slice(slices, &tmp, type, encoding,
11301508Saxel.duch@nginx.com                                            pattern_case);
11311508Saxel.duch@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
11321508Saxel.duch@nginx.com             return ret;
11331508Saxel.duch@nginx.com         }
11341508Saxel.duch@nginx.com 
11351508Saxel.duch@nginx.com         pattern->min_length += tmp.length;
11361508Saxel.duch@nginx.com     }
11371508Saxel.duch@nginx.com 
11381508Saxel.duch@nginx.com     end = test.start + test.length;
11391508Saxel.duch@nginx.com 
11401508Saxel.duch@nginx.com     if (test.length != 0 && end[-1] != '*') {
11411508Saxel.duch@nginx.com         p = end - 1;
11421508Saxel.duch@nginx.com 
11431508Saxel.duch@nginx.com         while (p != test.start) {
11441508Saxel.duch@nginx.com             c = *p--;
11451508Saxel.duch@nginx.com 
11461508Saxel.duch@nginx.com             if (c == '*') {
11471508Saxel.duch@nginx.com                 p += 2;
11481508Saxel.duch@nginx.com                 break;
11491474Saxel.duch@nginx.com             }
1150964Sigor@sysoev.ru         }
11511508Saxel.duch@nginx.com 
11521508Saxel.duch@nginx.com         tmp.start = p;
11531508Saxel.duch@nginx.com         tmp.length = end - p;
11541508Saxel.duch@nginx.com 
11551508Saxel.duch@nginx.com         test.length -= tmp.length;
11561508Saxel.duch@nginx.com         end = p;
11571508Saxel.duch@nginx.com 
11581508Saxel.duch@nginx.com         ret = nxt_http_route_pattern_slice(slices, &tmp,
11591508Saxel.duch@nginx.com                                            NXT_HTTP_ROUTE_PATTERN_END,
11601508Saxel.duch@nginx.com                                            encoding, pattern_case);
11611508Saxel.duch@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
11621508Saxel.duch@nginx.com             return ret;
11631508Saxel.duch@nginx.com         }
11641508Saxel.duch@nginx.com 
11651508Saxel.duch@nginx.com         pattern->min_length += tmp.length;
1166964Sigor@sysoev.ru     }
1167964Sigor@sysoev.ru 
11681508Saxel.duch@nginx.com     tmp.start = test.start;
11691508Saxel.duch@nginx.com     tmp.length = 0;
11701508Saxel.duch@nginx.com 
11711508Saxel.duch@nginx.com     p = tmp.start;
11721508Saxel.duch@nginx.com 
11731508Saxel.duch@nginx.com     while (p != end) {
11741508Saxel.duch@nginx.com         c = *p++;
11751508Saxel.duch@nginx.com 
11761508Saxel.duch@nginx.com         if (c != '*') {
11771508Saxel.duch@nginx.com             tmp.length++;
11781508Saxel.duch@nginx.com             continue;
11791508Saxel.duch@nginx.com         }
11801508Saxel.duch@nginx.com 
11811508Saxel.duch@nginx.com         if (tmp.length == 0) {
11821508Saxel.duch@nginx.com             tmp.start = p;
11831508Saxel.duch@nginx.com             continue;
11841508Saxel.duch@nginx.com         }
11851508Saxel.duch@nginx.com 
11861508Saxel.duch@nginx.com         ret = nxt_http_route_pattern_slice(slices, &tmp,
11871508Saxel.duch@nginx.com                                            NXT_HTTP_ROUTE_PATTERN_SUBSTRING,
11881508Saxel.duch@nginx.com                                            encoding, pattern_case);
11891508Saxel.duch@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
11901508Saxel.duch@nginx.com             return ret;
11911508Saxel.duch@nginx.com         }
11921508Saxel.duch@nginx.com 
11931508Saxel.duch@nginx.com         pattern->min_length += tmp.length;
11941508Saxel.duch@nginx.com 
11951508Saxel.duch@nginx.com         tmp.start = p;
11961508Saxel.duch@nginx.com         tmp.length = 0;
1197964Sigor@sysoev.ru     }
1198964Sigor@sysoev.ru 
11991508Saxel.duch@nginx.com     if (tmp.length != 0) {
12001508Saxel.duch@nginx.com         ret = nxt_http_route_pattern_slice(slices, &tmp,
12011508Saxel.duch@nginx.com                                            NXT_HTTP_ROUTE_PATTERN_SUBSTRING,
12021508Saxel.duch@nginx.com                                            encoding, pattern_case);
12031508Saxel.duch@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
12041508Saxel.duch@nginx.com             return ret;
12051508Saxel.duch@nginx.com         }
12061508Saxel.duch@nginx.com 
12071508Saxel.duch@nginx.com         pattern->min_length += tmp.length;
12081508Saxel.duch@nginx.com     }
12091032Sigor@sysoev.ru 
12101474Saxel.duch@nginx.com     return NXT_OK;
12111474Saxel.duch@nginx.com }
12121474Saxel.duch@nginx.com 
12131474Saxel.duch@nginx.com 
12141474Saxel.duch@nginx.com static nxt_int_t
12151474Saxel.duch@nginx.com nxt_http_route_decode_str(nxt_str_t *str, nxt_http_route_encoding_t encoding)
12161474Saxel.duch@nginx.com {
12171474Saxel.duch@nginx.com     u_char  *start, *end;
12181474Saxel.duch@nginx.com 
12191474Saxel.duch@nginx.com     switch (encoding) {
12201474Saxel.duch@nginx.com     case NXT_HTTP_ROUTE_ENCODING_NONE:
12211474Saxel.duch@nginx.com         break;
12221474Saxel.duch@nginx.com 
12231474Saxel.duch@nginx.com     case NXT_HTTP_ROUTE_ENCODING_URI:
12241474Saxel.duch@nginx.com         start = str->start;
12251474Saxel.duch@nginx.com 
12261474Saxel.duch@nginx.com         end = nxt_decode_uri(start, start, str->length);
12271474Saxel.duch@nginx.com         if (nxt_slow_path(end == NULL)) {
12281032Sigor@sysoev.ru             return NXT_ERROR;
12291032Sigor@sysoev.ru         }
12301032Sigor@sysoev.ru 
12311474Saxel.duch@nginx.com         str->length = end - start;
12321474Saxel.duch@nginx.com         break;
12331474Saxel.duch@nginx.com 
12341474Saxel.duch@nginx.com     case NXT_HTTP_ROUTE_ENCODING_URI_PLUS:
12351474Saxel.duch@nginx.com         start = str->start;
12361474Saxel.duch@nginx.com 
12371474Saxel.duch@nginx.com         end = nxt_decode_uri_plus(start, start, str->length);
12381474Saxel.duch@nginx.com         if (nxt_slow_path(end == NULL)) {
12391474Saxel.duch@nginx.com             return NXT_ERROR;
12401474Saxel.duch@nginx.com         }
12411474Saxel.duch@nginx.com 
12421474Saxel.duch@nginx.com         str->length = end - start;
12431474Saxel.duch@nginx.com         break;
12441474Saxel.duch@nginx.com 
12451474Saxel.duch@nginx.com     default:
12461474Saxel.duch@nginx.com         nxt_unreachable();
12471032Sigor@sysoev.ru     }
12481032Sigor@sysoev.ru 
12491032Sigor@sysoev.ru     return NXT_OK;
12501032Sigor@sysoev.ru }
12511032Sigor@sysoev.ru 
12521032Sigor@sysoev.ru 
12531508Saxel.duch@nginx.com static nxt_int_t
12541508Saxel.duch@nginx.com nxt_http_route_pattern_slice(nxt_array_t *slices,
12551508Saxel.duch@nginx.com     nxt_str_t *test,
12561508Saxel.duch@nginx.com     nxt_http_route_pattern_type_t type,
12571508Saxel.duch@nginx.com     nxt_http_route_encoding_t encoding,
12581032Sigor@sysoev.ru     nxt_http_route_pattern_case_t pattern_case)
12591032Sigor@sysoev.ru {
12601508Saxel.duch@nginx.com     u_char                          *start;
12611508Saxel.duch@nginx.com     nxt_int_t                       ret;
12621508Saxel.duch@nginx.com     nxt_http_route_pattern_slice_t  *slice;
12631508Saxel.duch@nginx.com 
12641508Saxel.duch@nginx.com     ret = nxt_http_route_decode_str(test, encoding);
12651508Saxel.duch@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
12661508Saxel.duch@nginx.com         return ret;
12671508Saxel.duch@nginx.com     }
12681508Saxel.duch@nginx.com 
12691508Saxel.duch@nginx.com     start = nxt_mp_nget(slices->mem_pool, test->length);
12701032Sigor@sysoev.ru     if (nxt_slow_path(start == NULL)) {
12711508Saxel.duch@nginx.com         return NXT_ERROR;
12721032Sigor@sysoev.ru     }
1273964Sigor@sysoev.ru 
1274964Sigor@sysoev.ru     switch (pattern_case) {
1275964Sigor@sysoev.ru 
1276964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_UPCASE:
12771032Sigor@sysoev.ru         nxt_memcpy_upcase(start, test->start, test->length);
1278964Sigor@sysoev.ru         break;
1279964Sigor@sysoev.ru 
1280964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_LOWCASE:
12811032Sigor@sysoev.ru         nxt_memcpy_lowcase(start, test->start, test->length);
1282964Sigor@sysoev.ru         break;
1283964Sigor@sysoev.ru 
1284964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_NOCASE:
12851032Sigor@sysoev.ru         nxt_memcpy(start, test->start, test->length);
1286964Sigor@sysoev.ru         break;
1287964Sigor@sysoev.ru     }
1288964Sigor@sysoev.ru 
12891508Saxel.duch@nginx.com     slice = nxt_array_add(slices);
12901564Svbart@nginx.com     if (nxt_slow_path(slice == NULL)) {
12911508Saxel.duch@nginx.com         return NXT_ERROR;
12921508Saxel.duch@nginx.com     }
12931508Saxel.duch@nginx.com 
12941508Saxel.duch@nginx.com     slice->type = type;
12951508Saxel.duch@nginx.com     slice->start = start;
12961508Saxel.duch@nginx.com     slice->length = test->length;
12971508Saxel.duch@nginx.com 
12981508Saxel.duch@nginx.com     return NXT_OK;
1299964Sigor@sysoev.ru }
1300964Sigor@sysoev.ru 
1301964Sigor@sysoev.ru 
13021472Svbart@nginx.com nxt_int_t
1303964Sigor@sysoev.ru nxt_http_routes_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
1304964Sigor@sysoev.ru {
13051472Svbart@nginx.com     nxt_int_t          ret;
13061033Svbart@nginx.com     nxt_http_route_t   **route, **end;
1307964Sigor@sysoev.ru     nxt_http_routes_t  *routes;
1308964Sigor@sysoev.ru 
1309964Sigor@sysoev.ru     routes = tmcf->router_conf->routes;
13101059Sigor@sysoev.ru 
1311964Sigor@sysoev.ru     if (routes != NULL) {
1312964Sigor@sysoev.ru         route = &routes->route[0];
13131033Svbart@nginx.com         end = route + routes->items;
1314964Sigor@sysoev.ru 
13151033Svbart@nginx.com         while (route < end) {
13161472Svbart@nginx.com             ret = nxt_http_route_resolve(task, tmcf, *route);
13171472Svbart@nginx.com             if (nxt_slow_path(ret != NXT_OK)) {
13181472Svbart@nginx.com                 return NXT_ERROR;
13191472Svbart@nginx.com             }
1320964Sigor@sysoev.ru 
1321964Sigor@sysoev.ru             route++;
1322964Sigor@sysoev.ru         }
1323964Sigor@sysoev.ru     }
13241472Svbart@nginx.com 
13251472Svbart@nginx.com     return NXT_OK;
1326964Sigor@sysoev.ru }
1327964Sigor@sysoev.ru 
1328964Sigor@sysoev.ru 
13291472Svbart@nginx.com static nxt_int_t
1330964Sigor@sysoev.ru nxt_http_route_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1331964Sigor@sysoev.ru     nxt_http_route_t *route)
1332964Sigor@sysoev.ru {
13331472Svbart@nginx.com     nxt_int_t               ret;
13341033Svbart@nginx.com     nxt_http_route_match_t  **match, **end;
1335964Sigor@sysoev.ru 
1336964Sigor@sysoev.ru     match = &route->match[0];
13371033Svbart@nginx.com     end = match + route->items;
1338964Sigor@sysoev.ru 
13391033Svbart@nginx.com     while (match < end) {
13401472Svbart@nginx.com         ret = nxt_http_action_resolve(task, tmcf, &(*match)->action);
13411472Svbart@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
13421472Svbart@nginx.com             return NXT_ERROR;
13431472Svbart@nginx.com         }
1344964Sigor@sysoev.ru 
1345964Sigor@sysoev.ru         match++;
1346964Sigor@sysoev.ru     }
13471472Svbart@nginx.com 
13481472Svbart@nginx.com     return NXT_OK;
1349964Sigor@sysoev.ru }
1350964Sigor@sysoev.ru 
1351964Sigor@sysoev.ru 
13521472Svbart@nginx.com static nxt_int_t
13531264Sigor@sysoev.ru nxt_http_action_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
13541264Sigor@sysoev.ru     nxt_http_action_t *action)
1355964Sigor@sysoev.ru {
13561923Sz.hong@f5.com     nxt_int_t  ret;
13571954Sz.hong@f5.com     nxt_str_t  pass;
1358964Sigor@sysoev.ru 
13591378Svbart@nginx.com     if (action->handler != NULL) {
13601923Sz.hong@f5.com         if (action->fallback != NULL) {
13611923Sz.hong@f5.com             return nxt_http_action_resolve(task, tmcf, action->fallback);
13621378Svbart@nginx.com         }
13631378Svbart@nginx.com 
13641472Svbart@nginx.com         return NXT_OK;
13651378Svbart@nginx.com     }
13661378Svbart@nginx.com 
13671954Sz.hong@f5.com     if (nxt_var_is_const(action->u.var)) {
13681954Sz.hong@f5.com         nxt_var_raw(action->u.var, &pass);
13691954Sz.hong@f5.com 
13701954Sz.hong@f5.com         ret = nxt_http_pass_find(tmcf->mem_pool, tmcf->router_conf, &pass,
13711954Sz.hong@f5.com                                  action);
13721954Sz.hong@f5.com         if (nxt_slow_path(ret != NXT_OK)) {
13731563Svbart@nginx.com             return NXT_ERROR;
13741563Svbart@nginx.com         }
13751563Svbart@nginx.com 
13761954Sz.hong@f5.com     } else {
13771954Sz.hong@f5.com         action->handler = nxt_http_pass_var;
13781472Svbart@nginx.com     }
13791472Svbart@nginx.com 
13801563Svbart@nginx.com     return NXT_OK;
13811563Svbart@nginx.com }
13821563Svbart@nginx.com 
13831563Svbart@nginx.com 
13841563Svbart@nginx.com static nxt_http_action_t *
13851954Sz.hong@f5.com nxt_http_pass_var(nxt_task_t *task, nxt_http_request_t *r,
13861563Svbart@nginx.com     nxt_http_action_t *action)
13871563Svbart@nginx.com {
13881954Sz.hong@f5.com     nxt_int_t  ret;
13891954Sz.hong@f5.com     nxt_str_t  str;
13901563Svbart@nginx.com     nxt_var_t  *var;
13911954Sz.hong@f5.com 
13921954Sz.hong@f5.com     var = action->u.var;
13931954Sz.hong@f5.com 
13941954Sz.hong@f5.com     nxt_var_raw(var, &str);
13951954Sz.hong@f5.com 
13961954Sz.hong@f5.com     nxt_debug(task, "http pass: \"%V\"", &str);
13971563Svbart@nginx.com 
13981563Svbart@nginx.com     ret = nxt_var_query_init(&r->var_query, r, r->mem_pool);
13991563Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
14001563Svbart@nginx.com         goto fail;
14011563Svbart@nginx.com     }
14021563Svbart@nginx.com 
14031954Sz.hong@f5.com     action = nxt_mp_get(r->mem_pool,
14041954Sz.hong@f5.com                         sizeof(nxt_http_action_t) + sizeof(nxt_str_t));
14051563Svbart@nginx.com     if (nxt_slow_path(action == NULL)) {
14061563Svbart@nginx.com         goto fail;
14071563Svbart@nginx.com     }
14081563Svbart@nginx.com 
14091954Sz.hong@f5.com     action->u.pass = nxt_pointer_to(action, sizeof(nxt_http_action_t));
14101954Sz.hong@f5.com 
14111954Sz.hong@f5.com     nxt_var_query(task, r->var_query, var, action->u.pass);
14121563Svbart@nginx.com     nxt_var_query_resolve(task, r->var_query, action,
14131954Sz.hong@f5.com                           nxt_http_pass_var_ready,
14141954Sz.hong@f5.com                           nxt_http_pass_var_error);
14151563Svbart@nginx.com     return NULL;
14161563Svbart@nginx.com 
14171563Svbart@nginx.com fail:
14181563Svbart@nginx.com 
14191563Svbart@nginx.com     nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
14201563Svbart@nginx.com     return NULL;
14211563Svbart@nginx.com }
14221563Svbart@nginx.com 
14231563Svbart@nginx.com 
14241563Svbart@nginx.com static void
14251954Sz.hong@f5.com nxt_http_pass_var_ready(nxt_task_t *task, void *obj, void *data)
14261563Svbart@nginx.com {
14271563Svbart@nginx.com     nxt_int_t           ret;
14281563Svbart@nginx.com     nxt_router_conf_t   *rtcf;
14291563Svbart@nginx.com     nxt_http_action_t   *action;
14301563Svbart@nginx.com     nxt_http_status_t   status;
14311563Svbart@nginx.com     nxt_http_request_t  *r;
14321563Svbart@nginx.com 
14331563Svbart@nginx.com     r = obj;
14341563Svbart@nginx.com     action = data;
14351563Svbart@nginx.com     rtcf = r->conf->socket_conf->router_conf;
14361563Svbart@nginx.com 
14371954Sz.hong@f5.com     nxt_debug(task, "http pass lookup: %V", action->u.pass);
14381954Sz.hong@f5.com 
14391954Sz.hong@f5.com     ret = nxt_http_pass_find(r->mem_pool, rtcf, action->u.pass, action);
14401563Svbart@nginx.com 
14411563Svbart@nginx.com     if (ret != NXT_OK) {
14421563Svbart@nginx.com         status = (ret == NXT_DECLINED) ? NXT_HTTP_NOT_FOUND
14431563Svbart@nginx.com                                        : NXT_HTTP_INTERNAL_SERVER_ERROR;
14441563Svbart@nginx.com 
14451563Svbart@nginx.com         nxt_http_request_error(task, r, status);
14461563Svbart@nginx.com         return;
14471563Svbart@nginx.com     }
14481563Svbart@nginx.com 
14491563Svbart@nginx.com     nxt_http_request_action(task, r, action);
14501563Svbart@nginx.com }
14511563Svbart@nginx.com 
14521563Svbart@nginx.com 
14531563Svbart@nginx.com static void
14541954Sz.hong@f5.com nxt_http_pass_var_error(nxt_task_t *task, void *obj, void *data)
14551563Svbart@nginx.com {
14561563Svbart@nginx.com     nxt_http_request_t  *r;
14571563Svbart@nginx.com 
14581563Svbart@nginx.com     r = obj;
14591563Svbart@nginx.com 
14601563Svbart@nginx.com     nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
14611563Svbart@nginx.com }
14621563Svbart@nginx.com 
14631563Svbart@nginx.com 
14641563Svbart@nginx.com static nxt_int_t
14651954Sz.hong@f5.com nxt_http_pass_find(nxt_mp_t *mp, nxt_router_conf_t *rtcf, nxt_str_t *pass,
14661563Svbart@nginx.com     nxt_http_action_t *action)
14671563Svbart@nginx.com {
14681954Sz.hong@f5.com     nxt_int_t  ret;
14691954Sz.hong@f5.com     nxt_str_t  segments[3];
14701954Sz.hong@f5.com 
14711954Sz.hong@f5.com     ret = nxt_http_pass_segments(mp, pass, segments, 3);
14721563Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
14731563Svbart@nginx.com         return ret;
14741563Svbart@nginx.com     }
14751563Svbart@nginx.com 
14761472Svbart@nginx.com     if (nxt_str_eq(&segments[0], "applications", 12)) {
14771925Sz.hong@f5.com         return nxt_router_application_init(rtcf, &segments[1], &segments[2],
14781925Sz.hong@f5.com                                            action);
14791472Svbart@nginx.com     }
14801472Svbart@nginx.com 
14811563Svbart@nginx.com     if (segments[2].length == 0) {
14821563Svbart@nginx.com         if (nxt_str_eq(&segments[0], "upstreams", 9)) {
14831563Svbart@nginx.com             return nxt_upstream_find(rtcf->upstreams, &segments[1], action);
14841563Svbart@nginx.com         }
14851563Svbart@nginx.com 
14861563Svbart@nginx.com         if (nxt_str_eq(&segments[0], "routes", 6)) {
14871563Svbart@nginx.com             return nxt_http_route_find(rtcf->routes, &segments[1], action);
14881563Svbart@nginx.com         }
14891563Svbart@nginx.com     }
14901563Svbart@nginx.com 
14911563Svbart@nginx.com     return NXT_DECLINED;
14921472Svbart@nginx.com }
14931472Svbart@nginx.com 
14941472Svbart@nginx.com 
14951472Svbart@nginx.com nxt_int_t
14961472Svbart@nginx.com nxt_http_pass_segments(nxt_mp_t *mp, nxt_str_t *pass, nxt_str_t *segments,
14971472Svbart@nginx.com     nxt_uint_t n)
14981472Svbart@nginx.com {
14991472Svbart@nginx.com     u_char     *p;
15001472Svbart@nginx.com     nxt_str_t  rest;
15011472Svbart@nginx.com 
15021472Svbart@nginx.com     if (nxt_slow_path(nxt_str_dup(mp, &rest, pass) == NULL)) {
15031472Svbart@nginx.com         return NXT_ERROR;
15041472Svbart@nginx.com     }
15051472Svbart@nginx.com 
15061472Svbart@nginx.com     nxt_memzero(segments, n * sizeof(nxt_str_t));
15071472Svbart@nginx.com 
15081472Svbart@nginx.com     do {
15091472Svbart@nginx.com         p = nxt_memchr(rest.start, '/', rest.length);
15101472Svbart@nginx.com 
15111472Svbart@nginx.com         if (p != NULL) {
15121472Svbart@nginx.com             n--;
15131472Svbart@nginx.com 
15141472Svbart@nginx.com             if (n == 0) {
15151472Svbart@nginx.com                 return NXT_DECLINED;
15161472Svbart@nginx.com             }
15171472Svbart@nginx.com 
15181472Svbart@nginx.com             segments->length = p - rest.start;
15191472Svbart@nginx.com             segments->start = rest.start;
15201472Svbart@nginx.com 
15211472Svbart@nginx.com             rest.length -= segments->length + 1;
15221472Svbart@nginx.com             rest.start = p + 1;
15231472Svbart@nginx.com 
15241472Svbart@nginx.com         } else {
15251472Svbart@nginx.com             n = 0;
15261472Svbart@nginx.com             *segments = rest;
1527964Sigor@sysoev.ru         }
1528964Sigor@sysoev.ru 
15291472Svbart@nginx.com         if (segments->length == 0) {
15301472Svbart@nginx.com             return NXT_DECLINED;
15311472Svbart@nginx.com         }
15321472Svbart@nginx.com 
15331472Svbart@nginx.com         p = nxt_decode_uri(segments->start, segments->start, segments->length);
15341472Svbart@nginx.com         if (p == NULL) {
15351472Svbart@nginx.com             return NXT_DECLINED;
15361472Svbart@nginx.com         }
15371472Svbart@nginx.com 
15381472Svbart@nginx.com         segments->length = p - segments->start;
15391472Svbart@nginx.com         segments++;
15401472Svbart@nginx.com 
15411472Svbart@nginx.com     } while (n);
15421472Svbart@nginx.com 
15431472Svbart@nginx.com     return NXT_OK;
1544964Sigor@sysoev.ru }
1545964Sigor@sysoev.ru 
1546964Sigor@sysoev.ru 
15471563Svbart@nginx.com static nxt_int_t
15481392Sigor@sysoev.ru nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name,
15491392Sigor@sysoev.ru     nxt_http_action_t *action)
1550964Sigor@sysoev.ru {
15511033Svbart@nginx.com     nxt_http_route_t  **route, **end;
1552964Sigor@sysoev.ru 
15531928Sz.hong@f5.com     if (routes == NULL) {
15541928Sz.hong@f5.com         return NXT_DECLINED;
15551928Sz.hong@f5.com     }
15561928Sz.hong@f5.com 
1557964Sigor@sysoev.ru     route = &routes->route[0];
15581033Svbart@nginx.com     end = route + routes->items;
1559964Sigor@sysoev.ru 
15601058Sigor@sysoev.ru     while (route < end) {
1561964Sigor@sysoev.ru         if (nxt_strstr_eq(&(*route)->name, name)) {
15621392Sigor@sysoev.ru             action->u.route = *route;
15631392Sigor@sysoev.ru             action->handler = nxt_http_route_handler;
15641392Sigor@sysoev.ru 
15651563Svbart@nginx.com             return NXT_OK;
1566964Sigor@sysoev.ru         }
1567964Sigor@sysoev.ru 
1568964Sigor@sysoev.ru         route++;
15691058Sigor@sysoev.ru     }
15701563Svbart@nginx.com 
15711563Svbart@nginx.com     return NXT_DECLINED;
1572964Sigor@sysoev.ru }
1573964Sigor@sysoev.ru 
1574964Sigor@sysoev.ru 
15751264Sigor@sysoev.ru nxt_http_action_t *
15761264Sigor@sysoev.ru nxt_http_action_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
15771954Sz.hong@f5.com     nxt_str_t *pass)
1578964Sigor@sysoev.ru {
15791954Sz.hong@f5.com     nxt_mp_t           *mp;
15801597Shongzhidao@gmail.com     nxt_int_t          ret;
15811264Sigor@sysoev.ru     nxt_http_action_t  *action;
1582964Sigor@sysoev.ru 
15831954Sz.hong@f5.com     mp = tmcf->router_conf->mem_pool;
15841954Sz.hong@f5.com 
15851954Sz.hong@f5.com     action = nxt_mp_alloc(mp, sizeof(nxt_http_action_t));
15861264Sigor@sysoev.ru     if (nxt_slow_path(action == NULL)) {
1587964Sigor@sysoev.ru         return NULL;
1588964Sigor@sysoev.ru     }
1589964Sigor@sysoev.ru 
15901959Sz.hong@f5.com     action->u.var = nxt_var_compile(pass, mp, 0);
15911954Sz.hong@f5.com     if (nxt_slow_path(action->u.var == NULL)) {
15921954Sz.hong@f5.com         return NULL;
15931954Sz.hong@f5.com     }
15941954Sz.hong@f5.com 
15951270Sigor@sysoev.ru     action->handler = NULL;
1596964Sigor@sysoev.ru 
15971597Shongzhidao@gmail.com     ret = nxt_http_action_resolve(task, tmcf, action);
15981597Shongzhidao@gmail.com     if (nxt_slow_path(ret != NXT_OK)) {
15991597Shongzhidao@gmail.com         return NULL;
16001597Shongzhidao@gmail.com     }
1601964Sigor@sysoev.ru 
16021264Sigor@sysoev.ru     return action;
1603964Sigor@sysoev.ru }
1604964Sigor@sysoev.ru 
1605964Sigor@sysoev.ru 
1606964Sigor@sysoev.ru /* COMPATIBILITY: listener application. */
1607964Sigor@sysoev.ru 
16081264Sigor@sysoev.ru nxt_http_action_t *
16091563Svbart@nginx.com nxt_http_pass_application(nxt_task_t *task, nxt_router_conf_t *rtcf,
1610964Sigor@sysoev.ru     nxt_str_t *name)
1611964Sigor@sysoev.ru {
16121264Sigor@sysoev.ru     nxt_http_action_t  *action;
1613964Sigor@sysoev.ru 
16141563Svbart@nginx.com     action = nxt_mp_alloc(rtcf->mem_pool, sizeof(nxt_http_action_t));
16151264Sigor@sysoev.ru     if (nxt_slow_path(action == NULL)) {
1616964Sigor@sysoev.ru         return NULL;
1617964Sigor@sysoev.ru     }
1618964Sigor@sysoev.ru 
16191925Sz.hong@f5.com     (void) nxt_router_application_init(rtcf, name, NULL, action);
16201473Svbart@nginx.com 
16211264Sigor@sysoev.ru     return action;
1622964Sigor@sysoev.ru }
1623964Sigor@sysoev.ru 
1624964Sigor@sysoev.ru 
16251264Sigor@sysoev.ru static nxt_http_action_t *
16261264Sigor@sysoev.ru nxt_http_route_handler(nxt_task_t *task, nxt_http_request_t *r,
16271264Sigor@sysoev.ru     nxt_http_action_t *start)
1628964Sigor@sysoev.ru {
1629964Sigor@sysoev.ru     nxt_http_route_t        *route;
16301264Sigor@sysoev.ru     nxt_http_action_t       *action;
16311033Svbart@nginx.com     nxt_http_route_match_t  **match, **end;
1632964Sigor@sysoev.ru 
1633964Sigor@sysoev.ru     route = start->u.route;
1634964Sigor@sysoev.ru     match = &route->match[0];
16351033Svbart@nginx.com     end = match + route->items;
1636964Sigor@sysoev.ru 
16371033Svbart@nginx.com     while (match < end) {
16381326Saxel.duch@nginx.com         action = nxt_http_route_match(task, r, *match);
16391264Sigor@sysoev.ru         if (action != NULL) {
16401264Sigor@sysoev.ru             return action;
1641964Sigor@sysoev.ru         }
1642964Sigor@sysoev.ru 
1643964Sigor@sysoev.ru         match++;
1644964Sigor@sysoev.ru     }
1645964Sigor@sysoev.ru 
1646964Sigor@sysoev.ru     nxt_http_request_error(task, r, NXT_HTTP_NOT_FOUND);
1647964Sigor@sysoev.ru 
1648964Sigor@sysoev.ru     return NULL;
1649964Sigor@sysoev.ru }
1650964Sigor@sysoev.ru 
1651964Sigor@sysoev.ru 
16521264Sigor@sysoev.ru static nxt_http_action_t *
16531326Saxel.duch@nginx.com nxt_http_route_match(nxt_task_t *task, nxt_http_request_t *r,
16541326Saxel.duch@nginx.com     nxt_http_route_match_t *match)
1655964Sigor@sysoev.ru {
16561060Sigor@sysoev.ru     nxt_int_t              ret;
16571059Sigor@sysoev.ru     nxt_http_route_test_t  *test, *end;
16581059Sigor@sysoev.ru 
16591059Sigor@sysoev.ru     test = &match->test[0];
16601059Sigor@sysoev.ru     end = test + match->items;
1661964Sigor@sysoev.ru 
16621059Sigor@sysoev.ru     while (test < end) {
16631324Saxel.duch@nginx.com         switch (test->rule->object) {
16641324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_TABLE:
16651324Saxel.duch@nginx.com             ret = nxt_http_route_table(r, test->table);
16661324Saxel.duch@nginx.com             break;
16671324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_SOURCE:
16681324Saxel.duch@nginx.com             ret = nxt_http_route_addr_rule(r, test->addr_rule, r->remote);
16691324Saxel.duch@nginx.com             break;
16701326Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_DESTINATION:
16711326Saxel.duch@nginx.com             if (r->local == NULL && nxt_fast_path(r->proto.any != NULL)) {
16721326Saxel.duch@nginx.com                 nxt_http_proto[r->protocol].local_addr(task, r);
16731326Saxel.duch@nginx.com             }
16741326Saxel.duch@nginx.com 
16751326Saxel.duch@nginx.com             ret = nxt_http_route_addr_rule(r, test->addr_rule, r->local);
16761326Saxel.duch@nginx.com             break;
16771324Saxel.duch@nginx.com         default:
16781059Sigor@sysoev.ru             ret = nxt_http_route_rule(r, test->rule);
16791324Saxel.duch@nginx.com             break;
16801059Sigor@sysoev.ru         }
16811059Sigor@sysoev.ru 
16821060Sigor@sysoev.ru         if (ret <= 0) {
16831264Sigor@sysoev.ru             /* 0 => NULL, -1 => NXT_HTTP_ACTION_ERROR. */
16841264Sigor@sysoev.ru             return (nxt_http_action_t *) (intptr_t) ret;
1685964Sigor@sysoev.ru         }
1686964Sigor@sysoev.ru 
16871059Sigor@sysoev.ru         test++;
1688964Sigor@sysoev.ru     }
1689964Sigor@sysoev.ru 
16901264Sigor@sysoev.ru     return &match->action;
1691964Sigor@sysoev.ru }
1692964Sigor@sysoev.ru 
1693964Sigor@sysoev.ru 
16941060Sigor@sysoev.ru static nxt_int_t
16951059Sigor@sysoev.ru nxt_http_route_table(nxt_http_request_t *r, nxt_http_route_table_t *table)
1696964Sigor@sysoev.ru {
16971060Sigor@sysoev.ru     nxt_int_t                 ret;
16981059Sigor@sysoev.ru     nxt_http_route_ruleset_t  **ruleset, **end;
16991059Sigor@sysoev.ru 
17001059Sigor@sysoev.ru     ret = 1;
17011059Sigor@sysoev.ru     ruleset = &table->ruleset[0];
17021059Sigor@sysoev.ru     end = ruleset + table->items;
17031059Sigor@sysoev.ru 
17041059Sigor@sysoev.ru     while (ruleset < end) {
17051059Sigor@sysoev.ru         ret = nxt_http_route_ruleset(r, *ruleset);
17061059Sigor@sysoev.ru 
17071060Sigor@sysoev.ru         if (ret != 0) {
17081059Sigor@sysoev.ru             return ret;
17091059Sigor@sysoev.ru         }
1710964Sigor@sysoev.ru 
17111059Sigor@sysoev.ru         ruleset++;
17121059Sigor@sysoev.ru     }
17131059Sigor@sysoev.ru 
17141059Sigor@sysoev.ru     return ret;
17151059Sigor@sysoev.ru }
17161059Sigor@sysoev.ru 
1717964Sigor@sysoev.ru 
17181060Sigor@sysoev.ru static nxt_int_t
17191059Sigor@sysoev.ru nxt_http_route_ruleset(nxt_http_request_t *r, nxt_http_route_ruleset_t *ruleset)
17201059Sigor@sysoev.ru {
17211060Sigor@sysoev.ru     nxt_int_t              ret;
17221059Sigor@sysoev.ru     nxt_http_route_rule_t  **rule, **end;
1723964Sigor@sysoev.ru 
17241059Sigor@sysoev.ru     rule = &ruleset->rule[0];
17251059Sigor@sysoev.ru     end = rule + ruleset->items;
1726964Sigor@sysoev.ru 
17271059Sigor@sysoev.ru     while (rule < end) {
17281060Sigor@sysoev.ru         ret = nxt_http_route_rule(r, *rule);
17291060Sigor@sysoev.ru 
17301060Sigor@sysoev.ru         if (ret <= 0) {
17311060Sigor@sysoev.ru             return ret;
1732964Sigor@sysoev.ru         }
1733964Sigor@sysoev.ru 
17341059Sigor@sysoev.ru         rule++;
17351059Sigor@sysoev.ru     }
17361059Sigor@sysoev.ru 
17371059Sigor@sysoev.ru     return 1;
17381059Sigor@sysoev.ru }
17391059Sigor@sysoev.ru 
1740964Sigor@sysoev.ru 
17411060Sigor@sysoev.ru static nxt_int_t
17421059Sigor@sysoev.ru nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
17431059Sigor@sysoev.ru {
17441059Sigor@sysoev.ru     void       *p, **pp;
17451059Sigor@sysoev.ru     u_char     *start;
17461059Sigor@sysoev.ru     size_t     length;
17471059Sigor@sysoev.ru     nxt_str_t  *s;
17481059Sigor@sysoev.ru 
17491059Sigor@sysoev.ru     switch (rule->object) {
17501059Sigor@sysoev.ru 
17511059Sigor@sysoev.ru     case NXT_HTTP_ROUTE_HEADER:
17521059Sigor@sysoev.ru         return nxt_http_route_header(r, rule);
1753964Sigor@sysoev.ru 
17541059Sigor@sysoev.ru     case NXT_HTTP_ROUTE_ARGUMENT:
17551061Sigor@sysoev.ru         return nxt_http_route_arguments(r, rule);
1756964Sigor@sysoev.ru 
17571059Sigor@sysoev.ru     case NXT_HTTP_ROUTE_COOKIE:
17581062Sigor@sysoev.ru         return nxt_http_route_cookies(r, rule);
17591059Sigor@sysoev.ru 
17601110Saxel.duch@nginx.com     case NXT_HTTP_ROUTE_SCHEME:
17611110Saxel.duch@nginx.com         return nxt_http_route_scheme(r, rule);
17621110Saxel.duch@nginx.com 
17631991Sz.hong@f5.com     case NXT_HTTP_ROUTE_QUERY:
17641991Sz.hong@f5.com         return nxt_http_route_query(r, rule);
17651991Sz.hong@f5.com 
17661059Sigor@sysoev.ru     default:
17671059Sigor@sysoev.ru         break;
17681059Sigor@sysoev.ru     }
1769964Sigor@sysoev.ru 
17701059Sigor@sysoev.ru     p = nxt_pointer_to(r, rule->u.offset);
17711059Sigor@sysoev.ru 
17721059Sigor@sysoev.ru     if (rule->object == NXT_HTTP_ROUTE_STRING) {
17731059Sigor@sysoev.ru         s = p;
1774964Sigor@sysoev.ru 
17751059Sigor@sysoev.ru     } else {
17761059Sigor@sysoev.ru         /* NXT_HTTP_ROUTE_STRING_PTR */
17771059Sigor@sysoev.ru         pp = p;
17781059Sigor@sysoev.ru         s = *pp;
1779964Sigor@sysoev.ru 
17801059Sigor@sysoev.ru         if (s == NULL) {
1781964Sigor@sysoev.ru             return 0;
1782964Sigor@sysoev.ru         }
1783964Sigor@sysoev.ru     }
1784964Sigor@sysoev.ru 
17851059Sigor@sysoev.ru     length = s->length;
17861059Sigor@sysoev.ru     start = s->start;
17871059Sigor@sysoev.ru 
17881059Sigor@sysoev.ru     return nxt_http_route_test_rule(r, rule, start, length);
17891059Sigor@sysoev.ru }
17901059Sigor@sysoev.ru 
17911059Sigor@sysoev.ru 
17921060Sigor@sysoev.ru static nxt_int_t
17931324Saxel.duch@nginx.com nxt_http_route_addr_pattern_match(nxt_http_route_addr_pattern_t *p,
17941324Saxel.duch@nginx.com     nxt_sockaddr_t *sa)
17951324Saxel.duch@nginx.com {
17961324Saxel.duch@nginx.com #if (NXT_INET6)
17971324Saxel.duch@nginx.com     uint32_t                    i;
17981324Saxel.duch@nginx.com #endif
17991324Saxel.duch@nginx.com     in_port_t                   in_port;
18001324Saxel.duch@nginx.com     nxt_int_t                   match;
18011324Saxel.duch@nginx.com     struct sockaddr_in          *sin;
18021324Saxel.duch@nginx.com #if (NXT_INET6)
18031324Saxel.duch@nginx.com     struct sockaddr_in6         *sin6;
18041324Saxel.duch@nginx.com #endif
18051324Saxel.duch@nginx.com     nxt_http_route_addr_base_t  *base;
18061324Saxel.duch@nginx.com 
18071324Saxel.duch@nginx.com     base = &p->base;
18081324Saxel.duch@nginx.com 
18091324Saxel.duch@nginx.com     switch (sa->u.sockaddr.sa_family) {
18101324Saxel.duch@nginx.com 
18111324Saxel.duch@nginx.com     case AF_INET:
18121324Saxel.duch@nginx.com 
18131324Saxel.duch@nginx.com         match = (base->addr_family == AF_INET
18141324Saxel.duch@nginx.com                  || base->addr_family == AF_UNSPEC);
18151324Saxel.duch@nginx.com         if (!match) {
18161324Saxel.duch@nginx.com             break;
18171324Saxel.duch@nginx.com         }
18181324Saxel.duch@nginx.com 
18191324Saxel.duch@nginx.com         sin = &sa->u.sockaddr_in;
18201324Saxel.duch@nginx.com         in_port = ntohs(sin->sin_port);
18211324Saxel.duch@nginx.com 
18221324Saxel.duch@nginx.com         match = (in_port >= base->port.start && in_port <= base->port.end);
18231324Saxel.duch@nginx.com         if (!match) {
18241324Saxel.duch@nginx.com             break;
18251324Saxel.duch@nginx.com         }
18261324Saxel.duch@nginx.com 
18271324Saxel.duch@nginx.com         switch (base->match_type) {
18281324Saxel.duch@nginx.com 
18291324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_ADDR_ANY:
18301324Saxel.duch@nginx.com             break;
18311324Saxel.duch@nginx.com 
18321324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_ADDR_EXACT:
18331324Saxel.duch@nginx.com             match = (nxt_memcmp(&sin->sin_addr, &p->addr.v4.start,
18341324Saxel.duch@nginx.com                                 sizeof(struct in_addr))
18351324Saxel.duch@nginx.com                      == 0);
18361324Saxel.duch@nginx.com             break;
18371324Saxel.duch@nginx.com 
18381324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_ADDR_RANGE:
18391324Saxel.duch@nginx.com             match = (nxt_memcmp(&sin->sin_addr, &p->addr.v4.start,
18401324Saxel.duch@nginx.com                                 sizeof(struct in_addr)) >= 0
18411324Saxel.duch@nginx.com                      && nxt_memcmp(&sin->sin_addr, &p->addr.v4.end,
18421324Saxel.duch@nginx.com                                    sizeof(struct in_addr)) <= 0);
18431324Saxel.duch@nginx.com             break;
18441324Saxel.duch@nginx.com 
18451324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_ADDR_CIDR:
18461324Saxel.duch@nginx.com             match = ((sin->sin_addr.s_addr & p->addr.v4.end)
18471324Saxel.duch@nginx.com                      == p->addr.v4.start);
18481324Saxel.duch@nginx.com             break;
18491324Saxel.duch@nginx.com 
18501324Saxel.duch@nginx.com         default:
18511324Saxel.duch@nginx.com             nxt_unreachable();
18521324Saxel.duch@nginx.com         }
18531324Saxel.duch@nginx.com 
18541324Saxel.duch@nginx.com         break;
18551324Saxel.duch@nginx.com 
18561324Saxel.duch@nginx.com #if (NXT_INET6)
18571324Saxel.duch@nginx.com     case AF_INET6:
18581324Saxel.duch@nginx.com 
18591324Saxel.duch@nginx.com         match = (base->addr_family == AF_INET6
18601324Saxel.duch@nginx.com                  || base->addr_family == AF_UNSPEC);
18611324Saxel.duch@nginx.com         if (!match) {
18621324Saxel.duch@nginx.com             break;
18631324Saxel.duch@nginx.com         }
18641324Saxel.duch@nginx.com 
18651324Saxel.duch@nginx.com         sin6 = &sa->u.sockaddr_in6;
18661324Saxel.duch@nginx.com         in_port = ntohs(sin6->sin6_port);
18671324Saxel.duch@nginx.com 
18681324Saxel.duch@nginx.com         match = (in_port >= base->port.start && in_port <= base->port.end);
18691324Saxel.duch@nginx.com         if (!match) {
18701324Saxel.duch@nginx.com             break;
18711324Saxel.duch@nginx.com         }
18721324Saxel.duch@nginx.com 
18731324Saxel.duch@nginx.com         switch (base->match_type) {
18741324Saxel.duch@nginx.com 
18751324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_ADDR_ANY:
18761324Saxel.duch@nginx.com             break;
18771324Saxel.duch@nginx.com 
18781324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_ADDR_EXACT:
18791324Saxel.duch@nginx.com             match = (nxt_memcmp(&sin6->sin6_addr, &p->addr.v6.start,
18801324Saxel.duch@nginx.com                                 sizeof(struct in6_addr))
18811324Saxel.duch@nginx.com                      == 0);
18821324Saxel.duch@nginx.com             break;
18831324Saxel.duch@nginx.com 
18841324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_ADDR_RANGE:
18851324Saxel.duch@nginx.com             match = (nxt_memcmp(&sin6->sin6_addr, &p->addr.v6.start,
18861324Saxel.duch@nginx.com                                 sizeof(struct in6_addr)) >= 0
18871324Saxel.duch@nginx.com                      && nxt_memcmp(&sin6->sin6_addr, &p->addr.v6.end,
18881324Saxel.duch@nginx.com                                    sizeof(struct in6_addr)) <= 0);
18891324Saxel.duch@nginx.com             break;
18901324Saxel.duch@nginx.com 
18911324Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_ADDR_CIDR:
18921324Saxel.duch@nginx.com             for (i = 0; i < 16; i++) {
18931324Saxel.duch@nginx.com                 match = ((sin6->sin6_addr.s6_addr[i]
18941324Saxel.duch@nginx.com                           & p->addr.v6.end.s6_addr[i])
18951324Saxel.duch@nginx.com                          == p->addr.v6.start.s6_addr[i]);
18961324Saxel.duch@nginx.com 
18971324Saxel.duch@nginx.com                 if (!match) {
18981324Saxel.duch@nginx.com                     break;
18991324Saxel.duch@nginx.com                 }
19001324Saxel.duch@nginx.com             }
19011324Saxel.duch@nginx.com 
19021324Saxel.duch@nginx.com             break;
19031324Saxel.duch@nginx.com 
19041324Saxel.duch@nginx.com         default:
19051324Saxel.duch@nginx.com             nxt_unreachable();
19061324Saxel.duch@nginx.com         }
19071324Saxel.duch@nginx.com 
19081324Saxel.duch@nginx.com         break;
19091324Saxel.duch@nginx.com #endif
19101324Saxel.duch@nginx.com 
19111324Saxel.duch@nginx.com     default:
19121324Saxel.duch@nginx.com         match = 0;
19131324Saxel.duch@nginx.com         break;
19141324Saxel.duch@nginx.com     }
19151324Saxel.duch@nginx.com 
19161324Saxel.duch@nginx.com     return match ^ base->negative;
19171324Saxel.duch@nginx.com }
19181324Saxel.duch@nginx.com 
19191324Saxel.duch@nginx.com 
19201936So.canty@f5.com nxt_int_t
19211324Saxel.duch@nginx.com nxt_http_route_addr_rule(nxt_http_request_t *r,
19221324Saxel.duch@nginx.com     nxt_http_route_addr_rule_t *addr_rule, nxt_sockaddr_t *sa)
19231324Saxel.duch@nginx.com {
19241390Saxel.duch@nginx.com     uint32_t                       n;
19251390Saxel.duch@nginx.com     nxt_bool_t                     matches;
19261324Saxel.duch@nginx.com     nxt_http_route_addr_pattern_t  *p;
19271324Saxel.duch@nginx.com 
19281324Saxel.duch@nginx.com     n = addr_rule->items;
19291930So.canty@f5.com 
19301930So.canty@f5.com     if (n == 0) {
19311930So.canty@f5.com         return 0;
19321930So.canty@f5.com     }
19331930So.canty@f5.com 
19341390Saxel.duch@nginx.com     p = &addr_rule->addr_pattern[0] - 1;
19351324Saxel.duch@nginx.com 
19361390Saxel.duch@nginx.com     do {
19371390Saxel.duch@nginx.com         p++;
19381390Saxel.duch@nginx.com         n--;
19391390Saxel.duch@nginx.com 
19401390Saxel.duch@nginx.com         matches = nxt_http_route_addr_pattern_match(p, sa);
19411390Saxel.duch@nginx.com 
19421390Saxel.duch@nginx.com         if (p->base.negative) {
19431390Saxel.duch@nginx.com             if (matches) {
19441390Saxel.duch@nginx.com                 continue;
19451390Saxel.duch@nginx.com             }
19461390Saxel.duch@nginx.com 
19471390Saxel.duch@nginx.com             return 0;
19481390Saxel.duch@nginx.com         }
19491390Saxel.duch@nginx.com 
19501390Saxel.duch@nginx.com         if (matches) {
19511324Saxel.duch@nginx.com             return 1;
19521324Saxel.duch@nginx.com         }
19531324Saxel.duch@nginx.com 
19541390Saxel.duch@nginx.com     } while (n > 0);
19551390Saxel.duch@nginx.com 
19561390Saxel.duch@nginx.com     return p->base.negative;
19571324Saxel.duch@nginx.com }
19581324Saxel.duch@nginx.com 
19591324Saxel.duch@nginx.com 
19601324Saxel.duch@nginx.com static nxt_int_t
19611059Sigor@sysoev.ru nxt_http_route_header(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
19621059Sigor@sysoev.ru {
19631060Sigor@sysoev.ru     nxt_int_t         ret;
19641059Sigor@sysoev.ru     nxt_http_field_t  *f;
19651059Sigor@sysoev.ru 
19661059Sigor@sysoev.ru     ret = 0;
19671059Sigor@sysoev.ru 
19681059Sigor@sysoev.ru     nxt_list_each(f, r->fields) {
19691059Sigor@sysoev.ru 
19701059Sigor@sysoev.ru         if (rule->u.name.hash != f->hash
19711059Sigor@sysoev.ru             || rule->u.name.length != f->name_length
19721059Sigor@sysoev.ru             || nxt_strncasecmp(rule->u.name.start, f->name, f->name_length)
19731059Sigor@sysoev.ru                != 0)
19741059Sigor@sysoev.ru         {
19751059Sigor@sysoev.ru             continue;
19761059Sigor@sysoev.ru         }
19771059Sigor@sysoev.ru 
19781059Sigor@sysoev.ru         ret = nxt_http_route_test_rule(r, rule, f->value, f->value_length);
19791721Saxel.duch@nginx.com         if (nxt_slow_path(ret == NXT_ERROR)) {
19801721Saxel.duch@nginx.com             return NXT_ERROR;
19811721Saxel.duch@nginx.com         }
19821059Sigor@sysoev.ru 
19831060Sigor@sysoev.ru         if (ret == 0) {
19841059Sigor@sysoev.ru             return ret;
19851059Sigor@sysoev.ru         }
19861059Sigor@sysoev.ru 
19871059Sigor@sysoev.ru     } nxt_list_loop;
19881059Sigor@sysoev.ru 
19891059Sigor@sysoev.ru     return ret;
19901059Sigor@sysoev.ru }
19911059Sigor@sysoev.ru 
19921059Sigor@sysoev.ru 
19931060Sigor@sysoev.ru static nxt_int_t
19941061Sigor@sysoev.ru nxt_http_route_arguments(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
19951061Sigor@sysoev.ru {
19961061Sigor@sysoev.ru     nxt_array_t  *arguments;
19971061Sigor@sysoev.ru 
19981061Sigor@sysoev.ru     arguments = nxt_http_route_arguments_parse(r);
19991061Sigor@sysoev.ru     if (nxt_slow_path(arguments == NULL)) {
20001061Sigor@sysoev.ru         return -1;
20011061Sigor@sysoev.ru     }
20021061Sigor@sysoev.ru 
20031061Sigor@sysoev.ru     return nxt_http_route_test_argument(r, rule, arguments);
20041061Sigor@sysoev.ru }
20051061Sigor@sysoev.ru 
20061061Sigor@sysoev.ru 
20071061Sigor@sysoev.ru static nxt_array_t *
20081061Sigor@sysoev.ru nxt_http_route_arguments_parse(nxt_http_request_t *r)
20091061Sigor@sysoev.ru {
20101061Sigor@sysoev.ru     size_t                 name_length;
20111989Sz.hong@f5.com     u_char                 *p, *dst, *dst_start, *start, *end, *name;
20121474Saxel.duch@nginx.com     uint8_t                d0, d1;
20131061Sigor@sysoev.ru     uint32_t               hash;
20141061Sigor@sysoev.ru     nxt_array_t            *args;
20151061Sigor@sysoev.ru     nxt_http_name_value_t  *nv;
20161061Sigor@sysoev.ru 
20171061Sigor@sysoev.ru     if (r->arguments != NULL) {
20181061Sigor@sysoev.ru         return r->arguments;
20191061Sigor@sysoev.ru     }
20201061Sigor@sysoev.ru 
20211061Sigor@sysoev.ru     args = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t));
20221061Sigor@sysoev.ru     if (nxt_slow_path(args == NULL)) {
20231061Sigor@sysoev.ru         return NULL;
20241061Sigor@sysoev.ru     }
20251061Sigor@sysoev.ru 
20261061Sigor@sysoev.ru     hash = NXT_HTTP_FIELD_HASH_INIT;
20271061Sigor@sysoev.ru     name = NULL;
20281061Sigor@sysoev.ru     name_length = 0;
20291061Sigor@sysoev.ru 
20301474Saxel.duch@nginx.com     dst_start = nxt_mp_nget(r->mem_pool, r->args->length);
20311474Saxel.duch@nginx.com     if (nxt_slow_path(dst_start == NULL)) {
20321474Saxel.duch@nginx.com         return NULL;
20331474Saxel.duch@nginx.com     }
20341474Saxel.duch@nginx.com 
20351991Sz.hong@f5.com     r->args_decoded.start = dst_start;
20361991Sz.hong@f5.com 
20371061Sigor@sysoev.ru     start = r->args->start;
20381061Sigor@sysoev.ru     end = start + r->args->length;
20391061Sigor@sysoev.ru 
20401474Saxel.duch@nginx.com     for (p = start, dst = dst_start; p < end; p++, dst++) {
20411989Sz.hong@f5.com         *dst = *p;
20421989Sz.hong@f5.com 
20431989Sz.hong@f5.com         switch (*p) {
20441474Saxel.duch@nginx.com         case '=':
20451989Sz.hong@f5.com             if (name == NULL) {
20461989Sz.hong@f5.com                 name_length = dst - dst_start;
20471989Sz.hong@f5.com                 name = dst_start;
20481989Sz.hong@f5.com                 dst_start = dst + 1;
20491474Saxel.duch@nginx.com             }
20501474Saxel.duch@nginx.com 
20511474Saxel.duch@nginx.com             continue;
20521474Saxel.duch@nginx.com 
20531474Saxel.duch@nginx.com         case '&':
20541989Sz.hong@f5.com             if (name_length != 0 || dst != dst_start) {
20551061Sigor@sysoev.ru                 nv = nxt_http_route_argument(args, name, name_length, hash,
20561474Saxel.duch@nginx.com                                              dst_start, dst);
20571061Sigor@sysoev.ru                 if (nxt_slow_path(nv == NULL)) {
20581061Sigor@sysoev.ru                     return NULL;
20591061Sigor@sysoev.ru                 }
20601061Sigor@sysoev.ru             }
20611061Sigor@sysoev.ru 
20621061Sigor@sysoev.ru             hash = NXT_HTTP_FIELD_HASH_INIT;
20631474Saxel.duch@nginx.com             name_length = 0;
20641061Sigor@sysoev.ru             name = NULL;
20651474Saxel.duch@nginx.com             dst_start = dst + 1;
20661474Saxel.duch@nginx.com 
20671474Saxel.duch@nginx.com             continue;
20681474Saxel.duch@nginx.com 
20691474Saxel.duch@nginx.com         case '+':
20701474Saxel.duch@nginx.com             *dst = ' ';
20711474Saxel.duch@nginx.com 
20721474Saxel.duch@nginx.com             break;
20731474Saxel.duch@nginx.com 
20741474Saxel.duch@nginx.com         case '%':
20751474Saxel.duch@nginx.com             if (nxt_slow_path(end - p <= 2)) {
20761474Saxel.duch@nginx.com                 break;
20771474Saxel.duch@nginx.com             }
20781474Saxel.duch@nginx.com 
20791474Saxel.duch@nginx.com             d0 = nxt_hex2int[p[1]];
20801474Saxel.duch@nginx.com             d1 = nxt_hex2int[p[2]];
20811474Saxel.duch@nginx.com 
20821474Saxel.duch@nginx.com             if (nxt_slow_path((d0 | d1) >= 16)) {
20831474Saxel.duch@nginx.com                 break;
20841474Saxel.duch@nginx.com             }
20851474Saxel.duch@nginx.com 
20861474Saxel.duch@nginx.com             p += 2;
20871989Sz.hong@f5.com             *dst = (d0 << 4) + d1;
20881474Saxel.duch@nginx.com 
20891474Saxel.duch@nginx.com             break;
20901474Saxel.duch@nginx.com         }
20911474Saxel.duch@nginx.com 
20921474Saxel.duch@nginx.com         if (name == NULL) {
20931989Sz.hong@f5.com             hash = nxt_http_field_hash_char(hash, *dst);
20941061Sigor@sysoev.ru         }
20951061Sigor@sysoev.ru     }
20961061Sigor@sysoev.ru 
20971991Sz.hong@f5.com     r->args_decoded.length = dst - r->args_decoded.start;
20981991Sz.hong@f5.com 
20991989Sz.hong@f5.com     if (name_length != 0 || dst != dst_start) {
21001474Saxel.duch@nginx.com         nv = nxt_http_route_argument(args, name, name_length, hash, dst_start,
21011474Saxel.duch@nginx.com                                      dst);
21021061Sigor@sysoev.ru         if (nxt_slow_path(nv == NULL)) {
21031061Sigor@sysoev.ru             return NULL;
21041061Sigor@sysoev.ru         }
21051061Sigor@sysoev.ru     }
21061061Sigor@sysoev.ru 
21071061Sigor@sysoev.ru     r->arguments = args;
21081061Sigor@sysoev.ru 
21091061Sigor@sysoev.ru     return args;
21101061Sigor@sysoev.ru }
21111061Sigor@sysoev.ru 
21121061Sigor@sysoev.ru 
21131061Sigor@sysoev.ru static nxt_http_name_value_t *
21141061Sigor@sysoev.ru nxt_http_route_argument(nxt_array_t *array, u_char *name, size_t name_length,
21151061Sigor@sysoev.ru     uint32_t hash, u_char *start, u_char *end)
21161061Sigor@sysoev.ru {
21171061Sigor@sysoev.ru     size_t                 length;
21181061Sigor@sysoev.ru     nxt_http_name_value_t  *nv;
21191061Sigor@sysoev.ru 
21201061Sigor@sysoev.ru     nv = nxt_array_add(array);
21211061Sigor@sysoev.ru     if (nxt_slow_path(nv == NULL)) {
21221061Sigor@sysoev.ru         return NULL;
21231061Sigor@sysoev.ru     }
21241061Sigor@sysoev.ru 
21251061Sigor@sysoev.ru     nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF;
21261061Sigor@sysoev.ru 
21271061Sigor@sysoev.ru     length = end - start;
21281061Sigor@sysoev.ru 
21291061Sigor@sysoev.ru     if (name == NULL) {
21301061Sigor@sysoev.ru         name_length = length;
21311061Sigor@sysoev.ru         name = start;
21321061Sigor@sysoev.ru         length = 0;
21331061Sigor@sysoev.ru     }
21341061Sigor@sysoev.ru 
21351061Sigor@sysoev.ru     nv->name_length = name_length;
21361061Sigor@sysoev.ru     nv->value_length = length;
21371061Sigor@sysoev.ru     nv->name = name;
21381061Sigor@sysoev.ru     nv->value = start;
21391061Sigor@sysoev.ru 
21401061Sigor@sysoev.ru     return nv;
21411061Sigor@sysoev.ru }
21421061Sigor@sysoev.ru 
21431061Sigor@sysoev.ru 
21441061Sigor@sysoev.ru static nxt_int_t
21451061Sigor@sysoev.ru nxt_http_route_test_argument(nxt_http_request_t *r,
21461061Sigor@sysoev.ru     nxt_http_route_rule_t *rule, nxt_array_t *array)
21471061Sigor@sysoev.ru {
21481721Saxel.duch@nginx.com     nxt_int_t              ret;
21491061Sigor@sysoev.ru     nxt_http_name_value_t  *nv, *end;
21501061Sigor@sysoev.ru 
21511061Sigor@sysoev.ru     ret = 0;
21521061Sigor@sysoev.ru 
21531061Sigor@sysoev.ru     nv = array->elts;
21541061Sigor@sysoev.ru     end = nv + array->nelts;
21551061Sigor@sysoev.ru 
21561061Sigor@sysoev.ru     while (nv < end) {
21571061Sigor@sysoev.ru 
21581061Sigor@sysoev.ru         if (rule->u.name.hash == nv->hash
21591061Sigor@sysoev.ru             && rule->u.name.length == nv->name_length
21601061Sigor@sysoev.ru             && nxt_memcmp(rule->u.name.start, nv->name, nv->name_length) == 0)
21611061Sigor@sysoev.ru         {
21621061Sigor@sysoev.ru             ret = nxt_http_route_test_rule(r, rule, nv->value,
21631061Sigor@sysoev.ru                                            nv->value_length);
21641721Saxel.duch@nginx.com             if (nxt_slow_path(ret == NXT_ERROR)) {
21651721Saxel.duch@nginx.com                 return NXT_ERROR;
21661721Saxel.duch@nginx.com             }
21671721Saxel.duch@nginx.com 
21681061Sigor@sysoev.ru             if (ret == 0) {
21691061Sigor@sysoev.ru                 break;
21701061Sigor@sysoev.ru             }
21711061Sigor@sysoev.ru         }
21721061Sigor@sysoev.ru 
21731061Sigor@sysoev.ru         nv++;
21741061Sigor@sysoev.ru     }
21751061Sigor@sysoev.ru 
21761061Sigor@sysoev.ru     return ret;
21771061Sigor@sysoev.ru }
21781061Sigor@sysoev.ru 
21791061Sigor@sysoev.ru 
21801061Sigor@sysoev.ru static nxt_int_t
21811110Saxel.duch@nginx.com nxt_http_route_scheme(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
21821110Saxel.duch@nginx.com {
21831508Saxel.duch@nginx.com     nxt_bool_t                      tls, https;
21841508Saxel.duch@nginx.com     nxt_http_route_pattern_slice_t  *pattern_slice;
21851508Saxel.duch@nginx.com 
21861721Saxel.duch@nginx.com     pattern_slice = rule->pattern[0].u.pattern_slices->elts;
21871508Saxel.duch@nginx.com     https = (pattern_slice->length == nxt_length("https"));
21881110Saxel.duch@nginx.com     tls = (r->tls != NULL);
21891110Saxel.duch@nginx.com 
21901110Saxel.duch@nginx.com     return (tls == https);
21911110Saxel.duch@nginx.com }
21921110Saxel.duch@nginx.com 
21931110Saxel.duch@nginx.com 
21941110Saxel.duch@nginx.com static nxt_int_t
21951991Sz.hong@f5.com nxt_http_route_query(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
21961991Sz.hong@f5.com {
21971991Sz.hong@f5.com     nxt_array_t  *arguments;
21981991Sz.hong@f5.com 
21991991Sz.hong@f5.com     arguments = nxt_http_route_arguments_parse(r);
22001991Sz.hong@f5.com     if (nxt_slow_path(arguments == NULL)) {
22011991Sz.hong@f5.com         return -1;
22021991Sz.hong@f5.com     }
22031991Sz.hong@f5.com 
22041991Sz.hong@f5.com     return nxt_http_route_test_rule(r, rule, r->args_decoded.start,
22051991Sz.hong@f5.com                                     r->args_decoded.length);
22061991Sz.hong@f5.com }
22071991Sz.hong@f5.com 
22081991Sz.hong@f5.com 
22091991Sz.hong@f5.com static nxt_int_t
22101062Sigor@sysoev.ru nxt_http_route_cookies(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
22111062Sigor@sysoev.ru {
22121062Sigor@sysoev.ru     nxt_array_t  *cookies;
22131062Sigor@sysoev.ru 
22141062Sigor@sysoev.ru     cookies = nxt_http_route_cookies_parse(r);
22151062Sigor@sysoev.ru     if (nxt_slow_path(cookies == NULL)) {
22161062Sigor@sysoev.ru         return -1;
22171062Sigor@sysoev.ru     }
22181062Sigor@sysoev.ru 
22191062Sigor@sysoev.ru     return nxt_http_route_test_cookie(r, rule, cookies);
22201062Sigor@sysoev.ru }
22211062Sigor@sysoev.ru 
22221062Sigor@sysoev.ru 
22231062Sigor@sysoev.ru static nxt_array_t *
22241062Sigor@sysoev.ru nxt_http_route_cookies_parse(nxt_http_request_t *r)
22251062Sigor@sysoev.ru {
22261062Sigor@sysoev.ru     nxt_int_t         ret;
22271062Sigor@sysoev.ru     nxt_array_t       *cookies;
22281062Sigor@sysoev.ru     nxt_http_field_t  *f;
22291062Sigor@sysoev.ru 
22301062Sigor@sysoev.ru     if (r->cookies != NULL) {
22311062Sigor@sysoev.ru         return r->cookies;
22321062Sigor@sysoev.ru     }
22331062Sigor@sysoev.ru 
22341062Sigor@sysoev.ru     cookies = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t));
22351062Sigor@sysoev.ru     if (nxt_slow_path(cookies == NULL)) {
22361062Sigor@sysoev.ru         return NULL;
22371062Sigor@sysoev.ru     }
22381062Sigor@sysoev.ru 
22391062Sigor@sysoev.ru     nxt_list_each(f, r->fields) {
22401062Sigor@sysoev.ru 
22411522Saxel.duch@nginx.com         if (f->hash != NXT_COOKIE_HASH
22421062Sigor@sysoev.ru             || f->name_length != 6
22431062Sigor@sysoev.ru             || nxt_strncasecmp(f->name, (u_char *) "Cookie", 6) != 0)
22441062Sigor@sysoev.ru         {
22451062Sigor@sysoev.ru             continue;
22461062Sigor@sysoev.ru         }
22471062Sigor@sysoev.ru 
22481062Sigor@sysoev.ru         ret = nxt_http_route_cookie_parse(cookies, f->value,
22491062Sigor@sysoev.ru                                           f->value + f->value_length);
22501062Sigor@sysoev.ru         if (ret != NXT_OK) {
22511062Sigor@sysoev.ru             return NULL;
22521062Sigor@sysoev.ru         }
22531062Sigor@sysoev.ru 
22541062Sigor@sysoev.ru     } nxt_list_loop;
22551062Sigor@sysoev.ru 
22561062Sigor@sysoev.ru     r->cookies = cookies;
22571062Sigor@sysoev.ru 
22581062Sigor@sysoev.ru     return cookies;
22591062Sigor@sysoev.ru }
22601062Sigor@sysoev.ru 
22611062Sigor@sysoev.ru 
22621062Sigor@sysoev.ru static nxt_int_t
22631062Sigor@sysoev.ru nxt_http_route_cookie_parse(nxt_array_t *cookies, u_char *start, u_char *end)
22641062Sigor@sysoev.ru {
22651062Sigor@sysoev.ru     size_t                 name_length;
22661062Sigor@sysoev.ru     u_char                 c, *p, *name;
22671062Sigor@sysoev.ru     nxt_http_name_value_t  *nv;
22681062Sigor@sysoev.ru 
22691062Sigor@sysoev.ru     name = NULL;
22701062Sigor@sysoev.ru     name_length = 0;
22711062Sigor@sysoev.ru 
22721062Sigor@sysoev.ru     for (p = start; p < end; p++) {
22731062Sigor@sysoev.ru         c = *p;
22741062Sigor@sysoev.ru 
22751062Sigor@sysoev.ru         if (c == '=') {
22761062Sigor@sysoev.ru             while (start[0] == ' ') { start++; }
22771062Sigor@sysoev.ru 
22781062Sigor@sysoev.ru             name_length = p - start;
22791062Sigor@sysoev.ru 
22801062Sigor@sysoev.ru             if (name_length != 0) {
22811062Sigor@sysoev.ru                 name = start;
22821062Sigor@sysoev.ru             }
22831062Sigor@sysoev.ru 
22841062Sigor@sysoev.ru             start = p + 1;
22851062Sigor@sysoev.ru 
22861062Sigor@sysoev.ru         } else if (c == ';') {
22871062Sigor@sysoev.ru             if (name != NULL) {
22881062Sigor@sysoev.ru                 nv = nxt_http_route_cookie(cookies, name, name_length,
22891062Sigor@sysoev.ru                                            start, p);
22901062Sigor@sysoev.ru                 if (nxt_slow_path(nv == NULL)) {
22911062Sigor@sysoev.ru                     return NXT_ERROR;
22921062Sigor@sysoev.ru                 }
22931062Sigor@sysoev.ru             }
22941062Sigor@sysoev.ru 
22951062Sigor@sysoev.ru             name = NULL;
22961062Sigor@sysoev.ru             start = p + 1;
22972078Salx.manpages@gmail.com         }
22981062Sigor@sysoev.ru     }
22991062Sigor@sysoev.ru 
23001062Sigor@sysoev.ru     if (name != NULL) {
23011062Sigor@sysoev.ru         nv = nxt_http_route_cookie(cookies, name, name_length, start, p);
23021062Sigor@sysoev.ru         if (nxt_slow_path(nv == NULL)) {
23031062Sigor@sysoev.ru             return NXT_ERROR;
23041062Sigor@sysoev.ru         }
23051062Sigor@sysoev.ru     }
23061062Sigor@sysoev.ru 
23071062Sigor@sysoev.ru     return NXT_OK;
23081062Sigor@sysoev.ru }
23091062Sigor@sysoev.ru 
23101062Sigor@sysoev.ru 
23111062Sigor@sysoev.ru static nxt_http_name_value_t *
23121062Sigor@sysoev.ru nxt_http_route_cookie(nxt_array_t *array, u_char *name, size_t name_length,
23131062Sigor@sysoev.ru     u_char *start, u_char *end)
23141062Sigor@sysoev.ru {
23151062Sigor@sysoev.ru     u_char                 c, *p;
23161062Sigor@sysoev.ru     uint32_t               hash;
23171062Sigor@sysoev.ru     nxt_http_name_value_t  *nv;
23181062Sigor@sysoev.ru 
23191062Sigor@sysoev.ru     nv = nxt_array_add(array);
23201062Sigor@sysoev.ru     if (nxt_slow_path(nv == NULL)) {
23211062Sigor@sysoev.ru         return NULL;
23221062Sigor@sysoev.ru     }
23231062Sigor@sysoev.ru 
23241062Sigor@sysoev.ru     nv->name_length = name_length;
23251062Sigor@sysoev.ru     nv->name = name;
23261062Sigor@sysoev.ru 
23271062Sigor@sysoev.ru     hash = NXT_HTTP_FIELD_HASH_INIT;
23281062Sigor@sysoev.ru 
23291062Sigor@sysoev.ru     for (p = name; p < name + name_length; p++) {
23301062Sigor@sysoev.ru         c = *p;
23311062Sigor@sysoev.ru         hash = nxt_http_field_hash_char(hash, c);
23321062Sigor@sysoev.ru     }
23331062Sigor@sysoev.ru 
23341062Sigor@sysoev.ru     nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF;
23351062Sigor@sysoev.ru 
23361062Sigor@sysoev.ru     while (start < end && end[-1] == ' ') { end--; }
23371062Sigor@sysoev.ru 
23381062Sigor@sysoev.ru     nv->value_length = end - start;
23391062Sigor@sysoev.ru     nv->value = start;
23401062Sigor@sysoev.ru 
23411062Sigor@sysoev.ru     return nv;
23421062Sigor@sysoev.ru }
23431062Sigor@sysoev.ru 
23441062Sigor@sysoev.ru 
23451062Sigor@sysoev.ru static nxt_int_t
23461062Sigor@sysoev.ru nxt_http_route_test_cookie(nxt_http_request_t *r,
23471062Sigor@sysoev.ru     nxt_http_route_rule_t *rule, nxt_array_t *array)
23481062Sigor@sysoev.ru {
23491721Saxel.duch@nginx.com     nxt_int_t              ret;
23501062Sigor@sysoev.ru     nxt_http_name_value_t  *nv, *end;
23511062Sigor@sysoev.ru 
23521062Sigor@sysoev.ru     ret = 0;
23531062Sigor@sysoev.ru 
23541062Sigor@sysoev.ru     nv = array->elts;
23551062Sigor@sysoev.ru     end = nv + array->nelts;
23561062Sigor@sysoev.ru 
23571062Sigor@sysoev.ru     while (nv < end) {
23581062Sigor@sysoev.ru 
23591062Sigor@sysoev.ru         if (rule->u.name.hash == nv->hash
23601062Sigor@sysoev.ru             && rule->u.name.length == nv->name_length
23611079Sigor@sysoev.ru             && nxt_memcmp(rule->u.name.start, nv->name, nv->name_length) == 0)
23621062Sigor@sysoev.ru         {
23631062Sigor@sysoev.ru             ret = nxt_http_route_test_rule(r, rule, nv->value,
23641062Sigor@sysoev.ru                                            nv->value_length);
23651721Saxel.duch@nginx.com             if (nxt_slow_path(ret == NXT_ERROR)) {
23661721Saxel.duch@nginx.com                 return NXT_ERROR;
23671721Saxel.duch@nginx.com             }
23681721Saxel.duch@nginx.com 
23691062Sigor@sysoev.ru             if (ret == 0) {
23701062Sigor@sysoev.ru                 break;
23711062Sigor@sysoev.ru             }
23721062Sigor@sysoev.ru         }
23731062Sigor@sysoev.ru 
23741062Sigor@sysoev.ru         nv++;
23751062Sigor@sysoev.ru     }
23761062Sigor@sysoev.ru 
23771062Sigor@sysoev.ru     return ret;
23781062Sigor@sysoev.ru }
23791062Sigor@sysoev.ru 
23801062Sigor@sysoev.ru 
23811859So.canty@f5.com nxt_int_t
23821059Sigor@sysoev.ru nxt_http_route_test_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule,
23831059Sigor@sysoev.ru     u_char *start, size_t length)
23841059Sigor@sysoev.ru {
23851060Sigor@sysoev.ru     nxt_int_t                 ret;
23861059Sigor@sysoev.ru     nxt_http_route_pattern_t  *pattern, *end;
23871059Sigor@sysoev.ru 
23881057Sigor@sysoev.ru     ret = 1;
2389964Sigor@sysoev.ru     pattern = &rule->pattern[0];
23901033Svbart@nginx.com     end = pattern + rule->items;
2391964Sigor@sysoev.ru 
23921057Sigor@sysoev.ru     while (pattern < end) {
2393964Sigor@sysoev.ru         ret = nxt_http_route_pattern(r, pattern, start, length);
23941721Saxel.duch@nginx.com         if (nxt_slow_path(ret == NXT_ERROR)) {
23951721Saxel.duch@nginx.com             return NXT_ERROR;
23961721Saxel.duch@nginx.com         }
2397964Sigor@sysoev.ru 
23981060Sigor@sysoev.ru         /* nxt_http_route_pattern() returns either 1 or 0. */
2399964Sigor@sysoev.ru         ret ^= pattern->negative;
2400964Sigor@sysoev.ru 
2401964Sigor@sysoev.ru         if (pattern->any == ret) {
2402964Sigor@sysoev.ru             return ret;
2403964Sigor@sysoev.ru         }
2404964Sigor@sysoev.ru 
2405964Sigor@sysoev.ru         pattern++;
24061057Sigor@sysoev.ru     }
2407964Sigor@sysoev.ru 
2408964Sigor@sysoev.ru     return ret;
2409964Sigor@sysoev.ru }
2410964Sigor@sysoev.ru 
2411964Sigor@sysoev.ru 
24121060Sigor@sysoev.ru static nxt_int_t
2413964Sigor@sysoev.ru nxt_http_route_pattern(nxt_http_request_t *r, nxt_http_route_pattern_t *pattern,
2414964Sigor@sysoev.ru     u_char *start, size_t length)
2415964Sigor@sysoev.ru {
24161508Saxel.duch@nginx.com     u_char                          *p, *end, *test;
24171508Saxel.duch@nginx.com     size_t                          test_length;
24181508Saxel.duch@nginx.com     uint32_t                        i;
24191508Saxel.duch@nginx.com     nxt_array_t                     *pattern_slices;
24201508Saxel.duch@nginx.com     nxt_http_route_pattern_slice_t  *pattern_slice;
2421964Sigor@sysoev.ru 
24221721Saxel.duch@nginx.com #if (NXT_HAVE_REGEX)
24231721Saxel.duch@nginx.com     if (pattern->regex) {
24241721Saxel.duch@nginx.com         if (r->regex_match == NULL) {
24251721Saxel.duch@nginx.com             r->regex_match = nxt_regex_match_create(r->mem_pool, 0);
24261721Saxel.duch@nginx.com             if (nxt_slow_path(r->regex_match == NULL)) {
24271721Saxel.duch@nginx.com                 return NXT_ERROR;
24281721Saxel.duch@nginx.com             }
24291721Saxel.duch@nginx.com         }
24301721Saxel.duch@nginx.com 
24311721Saxel.duch@nginx.com         return nxt_regex_match(pattern->u.regex, start, length, r->regex_match);
24321721Saxel.duch@nginx.com     }
24331721Saxel.duch@nginx.com #endif
24341721Saxel.duch@nginx.com 
2435964Sigor@sysoev.ru     if (length < pattern->min_length) {
2436964Sigor@sysoev.ru         return 0;
2437964Sigor@sysoev.ru     }
2438964Sigor@sysoev.ru 
24391721Saxel.duch@nginx.com     nxt_assert(pattern->u.pattern_slices != NULL);
24401721Saxel.duch@nginx.com 
24411721Saxel.duch@nginx.com     pattern_slices = pattern->u.pattern_slices;
24421508Saxel.duch@nginx.com     pattern_slice = pattern_slices->elts;
24431510Saxel.duch@nginx.com     end = start + length;
24441508Saxel.duch@nginx.com 
24451508Saxel.duch@nginx.com     for (i = 0; i < pattern_slices->nelts; i++, pattern_slice++) {
24461508Saxel.duch@nginx.com         test = pattern_slice->start;
24471508Saxel.duch@nginx.com         test_length = pattern_slice->length;
24481508Saxel.duch@nginx.com 
24491508Saxel.duch@nginx.com         switch (pattern_slice->type) {
24501508Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_PATTERN_EXACT:
24511508Saxel.duch@nginx.com             return ((length == pattern->min_length) &&
24521508Saxel.duch@nginx.com                     nxt_http_route_memcmp(start, test, test_length,
24531508Saxel.duch@nginx.com                                           pattern->case_sensitive));
24541508Saxel.duch@nginx.com 
24551508Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_PATTERN_BEGIN:
24561508Saxel.duch@nginx.com             if (nxt_http_route_memcmp(start, test, test_length,
24571508Saxel.duch@nginx.com                                       pattern->case_sensitive))
24581508Saxel.duch@nginx.com             {
24591510Saxel.duch@nginx.com                 start += test_length;
24601508Saxel.duch@nginx.com                 break;
24611508Saxel.duch@nginx.com             }
24621508Saxel.duch@nginx.com 
2463964Sigor@sysoev.ru             return 0;
24641508Saxel.duch@nginx.com 
24651508Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_PATTERN_END:
24661510Saxel.duch@nginx.com             p = end - test_length;
24671508Saxel.duch@nginx.com 
24681508Saxel.duch@nginx.com             if (nxt_http_route_memcmp(p, test, test_length,
24691508Saxel.duch@nginx.com                                       pattern->case_sensitive))
24701508Saxel.duch@nginx.com             {
24711510Saxel.duch@nginx.com                 end = p;
24721508Saxel.duch@nginx.com                 break;
24731508Saxel.duch@nginx.com             }
24741508Saxel.duch@nginx.com 
24751508Saxel.duch@nginx.com             return 0;
24761508Saxel.duch@nginx.com 
24771508Saxel.duch@nginx.com         case NXT_HTTP_ROUTE_PATTERN_SUBSTRING:
24781508Saxel.duch@nginx.com             if (pattern->case_sensitive) {
24791508Saxel.duch@nginx.com                 p = nxt_memstrn(start, end, (char *) test, test_length);
24801508Saxel.duch@nginx.com 
24811508Saxel.duch@nginx.com             } else {
24821508Saxel.duch@nginx.com                 p = nxt_memcasestrn(start, end, (char *) test, test_length);
24831508Saxel.duch@nginx.com             }
24841508Saxel.duch@nginx.com 
24851508Saxel.duch@nginx.com             if (p == NULL) {
24861508Saxel.duch@nginx.com                 return 0;
24871508Saxel.duch@nginx.com             }
24881510Saxel.duch@nginx.com 
24891510Saxel.duch@nginx.com             start = p + test_length;
24901032Sigor@sysoev.ru         }
2491964Sigor@sysoev.ru     }
2492964Sigor@sysoev.ru 
24931508Saxel.duch@nginx.com     return 1;
24941032Sigor@sysoev.ru }
24951032Sigor@sysoev.ru 
24961032Sigor@sysoev.ru 
24971060Sigor@sysoev.ru static nxt_int_t
24981032Sigor@sysoev.ru nxt_http_route_memcmp(u_char *start, u_char *test, size_t test_length,
24991032Sigor@sysoev.ru     nxt_bool_t case_sensitive)
25001032Sigor@sysoev.ru {
25011032Sigor@sysoev.ru     nxt_int_t  n;
25021032Sigor@sysoev.ru 
25031032Sigor@sysoev.ru     if (case_sensitive) {
25041032Sigor@sysoev.ru         n = nxt_memcmp(start, test, test_length);
25051032Sigor@sysoev.ru 
25061032Sigor@sysoev.ru     } else {
25071032Sigor@sysoev.ru         n = nxt_memcasecmp(start, test, test_length);
2508964Sigor@sysoev.ru     }
2509964Sigor@sysoev.ru 
25101032Sigor@sysoev.ru     return (n == 0);
2511964Sigor@sysoev.ru }
2512