summaryrefslogtreecommitdiffhomepage
path: root/src/nxt_http_route.c
diff options
context:
space:
mode:
authorAxel Duch <axel.duch@nginx.com>2020-05-14 12:29:06 +0200
committerAxel Duch <axel.duch@nginx.com>2020-05-14 12:29:06 +0200
commitee1e248f4b038bb9e03fd78463da580af03c28f7 (patch)
tree7023ed63db7edb5fa616bc41a424b1a6c1e35046 /src/nxt_http_route.c
parent376d758dd72ac27f2bd5bb833ba68f5c9b531880 (diff)
downloadunit-ee1e248f4b038bb9e03fd78463da580af03c28f7.tar.gz
unit-ee1e248f4b038bb9e03fd78463da580af03c28f7.tar.bz2
Router: decode uri and args.
Diffstat (limited to 'src/nxt_http_route.c')
-rw-r--r--src/nxt_http_route.c278
1 files changed, 221 insertions, 57 deletions
diff --git a/src/nxt_http_route.c b/src/nxt_http_route.c
index 06bc91da..5010c561 100644
--- a/src/nxt_http_route.c
+++ b/src/nxt_http_route.c
@@ -39,6 +39,13 @@ typedef enum {
} nxt_http_route_pattern_case_t;
+typedef enum {
+ NXT_HTTP_ROUTE_ENCODING_NONE = 0,
+ NXT_HTTP_ROUTE_ENCODING_URI,
+ NXT_HTTP_ROUTE_ENCODING_URI_PLUS
+} nxt_http_route_encoding_t;
+
+
typedef struct {
nxt_conf_value_t *pass;
nxt_conf_value_t *ret;
@@ -181,23 +188,27 @@ static nxt_int_t nxt_http_route_action_create(nxt_router_temp_conf_t *tmcf,
nxt_conf_value_t *cv, nxt_http_action_t *action);
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_bool_t case_sensitive, nxt_http_route_encoding_t encoding);
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_bool_t case_sensitive, nxt_http_route_encoding_t encoding);
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_bool_t case_sensitive, nxt_http_route_encoding_t encoding);
static 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);
static nxt_http_route_rule_t *nxt_http_route_rule_create(nxt_task_t *task,
nxt_mp_t *mp, nxt_conf_value_t *cv, nxt_bool_t case_sensitive,
- nxt_http_route_pattern_case_t pattern_case);
+ nxt_http_route_pattern_case_t pattern_case,
+ nxt_http_route_encoding_t encoding);
static int nxt_http_pattern_compare(const void *one, const void *two);
static int nxt_http_addr_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);
+ nxt_http_route_pattern_case_t pattern_case,
+ nxt_http_route_encoding_t encoding);
+static nxt_int_t nxt_http_route_decode_str(nxt_str_t *str,
+ nxt_http_route_encoding_t encoding);
static u_char *nxt_http_route_pattern_copy(nxt_mp_t *mp, nxt_str_t *test,
nxt_http_route_pattern_case_t pattern_case);
@@ -463,7 +474,8 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
if (mtcf.scheme != NULL) {
rule = nxt_http_route_rule_create(task, mp, mtcf.scheme, 1,
- NXT_HTTP_ROUTE_PATTERN_NOCASE);
+ NXT_HTTP_ROUTE_PATTERN_NOCASE,
+ NXT_HTTP_ROUTE_ENCODING_NONE);
if (rule == NULL) {
return NULL;
}
@@ -475,7 +487,8 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
if (mtcf.host != NULL) {
rule = nxt_http_route_rule_create(task, mp, mtcf.host, 1,
- NXT_HTTP_ROUTE_PATTERN_LOWCASE);
+ NXT_HTTP_ROUTE_PATTERN_LOWCASE,
+ NXT_HTTP_ROUTE_ENCODING_NONE);
if (rule == NULL) {
return NULL;
}
@@ -488,7 +501,8 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
if (mtcf.uri != NULL) {
rule = nxt_http_route_rule_create(task, mp, mtcf.uri, 1,
- NXT_HTTP_ROUTE_PATTERN_NOCASE);
+ NXT_HTTP_ROUTE_PATTERN_NOCASE,
+ NXT_HTTP_ROUTE_ENCODING_URI);
if (rule == NULL) {
return NULL;
}
@@ -501,7 +515,8 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
if (mtcf.method != NULL) {
rule = nxt_http_route_rule_create(task, mp, mtcf.method, 1,
- NXT_HTTP_ROUTE_PATTERN_UPCASE);
+ NXT_HTTP_ROUTE_PATTERN_UPCASE,
+ NXT_HTTP_ROUTE_ENCODING_NONE);
if (rule == NULL) {
return NULL;
}
@@ -514,7 +529,8 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
if (mtcf.headers != NULL) {
table = nxt_http_route_table_create(task, mp, mtcf.headers,
- NXT_HTTP_ROUTE_HEADER, 0);
+ NXT_HTTP_ROUTE_HEADER, 0,
+ NXT_HTTP_ROUTE_ENCODING_NONE);
if (table == NULL) {
return NULL;
}
@@ -525,7 +541,8 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
if (mtcf.arguments != NULL) {
table = nxt_http_route_table_create(task, mp, mtcf.arguments,
- NXT_HTTP_ROUTE_ARGUMENT, 1);
+ NXT_HTTP_ROUTE_ARGUMENT, 1,
+ NXT_HTTP_ROUTE_ENCODING_URI_PLUS);
if (table == NULL) {
return NULL;
}
@@ -536,7 +553,8 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
if (mtcf.cookies != NULL) {
table = nxt_http_route_table_create(task, mp, mtcf.cookies,
- NXT_HTTP_ROUTE_COOKIE, 1);
+ NXT_HTTP_ROUTE_COOKIE, 1,
+ NXT_HTTP_ROUTE_ENCODING_NONE);
if (table == NULL) {
return NULL;
}
@@ -699,7 +717,7 @@ nxt_http_route_action_create(nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv,
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_bool_t case_sensitive, nxt_http_route_encoding_t encoding)
{
size_t size;
uint32_t i, n;
@@ -722,8 +740,8 @@ nxt_http_route_table_create(nxt_task_t *task, nxt_mp_t *mp,
table->object = NXT_HTTP_ROUTE_TABLE;
if (!array) {
- ruleset = nxt_http_route_ruleset_create(task, mp, table_cv,
- object, case_sensitive);
+ ruleset = nxt_http_route_ruleset_create(task, mp, table_cv, object,
+ case_sensitive, encoding);
if (nxt_slow_path(ruleset == NULL)) {
return NULL;
}
@@ -736,8 +754,8 @@ nxt_http_route_table_create(nxt_task_t *task, nxt_mp_t *mp,
for (i = 0; i < n; i++) {
ruleset_cv = nxt_conf_get_array_element(table_cv, i);
- ruleset = nxt_http_route_ruleset_create(task, mp, ruleset_cv,
- object, case_sensitive);
+ ruleset = nxt_http_route_ruleset_create(task, mp, ruleset_cv, object,
+ case_sensitive, encoding);
if (nxt_slow_path(ruleset == NULL)) {
return NULL;
}
@@ -752,7 +770,7 @@ nxt_http_route_table_create(nxt_task_t *task, nxt_mp_t *mp,
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_bool_t case_sensitive, nxt_http_route_encoding_t encoding)
{
size_t size;
uint32_t i, n, next;
@@ -778,7 +796,7 @@ nxt_http_route_ruleset_create(nxt_task_t *task, nxt_mp_t *mp,
rule_cv = nxt_conf_next_object_member(ruleset_cv, &name, &next);
rule = nxt_http_route_rule_name_create(task, mp, rule_cv, &name,
- case_sensitive);
+ case_sensitive, encoding);
if (nxt_slow_path(rule == NULL)) {
return NULL;
}
@@ -793,15 +811,18 @@ nxt_http_route_ruleset_create(nxt_task_t *task, nxt_mp_t *mp,
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_conf_value_t *rule_cv, nxt_str_t *name, nxt_bool_t case_sensitive,
+ nxt_http_route_encoding_t encoding)
{
- u_char c, *p;
+ u_char c, *p, *src, *start, *end, plus;
+ uint8_t d0, d1;
uint32_t hash;
nxt_uint_t i;
nxt_http_route_rule_t *rule;
rule = nxt_http_route_rule_create(task, mp, rule_cv, case_sensitive,
- NXT_HTTP_ROUTE_PATTERN_NOCASE);
+ NXT_HTTP_ROUTE_PATTERN_NOCASE,
+ encoding);
if (nxt_slow_path(rule == NULL)) {
return NULL;
}
@@ -813,18 +834,65 @@ nxt_http_route_rule_name_create(nxt_task_t *task, nxt_mp_t *mp,
return NULL;
}
+ hash = NXT_HTTP_FIELD_HASH_INIT;
rule->u.name.start = p;
- hash = NXT_HTTP_FIELD_HASH_INIT;
+ if (encoding == NXT_HTTP_ROUTE_ENCODING_NONE) {
+ for (i = 0; i < name->length; i++) {
+ c = name->start[i];
+ *p++ = c;
- for (i = 0; i < name->length; i++) {
- c = name->start[i];
- *p++ = c;
+ c = case_sensitive ? c : nxt_lowcase(c);
+ hash = nxt_http_field_hash_char(hash, c);
+ }
+
+ goto end;
+ }
+
+ plus = (encoding == NXT_HTTP_ROUTE_ENCODING_URI_PLUS) ? ' ' : '+';
+
+ start = name->start;
+ end = start + name->length;
+
+ for (src = start; src < end; src++) {
+ c = *src;
+
+ switch (c) {
+ case '%':
+ if (nxt_slow_path(end - src <= 2)) {
+ return NULL;
+ }
+
+ d0 = nxt_hex2int[src[1]];
+ d1 = nxt_hex2int[src[2]];
+ src += 2;
+
+ if (nxt_slow_path((d0 | d1) >= 16)) {
+ return NULL;
+ }
+
+ c = (d0 << 4) + d1;
+ *p++ = c;
+ break;
+
+ case '+':
+ c = plus;
+ *p++ = c;
+ break;
+
+ default:
+ *p++ = c;
+ break;
+ }
c = case_sensitive ? c : nxt_lowcase(c);
hash = nxt_http_field_hash_char(hash, c);
}
+ rule->u.name.length = p - rule->u.name.start;
+
+end:
+
rule->u.name.hash = nxt_http_field_hash_end(hash) & 0xFFFF;
return rule;
@@ -834,7 +902,8 @@ nxt_http_route_rule_name_create(nxt_task_t *task, nxt_mp_t *mp,
static nxt_http_route_rule_t *
nxt_http_route_rule_create(nxt_task_t *task, nxt_mp_t *mp,
nxt_conf_value_t *cv, nxt_bool_t case_sensitive,
- nxt_http_route_pattern_case_t pattern_case)
+ nxt_http_route_pattern_case_t pattern_case,
+ nxt_http_route_encoding_t encoding)
{
size_t size;
uint32_t i, n;
@@ -860,7 +929,7 @@ nxt_http_route_rule_create(nxt_task_t *task, nxt_mp_t *mp,
if (string) {
pattern[0].case_sensitive = case_sensitive;
ret = nxt_http_route_pattern_create(task, mp, cv, &pattern[0],
- pattern_case);
+ pattern_case, encoding);
if (nxt_slow_path(ret != NXT_OK)) {
return NULL;
}
@@ -875,7 +944,7 @@ nxt_http_route_rule_create(nxt_task_t *task, nxt_mp_t *mp,
value = nxt_conf_get_array_element(cv, i);
ret = nxt_http_route_pattern_create(task, mp, value, &pattern[i],
- pattern_case);
+ pattern_case, encoding);
if (nxt_slow_path(ret != NXT_OK)) {
return NULL;
}
@@ -972,10 +1041,12 @@ nxt_http_addr_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)
+ nxt_http_route_pattern_case_t pattern_case,
+ nxt_http_route_encoding_t encoding)
{
u_char *start;
- nxt_str_t test;
+ nxt_str_t test, test2;
+ nxt_int_t ret;
nxt_uint_t n, length;
nxt_http_route_pattern_type_t type;
@@ -988,6 +1059,7 @@ nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp,
pattern->negative = 0;
pattern->any = 1;
+ pattern->min_length = 0;
if (test.length != 0) {
@@ -1000,7 +1072,6 @@ nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp,
}
if (test.length != 0) {
-
if (test.start[0] == '*') {
test.start++;
test.length--;
@@ -1026,18 +1097,45 @@ nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp,
length = test.length - 1;
for (n = 1; n < length; n++) {
- if (test.start[n] == '*') {
- test.length = n;
- type = NXT_HTTP_ROUTE_PATTERN_MIDDLE;
- break;
+ if (test.start[n] != '*') {
+ continue;
}
+
+ test.length = n;
+
+ test2.start = &test.start[n + 1];
+ test2.length = length - n;
+
+ ret = nxt_http_route_decode_str(&test2, encoding);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return ret;
+ }
+
+ type = NXT_HTTP_ROUTE_PATTERN_MIDDLE;
+
+ pattern->length2 = test2.length;
+ pattern->min_length += test2.length;
+
+ start = nxt_http_route_pattern_copy(mp, &test2,
+ pattern_case);
+ if (nxt_slow_path(start == NULL)) {
+ return NXT_ERROR;
+ }
+
+ pattern->start2 = start;
+ break;
}
}
+
+ ret = nxt_http_route_decode_str(&test, encoding);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return ret;
+ }
}
}
pattern->type = type;
- pattern->min_length = test.length;
+ pattern->min_length += test.length;
pattern->length1 = test.length;
start = nxt_http_route_pattern_copy(mp, &test, pattern_case);
@@ -1047,20 +1145,43 @@ nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp,
pattern->start1 = start;
- if (type == NXT_HTTP_ROUTE_PATTERN_MIDDLE) {
- length -= test.length;
- pattern->length2 = length;
- pattern->min_length += length;
+ return NXT_OK;
+}
+
+
+static nxt_int_t
+nxt_http_route_decode_str(nxt_str_t *str, nxt_http_route_encoding_t encoding)
+{
+ u_char *start, *end;
+
+ switch (encoding) {
+ case NXT_HTTP_ROUTE_ENCODING_NONE:
+ break;
+
+ case NXT_HTTP_ROUTE_ENCODING_URI:
+ start = str->start;
+
+ end = nxt_decode_uri(start, start, str->length);
+ if (nxt_slow_path(end == NULL)) {
+ return NXT_ERROR;
+ }
+
+ str->length = end - start;
+ break;
- test.start = &test.start[test.length + 1];
- test.length = length;
+ case NXT_HTTP_ROUTE_ENCODING_URI_PLUS:
+ start = str->start;
- start = nxt_http_route_pattern_copy(mp, &test, pattern_case);
- if (nxt_slow_path(start == NULL)) {
+ end = nxt_decode_uri_plus(start, start, str->length);
+ if (nxt_slow_path(end == NULL)) {
return NXT_ERROR;
}
- pattern->start2 = start;
+ str->length = end - start;
+ break;
+
+ default:
+ nxt_unreachable();
}
return NXT_OK;
@@ -1746,7 +1867,8 @@ static nxt_array_t *
nxt_http_route_arguments_parse(nxt_http_request_t *r)
{
size_t name_length;
- u_char c, *p, *start, *end, *name;
+ u_char c, *p, *dst, *dst_start, *start, *end, *name;
+ uint8_t d0, d1;
uint32_t hash;
nxt_bool_t valid;
nxt_array_t *args;
@@ -1766,39 +1888,81 @@ nxt_http_route_arguments_parse(nxt_http_request_t *r)
name = NULL;
name_length = 0;
+ dst_start = nxt_mp_nget(r->mem_pool, r->args->length);
+ if (nxt_slow_path(dst_start == NULL)) {
+ return NULL;
+ }
+
start = r->args->start;
end = start + r->args->length;
- for (p = start; p < end; p++) {
+ for (p = start, dst = dst_start; p < end; p++, dst++) {
c = *p;
+ *dst = c;
- if (c == '=') {
- name_length = p - start;
- name = start;
- start = p + 1;
+ switch (c) {
+ case '=':
+ if (name != NULL) {
+ break;
+ }
+
+ name_length = dst - dst_start;
valid = (name_length != 0);
+ name = dst_start;
+ dst_start = dst + 1;
+
+ continue;
- } else if (c == '&') {
+ case '&':
if (valid) {
nv = nxt_http_route_argument(args, name, name_length, hash,
- start, p);
+ dst_start, dst);
if (nxt_slow_path(nv == NULL)) {
return NULL;
}
}
hash = NXT_HTTP_FIELD_HASH_INIT;
+ name_length = 0;
valid = 1;
name = NULL;
- start = p + 1;
+ dst_start = dst + 1;
+
+ continue;
+
+ case '+':
+ c = ' ';
+ *dst = ' ';
+
+ break;
+
+ case '%':
+ if (nxt_slow_path(end - p <= 2)) {
+ break;
+ }
+
+ d0 = nxt_hex2int[p[1]];
+ d1 = nxt_hex2int[p[2]];
+
+ if (nxt_slow_path((d0 | d1) >= 16)) {
+ break;
+ }
+
+ p += 2;
+ c = (d0 << 4) + d1;
+ *dst = c;
+
+ break;
+ }
- } else if (name == NULL) {
+ if (name == NULL) {
hash = nxt_http_field_hash_char(hash, c);
}
}
if (valid) {
- nv = nxt_http_route_argument(args, name, name_length, hash, start, p);
+ nv = nxt_http_route_argument(args, name, name_length, hash, dst_start,
+ dst);
if (nxt_slow_path(nv == NULL)) {
return NULL;
}