xref: /unit/src/nxt_http_route.c (revision 1061)
1964Sigor@sysoev.ru 
2964Sigor@sysoev.ru /*
3964Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
4964Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
5964Sigor@sysoev.ru  */
6964Sigor@sysoev.ru 
7964Sigor@sysoev.ru #include <nxt_router.h>
8964Sigor@sysoev.ru #include <nxt_http.h>
9964Sigor@sysoev.ru 
10964Sigor@sysoev.ru 
11964Sigor@sysoev.ru typedef enum {
121059Sigor@sysoev.ru     NXT_HTTP_ROUTE_TABLE = 0,
131059Sigor@sysoev.ru     NXT_HTTP_ROUTE_STRING,
14964Sigor@sysoev.ru     NXT_HTTP_ROUTE_STRING_PTR,
15964Sigor@sysoev.ru     NXT_HTTP_ROUTE_HEADER,
16964Sigor@sysoev.ru     NXT_HTTP_ROUTE_ARGUMENT,
17964Sigor@sysoev.ru     NXT_HTTP_ROUTE_COOKIE,
18964Sigor@sysoev.ru } nxt_http_route_object_t;
19964Sigor@sysoev.ru 
20964Sigor@sysoev.ru 
21964Sigor@sysoev.ru typedef enum {
22964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_EXACT = 0,
23964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_BEGIN,
241032Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_MIDDLE,
25964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_END,
26964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_SUBSTRING,
27964Sigor@sysoev.ru } nxt_http_route_pattern_type_t;
28964Sigor@sysoev.ru 
29964Sigor@sysoev.ru 
30964Sigor@sysoev.ru typedef enum {
31964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_NOCASE = 0,
32964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_LOWCASE,
33964Sigor@sysoev.ru     NXT_HTTP_ROUTE_PATTERN_UPCASE,
34964Sigor@sysoev.ru } nxt_http_route_pattern_case_t;
35964Sigor@sysoev.ru 
36964Sigor@sysoev.ru 
37964Sigor@sysoev.ru typedef struct {
38964Sigor@sysoev.ru     nxt_conf_value_t               *host;
39964Sigor@sysoev.ru     nxt_conf_value_t               *uri;
40964Sigor@sysoev.ru     nxt_conf_value_t               *method;
411059Sigor@sysoev.ru     nxt_conf_value_t               *headers;
42*1061Sigor@sysoev.ru     nxt_conf_value_t               *arguments;
43964Sigor@sysoev.ru } nxt_http_route_match_conf_t;
44964Sigor@sysoev.ru 
45964Sigor@sysoev.ru 
46964Sigor@sysoev.ru typedef struct {
471032Sigor@sysoev.ru     u_char                         *start1;
481032Sigor@sysoev.ru     u_char                         *start2;
491032Sigor@sysoev.ru     uint32_t                       length1;
501032Sigor@sysoev.ru     uint32_t                       length2;
51964Sigor@sysoev.ru     uint32_t                       min_length;
52964Sigor@sysoev.ru 
53964Sigor@sysoev.ru     nxt_http_route_pattern_type_t  type:8;
54964Sigor@sysoev.ru     uint8_t                        case_sensitive;  /* 1 bit */
55964Sigor@sysoev.ru     uint8_t                        negative;        /* 1 bit */
56964Sigor@sysoev.ru     uint8_t                        any;             /* 1 bit */
57964Sigor@sysoev.ru } nxt_http_route_pattern_t;
58964Sigor@sysoev.ru 
59964Sigor@sysoev.ru 
60964Sigor@sysoev.ru typedef struct {
61*1061Sigor@sysoev.ru     uint16_t                       hash;
62*1061Sigor@sysoev.ru     uint16_t                       name_length;
63*1061Sigor@sysoev.ru     uint32_t                       value_length;
64*1061Sigor@sysoev.ru     u_char                         *name;
65*1061Sigor@sysoev.ru     u_char                         *value;
66*1061Sigor@sysoev.ru } nxt_http_name_value_t;
67*1061Sigor@sysoev.ru 
68*1061Sigor@sysoev.ru 
69*1061Sigor@sysoev.ru typedef struct {
701059Sigor@sysoev.ru     /* The object must be the first field. */
711059Sigor@sysoev.ru     nxt_http_route_object_t        object:8;
72964Sigor@sysoev.ru     uint32_t                       items;
731059Sigor@sysoev.ru 
741059Sigor@sysoev.ru     union {
751059Sigor@sysoev.ru         uintptr_t                  offset;
761059Sigor@sysoev.ru 
771059Sigor@sysoev.ru         struct {
781059Sigor@sysoev.ru             u_char                 *start;
791059Sigor@sysoev.ru             uint16_t               hash;
801059Sigor@sysoev.ru             uint16_t               length;
811059Sigor@sysoev.ru         } name;
821059Sigor@sysoev.ru     } u;
831059Sigor@sysoev.ru 
84964Sigor@sysoev.ru     nxt_http_route_pattern_t       pattern[0];
85964Sigor@sysoev.ru } nxt_http_route_rule_t;
86964Sigor@sysoev.ru 
87964Sigor@sysoev.ru 
88964Sigor@sysoev.ru typedef struct {
89964Sigor@sysoev.ru     uint32_t                       items;
901059Sigor@sysoev.ru     nxt_http_route_rule_t          *rule[0];
911059Sigor@sysoev.ru } nxt_http_route_ruleset_t;
921059Sigor@sysoev.ru 
931059Sigor@sysoev.ru 
941059Sigor@sysoev.ru typedef struct {
951059Sigor@sysoev.ru     /* The object must be the first field. */
961059Sigor@sysoev.ru     nxt_http_route_object_t        object:8;
971059Sigor@sysoev.ru     uint32_t                       items;
981059Sigor@sysoev.ru     nxt_http_route_ruleset_t       *ruleset[0];
991059Sigor@sysoev.ru } nxt_http_route_table_t;
1001059Sigor@sysoev.ru 
1011059Sigor@sysoev.ru 
1021059Sigor@sysoev.ru typedef union {
1031059Sigor@sysoev.ru     nxt_http_route_rule_t          *rule;
1041059Sigor@sysoev.ru     nxt_http_route_table_t         *table;
1051059Sigor@sysoev.ru } nxt_http_route_test_t;
1061059Sigor@sysoev.ru 
1071059Sigor@sysoev.ru 
1081059Sigor@sysoev.ru typedef struct {
1091059Sigor@sysoev.ru     uint32_t                       items;
110964Sigor@sysoev.ru     nxt_http_pass_t                pass;
1111059Sigor@sysoev.ru     nxt_http_route_test_t          test[0];
112964Sigor@sysoev.ru } nxt_http_route_match_t;
113964Sigor@sysoev.ru 
114964Sigor@sysoev.ru 
115964Sigor@sysoev.ru struct nxt_http_route_s {
116964Sigor@sysoev.ru     nxt_str_t                      name;
117964Sigor@sysoev.ru     uint32_t                       items;
118964Sigor@sysoev.ru     nxt_http_route_match_t         *match[0];
119964Sigor@sysoev.ru };
120964Sigor@sysoev.ru 
121964Sigor@sysoev.ru 
122964Sigor@sysoev.ru struct nxt_http_routes_s {
123964Sigor@sysoev.ru     uint32_t                       items;
124964Sigor@sysoev.ru     nxt_http_route_t               *route[0];
125964Sigor@sysoev.ru };
126964Sigor@sysoev.ru 
127964Sigor@sysoev.ru 
128964Sigor@sysoev.ru static nxt_http_route_t *nxt_http_route_create(nxt_task_t *task,
129964Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv);
130964Sigor@sysoev.ru static nxt_http_route_match_t *nxt_http_route_match_create(nxt_task_t *task,
131964Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv);
1321059Sigor@sysoev.ru static nxt_http_route_table_t *nxt_http_route_table_create(nxt_task_t *task,
133*1061Sigor@sysoev.ru     nxt_mp_t *mp, nxt_conf_value_t *table_cv, nxt_http_route_object_t object,
134*1061Sigor@sysoev.ru     nxt_bool_t case_sensitive);
1351059Sigor@sysoev.ru static nxt_http_route_ruleset_t *nxt_http_route_ruleset_create(nxt_task_t *task,
136*1061Sigor@sysoev.ru     nxt_mp_t *mp, nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object,
137*1061Sigor@sysoev.ru     nxt_bool_t case_sensitive);
138*1061Sigor@sysoev.ru static nxt_http_route_rule_t *nxt_http_route_rule_name_create(nxt_task_t *task,
139*1061Sigor@sysoev.ru     nxt_mp_t *mp, nxt_conf_value_t *rule_cv, nxt_str_t *name,
140*1061Sigor@sysoev.ru     nxt_bool_t case_sensitive);
141964Sigor@sysoev.ru static nxt_http_route_rule_t *nxt_http_route_rule_create(nxt_task_t *task,
1421059Sigor@sysoev.ru     nxt_mp_t *mp, nxt_conf_value_t *cv, nxt_bool_t case_sensitive,
1431059Sigor@sysoev.ru     nxt_http_route_pattern_case_t pattern_case);
144964Sigor@sysoev.ru static int nxt_http_pattern_compare(const void *one, const void *two);
145964Sigor@sysoev.ru static nxt_int_t nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp,
146964Sigor@sysoev.ru     nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern,
147964Sigor@sysoev.ru     nxt_http_route_pattern_case_t pattern_case);
1481032Sigor@sysoev.ru static u_char *nxt_http_route_pattern_copy(nxt_mp_t *mp, nxt_str_t *test,
1491032Sigor@sysoev.ru     nxt_http_route_pattern_case_t pattern_case);
150964Sigor@sysoev.ru 
151964Sigor@sysoev.ru static void nxt_http_route_resolve(nxt_task_t *task,
152964Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_http_route_t *route);
153964Sigor@sysoev.ru static void nxt_http_pass_resolve(nxt_task_t *task,
154964Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_http_pass_t *pass);
155964Sigor@sysoev.ru static nxt_http_route_t *nxt_http_route_find(nxt_http_routes_t *routes,
156964Sigor@sysoev.ru     nxt_str_t *name);
157964Sigor@sysoev.ru static void nxt_http_route_cleanup(nxt_task_t *task, nxt_http_route_t *routes);
158964Sigor@sysoev.ru 
159964Sigor@sysoev.ru static nxt_http_pass_t *nxt_http_route_pass(nxt_task_t *task,
160964Sigor@sysoev.ru     nxt_http_request_t *r, nxt_http_pass_t *start);
161964Sigor@sysoev.ru static nxt_http_pass_t *nxt_http_route_match(nxt_http_request_t *r,
162964Sigor@sysoev.ru     nxt_http_route_match_t *match);
1631060Sigor@sysoev.ru static nxt_int_t nxt_http_route_table(nxt_http_request_t *r,
1641059Sigor@sysoev.ru     nxt_http_route_table_t *table);
1651060Sigor@sysoev.ru static nxt_int_t nxt_http_route_ruleset(nxt_http_request_t *r,
1661059Sigor@sysoev.ru     nxt_http_route_ruleset_t *ruleset);
1671060Sigor@sysoev.ru static nxt_int_t nxt_http_route_rule(nxt_http_request_t *r,
168964Sigor@sysoev.ru     nxt_http_route_rule_t *rule);
1691060Sigor@sysoev.ru static nxt_int_t nxt_http_route_header(nxt_http_request_t *r,
1701059Sigor@sysoev.ru     nxt_http_route_rule_t *rule);
171*1061Sigor@sysoev.ru static nxt_int_t nxt_http_route_arguments(nxt_http_request_t *r,
172*1061Sigor@sysoev.ru     nxt_http_route_rule_t *rule);
173*1061Sigor@sysoev.ru static nxt_array_t *nxt_http_route_arguments_parse(nxt_http_request_t *r);
174*1061Sigor@sysoev.ru static nxt_http_name_value_t *nxt_http_route_argument(nxt_array_t *array,
175*1061Sigor@sysoev.ru     u_char *name, size_t name_length, uint32_t hash, u_char *start,
176*1061Sigor@sysoev.ru     u_char *end);
177*1061Sigor@sysoev.ru static nxt_int_t nxt_http_route_test_argument(nxt_http_request_t *r,
178*1061Sigor@sysoev.ru     nxt_http_route_rule_t *rule, nxt_array_t *array);
1791060Sigor@sysoev.ru static nxt_int_t nxt_http_route_test_rule(nxt_http_request_t *r,
1801059Sigor@sysoev.ru     nxt_http_route_rule_t *rule, u_char *start, size_t length);
1811060Sigor@sysoev.ru static nxt_int_t nxt_http_route_pattern(nxt_http_request_t *r,
182964Sigor@sysoev.ru     nxt_http_route_pattern_t *pattern, u_char *start, size_t length);
1831060Sigor@sysoev.ru static nxt_int_t nxt_http_route_memcmp(u_char *start, u_char *test,
1841032Sigor@sysoev.ru     size_t length, nxt_bool_t case_sensitive);
185964Sigor@sysoev.ru 
186964Sigor@sysoev.ru 
187964Sigor@sysoev.ru nxt_http_routes_t *
188964Sigor@sysoev.ru nxt_http_routes_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
189964Sigor@sysoev.ru     nxt_conf_value_t *routes_conf)
190964Sigor@sysoev.ru {
191964Sigor@sysoev.ru     size_t             size;
192964Sigor@sysoev.ru     uint32_t           i, n, next;
193964Sigor@sysoev.ru     nxt_mp_t           *mp;
194964Sigor@sysoev.ru     nxt_str_t          name, *string;
195964Sigor@sysoev.ru     nxt_bool_t         object;
196964Sigor@sysoev.ru     nxt_conf_value_t   *route_conf;
197964Sigor@sysoev.ru     nxt_http_route_t   *route;
198964Sigor@sysoev.ru     nxt_http_routes_t  *routes;
199964Sigor@sysoev.ru 
200964Sigor@sysoev.ru     object = (nxt_conf_type(routes_conf) == NXT_CONF_OBJECT);
201964Sigor@sysoev.ru     n = object ? nxt_conf_object_members_count(routes_conf) : 1;
202964Sigor@sysoev.ru     size = sizeof(nxt_http_routes_t) + n * sizeof(nxt_http_route_t *);
203964Sigor@sysoev.ru 
204964Sigor@sysoev.ru     mp = tmcf->router_conf->mem_pool;
205964Sigor@sysoev.ru 
206964Sigor@sysoev.ru     routes = nxt_mp_alloc(mp, size);
207964Sigor@sysoev.ru     if (nxt_slow_path(routes == NULL)) {
208964Sigor@sysoev.ru         return NULL;
209964Sigor@sysoev.ru     }
210964Sigor@sysoev.ru 
211964Sigor@sysoev.ru     routes->items = n;
212964Sigor@sysoev.ru 
213964Sigor@sysoev.ru     if (object) {
214964Sigor@sysoev.ru         next = 0;
215964Sigor@sysoev.ru 
216964Sigor@sysoev.ru         for (i = 0; i < n; i++) {
217964Sigor@sysoev.ru             route_conf = nxt_conf_next_object_member(routes_conf, &name, &next);
218964Sigor@sysoev.ru 
219964Sigor@sysoev.ru             route = nxt_http_route_create(task, tmcf, route_conf);
220964Sigor@sysoev.ru             if (nxt_slow_path(route == NULL)) {
221964Sigor@sysoev.ru                 return NULL;
222964Sigor@sysoev.ru             }
223964Sigor@sysoev.ru 
224964Sigor@sysoev.ru             routes->route[i] = route;
225964Sigor@sysoev.ru 
226964Sigor@sysoev.ru             string = nxt_str_dup(mp, &route->name, &name);
227964Sigor@sysoev.ru             if (nxt_slow_path(string == NULL)) {
228964Sigor@sysoev.ru                 return NULL;
229964Sigor@sysoev.ru             }
230964Sigor@sysoev.ru         }
231964Sigor@sysoev.ru 
232964Sigor@sysoev.ru     } else {
233964Sigor@sysoev.ru         route = nxt_http_route_create(task, tmcf, routes_conf);
234964Sigor@sysoev.ru         if (nxt_slow_path(route == NULL)) {
235964Sigor@sysoev.ru             return NULL;
236964Sigor@sysoev.ru         }
237964Sigor@sysoev.ru 
238964Sigor@sysoev.ru         routes->route[0] = route;
239964Sigor@sysoev.ru 
240964Sigor@sysoev.ru         route->name.length = 0;
241964Sigor@sysoev.ru         route->name.start = NULL;
242964Sigor@sysoev.ru     }
243964Sigor@sysoev.ru 
244964Sigor@sysoev.ru     return routes;
245964Sigor@sysoev.ru }
246964Sigor@sysoev.ru 
247964Sigor@sysoev.ru 
248964Sigor@sysoev.ru static nxt_conf_map_t  nxt_http_route_match_conf[] = {
249964Sigor@sysoev.ru     {
250964Sigor@sysoev.ru         nxt_string("host"),
251964Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
252964Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, host),
253964Sigor@sysoev.ru     },
254964Sigor@sysoev.ru 
255964Sigor@sysoev.ru     {
256964Sigor@sysoev.ru         nxt_string("uri"),
257964Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
258964Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, uri),
259964Sigor@sysoev.ru     },
260964Sigor@sysoev.ru 
261964Sigor@sysoev.ru     {
262964Sigor@sysoev.ru         nxt_string("method"),
263964Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
264964Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, method),
265964Sigor@sysoev.ru     },
2661059Sigor@sysoev.ru 
2671059Sigor@sysoev.ru     {
2681059Sigor@sysoev.ru         nxt_string("headers"),
2691059Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
2701059Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, headers),
2711059Sigor@sysoev.ru     },
272*1061Sigor@sysoev.ru 
273*1061Sigor@sysoev.ru     {
274*1061Sigor@sysoev.ru         nxt_string("arguments"),
275*1061Sigor@sysoev.ru         NXT_CONF_MAP_PTR,
276*1061Sigor@sysoev.ru         offsetof(nxt_http_route_match_conf_t, arguments),
277*1061Sigor@sysoev.ru     },
278964Sigor@sysoev.ru };
279964Sigor@sysoev.ru 
280964Sigor@sysoev.ru 
281964Sigor@sysoev.ru static nxt_http_route_t *
282964Sigor@sysoev.ru nxt_http_route_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
283964Sigor@sysoev.ru     nxt_conf_value_t *cv)
284964Sigor@sysoev.ru {
285964Sigor@sysoev.ru     size_t                  size;
286964Sigor@sysoev.ru     uint32_t                i, n;
287964Sigor@sysoev.ru     nxt_conf_value_t        *value;
288964Sigor@sysoev.ru     nxt_http_route_t        *route;
289964Sigor@sysoev.ru     nxt_http_route_match_t  *match, **m;
290964Sigor@sysoev.ru 
291964Sigor@sysoev.ru     n = nxt_conf_array_elements_count(cv);
292964Sigor@sysoev.ru     size = sizeof(nxt_http_route_t) + n * sizeof(nxt_http_route_match_t *);
293964Sigor@sysoev.ru 
294964Sigor@sysoev.ru     route = nxt_mp_alloc(tmcf->router_conf->mem_pool, size);
295964Sigor@sysoev.ru     if (nxt_slow_path(route == NULL)) {
296964Sigor@sysoev.ru         return NULL;
297964Sigor@sysoev.ru     }
298964Sigor@sysoev.ru 
299964Sigor@sysoev.ru     route->items = n;
300964Sigor@sysoev.ru     m = &route->match[0];
301964Sigor@sysoev.ru 
302964Sigor@sysoev.ru     for (i = 0; i < n; i++) {
303964Sigor@sysoev.ru         value = nxt_conf_get_array_element(cv, i);
304964Sigor@sysoev.ru 
305964Sigor@sysoev.ru         match = nxt_http_route_match_create(task, tmcf, value);
306964Sigor@sysoev.ru         if (match == NULL) {
307964Sigor@sysoev.ru             return NULL;
308964Sigor@sysoev.ru         }
309964Sigor@sysoev.ru 
310964Sigor@sysoev.ru         *m++ = match;
311964Sigor@sysoev.ru     }
312964Sigor@sysoev.ru 
313964Sigor@sysoev.ru     return route;
314964Sigor@sysoev.ru }
315964Sigor@sysoev.ru 
316964Sigor@sysoev.ru 
317964Sigor@sysoev.ru static nxt_http_route_match_t *
318964Sigor@sysoev.ru nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
319964Sigor@sysoev.ru     nxt_conf_value_t *cv)
320964Sigor@sysoev.ru {
321964Sigor@sysoev.ru     size_t                       size;
322964Sigor@sysoev.ru     uint32_t                     n;
3231059Sigor@sysoev.ru     nxt_mp_t                     *mp;
324964Sigor@sysoev.ru     nxt_int_t                    ret;
325964Sigor@sysoev.ru     nxt_str_t                    pass, *string;
326964Sigor@sysoev.ru     nxt_conf_value_t             *match_conf, *pass_conf;
3271059Sigor@sysoev.ru     nxt_http_route_test_t        *test;
3281059Sigor@sysoev.ru     nxt_http_route_rule_t        *rule;
3291059Sigor@sysoev.ru     nxt_http_route_table_t       *table;
330964Sigor@sysoev.ru     nxt_http_route_match_t       *match;
331964Sigor@sysoev.ru     nxt_http_route_match_conf_t  mtcf;
332964Sigor@sysoev.ru 
333964Sigor@sysoev.ru     static nxt_str_t  pass_path = nxt_string("/action/pass");
334964Sigor@sysoev.ru     static nxt_str_t  match_path = nxt_string("/match");
335964Sigor@sysoev.ru 
336964Sigor@sysoev.ru     pass_conf = nxt_conf_get_path(cv, &pass_path);
337964Sigor@sysoev.ru     if (nxt_slow_path(pass_conf == NULL)) {
338964Sigor@sysoev.ru         return NULL;
339964Sigor@sysoev.ru     }
340964Sigor@sysoev.ru 
341964Sigor@sysoev.ru     nxt_conf_get_string(pass_conf, &pass);
342964Sigor@sysoev.ru 
343964Sigor@sysoev.ru     match_conf = nxt_conf_get_path(cv, &match_path);
344964Sigor@sysoev.ru 
345964Sigor@sysoev.ru     n = (match_conf != NULL) ? nxt_conf_object_members_count(match_conf) : 0;
346964Sigor@sysoev.ru     size = sizeof(nxt_http_route_match_t) + n * sizeof(nxt_http_route_rule_t *);
347964Sigor@sysoev.ru 
3481059Sigor@sysoev.ru     mp = tmcf->router_conf->mem_pool;
3491059Sigor@sysoev.ru 
3501059Sigor@sysoev.ru     match = nxt_mp_alloc(mp, size);
351964Sigor@sysoev.ru     if (nxt_slow_path(match == NULL)) {
352964Sigor@sysoev.ru         return NULL;
353964Sigor@sysoev.ru     }
354964Sigor@sysoev.ru 
355964Sigor@sysoev.ru     match->pass.u.route = NULL;
356964Sigor@sysoev.ru     match->pass.handler = NULL;
357964Sigor@sysoev.ru     match->items = n;
358964Sigor@sysoev.ru 
3591059Sigor@sysoev.ru     string = nxt_str_dup(mp, &match->pass.name, &pass);
360964Sigor@sysoev.ru     if (nxt_slow_path(string == NULL)) {
361964Sigor@sysoev.ru         return NULL;
362964Sigor@sysoev.ru     }
363964Sigor@sysoev.ru 
364964Sigor@sysoev.ru     if (n == 0) {
365964Sigor@sysoev.ru         return match;
366964Sigor@sysoev.ru     }
367964Sigor@sysoev.ru 
368964Sigor@sysoev.ru     nxt_memzero(&mtcf, sizeof(mtcf));
369964Sigor@sysoev.ru 
370964Sigor@sysoev.ru     ret = nxt_conf_map_object(tmcf->mem_pool,
371964Sigor@sysoev.ru                               match_conf, nxt_http_route_match_conf,
372964Sigor@sysoev.ru                               nxt_nitems(nxt_http_route_match_conf), &mtcf);
373964Sigor@sysoev.ru     if (ret != NXT_OK) {
374964Sigor@sysoev.ru         return NULL;
375964Sigor@sysoev.ru     }
376964Sigor@sysoev.ru 
3771059Sigor@sysoev.ru     test = &match->test[0];
378964Sigor@sysoev.ru 
379964Sigor@sysoev.ru     if (mtcf.host != NULL) {
3801059Sigor@sysoev.ru         rule = nxt_http_route_rule_create(task, mp, mtcf.host, 1,
381964Sigor@sysoev.ru                                           NXT_HTTP_ROUTE_PATTERN_LOWCASE);
382964Sigor@sysoev.ru         if (rule == NULL) {
383964Sigor@sysoev.ru             return NULL;
384964Sigor@sysoev.ru         }
385964Sigor@sysoev.ru 
3861059Sigor@sysoev.ru         rule->u.offset = offsetof(nxt_http_request_t, host);
387964Sigor@sysoev.ru         rule->object = NXT_HTTP_ROUTE_STRING;
3881059Sigor@sysoev.ru         test->rule = rule;
3891059Sigor@sysoev.ru         test++;
390964Sigor@sysoev.ru     }
391964Sigor@sysoev.ru 
392964Sigor@sysoev.ru     if (mtcf.uri != NULL) {
3931059Sigor@sysoev.ru         rule = nxt_http_route_rule_create(task, mp, mtcf.uri, 1,
394964Sigor@sysoev.ru                                           NXT_HTTP_ROUTE_PATTERN_NOCASE);
395964Sigor@sysoev.ru         if (rule == NULL) {
396964Sigor@sysoev.ru             return NULL;
397964Sigor@sysoev.ru         }
398964Sigor@sysoev.ru 
3991059Sigor@sysoev.ru         rule->u.offset = offsetof(nxt_http_request_t, path);
400964Sigor@sysoev.ru         rule->object = NXT_HTTP_ROUTE_STRING_PTR;
4011059Sigor@sysoev.ru         test->rule = rule;
4021059Sigor@sysoev.ru         test++;
403964Sigor@sysoev.ru     }
404964Sigor@sysoev.ru 
405964Sigor@sysoev.ru     if (mtcf.method != NULL) {
4061059Sigor@sysoev.ru         rule = nxt_http_route_rule_create(task, mp, mtcf.method, 1,
407964Sigor@sysoev.ru                                           NXT_HTTP_ROUTE_PATTERN_UPCASE);
408964Sigor@sysoev.ru         if (rule == NULL) {
409964Sigor@sysoev.ru             return NULL;
410964Sigor@sysoev.ru         }
411964Sigor@sysoev.ru 
4121059Sigor@sysoev.ru         rule->u.offset = offsetof(nxt_http_request_t, method);
413964Sigor@sysoev.ru         rule->object = NXT_HTTP_ROUTE_STRING_PTR;
4141059Sigor@sysoev.ru         test->rule = rule;
4151059Sigor@sysoev.ru         test++;
4161059Sigor@sysoev.ru     }
4171059Sigor@sysoev.ru 
4181059Sigor@sysoev.ru     if (mtcf.headers != NULL) {
419*1061Sigor@sysoev.ru         table = nxt_http_route_table_create(task, mp, mtcf.headers,
420*1061Sigor@sysoev.ru                                             NXT_HTTP_ROUTE_HEADER, 0);
421*1061Sigor@sysoev.ru         if (table == NULL) {
422*1061Sigor@sysoev.ru             return NULL;
423*1061Sigor@sysoev.ru         }
424*1061Sigor@sysoev.ru 
425*1061Sigor@sysoev.ru         test->table = table;
426*1061Sigor@sysoev.ru         test++;
427*1061Sigor@sysoev.ru     }
428*1061Sigor@sysoev.ru 
429*1061Sigor@sysoev.ru     if (mtcf.arguments != NULL) {
430*1061Sigor@sysoev.ru         table = nxt_http_route_table_create(task, mp, mtcf.arguments,
431*1061Sigor@sysoev.ru                                             NXT_HTTP_ROUTE_ARGUMENT, 1);
4321059Sigor@sysoev.ru         if (table == NULL) {
4331059Sigor@sysoev.ru             return NULL;
4341059Sigor@sysoev.ru         }
4351059Sigor@sysoev.ru 
4361059Sigor@sysoev.ru         test->table = table;
4371059Sigor@sysoev.ru         test++;
438964Sigor@sysoev.ru     }
439964Sigor@sysoev.ru 
440964Sigor@sysoev.ru     return match;
441964Sigor@sysoev.ru }
442964Sigor@sysoev.ru 
443964Sigor@sysoev.ru 
4441059Sigor@sysoev.ru static nxt_http_route_table_t *
4451059Sigor@sysoev.ru nxt_http_route_table_create(nxt_task_t *task, nxt_mp_t *mp,
446*1061Sigor@sysoev.ru     nxt_conf_value_t *table_cv, nxt_http_route_object_t object,
447*1061Sigor@sysoev.ru     nxt_bool_t case_sensitive)
4481059Sigor@sysoev.ru {
4491059Sigor@sysoev.ru     size_t                    size;
4501059Sigor@sysoev.ru     uint32_t                  i, n;
4511059Sigor@sysoev.ru     nxt_bool_t                array;
4521059Sigor@sysoev.ru     nxt_conf_value_t          *ruleset_cv;
4531059Sigor@sysoev.ru     nxt_http_route_table_t    *table;
4541059Sigor@sysoev.ru     nxt_http_route_ruleset_t  *ruleset;
4551059Sigor@sysoev.ru 
4561059Sigor@sysoev.ru     array = (nxt_conf_type(table_cv) == NXT_CONF_ARRAY);
4571059Sigor@sysoev.ru     n = array ? nxt_conf_array_elements_count(table_cv) : 1;
4581059Sigor@sysoev.ru     size = sizeof(nxt_http_route_table_t)
4591059Sigor@sysoev.ru            + n * sizeof(nxt_http_route_ruleset_t *);
4601059Sigor@sysoev.ru 
4611059Sigor@sysoev.ru     table = nxt_mp_alloc(mp, size);
4621059Sigor@sysoev.ru     if (nxt_slow_path(table == NULL)) {
4631059Sigor@sysoev.ru         return NULL;
4641059Sigor@sysoev.ru     }
4651059Sigor@sysoev.ru 
4661059Sigor@sysoev.ru     table->items = n;
4671059Sigor@sysoev.ru     table->object = NXT_HTTP_ROUTE_TABLE;
4681059Sigor@sysoev.ru 
4691059Sigor@sysoev.ru     if (!array) {
470*1061Sigor@sysoev.ru         ruleset = nxt_http_route_ruleset_create(task, mp, table_cv,
471*1061Sigor@sysoev.ru                                                 object, case_sensitive);
4721059Sigor@sysoev.ru         if (nxt_slow_path(ruleset == NULL)) {
4731059Sigor@sysoev.ru             return NULL;
4741059Sigor@sysoev.ru         }
4751059Sigor@sysoev.ru 
4761059Sigor@sysoev.ru         table->ruleset[0] = ruleset;
4771059Sigor@sysoev.ru 
4781059Sigor@sysoev.ru         return table;
4791059Sigor@sysoev.ru     }
4801059Sigor@sysoev.ru 
4811059Sigor@sysoev.ru     for (i = 0; i < n; i++) {
4821059Sigor@sysoev.ru         ruleset_cv = nxt_conf_get_array_element(table_cv, i);
4831059Sigor@sysoev.ru 
484*1061Sigor@sysoev.ru         ruleset = nxt_http_route_ruleset_create(task, mp, ruleset_cv,
485*1061Sigor@sysoev.ru                                                 object, case_sensitive);
4861059Sigor@sysoev.ru         if (nxt_slow_path(ruleset == NULL)) {
4871059Sigor@sysoev.ru             return NULL;
4881059Sigor@sysoev.ru         }
4891059Sigor@sysoev.ru 
4901059Sigor@sysoev.ru         table->ruleset[i] = ruleset;
4911059Sigor@sysoev.ru     }
4921059Sigor@sysoev.ru 
4931059Sigor@sysoev.ru     return table;
4941059Sigor@sysoev.ru }
4951059Sigor@sysoev.ru 
4961059Sigor@sysoev.ru 
4971059Sigor@sysoev.ru static nxt_http_route_ruleset_t *
4981059Sigor@sysoev.ru nxt_http_route_ruleset_create(nxt_task_t *task, nxt_mp_t *mp,
499*1061Sigor@sysoev.ru     nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object,
500*1061Sigor@sysoev.ru     nxt_bool_t case_sensitive)
5011059Sigor@sysoev.ru {
5021059Sigor@sysoev.ru     size_t                    size;
5031059Sigor@sysoev.ru     uint32_t                  i, n, next;
5041059Sigor@sysoev.ru     nxt_str_t                 name;
5051059Sigor@sysoev.ru     nxt_conf_value_t          *rule_cv;
5061059Sigor@sysoev.ru     nxt_http_route_rule_t     *rule;
5071059Sigor@sysoev.ru     nxt_http_route_ruleset_t  *ruleset;
5081059Sigor@sysoev.ru 
5091059Sigor@sysoev.ru     n = nxt_conf_object_members_count(ruleset_cv);
5101059Sigor@sysoev.ru     size = sizeof(nxt_http_route_ruleset_t)
5111059Sigor@sysoev.ru            + n * sizeof(nxt_http_route_rule_t *);
5121059Sigor@sysoev.ru 
5131059Sigor@sysoev.ru     ruleset = nxt_mp_alloc(mp, size);
5141059Sigor@sysoev.ru     if (nxt_slow_path(ruleset == NULL)) {
5151059Sigor@sysoev.ru         return NULL;
5161059Sigor@sysoev.ru     }
5171059Sigor@sysoev.ru 
5181059Sigor@sysoev.ru     ruleset->items = n;
5191059Sigor@sysoev.ru 
5201059Sigor@sysoev.ru     next = 0;
5211059Sigor@sysoev.ru 
5221059Sigor@sysoev.ru     for (i = 0; i < n; i++) {
5231059Sigor@sysoev.ru         rule_cv = nxt_conf_next_object_member(ruleset_cv, &name, &next);
5241059Sigor@sysoev.ru 
525*1061Sigor@sysoev.ru         rule = nxt_http_route_rule_name_create(task, mp, rule_cv, &name,
526*1061Sigor@sysoev.ru                                                case_sensitive);
5271059Sigor@sysoev.ru         if (nxt_slow_path(rule == NULL)) {
5281059Sigor@sysoev.ru             return NULL;
5291059Sigor@sysoev.ru         }
5301059Sigor@sysoev.ru 
531*1061Sigor@sysoev.ru         rule->object = object;
5321059Sigor@sysoev.ru         ruleset->rule[i] = rule;
5331059Sigor@sysoev.ru     }
5341059Sigor@sysoev.ru 
5351059Sigor@sysoev.ru     return ruleset;
5361059Sigor@sysoev.ru }
5371059Sigor@sysoev.ru 
5381059Sigor@sysoev.ru 
539964Sigor@sysoev.ru static nxt_http_route_rule_t *
540*1061Sigor@sysoev.ru nxt_http_route_rule_name_create(nxt_task_t *task, nxt_mp_t *mp,
541*1061Sigor@sysoev.ru     nxt_conf_value_t *rule_cv, nxt_str_t *name, nxt_bool_t case_sensitive)
5421059Sigor@sysoev.ru {
5431059Sigor@sysoev.ru     u_char                 c, *p;
5441059Sigor@sysoev.ru     uint32_t               hash;
5451059Sigor@sysoev.ru     nxt_uint_t             i;
5461059Sigor@sysoev.ru     nxt_http_route_rule_t  *rule;
5471059Sigor@sysoev.ru 
548*1061Sigor@sysoev.ru     rule = nxt_http_route_rule_create(task, mp, rule_cv, case_sensitive,
5491059Sigor@sysoev.ru                                       NXT_HTTP_ROUTE_PATTERN_NOCASE);
5501059Sigor@sysoev.ru     if (nxt_slow_path(rule == NULL)) {
5511059Sigor@sysoev.ru         return NULL;
5521059Sigor@sysoev.ru     }
5531059Sigor@sysoev.ru 
5541059Sigor@sysoev.ru     rule->u.name.length = name->length;
5551059Sigor@sysoev.ru 
5561059Sigor@sysoev.ru     p = nxt_mp_nget(mp, name->length);
5571059Sigor@sysoev.ru     if (nxt_slow_path(p == NULL)) {
5581059Sigor@sysoev.ru         return NULL;
5591059Sigor@sysoev.ru     }
5601059Sigor@sysoev.ru 
5611059Sigor@sysoev.ru     rule->u.name.start = p;
5621059Sigor@sysoev.ru 
5631059Sigor@sysoev.ru     hash = NXT_HTTP_FIELD_HASH_INIT;
5641059Sigor@sysoev.ru 
5651059Sigor@sysoev.ru     for (i = 0; i < name->length; i++) {
5661059Sigor@sysoev.ru         c = name->start[i];
5671059Sigor@sysoev.ru         *p++ = c;
5681059Sigor@sysoev.ru 
5691059Sigor@sysoev.ru         c = nxt_lowcase(c);
5701059Sigor@sysoev.ru         hash = nxt_http_field_hash_char(hash, c);
5711059Sigor@sysoev.ru     }
5721059Sigor@sysoev.ru 
5731059Sigor@sysoev.ru     rule->u.name.hash = nxt_http_field_hash_end(hash) & 0xFFFF;
5741059Sigor@sysoev.ru 
5751059Sigor@sysoev.ru     return rule;
5761059Sigor@sysoev.ru }
5771059Sigor@sysoev.ru 
5781059Sigor@sysoev.ru 
5791059Sigor@sysoev.ru static nxt_http_route_rule_t *
5801059Sigor@sysoev.ru nxt_http_route_rule_create(nxt_task_t *task, nxt_mp_t *mp,
581964Sigor@sysoev.ru     nxt_conf_value_t *cv, nxt_bool_t case_sensitive,
582964Sigor@sysoev.ru     nxt_http_route_pattern_case_t pattern_case)
583964Sigor@sysoev.ru {
584964Sigor@sysoev.ru     size_t                    size;
585964Sigor@sysoev.ru     uint32_t                  i, n;
586964Sigor@sysoev.ru     nxt_int_t                 ret;
587964Sigor@sysoev.ru     nxt_bool_t                string;
588964Sigor@sysoev.ru     nxt_conf_value_t          *value;
589964Sigor@sysoev.ru     nxt_http_route_rule_t     *rule;
590964Sigor@sysoev.ru     nxt_http_route_pattern_t  *pattern;
591964Sigor@sysoev.ru 
592964Sigor@sysoev.ru     string = (nxt_conf_type(cv) != NXT_CONF_ARRAY);
593964Sigor@sysoev.ru     n = string ? 1 : nxt_conf_array_elements_count(cv);
594964Sigor@sysoev.ru     size = sizeof(nxt_http_route_rule_t) + n * sizeof(nxt_http_route_pattern_t);
595964Sigor@sysoev.ru 
596964Sigor@sysoev.ru     rule = nxt_mp_alloc(mp, size);
597964Sigor@sysoev.ru     if (nxt_slow_path(rule == NULL)) {
598964Sigor@sysoev.ru         return NULL;
599964Sigor@sysoev.ru     }
600964Sigor@sysoev.ru 
601964Sigor@sysoev.ru     rule->items = n;
602964Sigor@sysoev.ru 
603964Sigor@sysoev.ru     pattern = &rule->pattern[0];
604964Sigor@sysoev.ru 
605964Sigor@sysoev.ru     if (string) {
606964Sigor@sysoev.ru         pattern[0].case_sensitive = case_sensitive;
607964Sigor@sysoev.ru         ret = nxt_http_route_pattern_create(task, mp, cv, &pattern[0],
608964Sigor@sysoev.ru                                             pattern_case);
609964Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
610964Sigor@sysoev.ru             return NULL;
611964Sigor@sysoev.ru         }
612964Sigor@sysoev.ru 
613964Sigor@sysoev.ru         return rule;
614964Sigor@sysoev.ru     }
615964Sigor@sysoev.ru 
616964Sigor@sysoev.ru     nxt_conf_array_qsort(cv, nxt_http_pattern_compare);
617964Sigor@sysoev.ru 
618964Sigor@sysoev.ru     for (i = 0; i < n; i++) {
619964Sigor@sysoev.ru         pattern[i].case_sensitive = case_sensitive;
620964Sigor@sysoev.ru         value = nxt_conf_get_array_element(cv, i);
621964Sigor@sysoev.ru 
622964Sigor@sysoev.ru         ret = nxt_http_route_pattern_create(task, mp, value, &pattern[i],
623964Sigor@sysoev.ru                                             pattern_case);
624964Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
625964Sigor@sysoev.ru             return NULL;
626964Sigor@sysoev.ru         }
627964Sigor@sysoev.ru     }
628964Sigor@sysoev.ru 
629964Sigor@sysoev.ru     return rule;
630964Sigor@sysoev.ru }
631964Sigor@sysoev.ru 
632964Sigor@sysoev.ru 
633964Sigor@sysoev.ru static int
634964Sigor@sysoev.ru nxt_http_pattern_compare(const void *one, const void *two)
635964Sigor@sysoev.ru {
636964Sigor@sysoev.ru     nxt_str_t         test;
637964Sigor@sysoev.ru     nxt_bool_t        negative1, negative2;
638964Sigor@sysoev.ru     nxt_conf_value_t  *value;
639964Sigor@sysoev.ru 
640964Sigor@sysoev.ru     value = (nxt_conf_value_t *) one;
641964Sigor@sysoev.ru     nxt_conf_get_string(value, &test);
642964Sigor@sysoev.ru     negative1 = (test.length != 0 && test.start[0] == '!');
643964Sigor@sysoev.ru 
644964Sigor@sysoev.ru     value = (nxt_conf_value_t *) two;
645964Sigor@sysoev.ru     nxt_conf_get_string(value, &test);
646964Sigor@sysoev.ru     negative2 = (test.length != 0 && test.start[0] == '!');
647964Sigor@sysoev.ru 
648964Sigor@sysoev.ru     return (negative2 - negative1);
649964Sigor@sysoev.ru }
650964Sigor@sysoev.ru 
651964Sigor@sysoev.ru 
652964Sigor@sysoev.ru static nxt_int_t
653964Sigor@sysoev.ru nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp,
654964Sigor@sysoev.ru     nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern,
655964Sigor@sysoev.ru     nxt_http_route_pattern_case_t pattern_case)
656964Sigor@sysoev.ru {
657964Sigor@sysoev.ru     u_char                         *start;
658964Sigor@sysoev.ru     nxt_str_t                      test;
6591032Sigor@sysoev.ru     nxt_uint_t                     n, length;
660964Sigor@sysoev.ru     nxt_http_route_pattern_type_t  type;
661964Sigor@sysoev.ru 
6621032Sigor@sysoev.ru     /* Suppress warning about uninitialized variable. */
6631032Sigor@sysoev.ru     length = 0;
6641032Sigor@sysoev.ru 
665964Sigor@sysoev.ru     type = NXT_HTTP_ROUTE_PATTERN_EXACT;
666964Sigor@sysoev.ru 
667964Sigor@sysoev.ru     nxt_conf_get_string(cv, &test);
668964Sigor@sysoev.ru 
669964Sigor@sysoev.ru     pattern->negative = 0;
670964Sigor@sysoev.ru     pattern->any = 1;
671964Sigor@sysoev.ru 
672964Sigor@sysoev.ru     if (test.length != 0) {
673964Sigor@sysoev.ru 
674964Sigor@sysoev.ru         if (test.start[0] == '!') {
675964Sigor@sysoev.ru             test.start++;
676964Sigor@sysoev.ru             test.length--;
677964Sigor@sysoev.ru 
678964Sigor@sysoev.ru             pattern->negative = 1;
679964Sigor@sysoev.ru             pattern->any = 0;
680964Sigor@sysoev.ru         }
681964Sigor@sysoev.ru 
682964Sigor@sysoev.ru         if (test.length != 0) {
683964Sigor@sysoev.ru 
684964Sigor@sysoev.ru             if (test.start[0] == '*') {
685964Sigor@sysoev.ru                 test.start++;
686964Sigor@sysoev.ru                 test.length--;
687964Sigor@sysoev.ru 
688964Sigor@sysoev.ru                 if (test.length != 0) {
689964Sigor@sysoev.ru                     if (test.start[test.length - 1] == '*') {
690964Sigor@sysoev.ru                         test.length--;
691964Sigor@sysoev.ru                         type = NXT_HTTP_ROUTE_PATTERN_SUBSTRING;
692964Sigor@sysoev.ru 
693964Sigor@sysoev.ru                     } else {
694964Sigor@sysoev.ru                         type = NXT_HTTP_ROUTE_PATTERN_END;
695964Sigor@sysoev.ru                     }
696964Sigor@sysoev.ru 
697964Sigor@sysoev.ru                 } else {
698964Sigor@sysoev.ru                     type = NXT_HTTP_ROUTE_PATTERN_BEGIN;
699964Sigor@sysoev.ru                 }
700964Sigor@sysoev.ru 
701964Sigor@sysoev.ru             } else if (test.start[test.length - 1] == '*') {
702964Sigor@sysoev.ru                 test.length--;
703964Sigor@sysoev.ru                 type = NXT_HTTP_ROUTE_PATTERN_BEGIN;
7041032Sigor@sysoev.ru 
7051032Sigor@sysoev.ru             } else {
7061032Sigor@sysoev.ru                 length = test.length - 1;
7071032Sigor@sysoev.ru 
7081032Sigor@sysoev.ru                 for (n = 1; n < length; n++) {
7091032Sigor@sysoev.ru                     if (test.start[n] == '*') {
7101032Sigor@sysoev.ru                         test.length = n;
7111032Sigor@sysoev.ru                         type = NXT_HTTP_ROUTE_PATTERN_MIDDLE;
7121032Sigor@sysoev.ru                         break;
7131032Sigor@sysoev.ru                     }
7141032Sigor@sysoev.ru                 }
715964Sigor@sysoev.ru             }
716964Sigor@sysoev.ru         }
717964Sigor@sysoev.ru     }
718964Sigor@sysoev.ru 
719964Sigor@sysoev.ru     pattern->type = type;
720964Sigor@sysoev.ru     pattern->min_length = test.length;
7211032Sigor@sysoev.ru     pattern->length1 = test.length;
722964Sigor@sysoev.ru 
7231032Sigor@sysoev.ru     start = nxt_http_route_pattern_copy(mp, &test, pattern_case);
724964Sigor@sysoev.ru     if (nxt_slow_path(start == NULL)) {
725964Sigor@sysoev.ru         return NXT_ERROR;
726964Sigor@sysoev.ru     }
727964Sigor@sysoev.ru 
7281032Sigor@sysoev.ru     pattern->start1 = start;
7291032Sigor@sysoev.ru 
7301032Sigor@sysoev.ru     if (type == NXT_HTTP_ROUTE_PATTERN_MIDDLE) {
7311032Sigor@sysoev.ru         length -= test.length;
7321032Sigor@sysoev.ru         pattern->length2 = length;
7331032Sigor@sysoev.ru         pattern->min_length += length;
7341032Sigor@sysoev.ru 
7351032Sigor@sysoev.ru         test.start = &test.start[test.length + 1];
7361032Sigor@sysoev.ru         test.length = length;
7371032Sigor@sysoev.ru 
7381032Sigor@sysoev.ru         start = nxt_http_route_pattern_copy(mp, &test, pattern_case);
7391032Sigor@sysoev.ru         if (nxt_slow_path(start == NULL)) {
7401032Sigor@sysoev.ru             return NXT_ERROR;
7411032Sigor@sysoev.ru         }
7421032Sigor@sysoev.ru 
7431032Sigor@sysoev.ru         pattern->start2 = start;
7441032Sigor@sysoev.ru     }
7451032Sigor@sysoev.ru 
7461032Sigor@sysoev.ru     return NXT_OK;
7471032Sigor@sysoev.ru }
7481032Sigor@sysoev.ru 
7491032Sigor@sysoev.ru 
7501032Sigor@sysoev.ru static u_char *
7511032Sigor@sysoev.ru nxt_http_route_pattern_copy(nxt_mp_t *mp, nxt_str_t *test,
7521032Sigor@sysoev.ru     nxt_http_route_pattern_case_t pattern_case)
7531032Sigor@sysoev.ru {
7541032Sigor@sysoev.ru     u_char  *start;
7551032Sigor@sysoev.ru 
7561032Sigor@sysoev.ru     start = nxt_mp_nget(mp, test->length);
7571032Sigor@sysoev.ru     if (nxt_slow_path(start == NULL)) {
7581032Sigor@sysoev.ru         return start;
7591032Sigor@sysoev.ru     }
760964Sigor@sysoev.ru 
761964Sigor@sysoev.ru     switch (pattern_case) {
762964Sigor@sysoev.ru 
763964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_UPCASE:
7641032Sigor@sysoev.ru         nxt_memcpy_upcase(start, test->start, test->length);
765964Sigor@sysoev.ru         break;
766964Sigor@sysoev.ru 
767964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_LOWCASE:
7681032Sigor@sysoev.ru         nxt_memcpy_lowcase(start, test->start, test->length);
769964Sigor@sysoev.ru         break;
770964Sigor@sysoev.ru 
771964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_NOCASE:
7721032Sigor@sysoev.ru         nxt_memcpy(start, test->start, test->length);
773964Sigor@sysoev.ru         break;
774964Sigor@sysoev.ru     }
775964Sigor@sysoev.ru 
7761032Sigor@sysoev.ru     return start;
777964Sigor@sysoev.ru }
778964Sigor@sysoev.ru 
779964Sigor@sysoev.ru 
780964Sigor@sysoev.ru void
781964Sigor@sysoev.ru nxt_http_routes_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
782964Sigor@sysoev.ru {
7831033Svbart@nginx.com     nxt_http_route_t   **route, **end;
784964Sigor@sysoev.ru     nxt_http_routes_t  *routes;
785964Sigor@sysoev.ru 
786964Sigor@sysoev.ru     routes = tmcf->router_conf->routes;
7871059Sigor@sysoev.ru 
788964Sigor@sysoev.ru     if (routes != NULL) {
789964Sigor@sysoev.ru         route = &routes->route[0];
7901033Svbart@nginx.com         end = route + routes->items;
791964Sigor@sysoev.ru 
7921033Svbart@nginx.com         while (route < end) {
793964Sigor@sysoev.ru             nxt_http_route_resolve(task, tmcf, *route);
794964Sigor@sysoev.ru 
795964Sigor@sysoev.ru             route++;
796964Sigor@sysoev.ru         }
797964Sigor@sysoev.ru     }
798964Sigor@sysoev.ru }
799964Sigor@sysoev.ru 
800964Sigor@sysoev.ru 
801964Sigor@sysoev.ru static void
802964Sigor@sysoev.ru nxt_http_route_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
803964Sigor@sysoev.ru     nxt_http_route_t *route)
804964Sigor@sysoev.ru {
8051033Svbart@nginx.com     nxt_http_route_match_t  **match, **end;
806964Sigor@sysoev.ru 
807964Sigor@sysoev.ru     match = &route->match[0];
8081033Svbart@nginx.com     end = match + route->items;
809964Sigor@sysoev.ru 
8101033Svbart@nginx.com     while (match < end) {
811964Sigor@sysoev.ru         nxt_http_pass_resolve(task, tmcf, &(*match)->pass);
812964Sigor@sysoev.ru 
813964Sigor@sysoev.ru         match++;
814964Sigor@sysoev.ru     }
815964Sigor@sysoev.ru }
816964Sigor@sysoev.ru 
817964Sigor@sysoev.ru 
818964Sigor@sysoev.ru static void
819964Sigor@sysoev.ru nxt_http_pass_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
820964Sigor@sysoev.ru     nxt_http_pass_t *pass)
821964Sigor@sysoev.ru {
822964Sigor@sysoev.ru     nxt_str_t  name;
823964Sigor@sysoev.ru 
824964Sigor@sysoev.ru     name = pass->name;
825964Sigor@sysoev.ru 
826964Sigor@sysoev.ru     if (nxt_str_start(&name, "applications/", 13)) {
827964Sigor@sysoev.ru         name.length -= 13;
828964Sigor@sysoev.ru         name.start += 13;
829964Sigor@sysoev.ru 
830964Sigor@sysoev.ru         pass->u.application = nxt_router_listener_application(tmcf, &name);
831964Sigor@sysoev.ru         nxt_router_app_use(task, pass->u.application, 1);
832964Sigor@sysoev.ru 
833964Sigor@sysoev.ru         pass->handler = nxt_http_request_application;
834964Sigor@sysoev.ru 
835964Sigor@sysoev.ru     } else if (nxt_str_start(&name, "routes", 6)) {
836964Sigor@sysoev.ru 
837964Sigor@sysoev.ru         if (name.length == 6) {
838964Sigor@sysoev.ru             name.length = 0;
839964Sigor@sysoev.ru             name.start = NULL;
840964Sigor@sysoev.ru 
841964Sigor@sysoev.ru         } else if (name.start[6] == '/') {
842964Sigor@sysoev.ru             name.length -= 7;
843964Sigor@sysoev.ru             name.start += 7;
844964Sigor@sysoev.ru         }
845964Sigor@sysoev.ru 
846964Sigor@sysoev.ru         pass->u.route = nxt_http_route_find(tmcf->router_conf->routes, &name);
847964Sigor@sysoev.ru 
848964Sigor@sysoev.ru         pass->handler = nxt_http_route_pass;
849964Sigor@sysoev.ru     }
850964Sigor@sysoev.ru }
851964Sigor@sysoev.ru 
852964Sigor@sysoev.ru 
853964Sigor@sysoev.ru static nxt_http_route_t *
854964Sigor@sysoev.ru nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name)
855964Sigor@sysoev.ru {
8561033Svbart@nginx.com     nxt_http_route_t  **route, **end;
857964Sigor@sysoev.ru 
858964Sigor@sysoev.ru     route = &routes->route[0];
8591033Svbart@nginx.com     end = route + routes->items;
860964Sigor@sysoev.ru 
8611058Sigor@sysoev.ru     while (route < end) {
862964Sigor@sysoev.ru         if (nxt_strstr_eq(&(*route)->name, name)) {
863964Sigor@sysoev.ru             return *route;
864964Sigor@sysoev.ru         }
865964Sigor@sysoev.ru 
866964Sigor@sysoev.ru         route++;
8671058Sigor@sysoev.ru     }
868964Sigor@sysoev.ru 
869964Sigor@sysoev.ru     return NULL;
870964Sigor@sysoev.ru }
871964Sigor@sysoev.ru 
872964Sigor@sysoev.ru 
873964Sigor@sysoev.ru nxt_http_pass_t *
874964Sigor@sysoev.ru nxt_http_pass_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
875964Sigor@sysoev.ru     nxt_str_t *name)
876964Sigor@sysoev.ru {
877964Sigor@sysoev.ru     nxt_http_pass_t  *pass;
878964Sigor@sysoev.ru 
879964Sigor@sysoev.ru     pass = nxt_mp_alloc(tmcf->router_conf->mem_pool, sizeof(nxt_http_pass_t));
880964Sigor@sysoev.ru     if (nxt_slow_path(pass == NULL)) {
881964Sigor@sysoev.ru         return NULL;
882964Sigor@sysoev.ru     }
883964Sigor@sysoev.ru 
884964Sigor@sysoev.ru     pass->name = *name;
885964Sigor@sysoev.ru 
886964Sigor@sysoev.ru     nxt_http_pass_resolve(task, tmcf, pass);
887964Sigor@sysoev.ru 
888964Sigor@sysoev.ru     return pass;
889964Sigor@sysoev.ru }
890964Sigor@sysoev.ru 
891964Sigor@sysoev.ru 
892964Sigor@sysoev.ru /* COMPATIBILITY: listener application. */
893964Sigor@sysoev.ru 
894964Sigor@sysoev.ru nxt_http_pass_t *
895964Sigor@sysoev.ru nxt_http_pass_application(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
896964Sigor@sysoev.ru     nxt_str_t *name)
897964Sigor@sysoev.ru {
898964Sigor@sysoev.ru     nxt_http_pass_t  *pass;
899964Sigor@sysoev.ru 
900964Sigor@sysoev.ru     pass = nxt_mp_alloc(tmcf->router_conf->mem_pool, sizeof(nxt_http_pass_t));
901964Sigor@sysoev.ru     if (nxt_slow_path(pass == NULL)) {
902964Sigor@sysoev.ru         return NULL;
903964Sigor@sysoev.ru     }
904964Sigor@sysoev.ru 
905964Sigor@sysoev.ru     pass->name = *name;
906964Sigor@sysoev.ru 
907964Sigor@sysoev.ru     pass->u.application = nxt_router_listener_application(tmcf, name);
908964Sigor@sysoev.ru     nxt_router_app_use(task, pass->u.application, 1);
909964Sigor@sysoev.ru 
910964Sigor@sysoev.ru     pass->handler = nxt_http_request_application;
911964Sigor@sysoev.ru 
912964Sigor@sysoev.ru     return pass;
913964Sigor@sysoev.ru }
914964Sigor@sysoev.ru 
915964Sigor@sysoev.ru 
916964Sigor@sysoev.ru void
917964Sigor@sysoev.ru nxt_http_routes_cleanup(nxt_task_t *task, nxt_http_routes_t *routes)
918964Sigor@sysoev.ru {
9191033Svbart@nginx.com     nxt_http_route_t  **route, **end;
920964Sigor@sysoev.ru 
921964Sigor@sysoev.ru     if (routes != NULL) {
922964Sigor@sysoev.ru         route = &routes->route[0];
9231033Svbart@nginx.com         end = route + routes->items;
924964Sigor@sysoev.ru 
9251058Sigor@sysoev.ru         while (route < end) {
926964Sigor@sysoev.ru             nxt_http_route_cleanup(task, *route);
927964Sigor@sysoev.ru 
928964Sigor@sysoev.ru             route++;
9291058Sigor@sysoev.ru         }
930964Sigor@sysoev.ru     }
931964Sigor@sysoev.ru }
932964Sigor@sysoev.ru 
933964Sigor@sysoev.ru 
934964Sigor@sysoev.ru static void
935964Sigor@sysoev.ru nxt_http_route_cleanup(nxt_task_t *task, nxt_http_route_t *route)
936964Sigor@sysoev.ru {
9371033Svbart@nginx.com     nxt_http_route_match_t  **match, **end;
938964Sigor@sysoev.ru 
939964Sigor@sysoev.ru     match = &route->match[0];
9401033Svbart@nginx.com     end = match + route->items;
941964Sigor@sysoev.ru 
9421058Sigor@sysoev.ru     while (match < end) {
943964Sigor@sysoev.ru         nxt_http_pass_cleanup(task, &(*match)->pass);
944964Sigor@sysoev.ru 
945964Sigor@sysoev.ru         match++;
9461058Sigor@sysoev.ru     }
947964Sigor@sysoev.ru }
948964Sigor@sysoev.ru 
949964Sigor@sysoev.ru 
950964Sigor@sysoev.ru void
951964Sigor@sysoev.ru nxt_http_pass_cleanup(nxt_task_t *task, nxt_http_pass_t *pass)
952964Sigor@sysoev.ru {
953964Sigor@sysoev.ru     if (pass->handler == nxt_http_request_application) {
954964Sigor@sysoev.ru         nxt_router_app_use(task, pass->u.application, -1);
955964Sigor@sysoev.ru     }
956964Sigor@sysoev.ru }
957964Sigor@sysoev.ru 
958964Sigor@sysoev.ru 
959964Sigor@sysoev.ru static nxt_http_pass_t *
960964Sigor@sysoev.ru nxt_http_route_pass(nxt_task_t *task, nxt_http_request_t *r,
961964Sigor@sysoev.ru     nxt_http_pass_t *start)
962964Sigor@sysoev.ru {
963964Sigor@sysoev.ru     nxt_http_pass_t         *pass;
964964Sigor@sysoev.ru     nxt_http_route_t        *route;
9651033Svbart@nginx.com     nxt_http_route_match_t  **match, **end;
966964Sigor@sysoev.ru 
967964Sigor@sysoev.ru     route = start->u.route;
968964Sigor@sysoev.ru     match = &route->match[0];
9691033Svbart@nginx.com     end = match + route->items;
970964Sigor@sysoev.ru 
9711033Svbart@nginx.com     while (match < end) {
972964Sigor@sysoev.ru         pass = nxt_http_route_match(r, *match);
973964Sigor@sysoev.ru         if (pass != NULL) {
974964Sigor@sysoev.ru             return pass;
975964Sigor@sysoev.ru         }
976964Sigor@sysoev.ru 
977964Sigor@sysoev.ru         match++;
978964Sigor@sysoev.ru     }
979964Sigor@sysoev.ru 
980964Sigor@sysoev.ru     nxt_http_request_error(task, r, NXT_HTTP_NOT_FOUND);
981964Sigor@sysoev.ru 
982964Sigor@sysoev.ru     return NULL;
983964Sigor@sysoev.ru }
984964Sigor@sysoev.ru 
985964Sigor@sysoev.ru 
986964Sigor@sysoev.ru static nxt_http_pass_t *
987964Sigor@sysoev.ru nxt_http_route_match(nxt_http_request_t *r, nxt_http_route_match_t *match)
988964Sigor@sysoev.ru {
9891060Sigor@sysoev.ru     nxt_int_t              ret;
9901059Sigor@sysoev.ru     nxt_http_route_test_t  *test, *end;
9911059Sigor@sysoev.ru 
9921059Sigor@sysoev.ru     test = &match->test[0];
9931059Sigor@sysoev.ru     end = test + match->items;
994964Sigor@sysoev.ru 
9951059Sigor@sysoev.ru     while (test < end) {
9961059Sigor@sysoev.ru         if (test->rule->object != NXT_HTTP_ROUTE_TABLE) {
9971059Sigor@sysoev.ru             ret = nxt_http_route_rule(r, test->rule);
998964Sigor@sysoev.ru 
9991059Sigor@sysoev.ru         } else {
10001059Sigor@sysoev.ru             ret = nxt_http_route_table(r, test->table);
10011059Sigor@sysoev.ru         }
10021059Sigor@sysoev.ru 
10031060Sigor@sysoev.ru         if (ret <= 0) {
10041060Sigor@sysoev.ru             /* 0 => NULL, -1 => NXT_HTTP_PASS_ERROR. */
10051060Sigor@sysoev.ru             return (nxt_http_pass_t *) (intptr_t) ret;
1006964Sigor@sysoev.ru         }
1007964Sigor@sysoev.ru 
10081059Sigor@sysoev.ru         test++;
1009964Sigor@sysoev.ru     }
1010964Sigor@sysoev.ru 
1011964Sigor@sysoev.ru     return &match->pass;
1012964Sigor@sysoev.ru }
1013964Sigor@sysoev.ru 
1014964Sigor@sysoev.ru 
10151060Sigor@sysoev.ru static nxt_int_t
10161059Sigor@sysoev.ru nxt_http_route_table(nxt_http_request_t *r, nxt_http_route_table_t *table)
1017964Sigor@sysoev.ru {
10181060Sigor@sysoev.ru     nxt_int_t                 ret;
10191059Sigor@sysoev.ru     nxt_http_route_ruleset_t  **ruleset, **end;
10201059Sigor@sysoev.ru 
10211059Sigor@sysoev.ru     ret = 1;
10221059Sigor@sysoev.ru     ruleset = &table->ruleset[0];
10231059Sigor@sysoev.ru     end = ruleset + table->items;
10241059Sigor@sysoev.ru 
10251059Sigor@sysoev.ru     while (ruleset < end) {
10261059Sigor@sysoev.ru         ret = nxt_http_route_ruleset(r, *ruleset);
10271059Sigor@sysoev.ru 
10281060Sigor@sysoev.ru         if (ret != 0) {
10291059Sigor@sysoev.ru             return ret;
10301059Sigor@sysoev.ru         }
1031964Sigor@sysoev.ru 
10321059Sigor@sysoev.ru         ruleset++;
10331059Sigor@sysoev.ru     }
10341059Sigor@sysoev.ru 
10351059Sigor@sysoev.ru     return ret;
10361059Sigor@sysoev.ru }
10371059Sigor@sysoev.ru 
1038964Sigor@sysoev.ru 
10391060Sigor@sysoev.ru static nxt_int_t
10401059Sigor@sysoev.ru nxt_http_route_ruleset(nxt_http_request_t *r, nxt_http_route_ruleset_t *ruleset)
10411059Sigor@sysoev.ru {
10421060Sigor@sysoev.ru     nxt_int_t              ret;
10431059Sigor@sysoev.ru     nxt_http_route_rule_t  **rule, **end;
1044964Sigor@sysoev.ru 
10451059Sigor@sysoev.ru     rule = &ruleset->rule[0];
10461059Sigor@sysoev.ru     end = rule + ruleset->items;
1047964Sigor@sysoev.ru 
10481059Sigor@sysoev.ru     while (rule < end) {
10491060Sigor@sysoev.ru         ret = nxt_http_route_rule(r, *rule);
10501060Sigor@sysoev.ru 
10511060Sigor@sysoev.ru         if (ret <= 0) {
10521060Sigor@sysoev.ru             return ret;
1053964Sigor@sysoev.ru         }
1054964Sigor@sysoev.ru 
10551059Sigor@sysoev.ru         rule++;
10561059Sigor@sysoev.ru     }
10571059Sigor@sysoev.ru 
10581059Sigor@sysoev.ru     return 1;
10591059Sigor@sysoev.ru }
10601059Sigor@sysoev.ru 
1061964Sigor@sysoev.ru 
10621060Sigor@sysoev.ru static nxt_int_t
10631059Sigor@sysoev.ru nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
10641059Sigor@sysoev.ru {
10651059Sigor@sysoev.ru     void       *p, **pp;
10661059Sigor@sysoev.ru     u_char     *start;
10671059Sigor@sysoev.ru     size_t     length;
10681059Sigor@sysoev.ru     nxt_str_t  *s;
10691059Sigor@sysoev.ru 
10701059Sigor@sysoev.ru     switch (rule->object) {
10711059Sigor@sysoev.ru 
10721059Sigor@sysoev.ru     case NXT_HTTP_ROUTE_HEADER:
10731059Sigor@sysoev.ru         return nxt_http_route_header(r, rule);
1074964Sigor@sysoev.ru 
10751059Sigor@sysoev.ru     case NXT_HTTP_ROUTE_ARGUMENT:
1076*1061Sigor@sysoev.ru         return nxt_http_route_arguments(r, rule);
1077964Sigor@sysoev.ru 
10781059Sigor@sysoev.ru     case NXT_HTTP_ROUTE_COOKIE:
10791059Sigor@sysoev.ru         return 0;
10801059Sigor@sysoev.ru 
10811059Sigor@sysoev.ru     default:
10821059Sigor@sysoev.ru         break;
10831059Sigor@sysoev.ru     }
1084964Sigor@sysoev.ru 
10851059Sigor@sysoev.ru     p = nxt_pointer_to(r, rule->u.offset);
10861059Sigor@sysoev.ru 
10871059Sigor@sysoev.ru     if (rule->object == NXT_HTTP_ROUTE_STRING) {
10881059Sigor@sysoev.ru         s = p;
1089964Sigor@sysoev.ru 
10901059Sigor@sysoev.ru     } else {
10911059Sigor@sysoev.ru         /* NXT_HTTP_ROUTE_STRING_PTR */
10921059Sigor@sysoev.ru         pp = p;
10931059Sigor@sysoev.ru         s = *pp;
1094964Sigor@sysoev.ru 
10951059Sigor@sysoev.ru         if (s == NULL) {
1096964Sigor@sysoev.ru             return 0;
1097964Sigor@sysoev.ru         }
1098964Sigor@sysoev.ru     }
1099964Sigor@sysoev.ru 
11001059Sigor@sysoev.ru     length = s->length;
11011059Sigor@sysoev.ru     start = s->start;
11021059Sigor@sysoev.ru 
11031059Sigor@sysoev.ru     return nxt_http_route_test_rule(r, rule, start, length);
11041059Sigor@sysoev.ru }
11051059Sigor@sysoev.ru 
11061059Sigor@sysoev.ru 
11071060Sigor@sysoev.ru static nxt_int_t
11081059Sigor@sysoev.ru nxt_http_route_header(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
11091059Sigor@sysoev.ru {
11101060Sigor@sysoev.ru     nxt_int_t         ret;
11111059Sigor@sysoev.ru     nxt_http_field_t  *f;
11121059Sigor@sysoev.ru 
11131059Sigor@sysoev.ru     ret = 0;
11141059Sigor@sysoev.ru 
11151059Sigor@sysoev.ru     nxt_list_each(f, r->fields) {
11161059Sigor@sysoev.ru 
11171059Sigor@sysoev.ru         if (rule->u.name.hash != f->hash
11181059Sigor@sysoev.ru             || rule->u.name.length != f->name_length
11191059Sigor@sysoev.ru             || nxt_strncasecmp(rule->u.name.start, f->name, f->name_length)
11201059Sigor@sysoev.ru                != 0)
11211059Sigor@sysoev.ru         {
11221059Sigor@sysoev.ru             continue;
11231059Sigor@sysoev.ru         }
11241059Sigor@sysoev.ru 
11251059Sigor@sysoev.ru         ret = nxt_http_route_test_rule(r, rule, f->value, f->value_length);
11261059Sigor@sysoev.ru 
11271060Sigor@sysoev.ru         if (ret == 0) {
11281059Sigor@sysoev.ru             return ret;
11291059Sigor@sysoev.ru         }
11301059Sigor@sysoev.ru 
11311059Sigor@sysoev.ru     } nxt_list_loop;
11321059Sigor@sysoev.ru 
11331059Sigor@sysoev.ru     return ret;
11341059Sigor@sysoev.ru }
11351059Sigor@sysoev.ru 
11361059Sigor@sysoev.ru 
11371060Sigor@sysoev.ru static nxt_int_t
1138*1061Sigor@sysoev.ru nxt_http_route_arguments(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
1139*1061Sigor@sysoev.ru {
1140*1061Sigor@sysoev.ru     nxt_array_t  *arguments;
1141*1061Sigor@sysoev.ru 
1142*1061Sigor@sysoev.ru     if (r->args == NULL) {
1143*1061Sigor@sysoev.ru         return 0;
1144*1061Sigor@sysoev.ru     }
1145*1061Sigor@sysoev.ru 
1146*1061Sigor@sysoev.ru     arguments = nxt_http_route_arguments_parse(r);
1147*1061Sigor@sysoev.ru     if (nxt_slow_path(arguments == NULL)) {
1148*1061Sigor@sysoev.ru         return -1;
1149*1061Sigor@sysoev.ru     }
1150*1061Sigor@sysoev.ru 
1151*1061Sigor@sysoev.ru     return nxt_http_route_test_argument(r, rule, arguments);
1152*1061Sigor@sysoev.ru }
1153*1061Sigor@sysoev.ru 
1154*1061Sigor@sysoev.ru 
1155*1061Sigor@sysoev.ru static nxt_array_t *
1156*1061Sigor@sysoev.ru nxt_http_route_arguments_parse(nxt_http_request_t *r)
1157*1061Sigor@sysoev.ru {
1158*1061Sigor@sysoev.ru     size_t                 name_length;
1159*1061Sigor@sysoev.ru     u_char                 c, *p, *start, *end, *name;
1160*1061Sigor@sysoev.ru     uint32_t               hash;
1161*1061Sigor@sysoev.ru     nxt_bool_t             valid;
1162*1061Sigor@sysoev.ru     nxt_array_t            *args;
1163*1061Sigor@sysoev.ru     nxt_http_name_value_t  *nv;
1164*1061Sigor@sysoev.ru 
1165*1061Sigor@sysoev.ru     if (r->arguments != NULL) {
1166*1061Sigor@sysoev.ru         return r->arguments;
1167*1061Sigor@sysoev.ru     }
1168*1061Sigor@sysoev.ru 
1169*1061Sigor@sysoev.ru     args = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t));
1170*1061Sigor@sysoev.ru     if (nxt_slow_path(args == NULL)) {
1171*1061Sigor@sysoev.ru         return NULL;
1172*1061Sigor@sysoev.ru     }
1173*1061Sigor@sysoev.ru 
1174*1061Sigor@sysoev.ru     hash = NXT_HTTP_FIELD_HASH_INIT;
1175*1061Sigor@sysoev.ru     valid = 1;
1176*1061Sigor@sysoev.ru     name = NULL;
1177*1061Sigor@sysoev.ru     name_length = 0;
1178*1061Sigor@sysoev.ru 
1179*1061Sigor@sysoev.ru     start = r->args->start;
1180*1061Sigor@sysoev.ru     end = start + r->args->length;
1181*1061Sigor@sysoev.ru 
1182*1061Sigor@sysoev.ru     for (p = start; p < end; p++) {
1183*1061Sigor@sysoev.ru         c = *p;
1184*1061Sigor@sysoev.ru 
1185*1061Sigor@sysoev.ru         if (c == '=') {
1186*1061Sigor@sysoev.ru             name_length = p - start;
1187*1061Sigor@sysoev.ru             name = start;
1188*1061Sigor@sysoev.ru             start = p + 1;
1189*1061Sigor@sysoev.ru             valid = (name_length != 0);
1190*1061Sigor@sysoev.ru 
1191*1061Sigor@sysoev.ru         } else if (c == '&') {
1192*1061Sigor@sysoev.ru             if (valid) {
1193*1061Sigor@sysoev.ru                 nv = nxt_http_route_argument(args, name, name_length, hash,
1194*1061Sigor@sysoev.ru                                              start, p);
1195*1061Sigor@sysoev.ru                 if (nxt_slow_path(nv == NULL)) {
1196*1061Sigor@sysoev.ru                     return NULL;
1197*1061Sigor@sysoev.ru                 }
1198*1061Sigor@sysoev.ru             }
1199*1061Sigor@sysoev.ru 
1200*1061Sigor@sysoev.ru             hash = NXT_HTTP_FIELD_HASH_INIT;
1201*1061Sigor@sysoev.ru             valid = 1;
1202*1061Sigor@sysoev.ru             name = NULL;
1203*1061Sigor@sysoev.ru             start = p + 1;
1204*1061Sigor@sysoev.ru 
1205*1061Sigor@sysoev.ru         } else if (name == NULL) {
1206*1061Sigor@sysoev.ru             hash = nxt_http_field_hash_char(hash, c);
1207*1061Sigor@sysoev.ru         }
1208*1061Sigor@sysoev.ru     }
1209*1061Sigor@sysoev.ru 
1210*1061Sigor@sysoev.ru     if (valid) {
1211*1061Sigor@sysoev.ru         nv = nxt_http_route_argument(args, name, name_length, hash, start, p);
1212*1061Sigor@sysoev.ru         if (nxt_slow_path(nv == NULL)) {
1213*1061Sigor@sysoev.ru             return NULL;
1214*1061Sigor@sysoev.ru         }
1215*1061Sigor@sysoev.ru     }
1216*1061Sigor@sysoev.ru 
1217*1061Sigor@sysoev.ru     r->arguments = args;
1218*1061Sigor@sysoev.ru 
1219*1061Sigor@sysoev.ru     return args;
1220*1061Sigor@sysoev.ru }
1221*1061Sigor@sysoev.ru 
1222*1061Sigor@sysoev.ru 
1223*1061Sigor@sysoev.ru static nxt_http_name_value_t *
1224*1061Sigor@sysoev.ru nxt_http_route_argument(nxt_array_t *array, u_char *name, size_t name_length,
1225*1061Sigor@sysoev.ru     uint32_t hash, u_char *start, u_char *end)
1226*1061Sigor@sysoev.ru {
1227*1061Sigor@sysoev.ru     size_t                 length;
1228*1061Sigor@sysoev.ru     nxt_http_name_value_t  *nv;
1229*1061Sigor@sysoev.ru 
1230*1061Sigor@sysoev.ru     nv = nxt_array_add(array);
1231*1061Sigor@sysoev.ru     if (nxt_slow_path(nv == NULL)) {
1232*1061Sigor@sysoev.ru         return NULL;
1233*1061Sigor@sysoev.ru     }
1234*1061Sigor@sysoev.ru 
1235*1061Sigor@sysoev.ru     nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF;
1236*1061Sigor@sysoev.ru 
1237*1061Sigor@sysoev.ru     length = end - start;
1238*1061Sigor@sysoev.ru 
1239*1061Sigor@sysoev.ru     if (name == NULL) {
1240*1061Sigor@sysoev.ru         name_length = length;
1241*1061Sigor@sysoev.ru         name = start;
1242*1061Sigor@sysoev.ru         length = 0;
1243*1061Sigor@sysoev.ru     }
1244*1061Sigor@sysoev.ru 
1245*1061Sigor@sysoev.ru     nv->name_length = name_length;
1246*1061Sigor@sysoev.ru     nv->value_length = length;
1247*1061Sigor@sysoev.ru     nv->name = name;
1248*1061Sigor@sysoev.ru     nv->value = start;
1249*1061Sigor@sysoev.ru 
1250*1061Sigor@sysoev.ru     return nv;
1251*1061Sigor@sysoev.ru }
1252*1061Sigor@sysoev.ru 
1253*1061Sigor@sysoev.ru 
1254*1061Sigor@sysoev.ru static nxt_int_t
1255*1061Sigor@sysoev.ru nxt_http_route_test_argument(nxt_http_request_t *r,
1256*1061Sigor@sysoev.ru     nxt_http_route_rule_t *rule, nxt_array_t *array)
1257*1061Sigor@sysoev.ru {
1258*1061Sigor@sysoev.ru     nxt_bool_t             ret;
1259*1061Sigor@sysoev.ru     nxt_http_name_value_t  *nv, *end;
1260*1061Sigor@sysoev.ru 
1261*1061Sigor@sysoev.ru     ret = 0;
1262*1061Sigor@sysoev.ru 
1263*1061Sigor@sysoev.ru     nv = array->elts;
1264*1061Sigor@sysoev.ru     end = nv + array->nelts;
1265*1061Sigor@sysoev.ru 
1266*1061Sigor@sysoev.ru     while (nv < end) {
1267*1061Sigor@sysoev.ru 
1268*1061Sigor@sysoev.ru         if (rule->u.name.hash == nv->hash
1269*1061Sigor@sysoev.ru             && rule->u.name.length == nv->name_length
1270*1061Sigor@sysoev.ru             && nxt_memcmp(rule->u.name.start, nv->name, nv->name_length) == 0)
1271*1061Sigor@sysoev.ru         {
1272*1061Sigor@sysoev.ru             ret = nxt_http_route_test_rule(r, rule, nv->value,
1273*1061Sigor@sysoev.ru                                            nv->value_length);
1274*1061Sigor@sysoev.ru             if (ret == 0) {
1275*1061Sigor@sysoev.ru                 break;
1276*1061Sigor@sysoev.ru             }
1277*1061Sigor@sysoev.ru         }
1278*1061Sigor@sysoev.ru 
1279*1061Sigor@sysoev.ru         nv++;
1280*1061Sigor@sysoev.ru     }
1281*1061Sigor@sysoev.ru 
1282*1061Sigor@sysoev.ru     return ret;
1283*1061Sigor@sysoev.ru }
1284*1061Sigor@sysoev.ru 
1285*1061Sigor@sysoev.ru 
1286*1061Sigor@sysoev.ru static nxt_int_t
12871059Sigor@sysoev.ru nxt_http_route_test_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule,
12881059Sigor@sysoev.ru     u_char *start, size_t length)
12891059Sigor@sysoev.ru {
12901060Sigor@sysoev.ru     nxt_int_t                 ret;
12911059Sigor@sysoev.ru     nxt_http_route_pattern_t  *pattern, *end;
12921059Sigor@sysoev.ru 
12931057Sigor@sysoev.ru     ret = 1;
1294964Sigor@sysoev.ru     pattern = &rule->pattern[0];
12951033Svbart@nginx.com     end = pattern + rule->items;
1296964Sigor@sysoev.ru 
12971057Sigor@sysoev.ru     while (pattern < end) {
1298964Sigor@sysoev.ru         ret = nxt_http_route_pattern(r, pattern, start, length);
1299964Sigor@sysoev.ru 
13001060Sigor@sysoev.ru         /* nxt_http_route_pattern() returns either 1 or 0. */
1301964Sigor@sysoev.ru         ret ^= pattern->negative;
1302964Sigor@sysoev.ru 
1303964Sigor@sysoev.ru         if (pattern->any == ret) {
1304964Sigor@sysoev.ru             return ret;
1305964Sigor@sysoev.ru         }
1306964Sigor@sysoev.ru 
1307964Sigor@sysoev.ru         pattern++;
13081057Sigor@sysoev.ru     }
1309964Sigor@sysoev.ru 
1310964Sigor@sysoev.ru     return ret;
1311964Sigor@sysoev.ru }
1312964Sigor@sysoev.ru 
1313964Sigor@sysoev.ru 
13141060Sigor@sysoev.ru static nxt_int_t
1315964Sigor@sysoev.ru nxt_http_route_pattern(nxt_http_request_t *r, nxt_http_route_pattern_t *pattern,
1316964Sigor@sysoev.ru     u_char *start, size_t length)
1317964Sigor@sysoev.ru {
13181060Sigor@sysoev.ru     u_char     *p, *end, *test;
13191060Sigor@sysoev.ru     size_t     test_length;
13201060Sigor@sysoev.ru     nxt_int_t  ret;
1321964Sigor@sysoev.ru 
1322964Sigor@sysoev.ru     if (length < pattern->min_length) {
1323964Sigor@sysoev.ru         return 0;
1324964Sigor@sysoev.ru     }
1325964Sigor@sysoev.ru 
13261032Sigor@sysoev.ru     test = pattern->start1;
13271032Sigor@sysoev.ru     test_length = pattern->length1;
1328964Sigor@sysoev.ru 
1329964Sigor@sysoev.ru     switch (pattern->type) {
1330964Sigor@sysoev.ru 
1331964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_EXACT:
13321032Sigor@sysoev.ru         if (length != test_length) {
1333964Sigor@sysoev.ru             return 0;
1334964Sigor@sysoev.ru         }
1335964Sigor@sysoev.ru 
1336964Sigor@sysoev.ru         break;
1337964Sigor@sysoev.ru 
1338964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_BEGIN:
1339964Sigor@sysoev.ru         break;
1340964Sigor@sysoev.ru 
13411032Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_MIDDLE:
13421032Sigor@sysoev.ru         ret = nxt_http_route_memcmp(start, test, test_length,
13431032Sigor@sysoev.ru                                     pattern->case_sensitive);
13441032Sigor@sysoev.ru         if (!ret) {
13451032Sigor@sysoev.ru             return ret;
13461032Sigor@sysoev.ru         }
13471032Sigor@sysoev.ru 
13481032Sigor@sysoev.ru         test = pattern->start2;
13491032Sigor@sysoev.ru         test_length = pattern->length2;
13501032Sigor@sysoev.ru 
13511032Sigor@sysoev.ru         /* Fall through. */
13521032Sigor@sysoev.ru 
1353964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_END:
13541032Sigor@sysoev.ru         start += length - test_length;
1355964Sigor@sysoev.ru         break;
1356964Sigor@sysoev.ru 
1357964Sigor@sysoev.ru     case NXT_HTTP_ROUTE_PATTERN_SUBSTRING:
13581032Sigor@sysoev.ru         end = start + length;
13591032Sigor@sysoev.ru 
1360964Sigor@sysoev.ru         if (pattern->case_sensitive) {
13611032Sigor@sysoev.ru             p = nxt_memstrn(start, end, (char *) test, test_length);
13621032Sigor@sysoev.ru 
13631032Sigor@sysoev.ru         } else {
13641032Sigor@sysoev.ru             p = nxt_memcasestrn(start, end, (char *) test, test_length);
1365964Sigor@sysoev.ru         }
1366964Sigor@sysoev.ru 
13671032Sigor@sysoev.ru         return (p != NULL);
1368964Sigor@sysoev.ru     }
1369964Sigor@sysoev.ru 
13701032Sigor@sysoev.ru     return nxt_http_route_memcmp(start, test, test_length,
13711032Sigor@sysoev.ru                                  pattern->case_sensitive);
13721032Sigor@sysoev.ru }
13731032Sigor@sysoev.ru 
13741032Sigor@sysoev.ru 
13751060Sigor@sysoev.ru static nxt_int_t
13761032Sigor@sysoev.ru nxt_http_route_memcmp(u_char *start, u_char *test, size_t test_length,
13771032Sigor@sysoev.ru     nxt_bool_t case_sensitive)
13781032Sigor@sysoev.ru {
13791032Sigor@sysoev.ru     nxt_int_t  n;
13801032Sigor@sysoev.ru 
13811032Sigor@sysoev.ru     if (case_sensitive) {
13821032Sigor@sysoev.ru         n = nxt_memcmp(start, test, test_length);
13831032Sigor@sysoev.ru 
13841032Sigor@sysoev.ru     } else {
13851032Sigor@sysoev.ru         n = nxt_memcasecmp(start, test, test_length);
1386964Sigor@sysoev.ru     }
1387964Sigor@sysoev.ru 
13881032Sigor@sysoev.ru     return (n == 0);
1389964Sigor@sysoev.ru }
1390