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("pass"),
583 NXT_CONF_MAP_PTR,
584 offsetof(nxt_http_action_conf_t, pass)
585 },
586 {
587 nxt_string("return"),
588 NXT_CONF_MAP_PTR,
589 offsetof(nxt_http_action_conf_t, ret)
590 },
591 {
592 nxt_string("location"),
593 NXT_CONF_MAP_PTR,
594 offsetof(nxt_http_action_conf_t, location)
595 },
596 {
597 nxt_string("proxy"),
598 NXT_CONF_MAP_PTR,
599 offsetof(nxt_http_action_conf_t, proxy)
600 },
601 {
602 nxt_string("share"),
603 NXT_CONF_MAP_PTR,
604 offsetof(nxt_http_action_conf_t, share)
605 },
606 {
607 nxt_string("index"),
608 NXT_CONF_MAP_PTR,
609 offsetof(nxt_http_action_conf_t, index)
610 },
611 {
612 nxt_string("chroot"),
613 NXT_CONF_MAP_STR,
614 offsetof(nxt_http_action_conf_t, chroot)
615 },
616 {
617 nxt_string("follow_symlinks"),
618 NXT_CONF_MAP_PTR,
619 offsetof(nxt_http_action_conf_t, follow_symlinks)
620 },
621 {
622 nxt_string("traverse_mounts"),
623 NXT_CONF_MAP_PTR,
624 offsetof(nxt_http_action_conf_t, traverse_mounts)
625 },
626 {
627 nxt_string("types"),
628 NXT_CONF_MAP_PTR,
629 offsetof(nxt_http_action_conf_t, types)
630 },
631 {
632 nxt_string("fallback"),
633 NXT_CONF_MAP_PTR,
634 offsetof(nxt_http_action_conf_t, fallback)
635 },
636 };
637
638
639 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)640 nxt_http_action_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
641 nxt_conf_value_t *cv, nxt_http_action_t *action)
642 {
643 nxt_mp_t *mp;
644 nxt_int_t ret;
645 nxt_str_t pass;
646 nxt_router_conf_t *rtcf;
647 nxt_http_action_conf_t acf;
648
649 nxt_memzero(&acf, sizeof(acf));
650
651 ret = nxt_conf_map_object(tmcf->mem_pool, cv, nxt_http_route_action_conf,
652 nxt_nitems(nxt_http_route_action_conf), &acf);
653 if (ret != NXT_OK) {
654 return ret;
655 }
656
657 nxt_memzero(action, sizeof(nxt_http_action_t));
658
659 rtcf = tmcf->router_conf;
660 mp = rtcf->mem_pool;
661
662 if (acf.ret != NULL) {
663 return nxt_http_return_init(rtcf, 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.tstr = nxt_tstr_compile(rtcf->tstr_state, &pass, 0);
677 if (nxt_slow_path(action->u.tstr == 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_uri_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_uri_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_uri_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_uri_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_uri_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_uri_encoding_t encoding)
776 {
777 int64_t hash;
778 nxt_http_route_rule_t *rule;
779
780 rule = nxt_http_route_rule_create(task, mp, rule_cv, case_sensitive,
781 NXT_HTTP_ROUTE_PATTERN_NOCASE,
782 encoding);
783 if (nxt_slow_path(rule == NULL)) {
784 return NULL;
785 }
786
787 hash = nxt_http_field_hash(mp, name, case_sensitive, encoding);
788 if (nxt_slow_path(hash == -1)) {
789 return NULL;
790 }
791
792 rule->u.name.hash = hash;
793 rule->u.name.start = name->start;
794 rule->u.name.length = name->length;
795
796 return rule;
797 }
798
799
800 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)801 nxt_http_route_rule_create(nxt_task_t *task, nxt_mp_t *mp,
802 nxt_conf_value_t *cv, nxt_bool_t case_sensitive,
803 nxt_http_route_pattern_case_t pattern_case,
804 nxt_http_uri_encoding_t encoding)
805 {
806 size_t size;
807 uint32_t i, n;
808 nxt_int_t ret;
809 nxt_conf_value_t *value;
810 nxt_http_route_rule_t *rule;
811 nxt_http_route_pattern_t *pattern;
812
813 n = nxt_conf_array_elements_count_or_1(cv);
814 size = sizeof(nxt_http_route_rule_t) + n * sizeof(nxt_http_route_pattern_t);
815
816 rule = nxt_mp_alloc(mp, size);
817 if (nxt_slow_path(rule == NULL)) {
818 return NULL;
819 }
820
821 rule->items = n;
822
823 pattern = &rule->pattern[0];
824
825 nxt_conf_array_qsort(cv, nxt_http_pattern_compare);
826
827 for (i = 0; i < n; i++) {
828 pattern[i].case_sensitive = case_sensitive;
829 value = nxt_conf_get_array_element_or_itself(cv, i);
830
831 ret = nxt_http_route_pattern_create(task, mp, value, &pattern[i],
832 pattern_case, encoding);
833 if (nxt_slow_path(ret != NXT_OK)) {
834 return NULL;
835 }
836 }
837
838 return rule;
839 }
840
841
842 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)843 nxt_http_route_addr_rule_create(nxt_task_t *task, nxt_mp_t *mp,
844 nxt_conf_value_t *cv)
845 {
846 size_t size;
847 uint32_t i, n;
848 nxt_conf_value_t *value;
849 nxt_http_route_addr_rule_t *addr_rule;
850 nxt_http_route_addr_pattern_t *pattern;
851
852 n = nxt_conf_array_elements_count_or_1(cv);
853
854 size = sizeof(nxt_http_route_addr_rule_t)
855 + n * sizeof(nxt_http_route_addr_pattern_t);
856
857 addr_rule = nxt_mp_alloc(mp, size);
858 if (nxt_slow_path(addr_rule == NULL)) {
859 return NULL;
860 }
861
862 addr_rule->items = n;
863
864 for (i = 0; i < n; i++) {
865 pattern = &addr_rule->addr_pattern[i];
866 value = nxt_conf_get_array_element_or_itself(cv, i);
867
868 if (nxt_http_route_addr_pattern_parse(mp, pattern, value) != NXT_OK) {
869 return NULL;
870 }
871 }
872
873 if (n > 1) {
874 nxt_qsort(addr_rule->addr_pattern, addr_rule->items,
875 sizeof(nxt_http_route_addr_pattern_t),
876 nxt_http_addr_pattern_compare);
877 }
878
879 return addr_rule;
880 }
881
882
883 nxt_http_route_rule_t *
nxt_http_route_types_rule_create(nxt_task_t * task,nxt_mp_t * mp,nxt_conf_value_t * types)884 nxt_http_route_types_rule_create(nxt_task_t *task, nxt_mp_t *mp,
885 nxt_conf_value_t *types)
886 {
887 return nxt_http_route_rule_create(task, mp, types, 0,
888 NXT_HTTP_ROUTE_PATTERN_LOWCASE,
889 NXT_HTTP_URI_ENCODING_NONE);
890 }
891
892
893 static int
nxt_http_pattern_compare(const void * one,const void * two)894 nxt_http_pattern_compare(const void *one, const void *two)
895 {
896 nxt_str_t test;
897 nxt_bool_t negative1, negative2;
898 nxt_conf_value_t *value;
899
900 value = (nxt_conf_value_t *) one;
901 nxt_conf_get_string(value, &test);
902 negative1 = (test.length != 0 && test.start[0] == '!');
903
904 value = (nxt_conf_value_t *) two;
905 nxt_conf_get_string(value, &test);
906 negative2 = (test.length != 0 && test.start[0] == '!');
907
908 return (negative2 - negative1);
909 }
910
911
912 static int
nxt_http_addr_pattern_compare(const void * one,const void * two)913 nxt_http_addr_pattern_compare(const void *one, const void *two)
914 {
915 const nxt_http_route_addr_pattern_t *p1, *p2;
916
917 p1 = one;
918 p2 = two;
919
920 return (p2->base.negative - p1->base.negative);
921 }
922
923
924 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)925 nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp,
926 nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern,
927 nxt_http_route_pattern_case_t pattern_case,
928 nxt_http_uri_encoding_t encoding)
929 {
930 u_char c, *p, *end;
931 nxt_str_t test, tmp;
932 nxt_int_t ret;
933 nxt_array_t *slices;
934 #if (NXT_HAVE_REGEX)
935 nxt_regex_t *re;
936 nxt_regex_err_t err;
937 #endif
938 nxt_http_route_pattern_type_t type;
939 nxt_http_route_pattern_slice_t *slice;
940
941 type = NXT_HTTP_ROUTE_PATTERN_EXACT;
942
943 nxt_conf_get_string(cv, &test);
944
945 pattern->u.pattern_slices = NULL;
946 pattern->negative = 0;
947 pattern->any = 1;
948 pattern->min_length = 0;
949 #if (NXT_HAVE_REGEX)
950 pattern->regex = 0;
951 #endif
952
953 if (test.length != 0 && test.start[0] == '!') {
954 test.start++;
955 test.length--;
956
957 pattern->negative = 1;
958 pattern->any = 0;
959 }
960
961 if (test.length > 0 && test.start[0] == '~') {
962 #if (NXT_HAVE_REGEX)
963 test.start++;
964 test.length--;
965
966 re = nxt_regex_compile(mp, &test, &err);
967 if (nxt_slow_path(re == NULL)) {
968 if (err.offset < test.length) {
969 nxt_alert(task, "nxt_regex_compile(%V) failed: %s at offset %d",
970 &test, err.msg, (int) err.offset);
971 return NXT_ERROR;
972 }
973
974 nxt_alert(task, "nxt_regex_compile(%V) failed %s", &test, err.msg);
975
976 return NXT_ERROR;
977 }
978
979 pattern->u.regex = re;
980 pattern->regex = 1;
981
982 return NXT_OK;
983
984 #else
985 return NXT_ERROR;
986 #endif
987 }
988
989 slices = nxt_array_create(mp, 1, sizeof(nxt_http_route_pattern_slice_t));
990 if (nxt_slow_path(slices == NULL)) {
991 return NXT_ERROR;
992 }
993
994 pattern->u.pattern_slices = slices;
995
996 if (test.length == 0) {
997 slice = nxt_array_add(slices);
998 if (nxt_slow_path(slice == NULL)) {
999 return NXT_ERROR;
1000 }
1001
1002 slice->type = NXT_HTTP_ROUTE_PATTERN_EXACT;
1003 slice->start = NULL;
1004 slice->length = 0;
1005
1006 return NXT_OK;
1007 }
1008
1009 if (test.start[0] == '*') {
1010 /* 'type' is no longer 'EXACT', assume 'END'. */
1011 type = NXT_HTTP_ROUTE_PATTERN_END;
1012 test.start++;
1013 test.length--;
1014 }
1015
1016 if (type == NXT_HTTP_ROUTE_PATTERN_EXACT) {
1017 tmp.start = test.start;
1018
1019 p = memchr(test.start, '*', test.length);
1020
1021 if (p == NULL) {
1022 /* No '*' found - EXACT pattern. */
1023 tmp.length = test.length;
1024 type = NXT_HTTP_ROUTE_PATTERN_EXACT;
1025
1026 test.start += test.length;
1027 test.length = 0;
1028
1029 } else {
1030 /* '*' found - BEGIN pattern. */
1031 tmp.length = p - test.start;
1032 type = NXT_HTTP_ROUTE_PATTERN_BEGIN;
1033
1034 test.start = p + 1;
1035 test.length -= tmp.length + 1;
1036 }
1037
1038 ret = nxt_http_route_pattern_slice(slices, &tmp, type, encoding,
1039 pattern_case);
1040 if (nxt_slow_path(ret != NXT_OK)) {
1041 return ret;
1042 }
1043
1044 pattern->min_length += tmp.length;
1045 }
1046
1047 end = test.start + test.length;
1048
1049 if (test.length != 0 && end[-1] != '*') {
1050 p = end - 1;
1051
1052 while (p != test.start) {
1053 c = *p--;
1054
1055 if (c == '*') {
1056 p += 2;
1057 break;
1058 }
1059 }
1060
1061 tmp.start = p;
1062 tmp.length = end - p;
1063
1064 test.length -= tmp.length;
1065 end = p;
1066
1067 ret = nxt_http_route_pattern_slice(slices, &tmp,
1068 NXT_HTTP_ROUTE_PATTERN_END,
1069 encoding, pattern_case);
1070 if (nxt_slow_path(ret != NXT_OK)) {
1071 return ret;
1072 }
1073
1074 pattern->min_length += tmp.length;
1075 }
1076
1077 tmp.start = test.start;
1078 tmp.length = 0;
1079
1080 p = tmp.start;
1081
1082 while (p != end) {
1083 c = *p++;
1084
1085 if (c != '*') {
1086 tmp.length++;
1087 continue;
1088 }
1089
1090 if (tmp.length == 0) {
1091 tmp.start = p;
1092 continue;
1093 }
1094
1095 ret = nxt_http_route_pattern_slice(slices, &tmp,
1096 NXT_HTTP_ROUTE_PATTERN_SUBSTRING,
1097 encoding, pattern_case);
1098 if (nxt_slow_path(ret != NXT_OK)) {
1099 return ret;
1100 }
1101
1102 pattern->min_length += tmp.length;
1103
1104 tmp.start = p;
1105 tmp.length = 0;
1106 }
1107
1108 if (tmp.length != 0) {
1109 ret = nxt_http_route_pattern_slice(slices, &tmp,
1110 NXT_HTTP_ROUTE_PATTERN_SUBSTRING,
1111 encoding, pattern_case);
1112 if (nxt_slow_path(ret != NXT_OK)) {
1113 return ret;
1114 }
1115
1116 pattern->min_length += tmp.length;
1117 }
1118
1119 return NXT_OK;
1120 }
1121
1122
1123 static nxt_int_t
nxt_http_route_decode_str(nxt_str_t * str,nxt_http_uri_encoding_t encoding)1124 nxt_http_route_decode_str(nxt_str_t *str, nxt_http_uri_encoding_t encoding)
1125 {
1126 u_char *start, *end;
1127
1128 switch (encoding) {
1129 case NXT_HTTP_URI_ENCODING_NONE:
1130 break;
1131
1132 case NXT_HTTP_URI_ENCODING:
1133 start = str->start;
1134
1135 end = nxt_decode_uri(start, start, str->length);
1136 if (nxt_slow_path(end == NULL)) {
1137 return NXT_ERROR;
1138 }
1139
1140 str->length = end - start;
1141 break;
1142
1143 case NXT_HTTP_URI_ENCODING_PLUS:
1144 start = str->start;
1145
1146 end = nxt_decode_uri_plus(start, start, str->length);
1147 if (nxt_slow_path(end == NULL)) {
1148 return NXT_ERROR;
1149 }
1150
1151 str->length = end - start;
1152 break;
1153
1154 default:
1155 nxt_unreachable();
1156 }
1157
1158 return NXT_OK;
1159 }
1160
1161
1162 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)1163 nxt_http_route_pattern_slice(nxt_array_t *slices,
1164 nxt_str_t *test, nxt_http_route_pattern_type_t type,
1165 nxt_http_uri_encoding_t encoding,
1166 nxt_http_route_pattern_case_t pattern_case)
1167 {
1168 u_char *start;
1169 nxt_int_t ret;
1170 nxt_http_route_pattern_slice_t *slice;
1171
1172 ret = nxt_http_route_decode_str(test, encoding);
1173 if (nxt_slow_path(ret != NXT_OK)) {
1174 return ret;
1175 }
1176
1177 start = nxt_mp_nget(slices->mem_pool, test->length);
1178 if (nxt_slow_path(start == NULL)) {
1179 return NXT_ERROR;
1180 }
1181
1182 switch (pattern_case) {
1183
1184 case NXT_HTTP_ROUTE_PATTERN_UPCASE:
1185 nxt_memcpy_upcase(start, test->start, test->length);
1186 break;
1187
1188 case NXT_HTTP_ROUTE_PATTERN_LOWCASE:
1189 nxt_memcpy_lowcase(start, test->start, test->length);
1190 break;
1191
1192 case NXT_HTTP_ROUTE_PATTERN_NOCASE:
1193 nxt_memcpy(start, test->start, test->length);
1194 break;
1195 }
1196
1197 slice = nxt_array_add(slices);
1198 if (nxt_slow_path(slice == NULL)) {
1199 return NXT_ERROR;
1200 }
1201
1202 slice->type = type;
1203 slice->start = start;
1204 slice->length = test->length;
1205
1206 return NXT_OK;
1207 }
1208
1209
1210 nxt_int_t
nxt_http_routes_resolve(nxt_task_t * task,nxt_router_temp_conf_t * tmcf)1211 nxt_http_routes_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
1212 {
1213 nxt_int_t ret;
1214 nxt_http_route_t **route, **end;
1215 nxt_http_routes_t *routes;
1216
1217 routes = tmcf->router_conf->routes;
1218
1219 if (routes != NULL) {
1220 route = &routes->route[0];
1221 end = route + routes->items;
1222
1223 while (route < end) {
1224 ret = nxt_http_route_resolve(task, tmcf, *route);
1225 if (nxt_slow_path(ret != NXT_OK)) {
1226 return NXT_ERROR;
1227 }
1228
1229 route++;
1230 }
1231 }
1232
1233 return NXT_OK;
1234 }
1235
1236
1237 static nxt_int_t
nxt_http_route_resolve(nxt_task_t * task,nxt_router_temp_conf_t * tmcf,nxt_http_route_t * route)1238 nxt_http_route_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1239 nxt_http_route_t *route)
1240 {
1241 nxt_int_t ret;
1242 nxt_http_route_match_t **match, **end;
1243
1244 match = &route->match[0];
1245 end = match + route->items;
1246
1247 while (match < end) {
1248 ret = nxt_http_action_resolve(task, tmcf, &(*match)->action);
1249 if (nxt_slow_path(ret != NXT_OK)) {
1250 return NXT_ERROR;
1251 }
1252
1253 match++;
1254 }
1255
1256 return NXT_OK;
1257 }
1258
1259
1260 static nxt_int_t
nxt_http_action_resolve(nxt_task_t * task,nxt_router_temp_conf_t * tmcf,nxt_http_action_t * action)1261 nxt_http_action_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1262 nxt_http_action_t *action)
1263 {
1264 nxt_int_t ret;
1265 nxt_str_t pass;
1266
1267 if (action->handler != NULL) {
1268 if (action->fallback != NULL) {
1269 return nxt_http_action_resolve(task, tmcf, action->fallback);
1270 }
1271
1272 return NXT_OK;
1273 }
1274
1275 if (nxt_tstr_is_const(action->u.tstr)) {
1276 nxt_tstr_str(action->u.tstr, &pass);
1277
1278 ret = nxt_http_pass_find(tmcf->mem_pool, tmcf->router_conf, &pass,
1279 action);
1280 if (nxt_slow_path(ret != NXT_OK)) {
1281 return NXT_ERROR;
1282 }
1283
1284 } else {
1285 action->handler = nxt_http_pass_var;
1286 }
1287
1288 return NXT_OK;
1289 }
1290
1291
1292 static nxt_http_action_t *
nxt_http_pass_var(nxt_task_t * task,nxt_http_request_t * r,nxt_http_action_t * action)1293 nxt_http_pass_var(nxt_task_t *task, nxt_http_request_t *r,
1294 nxt_http_action_t *action)
1295 {
1296 nxt_int_t ret;
1297 nxt_str_t str;
1298 nxt_tstr_t *tstr;
1299 nxt_router_conf_t *rtcf;
1300
1301 tstr = action->u.tstr;
1302
1303 nxt_tstr_str(tstr, &str);
1304
1305 nxt_debug(task, "http pass: \"%V\"", &str);
1306
1307 rtcf = r->conf->socket_conf->router_conf;
1308
1309 ret = nxt_tstr_query_init(&r->tstr_query, rtcf->tstr_state, &r->tstr_cache,
1310 r, r->mem_pool);
1311 if (nxt_slow_path(ret != NXT_OK)) {
1312 goto fail;
1313 }
1314
1315 action = nxt_mp_get(r->mem_pool,
1316 sizeof(nxt_http_action_t) + sizeof(nxt_str_t));
1317 if (nxt_slow_path(action == NULL)) {
1318 goto fail;
1319 }
1320
1321 action->u.pass = nxt_pointer_to(action, sizeof(nxt_http_action_t));
1322
1323 nxt_tstr_query(task, r->tstr_query, tstr, action->u.pass);
1324 nxt_tstr_query_resolve(task, r->tstr_query, action,
1325 nxt_http_pass_query_ready,
1326 nxt_http_pass_query_error);
1327 return NULL;
1328
1329 fail:
1330
1331 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
1332 return NULL;
1333 }
1334
1335
1336 static void
nxt_http_pass_query_ready(nxt_task_t * task,void * obj,void * data)1337 nxt_http_pass_query_ready(nxt_task_t *task, void *obj, void *data)
1338 {
1339 nxt_int_t ret;
1340 nxt_router_conf_t *rtcf;
1341 nxt_http_action_t *action;
1342 nxt_http_status_t status;
1343 nxt_http_request_t *r;
1344
1345 r = obj;
1346 action = data;
1347 rtcf = r->conf->socket_conf->router_conf;
1348
1349 nxt_debug(task, "http pass lookup: %V", action->u.pass);
1350
1351 ret = nxt_http_pass_find(r->mem_pool, rtcf, action->u.pass, action);
1352
1353 if (ret != NXT_OK) {
1354 status = (ret == NXT_DECLINED) ? NXT_HTTP_NOT_FOUND
1355 : NXT_HTTP_INTERNAL_SERVER_ERROR;
1356
1357 nxt_http_request_error(task, r, status);
1358 return;
1359 }
1360
1361 nxt_http_request_action(task, r, action);
1362 }
1363
1364
1365 static void
nxt_http_pass_query_error(nxt_task_t * task,void * obj,void * data)1366 nxt_http_pass_query_error(nxt_task_t *task, void *obj, void *data)
1367 {
1368 nxt_http_request_t *r;
1369
1370 r = obj;
1371
1372 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
1373 }
1374
1375
1376 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)1377 nxt_http_pass_find(nxt_mp_t *mp, nxt_router_conf_t *rtcf, nxt_str_t *pass,
1378 nxt_http_action_t *action)
1379 {
1380 nxt_int_t ret;
1381 nxt_str_t segments[3];
1382
1383 ret = nxt_http_pass_segments(mp, pass, segments, 3);
1384 if (nxt_slow_path(ret != NXT_OK)) {
1385 return ret;
1386 }
1387
1388 if (nxt_str_eq(&segments[0], "applications", 12)) {
1389 return nxt_router_application_init(rtcf, &segments[1], &segments[2],
1390 action);
1391 }
1392
1393 if (segments[2].length == 0) {
1394 if (nxt_str_eq(&segments[0], "upstreams", 9)) {
1395 return nxt_upstream_find(rtcf->upstreams, &segments[1], action);
1396 }
1397
1398 if (nxt_str_eq(&segments[0], "routes", 6)) {
1399 return nxt_http_route_find(rtcf->routes, &segments[1], action);
1400 }
1401 }
1402
1403 return NXT_DECLINED;
1404 }
1405
1406
1407 nxt_int_t
nxt_http_pass_segments(nxt_mp_t * mp,nxt_str_t * pass,nxt_str_t * segments,nxt_uint_t n)1408 nxt_http_pass_segments(nxt_mp_t *mp, nxt_str_t *pass, nxt_str_t *segments,
1409 nxt_uint_t n)
1410 {
1411 u_char *p;
1412 nxt_str_t rest;
1413
1414 if (nxt_slow_path(nxt_str_dup(mp, &rest, pass) == NULL)) {
1415 return NXT_ERROR;
1416 }
1417
1418 nxt_memzero(segments, n * sizeof(nxt_str_t));
1419
1420 do {
1421 p = memchr(rest.start, '/', rest.length);
1422
1423 if (p != NULL) {
1424 n--;
1425
1426 if (n == 0) {
1427 return NXT_DECLINED;
1428 }
1429
1430 segments->length = p - rest.start;
1431 segments->start = rest.start;
1432
1433 rest.length -= segments->length + 1;
1434 rest.start = p + 1;
1435
1436 } else {
1437 n = 0;
1438 *segments = rest;
1439 }
1440
1441 if (segments->length == 0) {
1442 return NXT_DECLINED;
1443 }
1444
1445 p = nxt_decode_uri(segments->start, segments->start, segments->length);
1446 if (p == NULL) {
1447 return NXT_DECLINED;
1448 }
1449
1450 segments->length = p - segments->start;
1451 segments++;
1452
1453 } while (n);
1454
1455 return NXT_OK;
1456 }
1457
1458
1459 static nxt_int_t
nxt_http_route_find(nxt_http_routes_t * routes,nxt_str_t * name,nxt_http_action_t * action)1460 nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name,
1461 nxt_http_action_t *action)
1462 {
1463 nxt_http_route_t **route, **end;
1464
1465 if (routes == NULL) {
1466 return NXT_DECLINED;
1467 }
1468
1469 route = &routes->route[0];
1470 end = route + routes->items;
1471
1472 while (route < end) {
1473 if (nxt_strstr_eq(&(*route)->name, name)) {
1474 action->u.route = *route;
1475 action->handler = nxt_http_route_handler;
1476
1477 return NXT_OK;
1478 }
1479
1480 route++;
1481 }
1482
1483 return NXT_DECLINED;
1484 }
1485
1486
1487 nxt_http_action_t *
nxt_http_action_create(nxt_task_t * task,nxt_router_temp_conf_t * tmcf,nxt_str_t * pass)1488 nxt_http_action_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1489 nxt_str_t *pass)
1490 {
1491 nxt_mp_t *mp;
1492 nxt_int_t ret;
1493 nxt_router_conf_t *rtcf;
1494 nxt_http_action_t *action;
1495
1496 rtcf = tmcf->router_conf;
1497 mp = rtcf->mem_pool;
1498
1499 action = nxt_mp_alloc(mp, sizeof(nxt_http_action_t));
1500 if (nxt_slow_path(action == NULL)) {
1501 return NULL;
1502 }
1503
1504 action->u.tstr = nxt_tstr_compile(rtcf->tstr_state, pass, 0);
1505 if (nxt_slow_path(action->u.tstr == NULL)) {
1506 return NULL;
1507 }
1508
1509 action->handler = NULL;
1510
1511 ret = nxt_http_action_resolve(task, tmcf, action);
1512 if (nxt_slow_path(ret != NXT_OK)) {
1513 return NULL;
1514 }
1515
1516 return action;
1517 }
1518
1519
1520 /* COMPATIBILITY: listener application. */
1521
1522 nxt_http_action_t *
nxt_http_pass_application(nxt_task_t * task,nxt_router_conf_t * rtcf,nxt_str_t * name)1523 nxt_http_pass_application(nxt_task_t *task, nxt_router_conf_t *rtcf,
1524 nxt_str_t *name)
1525 {
1526 nxt_http_action_t *action;
1527
1528 action = nxt_mp_alloc(rtcf->mem_pool, sizeof(nxt_http_action_t));
1529 if (nxt_slow_path(action == NULL)) {
1530 return NULL;
1531 }
1532
1533 (void) nxt_router_application_init(rtcf, name, NULL, action);
1534
1535 return action;
1536 }
1537
1538
1539 static nxt_http_action_t *
nxt_http_route_handler(nxt_task_t * task,nxt_http_request_t * r,nxt_http_action_t * start)1540 nxt_http_route_handler(nxt_task_t *task, nxt_http_request_t *r,
1541 nxt_http_action_t *start)
1542 {
1543 size_t i;
1544 nxt_http_route_t *route;
1545 nxt_http_action_t *action;
1546
1547 route = start->u.route;
1548
1549 for (i = 0; i < route->items; i++) {
1550 action = nxt_http_route_match(task, r, route->match[i]);
1551
1552 if (nxt_slow_path(r->log_route)) {
1553 uint32_t lvl = (action == NULL) ? NXT_LOG_INFO : NXT_LOG_NOTICE;
1554 const char *sel = (action == NULL) ? "discarded" : "selected";
1555
1556 if (route->name.length == 0) {
1557 nxt_log(task, lvl, "\"routes/%z\" %s", i, sel);
1558 } else {
1559 nxt_log(task, lvl, "\"routes/%V/%z\" %s", &route->name, i, sel);
1560 }
1561 }
1562
1563 if (action != NULL) {
1564 return action;
1565 }
1566 }
1567
1568 nxt_http_request_error(task, r, NXT_HTTP_NOT_FOUND);
1569
1570 return NULL;
1571 }
1572
1573
1574 static nxt_http_action_t *
nxt_http_route_match(nxt_task_t * task,nxt_http_request_t * r,nxt_http_route_match_t * match)1575 nxt_http_route_match(nxt_task_t *task, nxt_http_request_t *r,
1576 nxt_http_route_match_t *match)
1577 {
1578 nxt_int_t ret;
1579 nxt_http_route_test_t *test, *end;
1580
1581 test = &match->test[0];
1582 end = test + match->items;
1583
1584 while (test < end) {
1585 switch (test->rule->object) {
1586 case NXT_HTTP_ROUTE_TABLE:
1587 ret = nxt_http_route_table(r, test->table);
1588 break;
1589 case NXT_HTTP_ROUTE_SOURCE:
1590 ret = nxt_http_route_addr_rule(r, test->addr_rule, r->remote);
1591 break;
1592 case NXT_HTTP_ROUTE_DESTINATION:
1593 if (r->local == NULL && nxt_fast_path(r->proto.any != NULL)) {
1594 nxt_http_proto[r->protocol].local_addr(task, r);
1595 }
1596
1597 ret = nxt_http_route_addr_rule(r, test->addr_rule, r->local);
1598 break;
1599 default:
1600 ret = nxt_http_route_rule(r, test->rule);
1601 break;
1602 }
1603
1604 if (ret <= 0) {
1605 /* 0 => NULL, -1 => NXT_HTTP_ACTION_ERROR. */
1606 return (nxt_http_action_t *) (intptr_t) ret;
1607 }
1608
1609 test++;
1610 }
1611
1612 return &match->action;
1613 }
1614
1615
1616 static nxt_int_t
nxt_http_route_table(nxt_http_request_t * r,nxt_http_route_table_t * table)1617 nxt_http_route_table(nxt_http_request_t *r, nxt_http_route_table_t *table)
1618 {
1619 nxt_int_t ret;
1620 nxt_http_route_ruleset_t **ruleset, **end;
1621
1622 ret = 1;
1623 ruleset = &table->ruleset[0];
1624 end = ruleset + table->items;
1625
1626 while (ruleset < end) {
1627 ret = nxt_http_route_ruleset(r, *ruleset);
1628
1629 if (ret != 0) {
1630 return ret;
1631 }
1632
1633 ruleset++;
1634 }
1635
1636 return ret;
1637 }
1638
1639
1640 static nxt_int_t
nxt_http_route_ruleset(nxt_http_request_t * r,nxt_http_route_ruleset_t * ruleset)1641 nxt_http_route_ruleset(nxt_http_request_t *r, nxt_http_route_ruleset_t *ruleset)
1642 {
1643 nxt_int_t ret;
1644 nxt_http_route_rule_t **rule, **end;
1645
1646 rule = &ruleset->rule[0];
1647 end = rule + ruleset->items;
1648
1649 while (rule < end) {
1650 ret = nxt_http_route_rule(r, *rule);
1651
1652 if (ret <= 0) {
1653 return ret;
1654 }
1655
1656 rule++;
1657 }
1658
1659 return 1;
1660 }
1661
1662
1663 static nxt_int_t
nxt_http_route_rule(nxt_http_request_t * r,nxt_http_route_rule_t * rule)1664 nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
1665 {
1666 void *p, **pp;
1667 u_char *start;
1668 size_t length;
1669 nxt_str_t *s;
1670
1671 switch (rule->object) {
1672
1673 case NXT_HTTP_ROUTE_HEADER:
1674 return nxt_http_route_header(r, rule);
1675
1676 case NXT_HTTP_ROUTE_ARGUMENT:
1677 return nxt_http_route_arguments(r, rule);
1678
1679 case NXT_HTTP_ROUTE_COOKIE:
1680 return nxt_http_route_cookies(r, rule);
1681
1682 case NXT_HTTP_ROUTE_SCHEME:
1683 return nxt_http_route_scheme(r, rule);
1684
1685 case NXT_HTTP_ROUTE_QUERY:
1686 return nxt_http_route_query(r, rule);
1687
1688 default:
1689 break;
1690 }
1691
1692 p = nxt_pointer_to(r, rule->u.offset);
1693
1694 if (rule->object == NXT_HTTP_ROUTE_STRING) {
1695 s = p;
1696
1697 } else {
1698 /* NXT_HTTP_ROUTE_STRING_PTR */
1699 pp = p;
1700 s = *pp;
1701
1702 if (s == NULL) {
1703 return 0;
1704 }
1705 }
1706
1707 length = s->length;
1708 start = s->start;
1709
1710 return nxt_http_route_test_rule(r, rule, start, length);
1711 }
1712
1713
1714 static nxt_int_t
nxt_http_route_addr_pattern_match(nxt_http_route_addr_pattern_t * p,nxt_sockaddr_t * sa)1715 nxt_http_route_addr_pattern_match(nxt_http_route_addr_pattern_t *p,
1716 nxt_sockaddr_t *sa)
1717 {
1718 #if (NXT_INET6)
1719 uint32_t i;
1720 #endif
1721 in_port_t in_port;
1722 nxt_int_t match;
1723 struct sockaddr_in *sin;
1724 #if (NXT_INET6)
1725 struct sockaddr_in6 *sin6;
1726 #endif
1727 nxt_http_route_addr_base_t *base;
1728
1729 base = &p->base;
1730
1731 switch (sa->u.sockaddr.sa_family) {
1732
1733 case AF_INET:
1734
1735 match = (base->addr_family == AF_INET
1736 || base->addr_family == AF_UNSPEC);
1737 if (!match) {
1738 break;
1739 }
1740
1741 sin = &sa->u.sockaddr_in;
1742 in_port = ntohs(sin->sin_port);
1743
1744 match = (in_port >= base->port.start && in_port <= base->port.end);
1745 if (!match) {
1746 break;
1747 }
1748
1749 switch (base->match_type) {
1750
1751 case NXT_HTTP_ROUTE_ADDR_ANY:
1752 break;
1753
1754 case NXT_HTTP_ROUTE_ADDR_EXACT:
1755 match = (memcmp(&sin->sin_addr, &p->addr.v4.start,
1756 sizeof(struct in_addr))
1757 == 0);
1758 break;
1759
1760 case NXT_HTTP_ROUTE_ADDR_RANGE:
1761 match = (memcmp(&sin->sin_addr, &p->addr.v4.start,
1762 sizeof(struct in_addr)) >= 0
1763 && memcmp(&sin->sin_addr, &p->addr.v4.end,
1764 sizeof(struct in_addr)) <= 0);
1765 break;
1766
1767 case NXT_HTTP_ROUTE_ADDR_CIDR:
1768 match = ((sin->sin_addr.s_addr & p->addr.v4.end)
1769 == p->addr.v4.start);
1770 break;
1771
1772 default:
1773 nxt_unreachable();
1774 }
1775
1776 break;
1777
1778 #if (NXT_INET6)
1779 case AF_INET6:
1780
1781 match = (base->addr_family == AF_INET6
1782 || base->addr_family == AF_UNSPEC);
1783 if (!match) {
1784 break;
1785 }
1786
1787 sin6 = &sa->u.sockaddr_in6;
1788 in_port = ntohs(sin6->sin6_port);
1789
1790 match = (in_port >= base->port.start && in_port <= base->port.end);
1791 if (!match) {
1792 break;
1793 }
1794
1795 switch (base->match_type) {
1796
1797 case NXT_HTTP_ROUTE_ADDR_ANY:
1798 break;
1799
1800 case NXT_HTTP_ROUTE_ADDR_EXACT:
1801 match = (memcmp(&sin6->sin6_addr, &p->addr.v6.start,
1802 sizeof(struct in6_addr))
1803 == 0);
1804 break;
1805
1806 case NXT_HTTP_ROUTE_ADDR_RANGE:
1807 match = (memcmp(&sin6->sin6_addr, &p->addr.v6.start,
1808 sizeof(struct in6_addr)) >= 0
1809 && memcmp(&sin6->sin6_addr, &p->addr.v6.end,
1810 sizeof(struct in6_addr)) <= 0);
1811 break;
1812
1813 case NXT_HTTP_ROUTE_ADDR_CIDR:
1814 for (i = 0; i < 16; i++) {
1815 match = ((sin6->sin6_addr.s6_addr[i]
1816 & p->addr.v6.end.s6_addr[i])
1817 == p->addr.v6.start.s6_addr[i]);
1818
1819 if (!match) {
1820 break;
1821 }
1822 }
1823
1824 break;
1825
1826 default:
1827 nxt_unreachable();
1828 }
1829
1830 break;
1831 #endif
1832
1833 #if (NXT_HAVE_UNIX_DOMAIN)
1834 case AF_UNIX:
1835
1836 match = (base->addr_family == AF_UNIX);
1837 break;
1838 #endif
1839
1840 default:
1841 match = 0;
1842 break;
1843 }
1844
1845 return match ^ base->negative;
1846 }
1847
1848
1849 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)1850 nxt_http_route_addr_rule(nxt_http_request_t *r,
1851 nxt_http_route_addr_rule_t *addr_rule, nxt_sockaddr_t *sa)
1852 {
1853 uint32_t n;
1854 nxt_bool_t matches;
1855 nxt_http_route_addr_pattern_t *p;
1856
1857 n = addr_rule->items;
1858
1859 if (n == 0) {
1860 return 0;
1861 }
1862
1863 p = &addr_rule->addr_pattern[0] - 1;
1864
1865 do {
1866 p++;
1867 n--;
1868
1869 matches = nxt_http_route_addr_pattern_match(p, sa);
1870
1871 if (p->base.negative) {
1872 if (matches) {
1873 continue;
1874 }
1875
1876 return 0;
1877 }
1878
1879 if (matches) {
1880 return 1;
1881 }
1882
1883 } while (n > 0);
1884
1885 return p->base.negative;
1886 }
1887
1888
1889 static nxt_int_t
nxt_http_route_header(nxt_http_request_t * r,nxt_http_route_rule_t * rule)1890 nxt_http_route_header(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
1891 {
1892 nxt_int_t ret;
1893 nxt_http_field_t *f;
1894
1895 ret = 0;
1896
1897 nxt_list_each(f, r->fields) {
1898
1899 if (rule->u.name.hash != f->hash
1900 || rule->u.name.length != f->name_length
1901 || nxt_strncasecmp(rule->u.name.start, f->name, f->name_length)
1902 != 0)
1903 {
1904 continue;
1905 }
1906
1907 ret = nxt_http_route_test_rule(r, rule, f->value, f->value_length);
1908 if (nxt_slow_path(ret == NXT_ERROR)) {
1909 return NXT_ERROR;
1910 }
1911
1912 if (ret == 0) {
1913 return ret;
1914 }
1915
1916 } nxt_list_loop;
1917
1918 return ret;
1919 }
1920
1921
1922 static nxt_int_t
nxt_http_route_arguments(nxt_http_request_t * r,nxt_http_route_rule_t * rule)1923 nxt_http_route_arguments(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
1924 {
1925 nxt_array_t *arguments;
1926
1927 arguments = nxt_http_arguments_parse(r);
1928 if (nxt_slow_path(arguments == NULL)) {
1929 return -1;
1930 }
1931
1932 return nxt_http_route_test_argument(r, rule, arguments);
1933 }
1934
1935
1936 static nxt_int_t
nxt_http_route_test_argument(nxt_http_request_t * r,nxt_http_route_rule_t * rule,nxt_array_t * array)1937 nxt_http_route_test_argument(nxt_http_request_t *r,
1938 nxt_http_route_rule_t *rule, nxt_array_t *array)
1939 {
1940 nxt_int_t ret;
1941 nxt_http_name_value_t *nv, *end;
1942
1943 ret = 0;
1944
1945 nv = array->elts;
1946 end = nv + array->nelts;
1947
1948 while (nv < end) {
1949
1950 if (rule->u.name.hash == nv->hash
1951 && rule->u.name.length == nv->name_length
1952 && memcmp(rule->u.name.start, nv->name, nv->name_length) == 0)
1953 {
1954 ret = nxt_http_route_test_rule(r, rule, nv->value,
1955 nv->value_length);
1956 if (nxt_slow_path(ret == NXT_ERROR)) {
1957 return NXT_ERROR;
1958 }
1959
1960 if (ret == 0) {
1961 break;
1962 }
1963 }
1964
1965 nv++;
1966 }
1967
1968 return ret;
1969 }
1970
1971
1972 static nxt_int_t
nxt_http_route_scheme(nxt_http_request_t * r,nxt_http_route_rule_t * rule)1973 nxt_http_route_scheme(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
1974 {
1975 nxt_bool_t https;
1976 nxt_http_route_pattern_slice_t *pattern_slice;
1977
1978 pattern_slice = rule->pattern[0].u.pattern_slices->elts;
1979 https = (pattern_slice->length == nxt_length("https"));
1980
1981 return (r->tls == https);
1982 }
1983
1984
1985 static nxt_int_t
nxt_http_route_query(nxt_http_request_t * r,nxt_http_route_rule_t * rule)1986 nxt_http_route_query(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
1987 {
1988 nxt_array_t *arguments;
1989
1990 arguments = nxt_http_arguments_parse(r);
1991 if (nxt_slow_path(arguments == NULL)) {
1992 return -1;
1993 }
1994
1995 return nxt_http_route_test_rule(r, rule, r->args_decoded.start,
1996 r->args_decoded.length);
1997 }
1998
1999
2000 static nxt_int_t
nxt_http_route_cookies(nxt_http_request_t * r,nxt_http_route_rule_t * rule)2001 nxt_http_route_cookies(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
2002 {
2003 nxt_array_t *cookies;
2004
2005 cookies = nxt_http_cookies_parse(r);
2006 if (nxt_slow_path(cookies == NULL)) {
2007 return -1;
2008 }
2009
2010 return nxt_http_route_test_cookie(r, rule, cookies);
2011 }
2012
2013
2014 static nxt_int_t
nxt_http_route_test_cookie(nxt_http_request_t * r,nxt_http_route_rule_t * rule,nxt_array_t * array)2015 nxt_http_route_test_cookie(nxt_http_request_t *r,
2016 nxt_http_route_rule_t *rule, nxt_array_t *array)
2017 {
2018 nxt_int_t ret;
2019 nxt_http_name_value_t *nv, *end;
2020
2021 ret = 0;
2022
2023 nv = array->elts;
2024 end = nv + array->nelts;
2025
2026 while (nv < end) {
2027
2028 if (rule->u.name.hash == nv->hash
2029 && rule->u.name.length == nv->name_length
2030 && memcmp(rule->u.name.start, nv->name, nv->name_length) == 0)
2031 {
2032 ret = nxt_http_route_test_rule(r, rule, nv->value,
2033 nv->value_length);
2034 if (nxt_slow_path(ret == NXT_ERROR)) {
2035 return NXT_ERROR;
2036 }
2037
2038 if (ret == 0) {
2039 break;
2040 }
2041 }
2042
2043 nv++;
2044 }
2045
2046 return ret;
2047 }
2048
2049
2050 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)2051 nxt_http_route_test_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule,
2052 u_char *start, size_t length)
2053 {
2054 nxt_int_t ret;
2055 nxt_http_route_pattern_t *pattern, *end;
2056
2057 ret = 1;
2058 pattern = &rule->pattern[0];
2059 end = pattern + rule->items;
2060
2061 while (pattern < end) {
2062 ret = nxt_http_route_pattern(r, pattern, start, length);
2063 if (nxt_slow_path(ret == NXT_ERROR)) {
2064 return NXT_ERROR;
2065 }
2066
2067 /* nxt_http_route_pattern() returns either 1 or 0. */
2068 ret ^= pattern->negative;
2069
2070 if (pattern->any == ret) {
2071 return ret;
2072 }
2073
2074 pattern++;
2075 }
2076
2077 return ret;
2078 }
2079
2080
2081 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)2082 nxt_http_route_pattern(nxt_http_request_t *r, nxt_http_route_pattern_t *pattern,
2083 u_char *start, size_t length)
2084 {
2085 u_char *p, *end, *test;
2086 size_t test_length;
2087 uint32_t i;
2088 nxt_array_t *pattern_slices;
2089 nxt_http_route_pattern_slice_t *pattern_slice;
2090
2091 #if (NXT_HAVE_REGEX)
2092 if (pattern->regex) {
2093 if (r->regex_match == NULL) {
2094 r->regex_match = nxt_regex_match_create(r->mem_pool, 0);
2095 if (nxt_slow_path(r->regex_match == NULL)) {
2096 return NXT_ERROR;
2097 }
2098 }
2099
2100 return nxt_regex_match(pattern->u.regex, start, length, r->regex_match);
2101 }
2102 #endif
2103
2104 if (length < pattern->min_length) {
2105 return 0;
2106 }
2107
2108 nxt_assert(pattern->u.pattern_slices != NULL);
2109
2110 pattern_slices = pattern->u.pattern_slices;
2111 pattern_slice = pattern_slices->elts;
2112 end = start + length;
2113
2114 for (i = 0; i < pattern_slices->nelts; i++, pattern_slice++) {
2115 test = pattern_slice->start;
2116 test_length = pattern_slice->length;
2117
2118 switch (pattern_slice->type) {
2119 case NXT_HTTP_ROUTE_PATTERN_EXACT:
2120 return ((length == pattern->min_length) &&
2121 nxt_http_route_memcmp(start, test, test_length,
2122 pattern->case_sensitive));
2123
2124 case NXT_HTTP_ROUTE_PATTERN_BEGIN:
2125 if (nxt_http_route_memcmp(start, test, test_length,
2126 pattern->case_sensitive))
2127 {
2128 start += test_length;
2129 break;
2130 }
2131
2132 return 0;
2133
2134 case NXT_HTTP_ROUTE_PATTERN_END:
2135 p = end - test_length;
2136
2137 if (nxt_http_route_memcmp(p, test, test_length,
2138 pattern->case_sensitive))
2139 {
2140 end = p;
2141 break;
2142 }
2143
2144 return 0;
2145
2146 case NXT_HTTP_ROUTE_PATTERN_SUBSTRING:
2147 if (pattern->case_sensitive) {
2148 p = nxt_memstrn(start, end, (char *) test, test_length);
2149
2150 } else {
2151 p = nxt_memcasestrn(start, end, (char *) test, test_length);
2152 }
2153
2154 if (p == NULL) {
2155 return 0;
2156 }
2157
2158 start = p + test_length;
2159 }
2160 }
2161
2162 return 1;
2163 }
2164
2165
2166 static nxt_int_t
nxt_http_route_memcmp(u_char * start,u_char * test,size_t test_length,nxt_bool_t case_sensitive)2167 nxt_http_route_memcmp(u_char *start, u_char *test, size_t test_length,
2168 nxt_bool_t case_sensitive)
2169 {
2170 nxt_int_t n;
2171
2172 if (case_sensitive) {
2173 n = memcmp(start, test, test_length);
2174
2175 } else {
2176 n = nxt_memcasecmp(start, test, test_length);
2177 }
2178
2179 return (n == 0);
2180 }
2181