From c2e4ed96242ebdf69e8e0142558e98e5138da3f5 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 11 Jul 2015 12:43:48 +0900 Subject: [PATCH] nghttpx: Deal with the path without trailing slash on pattern match If pattern ends with '/', and pattern and path matches without that slash, we consider they match to deal with request to the directory without trailing slash. That is if pattern is "/foo/" and path is "/foo", we consider they match. --- src/shrpx.cc | 66 +++++++++++++++++++++++++--------------- src/shrpx_config.cc | 12 +++++++- src/shrpx_config_test.cc | 7 +++++ 3 files changed, 60 insertions(+), 25 deletions(-) diff --git a/src/shrpx.cc b/src/shrpx.cc index 8bfadbc3..c9524e25 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -1002,38 +1002,56 @@ Connections: Set backend host and port. The multiple backend addresses are accepted by repeating this option. UNIX domain socket can be specified by prefixing path name - with "unix:" (e.g., unix:/var/run/backend.sock). + with "unix:" (e.g., unix:/var/run/backend.sock). + Optionally, if s are given, the backend address is only used if request matches the pattern. If -s, -p, --client or --http2-bridge is used, s are ignored. The pattern matching is closely designed to ServeMux in net/http package of Go programming language. - consists of path, host + path or host. The - path must starts with "/". If it ends with "/", it + consists of path, host + path or just host. + The path must starts with "/". If it ends with "/", it matches to the request path whose prefix is the path. - If it does not end with "/", it performs exact match - against the request path. If host is given, it performs - exact match against the request host. If host alone is - given, "/" is appended to it, so that it matches all - paths under the host (e.g., specifying "nghttp2.org" - equals to "nghttp2.org/"). Longer patterns take - precedence over shorter ones, breaking a tie by the - order of the appearance in the configuration. If - is omitted, "/" is used as pattern, which - matches all paths (catch-all pattern). For example, - -b'127.0.0.1,8080;nghttp2.org/httpbin/' matches the - request host "nghttp2.org" and the request path - "/httpbin/get", but does not match the request host - "nghttp2.org" and the request path "/index.html". The - multiple s can be specified, delimiting them by - ":". Specifying + To deal with the request to the directory without + trailing slash, pattern which ends with "/" also matches + the path if pattern == path + "/" (e.g., pattern "/foo/" + matches path "/foo"). If it does not end with "/", it + performs exact match against the request path. If host + is given, it performs exact match against the request + host. If host alone is given, "/" is appended to it, so + that it matches all paths under the host (e.g., + specifying "nghttp2.org" equals to "nghttp2.org/"). + + Longer patterns take precedence over shorter ones, + breaking a tie by the order of the appearance in the + configuration. + + If is omitted, "/" is used as pattern, which + matches all paths (catch-all pattern). The catch-all + backend must be given. + + When doing a match, nghttpx made some normalization to + pattern, request host and path. For host part, they are + converted to lower case. For path part, percent-encoded + unreserved characters defined in RFC 3986 are decoded, + and any dot-segments (".." and ".") are resolved and + removed. + + For example, -b'127.0.0.1,8080;nghttp2.org/httpbin/' + matches the request host "nghttp2.org" and the request + path "/httpbin/get", but does not match the request host + "nghttp2.org" and the request path "/index.html". + + The multiple s can be specified, delimiting + them by ":". Specifying -b'127.0.0.1,8080;nghttp2.org:www.nghttp2.org' has the same effect to specify -b'127.0.0.1,8080;nghttp2.org' - and -b'127.0.0.1,8080:www.nghttp2.org'. The backend - addresses sharing same are grouped together - forming load balancing group. Since ";" and ":" are - used as delimiter, must not contain these - characters. + and -b'127.0.0.1,8080:www.nghttp2.org'. + + The backend addresses sharing same are grouped + together forming load balancing group. Since ";" and + ":" are used as delimiter, must not contain + these characters. Default: )" << DEFAULT_DOWNSTREAM_HOST << "," << DEFAULT_DOWNSTREAM_PORT << R"( -f, --frontend=, diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index 5ea100f4..66b10ccf 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -1402,7 +1402,17 @@ bool path_match(const std::string &pattern, const std::string &path) { if (pattern.back() != '/') { return pattern == path; } - return util::startsWith(path, pattern); + + if (util::startsWith(path, pattern)) { + return true; + } + + // If pattern ends with '/', and pattern and path matches without + // that slash, we consider they match to deal with request to the + // directory without trailing slash. That is if pattern is "/foo/" + // and path is "/foo", we consider they match. + return util::streq(std::begin(path), path.size(), std::begin(pattern), + pattern.size() - 1); } } // namespace diff --git a/src/shrpx_config_test.cc b/src/shrpx_config_test.cc index 4f21fc48..9f458d43 100644 --- a/src/shrpx_config_test.cc +++ b/src/shrpx_config_test.cc @@ -192,6 +192,13 @@ void test_shrpx_config_match_downstream_addr_group(void) { CU_ASSERT(4 == match_downstream_addr_group("WWW.nghttp2.org", "/alpha", groups, 255)); + CU_ASSERT(1 == match_downstream_addr_group("nghttp2.org", "/alpha/bravo/", + groups, 255)); + + // /alpha/bravo also matches /alpha/bravo/ + CU_ASSERT(1 == match_downstream_addr_group("nghttp2.org", "/alpha/bravo", + groups, 255)); + // path part is case-sensitive CU_ASSERT(0 == match_downstream_addr_group("nghttp2.org", "/Alpha/bravo", groups, 255));