diff options
-rw-r--r-- | src/nxt_conf_validation.c | 117 | ||||
-rw-r--r-- | src/nxt_http_route.c | 278 | ||||
-rw-r--r-- | src/nxt_string.c | 43 | ||||
-rw-r--r-- | src/nxt_string.h | 3 |
4 files changed, 381 insertions, 60 deletions
diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c index 0f46560d..a7a8d139 100644 --- a/src/nxt_conf_validation.c +++ b/src/nxt_conf_validation.c @@ -85,6 +85,16 @@ static nxt_int_t nxt_conf_vldt_routes_member(nxt_conf_validation_t *vldt, nxt_str_t *name, nxt_conf_value_t *value); static nxt_int_t nxt_conf_vldt_route(nxt_conf_validation_t *vldt, nxt_conf_value_t *value); +static nxt_int_t nxt_conf_vldt_match_encoded_patterns_sets( + nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data); +static nxt_int_t nxt_conf_vldt_match_encoded_patterns_set( + nxt_conf_validation_t *vldt, nxt_conf_value_t *value); +static nxt_int_t nxt_conf_vldt_match_encoded_patterns_set_member( + nxt_conf_validation_t *vldt, nxt_str_t *name, nxt_conf_value_t *value); +static nxt_int_t nxt_conf_vldt_match_encoded_patterns( + nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data); +static nxt_int_t nxt_conf_vldt_match_encoded_pattern( + nxt_conf_validation_t *vldt, nxt_conf_value_t *value); static nxt_int_t nxt_conf_vldt_match_patterns(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data); static nxt_int_t nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt, @@ -343,12 +353,12 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_match_members[] = { { nxt_string("uri"), NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, - &nxt_conf_vldt_match_patterns, + &nxt_conf_vldt_match_encoded_patterns, NULL }, { nxt_string("arguments"), NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY, - &nxt_conf_vldt_match_patterns_sets, + &nxt_conf_vldt_match_encoded_patterns_sets, NULL }, { nxt_string("headers"), @@ -1379,6 +1389,109 @@ nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt, } +static nxt_int_t nxt_conf_vldt_match_encoded_patterns_sets( + nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data) +{ + if (nxt_conf_type(value) == NXT_CONF_ARRAY) { + return nxt_conf_vldt_array_iterator(vldt, value, + &nxt_conf_vldt_match_encoded_patterns_set); + } + + /* NXT_CONF_STRING */ + + return nxt_conf_vldt_match_encoded_patterns_set(vldt, value); +} + + +static nxt_int_t nxt_conf_vldt_match_encoded_patterns_set( + nxt_conf_validation_t *vldt, nxt_conf_value_t *value) +{ + if (nxt_conf_type(value) != NXT_CONF_OBJECT) { + return nxt_conf_vldt_error(vldt, "The \"match\" pattern for " + "\"arguments\" must be an object."); + } + + return nxt_conf_vldt_object_iterator(vldt, value, + &nxt_conf_vldt_match_encoded_patterns_set_member); +} + + +static nxt_int_t +nxt_conf_vldt_match_encoded_patterns_set_member(nxt_conf_validation_t *vldt, + nxt_str_t *name, nxt_conf_value_t *value) +{ + u_char *p, *end; + + if (nxt_slow_path(name->length == 0)) { + return nxt_conf_vldt_error(vldt, "The \"match\" pattern objects must " + "not contain empty member names."); + } + + p = nxt_mp_nget(vldt->pool, name->length); + if (nxt_slow_path(p == NULL)) { + return NXT_ERROR; + } + + end = nxt_decode_uri(p, name->start, name->length); + if (nxt_slow_path(end == NULL)) { + return nxt_conf_vldt_error(vldt, "The \"match\" pattern for " + "\"arguments\" is encoded but is invalid."); + } + + return nxt_conf_vldt_match_encoded_patterns(vldt, value, NULL); +} + + +static nxt_int_t +nxt_conf_vldt_match_encoded_patterns(nxt_conf_validation_t *vldt, + nxt_conf_value_t *value, void *data) +{ + if (nxt_conf_type(value) == NXT_CONF_ARRAY) { + return nxt_conf_vldt_array_iterator(vldt, value, + &nxt_conf_vldt_match_encoded_pattern); + } + + /* NXT_CONF_STRING */ + + return nxt_conf_vldt_match_encoded_pattern(vldt, value); +} + + +static nxt_int_t +nxt_conf_vldt_match_encoded_pattern(nxt_conf_validation_t *vldt, + nxt_conf_value_t *value) +{ + u_char *p, *end; + nxt_int_t ret; + nxt_str_t pattern; + + if (nxt_conf_type(value) != NXT_CONF_STRING) { + return nxt_conf_vldt_error(vldt, "The \"match\" pattern for \"uri\" " + "must be a string."); + } + + ret = nxt_conf_vldt_match_pattern(vldt, value); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + + nxt_conf_get_string(value, &pattern); + + p = nxt_mp_nget(vldt->pool, pattern.length); + if (nxt_slow_path(p == NULL)) { + return NXT_ERROR; + } + + end = nxt_decode_uri(p, pattern.start, pattern.length); + if (nxt_slow_path(end == NULL)) { + return nxt_conf_vldt_error(vldt, "The \"match\" pattern for \"uri\" " + "is encoded but is invalid."); + } + + return NXT_OK; +} + + static nxt_int_t nxt_conf_vldt_match_addrs(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data) 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; } diff --git a/src/nxt_string.c b/src/nxt_string.c index 54f96abc..ab568990 100644 --- a/src/nxt_string.c +++ b/src/nxt_string.c @@ -475,7 +475,7 @@ nxt_strvers_match(u_char *version, u_char *prefix, size_t length) } -static const uint8_t nxt_hex2int[256] +const uint8_t nxt_hex2int[256] nxt_aligned(32) = { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, @@ -551,6 +551,47 @@ nxt_decode_uri(u_char *dst, u_char *src, size_t length) } +u_char * +nxt_decode_uri_plus(u_char *dst, u_char *src, size_t length) +{ + u_char *end, ch; + uint8_t d0, d1; + + nxt_prefetch(&nxt_hex2int['0']); + + end = src + length; + + while (src < end) { + ch = *src++; + + switch (ch) { + case '%': + if (nxt_slow_path(end - src < 2)) { + return NULL; + } + + d0 = nxt_hex2int[*src++]; + d1 = nxt_hex2int[*src++]; + + if (nxt_slow_path((d0 | d1) >= 16)) { + return NULL; + } + + ch = (d0 << 4) + d1; + break; + + case '+': + ch = ' '; + break; + } + + *dst++ = ch; + } + + return dst; +} + + uintptr_t nxt_encode_uri(u_char *dst, u_char *src, size_t length) { diff --git a/src/nxt_string.h b/src/nxt_string.h index 7863c60e..7d1e044d 100644 --- a/src/nxt_string.h +++ b/src/nxt_string.h @@ -174,10 +174,13 @@ NXT_EXPORT nxt_bool_t nxt_strvers_match(u_char *version, u_char *prefix, size_t length); NXT_EXPORT u_char *nxt_decode_uri(u_char *dst, u_char *src, size_t length); +NXT_EXPORT u_char *nxt_decode_uri_plus(u_char *dst, u_char *src, size_t length); NXT_EXPORT uintptr_t nxt_encode_uri(u_char *dst, u_char *src, size_t length); NXT_EXPORT uintptr_t nxt_encode_complex_uri(u_char *dst, u_char *src, size_t length); NXT_EXPORT nxt_bool_t nxt_is_complex_uri_encoded(u_char *s, size_t length); +NXT_EXPORT const uint8_t nxt_hex2int[256]; + #endif /* _NXT_STRING_H_INCLUDED_ */ |