nghttpx: Add workaround to include ':' in backend pattern

This commit is contained in:
Tatsuhiro Tsujikawa 2020-11-27 22:15:46 +09:00
parent ffcdf5dfbc
commit 6787423edc
4 changed files with 61 additions and 5 deletions

View File

@ -1841,6 +1841,53 @@ StringRef normalize_path(BlockAllocator &balloc, const StringRef &path,
query); query);
} }
StringRef normalize_path_colon(BlockAllocator &balloc, const StringRef &path,
const StringRef &query) {
// First, decode %XX for unreserved characters and ':', then do
// http2::path_join
// We won't find %XX if length is less than 3.
if (path.size() < 3 ||
std::find(std::begin(path), std::end(path), '%') == std::end(path)) {
return path_join(balloc, StringRef{}, StringRef{}, path, query);
}
// includes last terminal NULL.
auto result = make_byte_ref(balloc, path.size() + 1);
auto p = result.base;
auto it = std::begin(path);
for (; it + 2 < std::end(path);) {
if (*it == '%') {
if (util::is_hex_digit(*(it + 1)) && util::is_hex_digit(*(it + 2))) {
auto c =
(util::hex_to_uint(*(it + 1)) << 4) + util::hex_to_uint(*(it + 2));
if (util::in_rfc3986_unreserved_chars(c) || c == ':') {
*p++ = c;
it += 3;
continue;
}
*p++ = '%';
*p++ = util::upcase(*(it + 1));
*p++ = util::upcase(*(it + 2));
it += 3;
continue;
}
}
*p++ = *it++;
}
p = std::copy(it, std::end(path), p);
*p = '\0';
return path_join(balloc, StringRef{}, StringRef{}, StringRef{result.base, p},
query);
}
std::string normalize_path(const StringRef &path, const StringRef &query) { std::string normalize_path(const StringRef &path, const StringRef &query) {
BlockAllocator balloc(1024, 1024); BlockAllocator balloc(1024, 1024);

View File

@ -410,6 +410,12 @@ StringRef to_method_string(int method_token);
StringRef normalize_path(BlockAllocator &balloc, const StringRef &path, StringRef normalize_path(BlockAllocator &balloc, const StringRef &path,
const StringRef &query); const StringRef &query);
// normalize_path_colon is like normalize_path, but it additionally
// does percent-decoding %3A in order to workaround the issue that ':'
// cannot be included in backend pattern.
StringRef normalize_path_colon(BlockAllocator &balloc, const StringRef &path,
const StringRef &query);
std::string normalize_path(const StringRef &path, const StringRef &query); std::string normalize_path(const StringRef &path, const StringRef &query);
StringRef rewrite_clean_path(BlockAllocator &balloc, const StringRef &src); StringRef rewrite_clean_path(BlockAllocator &balloc, const StringRef &src);

View File

@ -1877,8 +1877,11 @@ Connections:
affinity is enabled. affinity is enabled.
Since ";" and ":" are used as delimiter, <PATTERN> must Since ";" and ":" are used as delimiter, <PATTERN> must
not contain these characters. Since ";" has special not contain these characters. In order to include ":"
meaning in shell, the option value must be quoted. in <PATTERN>, one has to specify "%3A" (which is
percent-encoded from of ":") instead. Since ";" has
special meaning in shell, the option value must be
quoted.
Default: )" Default: )"
<< DEFAULT_DOWNSTREAM_HOST << "," << DEFAULT_DOWNSTREAM_PORT << R"( << DEFAULT_DOWNSTREAM_HOST << "," << DEFAULT_DOWNSTREAM_PORT << R"(

View File

@ -1109,9 +1109,9 @@ int parse_mapping(Config *config, DownstreamAddrConfig &addr,
*p = '\0'; *p = '\0';
pattern = StringRef{iov.base, p}; pattern = StringRef{iov.base, p};
} else { } else {
auto path = http2::normalize_path(downstreamconf.balloc, auto path = http2::normalize_path_colon(
StringRef{slash, std::end(raw_pattern)}, downstreamconf.balloc, StringRef{slash, std::end(raw_pattern)},
StringRef{}); StringRef{});
auto iov = make_byte_ref(downstreamconf.balloc, auto iov = make_byte_ref(downstreamconf.balloc,
std::distance(std::begin(raw_pattern), slash) + std::distance(std::begin(raw_pattern), slash) +
path.size() + 1); path.size() + 1);