summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorIgor Sysoev <igor@sysoev.ru>2019-04-10 13:47:34 +0300
committerIgor Sysoev <igor@sysoev.ru>2019-04-10 13:47:34 +0300
commit8339b1515816ec8d3661514dc3edb73874580977 (patch)
treede9b77da32ed2145a5d8285f9273e829e235d871
parentac7e65a722d38786c63716c026ab588e3d205a25 (diff)
downloadunit-8339b1515816ec8d3661514dc3edb73874580977.tar.gz
unit-8339b1515816ec8d3661514dc3edb73874580977.tar.bz2
Added support for wildcards in the middle of match patterns.
Diffstat (limited to '')
-rw-r--r--src/nxt_conf_validation.c27
-rw-r--r--src/nxt_http_route.c126
2 files changed, 129 insertions, 24 deletions
diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c
index ee87b0f6..e2e1b89e 100644
--- a/src/nxt_conf_validation.c
+++ b/src/nxt_conf_validation.c
@@ -741,6 +741,12 @@ nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt,
nxt_str_t pattern;
nxt_uint_t i, first, last;
+ enum {
+ sw_none,
+ sw_side,
+ sw_middle
+ } state;
+
if (nxt_conf_type(value) != NXT_CONF_STRING) {
return nxt_conf_vldt_error(vldt,
"The \"match\" patterns must be strings.");
@@ -754,17 +760,32 @@ nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt,
first = (pattern.start[0] == '!');
last = pattern.length - 1;
+ state = sw_none;
for (i = first; i != pattern.length; i++) {
+
ch = pattern.start[i];
if (ch != '*') {
continue;
}
- if (i != first && i != last) {
- return nxt_conf_vldt_error(vldt, "The \"match\" patterns can only "
- "contain \"*\" markers at the sides.");
+ switch (state) {
+ case sw_none:
+ state = (i == first) ? sw_side : sw_middle;
+ break;
+
+ case sw_side:
+ if (i == last) {
+ break;
+ }
+
+ /* Fall through. */
+
+ case sw_middle:
+ return nxt_conf_vldt_error(vldt, "The \"match\" patterns can "
+ "either contain \"*\" markers at "
+ "the sides or only one in the middle.");
}
}
diff --git a/src/nxt_http_route.c b/src/nxt_http_route.c
index 133c39ab..f1076b88 100644
--- a/src/nxt_http_route.c
+++ b/src/nxt_http_route.c
@@ -21,6 +21,7 @@ typedef enum {
typedef enum {
NXT_HTTP_ROUTE_PATTERN_EXACT = 0,
NXT_HTTP_ROUTE_PATTERN_BEGIN,
+ NXT_HTTP_ROUTE_PATTERN_MIDDLE,
NXT_HTTP_ROUTE_PATTERN_END,
NXT_HTTP_ROUTE_PATTERN_SUBSTRING,
} nxt_http_route_pattern_type_t;
@@ -41,7 +42,10 @@ typedef struct {
typedef struct {
- nxt_str_t test;
+ u_char *start1;
+ u_char *start2;
+ uint32_t length1;
+ uint32_t length2;
uint32_t min_length;
nxt_http_route_pattern_type_t type:8;
@@ -90,6 +94,8 @@ static int nxt_http_pattern_compare(const void *one, const void *two);
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);
+static u_char *nxt_http_route_pattern_copy(nxt_mp_t *mp, nxt_str_t *test,
+ nxt_http_route_pattern_case_t pattern_case);
static void nxt_http_route_resolve(nxt_task_t *task,
nxt_router_temp_conf_t *tmcf, nxt_http_route_t *route);
@@ -107,6 +113,8 @@ static nxt_bool_t nxt_http_route_rule(nxt_http_request_t *r,
nxt_http_route_rule_t *rule);
static nxt_bool_t nxt_http_route_pattern(nxt_http_request_t *r,
nxt_http_route_pattern_t *pattern, u_char *start, size_t length);
+static nxt_bool_t nxt_http_route_memcmp(u_char *start, u_char *test,
+ size_t length, nxt_bool_t case_sensitive);
nxt_http_routes_t *
@@ -407,8 +415,12 @@ nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp,
{
u_char *start;
nxt_str_t test;
+ nxt_uint_t n, length;
nxt_http_route_pattern_type_t type;
+ /* Suppress warning about uninitialized variable. */
+ length = 0;
+
type = NXT_HTTP_ROUTE_PATTERN_EXACT;
nxt_conf_get_string(cv, &test);
@@ -448,37 +460,79 @@ nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp,
} else if (test.start[test.length - 1] == '*') {
test.length--;
type = NXT_HTTP_ROUTE_PATTERN_BEGIN;
+
+ } else {
+ length = test.length - 1;
+
+ for (n = 1; n < length; n++) {
+ if (test.start[n] == '*') {
+ test.length = n;
+ type = NXT_HTTP_ROUTE_PATTERN_MIDDLE;
+ break;
+ }
+ }
}
}
}
pattern->type = type;
pattern->min_length = test.length;
- pattern->test.length = test.length;
+ pattern->length1 = test.length;
- start = nxt_mp_nget(mp, test.length);
+ start = nxt_http_route_pattern_copy(mp, &test, pattern_case);
if (nxt_slow_path(start == NULL)) {
return NXT_ERROR;
}
- pattern->test.start = start;
+ pattern->start1 = start;
+
+ if (type == NXT_HTTP_ROUTE_PATTERN_MIDDLE) {
+ length -= test.length;
+ pattern->length2 = length;
+ pattern->min_length += length;
+
+ test.start = &test.start[test.length + 1];
+ test.length = length;
+
+ start = nxt_http_route_pattern_copy(mp, &test, pattern_case);
+ if (nxt_slow_path(start == NULL)) {
+ return NXT_ERROR;
+ }
+
+ pattern->start2 = start;
+ }
+
+ return NXT_OK;
+}
+
+
+static u_char *
+nxt_http_route_pattern_copy(nxt_mp_t *mp, nxt_str_t *test,
+ nxt_http_route_pattern_case_t pattern_case)
+{
+ u_char *start;
+
+ start = nxt_mp_nget(mp, test->length);
+ if (nxt_slow_path(start == NULL)) {
+ return start;
+ }
switch (pattern_case) {
case NXT_HTTP_ROUTE_PATTERN_UPCASE:
- nxt_memcpy_upcase(start, test.start, test.length);
+ nxt_memcpy_upcase(start, test->start, test->length);
break;
case NXT_HTTP_ROUTE_PATTERN_LOWCASE:
- nxt_memcpy_lowcase(start, test.start, test.length);
+ nxt_memcpy_lowcase(start, test->start, test->length);
break;
case NXT_HTTP_ROUTE_PATTERN_NOCASE:
- nxt_memcpy(start, test.start, test.length);
+ nxt_memcpy(start, test->start, test->length);
break;
}
- return NXT_OK;
+ return start;
}
@@ -805,18 +859,21 @@ static nxt_bool_t
nxt_http_route_pattern(nxt_http_request_t *r, nxt_http_route_pattern_t *pattern,
u_char *start, size_t length)
{
- nxt_str_t *test;
+ u_char *p, *end, *test;
+ size_t test_length;
+ nxt_bool_t ret;
if (length < pattern->min_length) {
return 0;
}
- test = &pattern->test;
+ test = pattern->start1;
+ test_length = pattern->length1;
switch (pattern->type) {
case NXT_HTTP_ROUTE_PATTERN_EXACT:
- if (length != test->length) {
+ if (length != test_length) {
return 0;
}
@@ -825,25 +882,52 @@ nxt_http_route_pattern(nxt_http_request_t *r, nxt_http_route_pattern_t *pattern,
case NXT_HTTP_ROUTE_PATTERN_BEGIN:
break;
+ case NXT_HTTP_ROUTE_PATTERN_MIDDLE:
+ ret = nxt_http_route_memcmp(start, test, test_length,
+ pattern->case_sensitive);
+ if (!ret) {
+ return ret;
+ }
+
+ test = pattern->start2;
+ test_length = pattern->length2;
+
+ /* Fall through. */
+
case NXT_HTTP_ROUTE_PATTERN_END:
- start += length - test->length;
+ start += length - test_length;
break;
case NXT_HTTP_ROUTE_PATTERN_SUBSTRING:
+ end = start + length;
+
if (pattern->case_sensitive) {
- return (nxt_memstrn(start, start + length,
- (char *) test->start, test->length)
- != NULL);
+ p = nxt_memstrn(start, end, (char *) test, test_length);
+
+ } else {
+ p = nxt_memcasestrn(start, end, (char *) test, test_length);
}
- return (nxt_memcasestrn(start, start + length,
- (char *) test->start, test->length)
- != NULL);
+ return (p != NULL);
}
- if (pattern->case_sensitive) {
- return (nxt_memcmp(start, test->start, test->length) == 0);
+ return nxt_http_route_memcmp(start, test, test_length,
+ pattern->case_sensitive);
+}
+
+
+static nxt_bool_t
+nxt_http_route_memcmp(u_char *start, u_char *test, size_t test_length,
+ nxt_bool_t case_sensitive)
+{
+ nxt_int_t n;
+
+ if (case_sensitive) {
+ n = nxt_memcmp(start, test, test_length);
+
+ } else {
+ n = nxt_memcasecmp(start, test, test_length);
}
- return (nxt_memcasecmp(start, test->start, test->length) == 0);
+ return (n == 0);
}