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