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