Commit c2e4ed96 authored by Tatsuhiro Tsujikawa's avatar Tatsuhiro Tsujikawa

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.
parent d457f39b
......@@ -1003,37 +1003,55 @@ Connections:
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).
Optionally, if <PATTERN>s are given, the backend address
is only used if request matches the pattern. If -s, -p,
--client or --http2-bridge is used, <PATTERN>s are
ignored. The pattern matching is closely designed to
ServeMux in net/http package of Go programming language.
<PATTERN> consists of path, host + path or host. The
path must starts with "/". If it ends with "/", it
<PATTERN> 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
<PATTERN> 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 <PATTERN>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 <PATTERN> 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 <PATTERN>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 <PATTERN> are grouped together
forming load balancing group. Since ";" and ":" are
used as delimiter, <PATTERN> must not contain these
characters.
and -b'127.0.0.1,8080:www.nghttp2.org'.
The backend addresses sharing same <PATTERN> are grouped
together forming load balancing group. Since ";" and
":" are used as delimiter, <PATTERN> must not contain
these characters.
Default: )" << DEFAULT_DOWNSTREAM_HOST << ","
<< DEFAULT_DOWNSTREAM_PORT << R"(
-f, --frontend=<HOST>,<PORT>
......
......@@ -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
......
......@@ -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));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment