diff options
author | Axel Duch <axel.duch@nginx.com> | 2020-05-14 12:29:06 +0200 |
---|---|---|
committer | Axel Duch <axel.duch@nginx.com> | 2020-05-14 12:29:06 +0200 |
commit | ee1e248f4b038bb9e03fd78463da580af03c28f7 (patch) | |
tree | 7023ed63db7edb5fa616bc41a424b1a6c1e35046 /src/nxt_http_route.c | |
parent | 376d758dd72ac27f2bd5bb833ba68f5c9b531880 (diff) | |
download | unit-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.c | 278 |
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; } |