1
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) NGINX, Inc.
5 */
6
7 #include <nxt_router.h>
8 #include <nxt_http.h>
9 #include <nxt_sockaddr.h>
10 #include <nxt_http_route_addr.h>
11 #include <nxt_regex.h>
12
13
14 typedef enum {
15 NXT_HTTP_ROUTE_TABLE = 0,
16 NXT_HTTP_ROUTE_STRING,
17 NXT_HTTP_ROUTE_STRING_PTR,
18 NXT_HTTP_ROUTE_HEADER,
19 NXT_HTTP_ROUTE_ARGUMENT,
20 NXT_HTTP_ROUTE_COOKIE,
21 NXT_HTTP_ROUTE_SCHEME,
22 NXT_HTTP_ROUTE_QUERY,
23 NXT_HTTP_ROUTE_SOURCE,
24 NXT_HTTP_ROUTE_DESTINATION,
25 } nxt_http_route_object_t;
26
27
28 typedef enum {
29 NXT_HTTP_ROUTE_PATTERN_EXACT = 0,
30 NXT_HTTP_ROUTE_PATTERN_BEGIN,
31 NXT_HTTP_ROUTE_PATTERN_END,
32 NXT_HTTP_ROUTE_PATTERN_SUBSTRING,
33 } nxt_http_route_pattern_type_t;
34
35
36 typedef enum {
37 NXT_HTTP_ROUTE_PATTERN_NOCASE = 0,
38 NXT_HTTP_ROUTE_PATTERN_LOWCASE,
39 NXT_HTTP_ROUTE_PATTERN_UPCASE,
40 } nxt_http_route_pattern_case_t;
41
42
43 typedef enum {
44 NXT_HTTP_ROUTE_ENCODING_NONE = 0,
45 NXT_HTTP_ROUTE_ENCODING_URI,
46 NXT_HTTP_ROUTE_ENCODING_URI_PLUS
47 } nxt_http_route_encoding_t;
48
49
50 typedef struct {
51 nxt_conf_value_t *host;
52 nxt_conf_value_t *uri;
53 nxt_conf_value_t *method;
54 nxt_conf_value_t *headers;
55 nxt_conf_value_t *arguments;
56 nxt_conf_value_t *cookies;
57 nxt_conf_value_t *scheme;
58 nxt_conf_value_t *query;
59 nxt_conf_value_t *source;
60 nxt_conf_value_t *destination;
61 } nxt_http_route_match_conf_t;
62
63
64 typedef struct {
65 u_char *start;
66 uint32_t length;
67 nxt_http_route_pattern_type_t type:8;
68 } nxt_http_route_pattern_slice_t;
69
70
71 typedef struct {
72 union {
73 nxt_array_t *pattern_slices;
74 #if (NXT_HAVE_REGEX)
75 nxt_regex_t *regex;
76 #endif
77 } u;
78 uint32_t min_length;
79
80 uint8_t case_sensitive; /* 1 bit */
81 uint8_t negative; /* 1 bit */
82 uint8_t any; /* 1 bit */
83 #if (NXT_HAVE_REGEX)
84 uint8_t regex; /* 1 bit */
85 #endif
86 } nxt_http_route_pattern_t;
87
88
89 typedef struct {
90 uint16_t hash;
91 uint16_t name_length;
92 uint32_t value_length;
93 u_char *name;
94 u_char *value;
95 } nxt_http_cookie_t;
96
97
98 struct nxt_http_route_rule_s {
99 /* The object must be the first field. */
100 nxt_http_route_object_t object:8;
101 uint32_t items;
102
103 union {
104 uintptr_t offset;
105
106 struct {
107 u_char *start;
108 uint16_t hash;
109 uint16_t length;
110 } name;
111 } u;
112
113 nxt_http_route_pattern_t pattern[0];
114 };
115
116
117 typedef struct {
118 uint32_t items;
119 nxt_http_route_rule_t *rule[0];
120 } nxt_http_route_ruleset_t;
121
122
123 typedef struct {
124 /* The object must be the first field. */
125 nxt_http_route_object_t object:8;
126 uint32_t items;
127 nxt_http_route_ruleset_t *ruleset[0];
128 } nxt_http_route_table_t;
129
130
131 struct nxt_http_route_addr_rule_s {
132 /* The object must be the first field. */
133 nxt_http_route_object_t object:8;
134 uint32_t items;
135 nxt_http_route_addr_pattern_t addr_pattern[0];
136 };
137
138
139 typedef union {
140 nxt_http_route_rule_t *rule;
141 nxt_http_route_table_t *table;
142 nxt_http_route_addr_rule_t *addr_rule;
143 } nxt_http_route_test_t;
144
145
146 typedef struct {
147 uint32_t items;
148 nxt_http_action_t action;
149 nxt_http_route_test_t test[0];
150 } nxt_http_route_match_t;
151
152
153 struct nxt_http_route_s {
154 nxt_str_t name;
155 uint32_t items;
156 nxt_http_route_match_t *match[0];
157 };
158
159
160 struct nxt_http_routes_s {
161 uint32_t items;
162 nxt_http_route_t *route[0];
163 };
164
165
166 static nxt_http_route_t *nxt_http_route_create(nxt_task_t *task,
167 nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv);
168 static nxt_http_route_match_t *nxt_http_route_match_create(nxt_task_t *task,
169 nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv);
170 static nxt_http_route_table_t *nxt_http_route_table_create(nxt_task_t *task,
171 nxt_mp_t *mp, nxt_conf_value_t *table_cv, nxt_http_route_object_t object,
172 nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding);
173 static nxt_http_route_ruleset_t *nxt_http_route_ruleset_create(nxt_task_t *task,
174 nxt_mp_t *mp, nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object,
175 nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding);
176 static nxt_http_route_rule_t *nxt_http_route_rule_name_create(nxt_task_t *task,
177 nxt_mp_t *mp, nxt_conf_value_t *rule_cv, nxt_str_t *name,
178 nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding);
179 static nxt_http_route_rule_t *nxt_http_route_rule_create(nxt_task_t *task,
180 nxt_mp_t *mp, nxt_conf_value_t *cv, nxt_bool_t case_sensitive,
181 nxt_http_route_pattern_case_t pattern_case,
182 nxt_http_route_encoding_t encoding);
183 static int nxt_http_pattern_compare(const void *one, const void *two);
184 static int nxt_http_addr_pattern_compare(const void *one, const void *two);
185 static nxt_int_t nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp,
186 nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern,
187 nxt_http_route_pattern_case_t pattern_case,
188 nxt_http_route_encoding_t encoding);
189 static nxt_int_t nxt_http_route_decode_str(nxt_str_t *str,
190 nxt_http_route_encoding_t encoding);
191 static nxt_int_t nxt_http_route_pattern_slice(nxt_array_t *slices,
192 nxt_str_t *test,
193 nxt_http_route_pattern_type_t type,
194 nxt_http_route_encoding_t encoding,
195 nxt_http_route_pattern_case_t pattern_case);
196
197 static nxt_int_t nxt_http_route_resolve(nxt_task_t *task,
198 nxt_router_temp_conf_t *tmcf, nxt_http_route_t *route);
199 static nxt_int_t nxt_http_action_resolve(nxt_task_t *task,
200 nxt_router_temp_conf_t *tmcf, nxt_http_action_t *action);
201 static nxt_http_action_t *nxt_http_pass_var(nxt_task_t *task,
202 nxt_http_request_t *r, nxt_http_action_t *action);
203 static void nxt_http_pass_var_ready(nxt_task_t *task, void *obj, void *data);
204 static void nxt_http_pass_var_error(nxt_task_t *task, void *obj, void *data);
205 static nxt_int_t nxt_http_pass_find(nxt_mp_t *mp, nxt_router_conf_t *rtcf,
206 nxt_str_t *pass, nxt_http_action_t *action);
207 static nxt_int_t nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name,
208 nxt_http_action_t *action);
209
210 static nxt_http_action_t *nxt_http_route_handler(nxt_task_t *task,
211 nxt_http_request_t *r, nxt_http_action_t *start);
212 static nxt_http_action_t *nxt_http_route_match(nxt_task_t *task,
213 nxt_http_request_t *r, nxt_http_route_match_t *match);
214 static nxt_int_t nxt_http_route_table(nxt_http_request_t *r,
215 nxt_http_route_table_t *table);
216 static nxt_int_t nxt_http_route_ruleset(nxt_http_request_t *r,
217 nxt_http_route_ruleset_t *ruleset);
218 static nxt_int_t nxt_http_route_rule(nxt_http_request_t *r,
219 nxt_http_route_rule_t *rule);
220 static nxt_int_t nxt_http_route_header(nxt_http_request_t *r,
221 nxt_http_route_rule_t *rule);
222 static nxt_int_t nxt_http_route_arguments(nxt_http_request_t *r,
223 nxt_http_route_rule_t *rule);
224 static nxt_int_t nxt_http_route_test_argument(nxt_http_request_t *r,
225 nxt_http_route_rule_t *rule, nxt_array_t *array);
226 static nxt_int_t nxt_http_route_scheme(nxt_http_request_t *r,
227 nxt_http_route_rule_t *rule);
228 static nxt_int_t nxt_http_route_query(nxt_http_request_t *r,
229 nxt_http_route_rule_t *rule);
230 static nxt_int_t nxt_http_route_cookies(nxt_http_request_t *r,
231 nxt_http_route_rule_t *rule);
232 static nxt_int_t nxt_http_route_test_cookie(nxt_http_request_t *r,
233 nxt_http_route_rule_t *rule, nxt_array_t *array);
234 static nxt_int_t nxt_http_route_pattern(nxt_http_request_t *r,
235 nxt_http_route_pattern_t *pattern, u_char *start, size_t length);
236 static nxt_int_t nxt_http_route_memcmp(u_char *start, u_char *test,
237 size_t length, nxt_bool_t case_sensitive);
238
239
240 nxt_http_routes_t *
nxt_http_routes_create(nxt_task_t * task,nxt_router_temp_conf_t * tmcf,nxt_conf_value_t * routes_conf)241 nxt_http_routes_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
242 nxt_conf_value_t *routes_conf)
243 {
244 size_t size;
245 uint32_t i, n, next;
246 nxt_mp_t *mp;
247 nxt_str_t name, *string;
248 nxt_bool_t object;
249 nxt_conf_value_t *route_conf;
250 nxt_http_route_t *route;
251 nxt_http_routes_t *routes;
252
253 object = (nxt_conf_type(routes_conf) == NXT_CONF_OBJECT);
254 n = object ? nxt_conf_object_members_count(routes_conf) : 1;
255 size = sizeof(nxt_http_routes_t) + n * sizeof(nxt_http_route_t *);
256
257 mp = tmcf->router_conf->mem_pool;
258
259 routes = nxt_mp_alloc(mp, size);
260 if (nxt_slow_path(routes == NULL)) {
261 return NULL;
262 }
263
264 routes->items = n;
265
266 if (object) {
267 next = 0;
268
269 for (i = 0; i < n; i++) {
270 route_conf = nxt_conf_next_object_member(routes_conf, &name, &next);
271
272 route = nxt_http_route_create(task, tmcf, route_conf);
273 if (nxt_slow_path(route == NULL)) {
274 return NULL;
275 }
276
277 routes->route[i] = route;
278
279 string = nxt_str_dup(mp, &route->name, &name);
280 if (nxt_slow_path(string == NULL)) {
281 return NULL;
282 }
283 }
284
285 } else {
286 route = nxt_http_route_create(task, tmcf, routes_conf);
287 if (nxt_slow_path(route == NULL)) {
288 return NULL;
289 }
290
291 routes->route[0] = route;
292
293 route->name.length = 0;
294 route->name.start = NULL;
295 }
296
297 return routes;
298 }
299
300
301 static nxt_conf_map_t nxt_http_route_match_conf[] = {
302 {
303 nxt_string("scheme"),
304 NXT_CONF_MAP_PTR,
305 offsetof(nxt_http_route_match_conf_t, scheme)
306 },
307 {
308 nxt_string("host"),
309 NXT_CONF_MAP_PTR,
310 offsetof(nxt_http_route_match_conf_t, host),
311 },
312
313 {
314 nxt_string("uri"),
315 NXT_CONF_MAP_PTR,
316 offsetof(nxt_http_route_match_conf_t, uri),
317 },
318
319 {
320 nxt_string("method"),
321 NXT_CONF_MAP_PTR,
322 offsetof(nxt_http_route_match_conf_t, method),
323 },
324
325 {
326 nxt_string("headers"),
327 NXT_CONF_MAP_PTR,
328 offsetof(nxt_http_route_match_conf_t, headers),
329 },
330
331 {
332 nxt_string("arguments"),
333 NXT_CONF_MAP_PTR,
334 offsetof(nxt_http_route_match_conf_t, arguments),
335 },
336
337 {
338 nxt_string("cookies"),
339 NXT_CONF_MAP_PTR,
340 offsetof(nxt_http_route_match_conf_t, cookies),
341 },
342
343 {
344 nxt_string("query"),
345 NXT_CONF_MAP_PTR,
346 offsetof(nxt_http_route_match_conf_t, query),
347 },
348
349 {
350 nxt_string("source"),
351 NXT_CONF_MAP_PTR,
352 offsetof(nxt_http_route_match_conf_t, source),
353 },
354
355 {
356 nxt_string("destination"),
357 NXT_CONF_MAP_PTR,
358 offsetof(nxt_http_route_match_conf_t, destination),
359 },
360 };
361
362
363 static nxt_http_route_t *
nxt_http_route_create(nxt_task_t * task,nxt_router_temp_conf_t * tmcf,nxt_conf_value_t * cv)364 nxt_http_route_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
365 nxt_conf_value_t *cv)
366 {
367 size_t size;
368 uint32_t i, n;
369 nxt_conf_value_t *value;
370 nxt_http_route_t *route;
371 nxt_http_route_match_t *match, **m;
372
373 n = nxt_conf_array_elements_count(cv);
374 size = sizeof(nxt_http_route_t) + n * sizeof(nxt_http_route_match_t *);
375
376 route = nxt_mp_alloc(tmcf->router_conf->mem_pool, size);
377 if (nxt_slow_path(route == NULL)) {
378 return NULL;
379 }
380
381 route->items = n;
382 m = &route->match[0];
383
384 for (i = 0; i < n; i++) {
385 value = nxt_conf_get_array_element(cv, i);
386
387 match = nxt_http_route_match_create(task, tmcf, value);
388 if (match == NULL) {
389 return NULL;
390 }
391
392 *m++ = match;
393 }
394
395 return route;
396 }
397
398
399 static nxt_http_route_match_t *
nxt_http_route_match_create(nxt_task_t * task,nxt_router_temp_conf_t * tmcf,nxt_conf_value_t * cv)400 nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
401 nxt_conf_value_t *cv)
402 {
403 size_t size;
404 uint32_t n;
405 nxt_mp_t *mp;
406 nxt_int_t ret;
407 nxt_conf_value_t *match_conf, *action_conf;
408 nxt_http_route_test_t *test;
409 nxt_http_route_rule_t *rule;
410 nxt_http_route_table_t *table;
411 nxt_http_route_match_t *match;
412 nxt_http_route_addr_rule_t *addr_rule;
413 nxt_http_route_match_conf_t mtcf;
414
415 static nxt_str_t match_path = nxt_string("/match");
416 static nxt_str_t action_path = nxt_string("/action");
417
418 match_conf = nxt_conf_get_path(cv, &match_path);
419
420 n = (match_conf != NULL) ? nxt_conf_object_members_count(match_conf) : 0;
421 size = sizeof(nxt_http_route_match_t) + n * sizeof(nxt_http_route_test_t *);
422
423 mp = tmcf->router_conf->mem_pool;
424
425 match = nxt_mp_alloc(mp, size);
426 if (nxt_slow_path(match == NULL)) {
427 return NULL;
428 }
429
430 match->items = n;
431
432 action_conf = nxt_conf_get_path(cv, &action_path);
433 if (nxt_slow_path(action_conf == NULL)) {
434 return NULL;
435 }
436
437 ret = nxt_http_action_init(task, tmcf, action_conf, &match->action);
438 if (nxt_slow_path(ret != NXT_OK)) {
439 return NULL;
440 }
441
442 if (n == 0) {
443 return match;
444 }
445
446 nxt_memzero(&mtcf, sizeof(mtcf));
447
448 ret = nxt_conf_map_object(tmcf->mem_pool,
449 match_conf, nxt_http_route_match_conf,
450 nxt_nitems(nxt_http_route_match_conf), &mtcf);
451 if (ret != NXT_OK) {
452 return NULL;
453 }
454
455 test = &match->test[0];
456
457 if (mtcf.scheme != NULL) {
458 rule = nxt_http_route_rule_create(task, mp, mtcf.scheme, 1,
459 NXT_HTTP_ROUTE_PATTERN_NOCASE,
460 NXT_HTTP_ROUTE_ENCODING_NONE);
461 if (rule == NULL) {
462 return NULL;
463 }
464
465 rule->object = NXT_HTTP_ROUTE_SCHEME;
466 test->rule = rule;
467 test++;
468 }
469
470 if (mtcf.host != NULL) {
471 rule = nxt_http_route_rule_create(task, mp, mtcf.host, 1,
472 NXT_HTTP_ROUTE_PATTERN_LOWCASE,
473 NXT_HTTP_ROUTE_ENCODING_NONE);
474 if (rule == NULL) {
475 return NULL;
476 }
477
478 rule->u.offset = offsetof(nxt_http_request_t, host);
479 rule->object = NXT_HTTP_ROUTE_STRING;
480 test->rule = rule;
481 test++;
482 }
483
484 if (mtcf.uri != NULL) {
485 rule = nxt_http_route_rule_create(task, mp, mtcf.uri, 1,
486 NXT_HTTP_ROUTE_PATTERN_NOCASE,
487 NXT_HTTP_ROUTE_ENCODING_URI);
488 if (rule == NULL) {
489 return NULL;
490 }
491
492 rule->u.offset = offsetof(nxt_http_request_t, path);
493 rule->object = NXT_HTTP_ROUTE_STRING_PTR;
494 test->rule = rule;
495 test++;
496 }
497
498 if (mtcf.method != NULL) {
499 rule = nxt_http_route_rule_create(task, mp, mtcf.method, 1,
500 NXT_HTTP_ROUTE_PATTERN_UPCASE,
501 NXT_HTTP_ROUTE_ENCODING_NONE);
502 if (rule == NULL) {
503 return NULL;
504 }
505
506 rule->u.offset = offsetof(nxt_http_request_t, method);
507 rule->object = NXT_HTTP_ROUTE_STRING_PTR;
508 test->rule = rule;
509 test++;
510 }
511
512 if (mtcf.headers != NULL) {
513 table = nxt_http_route_table_create(task, mp, mtcf.headers,
514 NXT_HTTP_ROUTE_HEADER, 0,
515 NXT_HTTP_ROUTE_ENCODING_NONE);
516 if (table == NULL) {
517 return NULL;
518 }
519
520 test->table = table;
521 test++;
522 }
523
524 if (mtcf.arguments != NULL) {
525 table = nxt_http_route_table_create(task, mp, mtcf.arguments,
526 NXT_HTTP_ROUTE_ARGUMENT, 1,
527 NXT_HTTP_ROUTE_ENCODING_URI_PLUS);
528 if (table == NULL) {
529 return NULL;
530 }
531
532 test->table = table;
533 test++;
534 }
535
536 if (mtcf.cookies != NULL) {
537 table = nxt_http_route_table_create(task, mp, mtcf.cookies,
538 NXT_HTTP_ROUTE_COOKIE, 1,
539 NXT_HTTP_ROUTE_ENCODING_NONE);
540 if (table == NULL) {
541 return NULL;
542 }
543
544 test->table = table;
545 test++;
546 }
547
548 if (mtcf.query != NULL) {
549 rule = nxt_http_route_rule_create(task, mp, mtcf.query, 1,
550 NXT_HTTP_ROUTE_PATTERN_NOCASE,
551 NXT_HTTP_ROUTE_ENCODING_URI_PLUS);
552 if (rule == NULL) {
553 return NULL;
554 }
555
556 rule->object = NXT_HTTP_ROUTE_QUERY;
557 test->rule = rule;
558 test++;
559 }
560
561 if (mtcf.source != NULL) {
562 addr_rule = nxt_http_route_addr_rule_create(task, mp, mtcf.source);
563 if (addr_rule == NULL) {
564 return NULL;
565 }
566
567 addr_rule->object = NXT_HTTP_ROUTE_SOURCE;
568 test->addr_rule = addr_rule;
569 test++;
570 }
571
572 if (mtcf.destination != NULL) {
573 addr_rule = nxt_http_route_addr_rule_create(task, mp, mtcf.destination);
574 if (addr_rule == NULL) {
575 return NULL;
576 }
577
578 addr_rule->object = NXT_HTTP_ROUTE_DESTINATION;
579 test->addr_rule = addr_rule;
580 test++;
581 }
582
583 return match;
584 }
585
586
587 static nxt_conf_map_t nxt_http_route_action_conf[] = {
588 {
589 nxt_string("pass"),
590 NXT_CONF_MAP_PTR,
591 offsetof(nxt_http_action_conf_t, pass)
592 },
593 {
594 nxt_string("return"),
595 NXT_CONF_MAP_PTR,
596 offsetof(nxt_http_action_conf_t, ret)
597 },
598 {
599 nxt_string("location"),
600 NXT_CONF_MAP_PTR,
601 offsetof(nxt_http_action_conf_t, location)
602 },
603 {
604 nxt_string("proxy"),
605 NXT_CONF_MAP_PTR,
606 offsetof(nxt_http_action_conf_t, proxy)
607 },
608 {
609 nxt_string("share"),
610 NXT_CONF_MAP_PTR,
611 offsetof(nxt_http_action_conf_t, share)
612 },
613 {
614 nxt_string("chroot"),
615 NXT_CONF_MAP_STR,
616 offsetof(nxt_http_action_conf_t, chroot)
617 },
618 {
619 nxt_string("follow_symlinks"),
620 NXT_CONF_MAP_PTR,
621 offsetof(nxt_http_action_conf_t, follow_symlinks)
622 },
623 {
624 nxt_string("traverse_mounts"),
625 NXT_CONF_MAP_PTR,
626 offsetof(nxt_http_action_conf_t, traverse_mounts)
627 },
628 {
629 nxt_string("types"),
630 NXT_CONF_MAP_PTR,
631 offsetof(nxt_http_action_conf_t, types)
632 },
633 {
634 nxt_string("fallback"),
635 NXT_CONF_MAP_PTR,
636 offsetof(nxt_http_action_conf_t, fallback)
637 },
638 };
639
640
641 nxt_int_t
nxt_http_action_init(nxt_task_t * task,nxt_router_temp_conf_t * tmcf,nxt_conf_value_t * cv,nxt_http_action_t * action)642 nxt_http_action_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
643 nxt_conf_value_t *cv, nxt_http_action_t *action)
644 {
645 nxt_mp_t *mp;
646 nxt_int_t ret;
647 nxt_str_t pass;
648 nxt_http_action_conf_t acf;
649
650 nxt_memzero(&acf, sizeof(acf));
651
652 ret = nxt_conf_map_object(tmcf->mem_pool, cv, nxt_http_route_action_conf,
653 nxt_nitems(nxt_http_route_action_conf), &acf);
654 if (ret != NXT_OK) {
655 return ret;
656 }
657
658 nxt_memzero(action, sizeof(nxt_http_action_t));
659
660 mp = tmcf->router_conf->mem_pool;
661
662 if (acf.ret != NULL) {
663 return nxt_http_return_init(mp, action, &acf);
664 }
665
666 if (acf.share != NULL) {
667 return nxt_http_static_init(task, tmcf, action, &acf);
668 }
669
670 if (acf.proxy != NULL) {
671 return nxt_http_proxy_init(mp, action, &acf);
672 }
673
674 nxt_conf_get_string(acf.pass, &pass);
675
676 action->u.var = nxt_var_compile(&pass, mp, 0);
677 if (nxt_slow_path(action->u.var == NULL)) {
678 return NXT_ERROR;
679 }
680
681 return NXT_OK;
682 }
683
684
685 static nxt_http_route_table_t *
nxt_http_route_table_create(nxt_task_t * task,nxt_mp_t * mp,nxt_conf_value_t * table_cv,nxt_http_route_object_t object,nxt_bool_t case_sensitive,nxt_http_route_encoding_t encoding)686 nxt_http_route_table_create(nxt_task_t *task, nxt_mp_t *mp,
687 nxt_conf_value_t *table_cv, nxt_http_route_object_t object,
688 nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding)
689 {
690 size_t size;
691 uint32_t i, n;
692 nxt_conf_value_t *ruleset_cv;
693 nxt_http_route_table_t *table;
694 nxt_http_route_ruleset_t *ruleset;
695
696 n = nxt_conf_array_elements_count_or_1(table_cv);
697 size = sizeof(nxt_http_route_table_t)
698 + n * sizeof(nxt_http_route_ruleset_t *);
699
700 table = nxt_mp_alloc(mp, size);
701 if (nxt_slow_path(table == NULL)) {
702 return NULL;
703 }
704
705 table->items = n;
706 table->object = NXT_HTTP_ROUTE_TABLE;
707
708 for (i = 0; i < n; i++) {
709 ruleset_cv = nxt_conf_get_array_element_or_itself(table_cv, i);
710
711 ruleset = nxt_http_route_ruleset_create(task, mp, ruleset_cv, object,
712 case_sensitive, encoding);
713 if (nxt_slow_path(ruleset == NULL)) {
714 return NULL;
715 }
716
717 table->ruleset[i] = ruleset;
718 }
719
720 return table;
721 }
722
723
724 static nxt_http_route_ruleset_t *
nxt_http_route_ruleset_create(nxt_task_t * task,nxt_mp_t * mp,nxt_conf_value_t * ruleset_cv,nxt_http_route_object_t object,nxt_bool_t case_sensitive,nxt_http_route_encoding_t encoding)725 nxt_http_route_ruleset_create(nxt_task_t *task, nxt_mp_t *mp,
726 nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object,
727 nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding)
728 {
729 size_t size;
730 uint32_t i, n, next;
731 nxt_str_t name;
732 nxt_conf_value_t *rule_cv;
733 nxt_http_route_rule_t *rule;
734 nxt_http_route_ruleset_t *ruleset;
735
736 n = nxt_conf_object_members_count(ruleset_cv);
737 size = sizeof(nxt_http_route_ruleset_t)
738 + n * sizeof(nxt_http_route_rule_t *);
739
740 ruleset = nxt_mp_alloc(mp, size);
741 if (nxt_slow_path(ruleset == NULL)) {
742 return NULL;
743 }
744
745 ruleset->items = n;
746
747 next = 0;
748
749 /*
750 * A workaround for GCC 10 with -flto -O2 flags that warns about "name"
751 * may be uninitialized in nxt_http_route_rule_name_create().
752 */
753 nxt_str_null(&name);
754
755 for (i = 0; i < n; i++) {
756 rule_cv = nxt_conf_next_object_member(ruleset_cv, &name, &next);
757
758 rule = nxt_http_route_rule_name_create(task, mp, rule_cv, &name,
759 case_sensitive, encoding);
760 if (nxt_slow_path(rule == NULL)) {
761 return NULL;
762 }
763
764 rule->object = object;
765 ruleset->rule[i] = rule;
766 }
767
768 return ruleset;
769 }
770
771
772 static nxt_http_route_rule_t *
nxt_http_route_rule_name_create(nxt_task_t * task,nxt_mp_t * mp,nxt_conf_value_t * rule_cv,nxt_str_t * name,nxt_bool_t case_sensitive,nxt_http_route_encoding_t encoding)773 nxt_http_route_rule_name_create(nxt_task_t *task, nxt_mp_t *mp,
774 nxt_conf_value_t *rule_cv, nxt_str_t *name, nxt_bool_t case_sensitive,
775 nxt_http_route_encoding_t encoding)
776 {
777 u_char c, *p, *src, *start, *end, plus;
778 uint8_t d0, d1;
779 uint32_t hash;
780 nxt_uint_t i;
781 nxt_http_route_rule_t *rule;
782
783 rule = nxt_http_route_rule_create(task, mp, rule_cv, case_sensitive,
784 NXT_HTTP_ROUTE_PATTERN_NOCASE,
785 encoding);
786 if (nxt_slow_path(rule == NULL)) {
787 return NULL;
788 }
789
790 rule->u.name.length = name->length;
791
792 p = nxt_mp_nget(mp, name->length);
793 if (nxt_slow_path(p == NULL)) {
794 return NULL;
795 }
796
797 hash = NXT_HTTP_FIELD_HASH_INIT;
798 rule->u.name.start = p;
799
800 if (encoding == NXT_HTTP_ROUTE_ENCODING_NONE) {
801 for (i = 0; i < name->length; i++) {
802 c = name->start[i];
803 *p++ = c;
804
805 c = case_sensitive ? c : nxt_lowcase(c);
806 hash = nxt_http_field_hash_char(hash, c);
807 }
808
809 goto end;
810 }
811
812 plus = (encoding == NXT_HTTP_ROUTE_ENCODING_URI_PLUS) ? ' ' : '+';
813
814 start = name->start;
815 end = start + name->length;
816
817 for (src = start; src < end; src++) {
818 c = *src;
819
820 switch (c) {
821 case '%':
822 if (nxt_slow_path(end - src <= 2)) {
823 return NULL;
824 }
825
826 d0 = nxt_hex2int[src[1]];
827 d1 = nxt_hex2int[src[2]];
828 src += 2;
829
830 if (nxt_slow_path((d0 | d1) >= 16)) {
831 return NULL;
832 }
833
834 c = (d0 << 4) + d1;
835 *p++ = c;
836 break;
837
838 case '+':
839 c = plus;
840 *p++ = c;
841 break;
842
843 default:
844 *p++ = c;
845 break;
846 }
847
848 c = case_sensitive ? c : nxt_lowcase(c);
849 hash = nxt_http_field_hash_char(hash, c);
850 }
851
852 rule->u.name.length = p - rule->u.name.start;
853
854 end:
855
856 rule->u.name.hash = nxt_http_field_hash_end(hash) & 0xFFFF;
857
858 return rule;
859 }
860
861
862 static nxt_http_route_rule_t *
nxt_http_route_rule_create(nxt_task_t * task,nxt_mp_t * mp,nxt_conf_value_t * cv,nxt_bool_t case_sensitive,nxt_http_route_pattern_case_t pattern_case,nxt_http_route_encoding_t encoding)863 nxt_http_route_rule_create(nxt_task_t *task, nxt_mp_t *mp,
864 nxt_conf_value_t *cv, nxt_bool_t case_sensitive,
865 nxt_http_route_pattern_case_t pattern_case,
866 nxt_http_route_encoding_t encoding)
867 {
868 size_t size;
869 uint32_t i, n;
870 nxt_int_t ret;
871 nxt_conf_value_t *value;
872 nxt_http_route_rule_t *rule;
873 nxt_http_route_pattern_t *pattern;
874
875 n = nxt_conf_array_elements_count_or_1(cv);
876 size = sizeof(nxt_http_route_rule_t) + n * sizeof(nxt_http_route_pattern_t);
877
878 rule = nxt_mp_alloc(mp, size);
879 if (nxt_slow_path(rule == NULL)) {
880 return NULL;
881 }
882
883 rule->items = n;
884
885 pattern = &rule->pattern[0];
886
887 nxt_conf_array_qsort(cv, nxt_http_pattern_compare);
888
889 for (i = 0; i < n; i++) {
890 pattern[i].case_sensitive = case_sensitive;
891 value = nxt_conf_get_array_element_or_itself(cv, i);
892
893 ret = nxt_http_route_pattern_create(task, mp, value, &pattern[i],
894 pattern_case, encoding);
895 if (nxt_slow_path(ret != NXT_OK)) {
896 return NULL;
897 }
898 }
899
900 return rule;
901 }
902
903
904 nxt_http_route_addr_rule_t *
nxt_http_route_addr_rule_create(nxt_task_t * task,nxt_mp_t * mp,nxt_conf_value_t * cv)905 nxt_http_route_addr_rule_create(nxt_task_t *task, nxt_mp_t *mp,
906 nxt_conf_value_t *cv)
907 {
908 size_t size;
909 uint32_t i, n;
910 nxt_conf_value_t *value;
911 nxt_http_route_addr_rule_t *addr_rule;
912 nxt_http_route_addr_pattern_t *pattern;
913
914 n = nxt_conf_array_elements_count_or_1(cv);
915
916 size = sizeof(nxt_http_route_addr_rule_t)
917 + n * sizeof(nxt_http_route_addr_pattern_t);
918
919 addr_rule = nxt_mp_alloc(mp, size);
920 if (nxt_slow_path(addr_rule == NULL)) {
921 return NULL;
922 }
923
924 addr_rule->items = n;
925
926 for (i = 0; i < n; i++) {
927 pattern = &addr_rule->addr_pattern[i];
928 value = nxt_conf_get_array_element_or_itself(cv, i);
929
930 if (nxt_http_route_addr_pattern_parse(mp, pattern, value) != NXT_OK) {
931 return NULL;
932 }
933 }
934
935 if (n > 1) {
936 nxt_qsort(addr_rule->addr_pattern, addr_rule->items,
937 sizeof(nxt_http_route_addr_pattern_t),
938 nxt_http_addr_pattern_compare);
939 }
940
941 return addr_rule;
942 }
943
944
945 nxt_http_route_rule_t *
nxt_http_route_types_rule_create(nxt_task_t * task,nxt_mp_t * mp,nxt_conf_value_t * types)946 nxt_http_route_types_rule_create(nxt_task_t *task, nxt_mp_t *mp,
947 nxt_conf_value_t *types)
948 {
949 return nxt_http_route_rule_create(task, mp, types, 0,
950 NXT_HTTP_ROUTE_PATTERN_LOWCASE,
951 NXT_HTTP_ROUTE_ENCODING_NONE);
952 }
953
954
955 static int
nxt_http_pattern_compare(const void * one,const void * two)956 nxt_http_pattern_compare(const void *one, const void *two)
957 {
958 nxt_str_t test;
959 nxt_bool_t negative1, negative2;
960 nxt_conf_value_t *value;
961
962 value = (nxt_conf_value_t *) one;
963 nxt_conf_get_string(value, &test);
964 negative1 = (test.length != 0 && test.start[0] == '!');
965
966 value = (nxt_conf_value_t *) two;
967 nxt_conf_get_string(value, &test);
968 negative2 = (test.length != 0 && test.start[0] == '!');
969
970 return (negative2 - negative1);
971 }
972
973
974 static int
nxt_http_addr_pattern_compare(const void * one,const void * two)975 nxt_http_addr_pattern_compare(const void *one, const void *two)
976 {
977 const nxt_http_route_addr_pattern_t *p1, *p2;
978
979 p1 = one;
980 p2 = two;
981
982 return (p2->base.negative - p1->base.negative);
983 }
984
985
986 static nxt_int_t
nxt_http_route_pattern_create(nxt_task_t * task,nxt_mp_t * mp,nxt_conf_value_t * cv,nxt_http_route_pattern_t * pattern,nxt_http_route_pattern_case_t pattern_case,nxt_http_route_encoding_t encoding)987 nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp,
988 nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern,
989 nxt_http_route_pattern_case_t pattern_case,
990 nxt_http_route_encoding_t encoding)
991 {
992 u_char c, *p, *end;
993 nxt_str_t test, tmp;
994 nxt_int_t ret;
995 nxt_array_t *slices;
996 #if (NXT_HAVE_REGEX)
997 nxt_regex_t *re;
998 nxt_regex_err_t err;
999 #endif
1000 nxt_http_route_pattern_type_t type;
1001 nxt_http_route_pattern_slice_t *slice;
1002
1003 type = NXT_HTTP_ROUTE_PATTERN_EXACT;
1004
1005 nxt_conf_get_string(cv, &test);
1006
1007 pattern->u.pattern_slices = NULL;
1008 pattern->negative = 0;
1009 pattern->any = 1;
1010 pattern->min_length = 0;
1011 #if (NXT_HAVE_REGEX)
1012 pattern->regex = 0;
1013 #endif
1014
1015 if (test.length != 0 && test.start[0] == '!') {
1016 test.start++;
1017 test.length--;
1018
1019 pattern->negative = 1;
1020 pattern->any = 0;
1021 }
1022
1023 if (test.length > 0 && test.start[0] == '~') {
1024 #if (NXT_HAVE_REGEX)
1025 test.start++;
1026 test.length--;
1027
1028 re = nxt_regex_compile(mp, &test, &err);
1029 if (nxt_slow_path(re == NULL)) {
1030 if (err.offset < test.length) {
1031 nxt_alert(task, "nxt_regex_compile(%V) failed: %s at offset %d",
1032 &test, err.msg, (int) err.offset);
1033 return NXT_ERROR;
1034 }
1035
1036 nxt_alert(task, "nxt_regex_compile(%V) failed %s", &test, err.msg);
1037
1038 return NXT_ERROR;
1039 }
1040
1041 pattern->u.regex = re;
1042 pattern->regex = 1;
1043
1044 return NXT_OK;
1045
1046 #else
1047 return NXT_ERROR;
1048 #endif
1049 }
1050
1051 slices = nxt_array_create(mp, 1, sizeof(nxt_http_route_pattern_slice_t));
1052 if (nxt_slow_path(slices == NULL)) {
1053 return NXT_ERROR;
1054 }
1055
1056 pattern->u.pattern_slices = slices;
1057
1058 if (test.length == 0) {
1059 slice = nxt_array_add(slices);
1060 if (nxt_slow_path(slice == NULL)) {
1061 return NXT_ERROR;
1062 }
1063
1064 slice->type = NXT_HTTP_ROUTE_PATTERN_EXACT;
1065 slice->start = NULL;
1066 slice->length = 0;
1067
1068 return NXT_OK;
1069 }
1070
1071 if (test.start[0] == '*') {
1072 /* 'type' is no longer 'EXACT', assume 'END'. */
1073 type = NXT_HTTP_ROUTE_PATTERN_END;
1074 test.start++;
1075 test.length--;
1076 }
1077
1078 if (type == NXT_HTTP_ROUTE_PATTERN_EXACT) {
1079 tmp.start = test.start;
1080
1081 p = nxt_memchr(test.start, '*', test.length);
1082
1083 if (p == NULL) {
1084 /* No '*' found - EXACT pattern. */
1085 tmp.length = test.length;
1086 type = NXT_HTTP_ROUTE_PATTERN_EXACT;
1087
1088 test.start += test.length;
1089 test.length = 0;
1090
1091 } else {
1092 /* '*' found - BEGIN pattern. */
1093 tmp.length = p - test.start;
1094 type = NXT_HTTP_ROUTE_PATTERN_BEGIN;
1095
1096 test.start = p + 1;
1097 test.length -= tmp.length + 1;
1098 }
1099
1100 ret = nxt_http_route_pattern_slice(slices, &tmp, type, encoding,
1101 pattern_case);
1102 if (nxt_slow_path(ret != NXT_OK)) {
1103 return ret;
1104 }
1105
1106 pattern->min_length += tmp.length;
1107 }
1108
1109 end = test.start + test.length;
1110
1111 if (test.length != 0 && end[-1] != '*') {
1112 p = end - 1;
1113
1114 while (p != test.start) {
1115 c = *p--;
1116
1117 if (c == '*') {
1118 p += 2;
1119 break;
1120 }
1121 }
1122
1123 tmp.start = p;
1124 tmp.length = end - p;
1125
1126 test.length -= tmp.length;
1127 end = p;
1128
1129 ret = nxt_http_route_pattern_slice(slices, &tmp,
1130 NXT_HTTP_ROUTE_PATTERN_END,
1131 encoding, pattern_case);
1132 if (nxt_slow_path(ret != NXT_OK)) {
1133 return ret;
1134 }
1135
1136 pattern->min_length += tmp.length;
1137 }
1138
1139 tmp.start = test.start;
1140 tmp.length = 0;
1141
1142 p = tmp.start;
1143
1144 while (p != end) {
1145 c = *p++;
1146
1147 if (c != '*') {
1148 tmp.length++;
1149 continue;
1150 }
1151
1152 if (tmp.length == 0) {
1153 tmp.start = p;
1154 continue;
1155 }
1156
1157 ret = nxt_http_route_pattern_slice(slices, &tmp,
1158 NXT_HTTP_ROUTE_PATTERN_SUBSTRING,
1159 encoding, pattern_case);
1160 if (nxt_slow_path(ret != NXT_OK)) {
1161 return ret;
1162 }
1163
1164 pattern->min_length += tmp.length;
1165
1166 tmp.start = p;
1167 tmp.length = 0;
1168 }
1169
1170 if (tmp.length != 0) {
1171 ret = nxt_http_route_pattern_slice(slices, &tmp,
1172 NXT_HTTP_ROUTE_PATTERN_SUBSTRING,
1173 encoding, pattern_case);
1174 if (nxt_slow_path(ret != NXT_OK)) {
1175 return ret;
1176 }
1177
1178 pattern->min_length += tmp.length;
1179 }
1180
1181 return NXT_OK;
1182 }
1183
1184
1185 static nxt_int_t
nxt_http_route_decode_str(nxt_str_t * str,nxt_http_route_encoding_t encoding)1186 nxt_http_route_decode_str(nxt_str_t *str, nxt_http_route_encoding_t encoding)
1187 {
1188 u_char *start, *end;
1189
1190 switch (encoding) {
1191 case NXT_HTTP_ROUTE_ENCODING_NONE:
1192 break;
1193
1194 case NXT_HTTP_ROUTE_ENCODING_URI:
1195 start = str->start;
1196
1197 end = nxt_decode_uri(start, start, str->length);
1198 if (nxt_slow_path(end == NULL)) {
1199 return NXT_ERROR;
1200 }
1201
1202 str->length = end - start;
1203 break;
1204
1205 case NXT_HTTP_ROUTE_ENCODING_URI_PLUS:
1206 start = str->start;
1207
1208 end = nxt_decode_uri_plus(start, start, str->length);
1209 if (nxt_slow_path(end == NULL)) {
1210 return NXT_ERROR;
1211 }
1212
1213 str->length = end - start;
1214 break;
1215
1216 default:
1217 nxt_unreachable();
1218 }
1219
1220 return NXT_OK;
1221 }
1222
1223
1224 static nxt_int_t
nxt_http_route_pattern_slice(nxt_array_t * slices,nxt_str_t * test,nxt_http_route_pattern_type_t type,nxt_http_route_encoding_t encoding,nxt_http_route_pattern_case_t pattern_case)1225 nxt_http_route_pattern_slice(nxt_array_t *slices,
1226 nxt_str_t *test,
1227 nxt_http_route_pattern_type_t type,
1228 nxt_http_route_encoding_t encoding,
1229 nxt_http_route_pattern_case_t pattern_case)
1230 {
1231 u_char *start;
1232 nxt_int_t ret;
1233 nxt_http_route_pattern_slice_t *slice;
1234
1235 ret = nxt_http_route_decode_str(test, encoding);
1236 if (nxt_slow_path(ret != NXT_OK)) {
1237 return ret;
1238 }
1239
1240 start = nxt_mp_nget(slices->mem_pool, test->length);
1241 if (nxt_slow_path(start == NULL)) {
1242 return NXT_ERROR;
1243 }
1244
1245 switch (pattern_case) {
1246
1247 case NXT_HTTP_ROUTE_PATTERN_UPCASE:
1248 nxt_memcpy_upcase(start, test->start, test->length);
1249 break;
1250
1251 case NXT_HTTP_ROUTE_PATTERN_LOWCASE:
1252 nxt_memcpy_lowcase(start, test->start, test->length);
1253 break;
1254
1255 case NXT_HTTP_ROUTE_PATTERN_NOCASE:
1256 nxt_memcpy(start, test->start, test->length);
1257 break;
1258 }
1259
1260 slice = nxt_array_add(slices);
1261 if (nxt_slow_path(slice == NULL)) {
1262 return NXT_ERROR;
1263 }
1264
1265 slice->type = type;
1266 slice->start = start;
1267 slice->length = test->length;
1268
1269 return NXT_OK;
1270 }
1271
1272
1273 nxt_int_t
nxt_http_routes_resolve(nxt_task_t * task,nxt_router_temp_conf_t * tmcf)1274 nxt_http_routes_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
1275 {
1276 nxt_int_t ret;
1277 nxt_http_route_t **route, **end;
1278 nxt_http_routes_t *routes;
1279
1280 routes = tmcf->router_conf->routes;
1281
1282 if (routes != NULL) {
1283 route = &routes->route[0];
1284 end = route + routes->items;
1285
1286 while (route < end) {
1287 ret = nxt_http_route_resolve(task, tmcf, *route);
1288 if (nxt_slow_path(ret != NXT_OK)) {
1289 return NXT_ERROR;
1290 }
1291
1292 route++;
1293 }
1294 }
1295
1296 return NXT_OK;
1297 }
1298
1299
1300 static nxt_int_t
nxt_http_route_resolve(nxt_task_t * task,nxt_router_temp_conf_t * tmcf,nxt_http_route_t * route)1301 nxt_http_route_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1302 nxt_http_route_t *route)
1303 {
1304 nxt_int_t ret;
1305 nxt_http_route_match_t **match, **end;
1306
1307 match = &route->match[0];
1308 end = match + route->items;
1309
1310 while (match < end) {
1311 ret = nxt_http_action_resolve(task, tmcf, &(*match)->action);
1312 if (nxt_slow_path(ret != NXT_OK)) {
1313 return NXT_ERROR;
1314 }
1315
1316 match++;
1317 }
1318
1319 return NXT_OK;
1320 }
1321
1322
1323 static nxt_int_t
nxt_http_action_resolve(nxt_task_t * task,nxt_router_temp_conf_t * tmcf,nxt_http_action_t * action)1324 nxt_http_action_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1325 nxt_http_action_t *action)
1326 {
1327 nxt_int_t ret;
1328 nxt_str_t pass;
1329
1330 if (action->handler != NULL) {
1331 if (action->fallback != NULL) {
1332 return nxt_http_action_resolve(task, tmcf, action->fallback);
1333 }
1334
1335 return NXT_OK;
1336 }
1337
1338 if (nxt_var_is_const(action->u.var)) {
1339 nxt_var_raw(action->u.var, &pass);
1340
1341 ret = nxt_http_pass_find(tmcf->mem_pool, tmcf->router_conf, &pass,
1342 action);
1343 if (nxt_slow_path(ret != NXT_OK)) {
1344 return NXT_ERROR;
1345 }
1346
1347 } else {
1348 action->handler = nxt_http_pass_var;
1349 }
1350
1351 return NXT_OK;
1352 }
1353
1354
1355 static nxt_http_action_t *
nxt_http_pass_var(nxt_task_t * task,nxt_http_request_t * r,nxt_http_action_t * action)1356 nxt_http_pass_var(nxt_task_t *task, nxt_http_request_t *r,
1357 nxt_http_action_t *action)
1358 {
1359 nxt_int_t ret;
1360 nxt_str_t str;
1361 nxt_var_t *var;
1362
1363 var = action->u.var;
1364
1365 nxt_var_raw(var, &str);
1366
1367 nxt_debug(task, "http pass: \"%V\"", &str);
1368
1369 ret = nxt_var_query_init(&r->var_query, r, r->mem_pool);
1370 if (nxt_slow_path(ret != NXT_OK)) {
1371 goto fail;
1372 }
1373
1374 action = nxt_mp_get(r->mem_pool,
1375 sizeof(nxt_http_action_t) + sizeof(nxt_str_t));
1376 if (nxt_slow_path(action == NULL)) {
1377 goto fail;
1378 }
1379
1380 action->u.pass = nxt_pointer_to(action, sizeof(nxt_http_action_t));
1381
1382 nxt_var_query(task, r->var_query, var, action->u.pass);
1383 nxt_var_query_resolve(task, r->var_query, action,
1384 nxt_http_pass_var_ready,
1385 nxt_http_pass_var_error);
1386 return NULL;
1387
1388 fail:
1389
1390 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
1391 return NULL;
1392 }
1393
1394
1395 static void
nxt_http_pass_var_ready(nxt_task_t * task,void * obj,void * data)1396 nxt_http_pass_var_ready(nxt_task_t *task, void *obj, void *data)
1397 {
1398 nxt_int_t ret;
1399 nxt_router_conf_t *rtcf;
1400 nxt_http_action_t *action;
1401 nxt_http_status_t status;
1402 nxt_http_request_t *r;
1403
1404 r = obj;
1405 action = data;
1406 rtcf = r->conf->socket_conf->router_conf;
1407
1408 nxt_debug(task, "http pass lookup: %V", action->u.pass);
1409
1410 ret = nxt_http_pass_find(r->mem_pool, rtcf, action->u.pass, action);
1411
1412 if (ret != NXT_OK) {
1413 status = (ret == NXT_DECLINED) ? NXT_HTTP_NOT_FOUND
1414 : NXT_HTTP_INTERNAL_SERVER_ERROR;
1415
1416 nxt_http_request_error(task, r, status);
1417 return;
1418 }
1419
1420 nxt_http_request_action(task, r, action);
1421 }
1422
1423
1424 static void
nxt_http_pass_var_error(nxt_task_t * task,void * obj,void * data)1425 nxt_http_pass_var_error(nxt_task_t *task, void *obj, void *data)
1426 {
1427 nxt_http_request_t *r;
1428
1429 r = obj;
1430
1431 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
1432 }
1433
1434
1435 static nxt_int_t
nxt_http_pass_find(nxt_mp_t * mp,nxt_router_conf_t * rtcf,nxt_str_t * pass,nxt_http_action_t * action)1436 nxt_http_pass_find(nxt_mp_t *mp, nxt_router_conf_t *rtcf, nxt_str_t *pass,
1437 nxt_http_action_t *action)
1438 {
1439 nxt_int_t ret;
1440 nxt_str_t segments[3];
1441
1442 ret = nxt_http_pass_segments(mp, pass, segments, 3);
1443 if (nxt_slow_path(ret != NXT_OK)) {
1444 return ret;
1445 }
1446
1447 if (nxt_str_eq(&segments[0], "applications", 12)) {
1448 return nxt_router_application_init(rtcf, &segments[1], &segments[2],
1449 action);
1450 }
1451
1452 if (segments[2].length == 0) {
1453 if (nxt_str_eq(&segments[0], "upstreams", 9)) {
1454 return nxt_upstream_find(rtcf->upstreams, &segments[1], action);
1455 }
1456
1457 if (nxt_str_eq(&segments[0], "routes", 6)) {
1458 return nxt_http_route_find(rtcf->routes, &segments[1], action);
1459 }
1460 }
1461
1462 return NXT_DECLINED;
1463 }
1464
1465
1466 nxt_int_t
nxt_http_pass_segments(nxt_mp_t * mp,nxt_str_t * pass,nxt_str_t * segments,nxt_uint_t n)1467 nxt_http_pass_segments(nxt_mp_t *mp, nxt_str_t *pass, nxt_str_t *segments,
1468 nxt_uint_t n)
1469 {
1470 u_char *p;
1471 nxt_str_t rest;
1472
1473 if (nxt_slow_path(nxt_str_dup(mp, &rest, pass) == NULL)) {
1474 return NXT_ERROR;
1475 }
1476
1477 nxt_memzero(segments, n * sizeof(nxt_str_t));
1478
1479 do {
1480 p = nxt_memchr(rest.start, '/', rest.length);
1481
1482 if (p != NULL) {
1483 n--;
1484
1485 if (n == 0) {
1486 return NXT_DECLINED;
1487 }
1488
1489 segments->length = p - rest.start;
1490 segments->start = rest.start;
1491
1492 rest.length -= segments->length + 1;
1493 rest.start = p + 1;
1494
1495 } else {
1496 n = 0;
1497 *segments = rest;
1498 }
1499
1500 if (segments->length == 0) {
1501 return NXT_DECLINED;
1502 }
1503
1504 p = nxt_decode_uri(segments->start, segments->start, segments->length);
1505 if (p == NULL) {
1506 return NXT_DECLINED;
1507 }
1508
1509 segments->length = p - segments->start;
1510 segments++;
1511
1512 } while (n);
1513
1514 return NXT_OK;
1515 }
1516
1517
1518 static nxt_int_t
nxt_http_route_find(nxt_http_routes_t * routes,nxt_str_t * name,nxt_http_action_t * action)1519 nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name,
1520 nxt_http_action_t *action)
1521 {
1522 nxt_http_route_t **route, **end;
1523
1524 if (routes == NULL) {
1525 return NXT_DECLINED;
1526 }
1527
1528 route = &routes->route[0];
1529 end = route + routes->items;
1530
1531 while (route < end) {
1532 if (nxt_strstr_eq(&(*route)->name, name)) {
1533 action->u.route = *route;
1534 action->handler = nxt_http_route_handler;
1535
1536 return NXT_OK;
1537 }
1538
1539 route++;
1540 }
1541
1542 return NXT_DECLINED;
1543 }
1544
1545
1546 nxt_http_action_t *
nxt_http_action_create(nxt_task_t * task,nxt_router_temp_conf_t * tmcf,nxt_str_t * pass)1547 nxt_http_action_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1548 nxt_str_t *pass)
1549 {
1550 nxt_mp_t *mp;
1551 nxt_int_t ret;
1552 nxt_http_action_t *action;
1553
1554 mp = tmcf->router_conf->mem_pool;
1555
1556 action = nxt_mp_alloc(mp, sizeof(nxt_http_action_t));
1557 if (nxt_slow_path(action == NULL)) {
1558 return NULL;
1559 }
1560
1561 action->u.var = nxt_var_compile(pass, mp, 0);
1562 if (nxt_slow_path(action->u.var == NULL)) {
1563 return NULL;
1564 }
1565
1566 action->handler = NULL;
1567
1568 ret = nxt_http_action_resolve(task, tmcf, action);
1569 if (nxt_slow_path(ret != NXT_OK)) {
1570 return NULL;
1571 }
1572
1573 return action;
1574 }
1575
1576
1577 /* COMPATIBILITY: listener application. */
1578
1579 nxt_http_action_t *
nxt_http_pass_application(nxt_task_t * task,nxt_router_conf_t * rtcf,nxt_str_t * name)1580 nxt_http_pass_application(nxt_task_t *task, nxt_router_conf_t *rtcf,
1581 nxt_str_t *name)
1582 {
1583 nxt_http_action_t *action;
1584
1585 action = nxt_mp_alloc(rtcf->mem_pool, sizeof(nxt_http_action_t));
1586 if (nxt_slow_path(action == NULL)) {
1587 return NULL;
1588 }
1589
1590 (void) nxt_router_application_init(rtcf, name, NULL, action);
1591
1592 return action;
1593 }
1594
1595
1596 static nxt_http_action_t *
nxt_http_route_handler(nxt_task_t * task,nxt_http_request_t * r,nxt_http_action_t * start)1597 nxt_http_route_handler(nxt_task_t *task, nxt_http_request_t *r,
1598 nxt_http_action_t *start)
1599 {
1600 nxt_http_route_t *route;
1601 nxt_http_action_t *action;
1602 nxt_http_route_match_t **match, **end;
1603
1604 route = start->u.route;
1605 match = &route->match[0];
1606 end = match + route->items;
1607
1608 while (match < end) {
1609 action = nxt_http_route_match(task, r, *match);
1610 if (action != NULL) {
1611 return action;
1612 }
1613
1614 match++;
1615 }
1616
1617 nxt_http_request_error(task, r, NXT_HTTP_NOT_FOUND);
1618
1619 return NULL;
1620 }
1621
1622
1623 static nxt_http_action_t *
nxt_http_route_match(nxt_task_t * task,nxt_http_request_t * r,nxt_http_route_match_t * match)1624 nxt_http_route_match(nxt_task_t *task, nxt_http_request_t *r,
1625 nxt_http_route_match_t *match)
1626 {
1627 nxt_int_t ret;
1628 nxt_http_route_test_t *test, *end;
1629
1630 test = &match->test[0];
1631 end = test + match->items;
1632
1633 while (test < end) {
1634 switch (test->rule->object) {
1635 case NXT_HTTP_ROUTE_TABLE:
1636 ret = nxt_http_route_table(r, test->table);
1637 break;
1638 case NXT_HTTP_ROUTE_SOURCE:
1639 ret = nxt_http_route_addr_rule(r, test->addr_rule, r->remote);
1640 break;
1641 case NXT_HTTP_ROUTE_DESTINATION:
1642 if (r->local == NULL && nxt_fast_path(r->proto.any != NULL)) {
1643 nxt_http_proto[r->protocol].local_addr(task, r);
1644 }
1645
1646 ret = nxt_http_route_addr_rule(r, test->addr_rule, r->local);
1647 break;
1648 default:
1649 ret = nxt_http_route_rule(r, test->rule);
1650 break;
1651 }
1652
1653 if (ret <= 0) {
1654 /* 0 => NULL, -1 => NXT_HTTP_ACTION_ERROR. */
1655 return (nxt_http_action_t *) (intptr_t) ret;
1656 }
1657
1658 test++;
1659 }
1660
1661 return &match->action;
1662 }
1663
1664
1665 static nxt_int_t
nxt_http_route_table(nxt_http_request_t * r,nxt_http_route_table_t * table)1666 nxt_http_route_table(nxt_http_request_t *r, nxt_http_route_table_t *table)
1667 {
1668 nxt_int_t ret;
1669 nxt_http_route_ruleset_t **ruleset, **end;
1670
1671 ret = 1;
1672 ruleset = &table->ruleset[0];
1673 end = ruleset + table->items;
1674
1675 while (ruleset < end) {
1676 ret = nxt_http_route_ruleset(r, *ruleset);
1677
1678 if (ret != 0) {
1679 return ret;
1680 }
1681
1682 ruleset++;
1683 }
1684
1685 return ret;
1686 }
1687
1688
1689 static nxt_int_t
nxt_http_route_ruleset(nxt_http_request_t * r,nxt_http_route_ruleset_t * ruleset)1690 nxt_http_route_ruleset(nxt_http_request_t *r, nxt_http_route_ruleset_t *ruleset)
1691 {
1692 nxt_int_t ret;
1693 nxt_http_route_rule_t **rule, **end;
1694
1695 rule = &ruleset->rule[0];
1696 end = rule + ruleset->items;
1697
1698 while (rule < end) {
1699 ret = nxt_http_route_rule(r, *rule);
1700
1701 if (ret <= 0) {
1702 return ret;
1703 }
1704
1705 rule++;
1706 }
1707
1708 return 1;
1709 }
1710
1711
1712 static nxt_int_t
nxt_http_route_rule(nxt_http_request_t * r,nxt_http_route_rule_t * rule)1713 nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
1714 {
1715 void *p, **pp;
1716 u_char *start;
1717 size_t length;
1718 nxt_str_t *s;
1719
1720 switch (rule->object) {
1721
1722 case NXT_HTTP_ROUTE_HEADER:
1723 return nxt_http_route_header(r, rule);
1724
1725 case NXT_HTTP_ROUTE_ARGUMENT:
1726 return nxt_http_route_arguments(r, rule);
1727
1728 case NXT_HTTP_ROUTE_COOKIE:
1729 return nxt_http_route_cookies(r, rule);
1730
1731 case NXT_HTTP_ROUTE_SCHEME:
1732 return nxt_http_route_scheme(r, rule);
1733
1734 case NXT_HTTP_ROUTE_QUERY:
1735 return nxt_http_route_query(r, rule);
1736
1737 default:
1738 break;
1739 }
1740
1741 p = nxt_pointer_to(r, rule->u.offset);
1742
1743 if (rule->object == NXT_HTTP_ROUTE_STRING) {
1744 s = p;
1745
1746 } else {
1747 /* NXT_HTTP_ROUTE_STRING_PTR */
1748 pp = p;
1749 s = *pp;
1750
1751 if (s == NULL) {
1752 return 0;
1753 }
1754 }
1755
1756 length = s->length;
1757 start = s->start;
1758
1759 return nxt_http_route_test_rule(r, rule, start, length);
1760 }
1761
1762
1763 static nxt_int_t
nxt_http_route_addr_pattern_match(nxt_http_route_addr_pattern_t * p,nxt_sockaddr_t * sa)1764 nxt_http_route_addr_pattern_match(nxt_http_route_addr_pattern_t *p,
1765 nxt_sockaddr_t *sa)
1766 {
1767 #if (NXT_INET6)
1768 uint32_t i;
1769 #endif
1770 in_port_t in_port;
1771 nxt_int_t match;
1772 struct sockaddr_in *sin;
1773 #if (NXT_INET6)
1774 struct sockaddr_in6 *sin6;
1775 #endif
1776 nxt_http_route_addr_base_t *base;
1777
1778 base = &p->base;
1779
1780 switch (sa->u.sockaddr.sa_family) {
1781
1782 case AF_INET:
1783
1784 match = (base->addr_family == AF_INET
1785 || base->addr_family == AF_UNSPEC);
1786 if (!match) {
1787 break;
1788 }
1789
1790 sin = &sa->u.sockaddr_in;
1791 in_port = ntohs(sin->sin_port);
1792
1793 match = (in_port >= base->port.start && in_port <= base->port.end);
1794 if (!match) {
1795 break;
1796 }
1797
1798 switch (base->match_type) {
1799
1800 case NXT_HTTP_ROUTE_ADDR_ANY:
1801 break;
1802
1803 case NXT_HTTP_ROUTE_ADDR_EXACT:
1804 match = (nxt_memcmp(&sin->sin_addr, &p->addr.v4.start,
1805 sizeof(struct in_addr))
1806 == 0);
1807 break;
1808
1809 case NXT_HTTP_ROUTE_ADDR_RANGE:
1810 match = (nxt_memcmp(&sin->sin_addr, &p->addr.v4.start,
1811 sizeof(struct in_addr)) >= 0
1812 && nxt_memcmp(&sin->sin_addr, &p->addr.v4.end,
1813 sizeof(struct in_addr)) <= 0);
1814 break;
1815
1816 case NXT_HTTP_ROUTE_ADDR_CIDR:
1817 match = ((sin->sin_addr.s_addr & p->addr.v4.end)
1818 == p->addr.v4.start);
1819 break;
1820
1821 default:
1822 nxt_unreachable();
1823 }
1824
1825 break;
1826
1827 #if (NXT_INET6)
1828 case AF_INET6:
1829
1830 match = (base->addr_family == AF_INET6
1831 || base->addr_family == AF_UNSPEC);
1832 if (!match) {
1833 break;
1834 }
1835
1836 sin6 = &sa->u.sockaddr_in6;
1837 in_port = ntohs(sin6->sin6_port);
1838
1839 match = (in_port >= base->port.start && in_port <= base->port.end);
1840 if (!match) {
1841 break;
1842 }
1843
1844 switch (base->match_type) {
1845
1846 case NXT_HTTP_ROUTE_ADDR_ANY:
1847 break;
1848
1849 case NXT_HTTP_ROUTE_ADDR_EXACT:
1850 match = (nxt_memcmp(&sin6->sin6_addr, &p->addr.v6.start,
1851 sizeof(struct in6_addr))
1852 == 0);
1853 break;
1854
1855 case NXT_HTTP_ROUTE_ADDR_RANGE:
1856 match = (nxt_memcmp(&sin6->sin6_addr, &p->addr.v6.start,
1857 sizeof(struct in6_addr)) >= 0
1858 && nxt_memcmp(&sin6->sin6_addr, &p->addr.v6.end,
1859 sizeof(struct in6_addr)) <= 0);
1860 break;
1861
1862 case NXT_HTTP_ROUTE_ADDR_CIDR:
1863 for (i = 0; i < 16; i++) {
1864 match = ((sin6->sin6_addr.s6_addr[i]
1865 & p->addr.v6.end.s6_addr[i])
1866 == p->addr.v6.start.s6_addr[i]);
1867
1868 if (!match) {
1869 break;
1870 }
1871 }
1872
1873 break;
1874
1875 default:
1876 nxt_unreachable();
1877 }
1878
1879 break;
1880 #endif
1881
1882 default:
1883 match = 0;
1884 break;
1885 }
1886
1887 return match ^ base->negative;
1888 }
1889
1890
1891 nxt_int_t
nxt_http_route_addr_rule(nxt_http_request_t * r,nxt_http_route_addr_rule_t * addr_rule,nxt_sockaddr_t * sa)1892 nxt_http_route_addr_rule(nxt_http_request_t *r,
1893 nxt_http_route_addr_rule_t *addr_rule, nxt_sockaddr_t *sa)
1894 {
1895 uint32_t n;
1896 nxt_bool_t matches;
1897 nxt_http_route_addr_pattern_t *p;
1898
1899 n = addr_rule->items;
1900
1901 if (n == 0) {
1902 return 0;
1903 }
1904
1905 p = &addr_rule->addr_pattern[0] - 1;
1906
1907 do {
1908 p++;
1909 n--;
1910
1911 matches = nxt_http_route_addr_pattern_match(p, sa);
1912
1913 if (p->base.negative) {
1914 if (matches) {
1915 continue;
1916 }
1917
1918 return 0;
1919 }
1920
1921 if (matches) {
1922 return 1;
1923 }
1924
1925 } while (n > 0);
1926
1927 return p->base.negative;
1928 }
1929
1930
1931 static nxt_int_t
nxt_http_route_header(nxt_http_request_t * r,nxt_http_route_rule_t * rule)1932 nxt_http_route_header(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
1933 {
1934 nxt_int_t ret;
1935 nxt_http_field_t *f;
1936
1937 ret = 0;
1938
1939 nxt_list_each(f, r->fields) {
1940
1941 if (rule->u.name.hash != f->hash
1942 || rule->u.name.length != f->name_length
1943 || nxt_strncasecmp(rule->u.name.start, f->name, f->name_length)
1944 != 0)
1945 {
1946 continue;
1947 }
1948
1949 ret = nxt_http_route_test_rule(r, rule, f->value, f->value_length);
1950 if (nxt_slow_path(ret == NXT_ERROR)) {
1951 return NXT_ERROR;
1952 }
1953
1954 if (ret == 0) {
1955 return ret;
1956 }
1957
1958 } nxt_list_loop;
1959
1960 return ret;
1961 }
1962
1963
1964 static nxt_int_t
nxt_http_route_arguments(nxt_http_request_t * r,nxt_http_route_rule_t * rule)1965 nxt_http_route_arguments(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
1966 {
1967 nxt_array_t *arguments;
1968
1969 arguments = nxt_http_arguments_parse(r);
1970 if (nxt_slow_path(arguments == NULL)) {
1971 return -1;
1972 }
1973
1974 return nxt_http_route_test_argument(r, rule, arguments);
1975 }
1976
1977
1978 static nxt_int_t
nxt_http_route_test_argument(nxt_http_request_t * r,nxt_http_route_rule_t * rule,nxt_array_t * array)1979 nxt_http_route_test_argument(nxt_http_request_t *r,
1980 nxt_http_route_rule_t *rule, nxt_array_t *array)
1981 {
1982 nxt_int_t ret;
1983 nxt_http_name_value_t *nv, *end;
1984
1985 ret = 0;
1986
1987 nv = array->elts;
1988 end = nv + array->nelts;
1989
1990 while (nv < end) {
1991
1992 if (rule->u.name.hash == nv->hash
1993 && rule->u.name.length == nv->name_length
1994 && nxt_memcmp(rule->u.name.start, nv->name, nv->name_length) == 0)
1995 {
1996 ret = nxt_http_route_test_rule(r, rule, nv->value,
1997 nv->value_length);
1998 if (nxt_slow_path(ret == NXT_ERROR)) {
1999 return NXT_ERROR;
2000 }
2001
2002 if (ret == 0) {
2003 break;
2004 }
2005 }
2006
2007 nv++;
2008 }
2009
2010 return ret;
2011 }
2012
2013
2014 static nxt_int_t
nxt_http_route_scheme(nxt_http_request_t * r,nxt_http_route_rule_t * rule)2015 nxt_http_route_scheme(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
2016 {
2017 nxt_bool_t tls, https;
2018 nxt_http_route_pattern_slice_t *pattern_slice;
2019
2020 pattern_slice = rule->pattern[0].u.pattern_slices->elts;
2021 https = (pattern_slice->length == nxt_length("https"));
2022 tls = (r->tls != NULL);
2023
2024 return (tls == https);
2025 }
2026
2027
2028 static nxt_int_t
nxt_http_route_query(nxt_http_request_t * r,nxt_http_route_rule_t * rule)2029 nxt_http_route_query(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
2030 {
2031 nxt_array_t *arguments;
2032
2033 arguments = nxt_http_arguments_parse(r);
2034 if (nxt_slow_path(arguments == NULL)) {
2035 return -1;
2036 }
2037
2038 return nxt_http_route_test_rule(r, rule, r->args_decoded.start,
2039 r->args_decoded.length);
2040 }
2041
2042
2043 static nxt_int_t
nxt_http_route_cookies(nxt_http_request_t * r,nxt_http_route_rule_t * rule)2044 nxt_http_route_cookies(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
2045 {
2046 nxt_array_t *cookies;
2047
2048 cookies = nxt_http_cookies_parse(r);
2049 if (nxt_slow_path(cookies == NULL)) {
2050 return -1;
2051 }
2052
2053 return nxt_http_route_test_cookie(r, rule, cookies);
2054 }
2055
2056
2057 static nxt_int_t
nxt_http_route_test_cookie(nxt_http_request_t * r,nxt_http_route_rule_t * rule,nxt_array_t * array)2058 nxt_http_route_test_cookie(nxt_http_request_t *r,
2059 nxt_http_route_rule_t *rule, nxt_array_t *array)
2060 {
2061 nxt_int_t ret;
2062 nxt_http_name_value_t *nv, *end;
2063
2064 ret = 0;
2065
2066 nv = array->elts;
2067 end = nv + array->nelts;
2068
2069 while (nv < end) {
2070
2071 if (rule->u.name.hash == nv->hash
2072 && rule->u.name.length == nv->name_length
2073 && nxt_memcmp(rule->u.name.start, nv->name, nv->name_length) == 0)
2074 {
2075 ret = nxt_http_route_test_rule(r, rule, nv->value,
2076 nv->value_length);
2077 if (nxt_slow_path(ret == NXT_ERROR)) {
2078 return NXT_ERROR;
2079 }
2080
2081 if (ret == 0) {
2082 break;
2083 }
2084 }
2085
2086 nv++;
2087 }
2088
2089 return ret;
2090 }
2091
2092
2093 nxt_int_t
nxt_http_route_test_rule(nxt_http_request_t * r,nxt_http_route_rule_t * rule,u_char * start,size_t length)2094 nxt_http_route_test_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule,
2095 u_char *start, size_t length)
2096 {
2097 nxt_int_t ret;
2098 nxt_http_route_pattern_t *pattern, *end;
2099
2100 ret = 1;
2101 pattern = &rule->pattern[0];
2102 end = pattern + rule->items;
2103
2104 while (pattern < end) {
2105 ret = nxt_http_route_pattern(r, pattern, start, length);
2106 if (nxt_slow_path(ret == NXT_ERROR)) {
2107 return NXT_ERROR;
2108 }
2109
2110 /* nxt_http_route_pattern() returns either 1 or 0. */
2111 ret ^= pattern->negative;
2112
2113 if (pattern->any == ret) {
2114 return ret;
2115 }
2116
2117 pattern++;
2118 }
2119
2120 return ret;
2121 }
2122
2123
2124 static nxt_int_t
nxt_http_route_pattern(nxt_http_request_t * r,nxt_http_route_pattern_t * pattern,u_char * start,size_t length)2125 nxt_http_route_pattern(nxt_http_request_t *r, nxt_http_route_pattern_t *pattern,
2126 u_char *start, size_t length)
2127 {
2128 u_char *p, *end, *test;
2129 size_t test_length;
2130 uint32_t i;
2131 nxt_array_t *pattern_slices;
2132 nxt_http_route_pattern_slice_t *pattern_slice;
2133
2134 #if (NXT_HAVE_REGEX)
2135 if (pattern->regex) {
2136 if (r->regex_match == NULL) {
2137 r->regex_match = nxt_regex_match_create(r->mem_pool, 0);
2138 if (nxt_slow_path(r->regex_match == NULL)) {
2139 return NXT_ERROR;
2140 }
2141 }
2142
2143 return nxt_regex_match(pattern->u.regex, start, length, r->regex_match);
2144 }
2145 #endif
2146
2147 if (length < pattern->min_length) {
2148 return 0;
2149 }
2150
2151 nxt_assert(pattern->u.pattern_slices != NULL);
2152
2153 pattern_slices = pattern->u.pattern_slices;
2154 pattern_slice = pattern_slices->elts;
2155 end = start + length;
2156
2157 for (i = 0; i < pattern_slices->nelts; i++, pattern_slice++) {
2158 test = pattern_slice->start;
2159 test_length = pattern_slice->length;
2160
2161 switch (pattern_slice->type) {
2162 case NXT_HTTP_ROUTE_PATTERN_EXACT:
2163 return ((length == pattern->min_length) &&
2164 nxt_http_route_memcmp(start, test, test_length,
2165 pattern->case_sensitive));
2166
2167 case NXT_HTTP_ROUTE_PATTERN_BEGIN:
2168 if (nxt_http_route_memcmp(start, test, test_length,
2169 pattern->case_sensitive))
2170 {
2171 start += test_length;
2172 break;
2173 }
2174
2175 return 0;
2176
2177 case NXT_HTTP_ROUTE_PATTERN_END:
2178 p = end - test_length;
2179
2180 if (nxt_http_route_memcmp(p, test, test_length,
2181 pattern->case_sensitive))
2182 {
2183 end = p;
2184 break;
2185 }
2186
2187 return 0;
2188
2189 case NXT_HTTP_ROUTE_PATTERN_SUBSTRING:
2190 if (pattern->case_sensitive) {
2191 p = nxt_memstrn(start, end, (char *) test, test_length);
2192
2193 } else {
2194 p = nxt_memcasestrn(start, end, (char *) test, test_length);
2195 }
2196
2197 if (p == NULL) {
2198 return 0;
2199 }
2200
2201 start = p + test_length;
2202 }
2203 }
2204
2205 return 1;
2206 }
2207
2208
2209 static nxt_int_t
nxt_http_route_memcmp(u_char * start,u_char * test,size_t test_length,nxt_bool_t case_sensitive)2210 nxt_http_route_memcmp(u_char *start, u_char *test, size_t test_length,
2211 nxt_bool_t case_sensitive)
2212 {
2213 nxt_int_t n;
2214
2215 if (case_sensitive) {
2216 n = nxt_memcmp(start, test, test_length);
2217
2218 } else {
2219 n = nxt_memcasecmp(start, test, test_length);
2220 }
2221
2222 return (n == 0);
2223 }
2224