diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c index f8f738472..019de4343 100644 --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -1565,6 +1565,26 @@ ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) /* ~}| {zyx wvut srqp onml kjih gfed cba` */ 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + }; + + /* " ", "#", "%", "?", not allowed */ + + static uint32_t uri_path[] = { + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + + /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ + 0xd800002d, /* 1101 1000 0000 0000 0000 0000 0010 1101 */ + + /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ + 0x50000000, /* 0101 0000 0000 0000 0000 0000 0000 0000 */ + + /* ~}| {zyx wvut srqp onml kjih gfed cba` */ + 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ @@ -1634,7 +1654,7 @@ ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) /* mail_auth is the same as memcached */ static uint32_t *map[] = - { uri, args, uri_component, html, refresh, memcached, memcached }; + { uri, args, uri_component, html, refresh, memcached, memcached, uri_path }; escape = map[type]; diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h index 713eb42a7..0183ed71a 100644 --- a/src/core/ngx_string.h +++ b/src/core/ngx_string.h @@ -203,6 +203,7 @@ u_char *ngx_utf8_cpystrn(u_char *dst, u_char *src, size_t n, size_t len); #define NGX_ESCAPE_REFRESH 4 #define NGX_ESCAPE_MEMCACHED 5 #define NGX_ESCAPE_MAIL_AUTH 6 +#define NGX_ESCAPE_URI_PATH 7 #define NGX_UNESCAPE_URI 1 #define NGX_UNESCAPE_REDIRECT 2 diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 8d5385c1d..88016363d 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -1208,12 +1208,8 @@ ngx_http_proxy_create_key(ngx_http_request_t *r) loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0; - if (r->quoted_uri || r->internal) { - escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len, - r->uri.len - loc_len, NGX_ESCAPE_URI); - } else { - escape = 0; - } + escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len, + r->uri.len - loc_len, NGX_ESCAPE_URI_PATH); len = ctx->vars.uri.len + r->uri.len - loc_len + escape + sizeof("?") - 1 + r->args.len; @@ -1231,7 +1227,7 @@ ngx_http_proxy_create_key(ngx_http_request_t *r) if (escape) { ngx_escape_uri(p, r->uri.data + loc_len, - r->uri.len - loc_len, NGX_ESCAPE_URI); + r->uri.len - loc_len, NGX_ESCAPE_URI_PATH); p += r->uri.len - loc_len + escape; } else { @@ -1321,10 +1317,8 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0; - if (r->quoted_uri || r->internal) { - escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len, - r->uri.len - loc_len, NGX_ESCAPE_URI); - } + escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len, + r->uri.len - loc_len, NGX_ESCAPE_URI_PATH); uri_len = ctx->vars.uri.len + r->uri.len - loc_len + escape + sizeof("?") - 1 + r->args.len; @@ -1448,7 +1442,7 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) if (escape) { ngx_escape_uri(b->last, r->uri.data + loc_len, - r->uri.len - loc_len, NGX_ESCAPE_URI); + r->uri.len - loc_len, NGX_ESCAPE_URI_PATH); b->last += r->uri.len - loc_len + escape; } else { diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c index a45c04554..22afac00f 100644 --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -1295,7 +1295,7 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes) switch (ch) { #if (NGX_WIN32) case '\\': - if (u - 2 >= r->uri.data + if (u - r->uri.data >= 2 && *(u - 1) == '.' && *(u - 2) != '.') { u--; @@ -1319,7 +1319,7 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes) #endif case '/': #if (NGX_WIN32) - if (u - 2 >= r->uri.data + if (u - r->uri.data >= 2 && *(u - 1) == '.' && *(u - 2) != '.') { u--; @@ -1457,13 +1457,12 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes) case '/': case '?': case '#': - u -= 4; + u -= 3; for ( ;; ) { - if (u < r->uri.data) { + if (u <= r->uri.data) { return NGX_HTTP_PARSE_INVALID_REQUEST; } - if (*u == '/') { - u++; + if (u[-1] == '/') { break; } u--; @@ -1561,15 +1560,14 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes) u--; } else if (state == sw_dot_dot) { - u -= 4; + u -= 3; for ( ;; ) { - if (u < r->uri.data) { + if (u <= r->uri.data) { return NGX_HTTP_PARSE_INVALID_REQUEST; } - if (*u == '/') { - u++; + if (u[-1] == '/') { break; }