Skip to content

Commit

Permalink
nghttpx: Add workaround to include ':' in backend pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
tatsuhiro-t committed Nov 27, 2020
1 parent ffcdf5d commit 6787423
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 5 deletions.
47 changes: 47 additions & 0 deletions src/http2.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1841,6 +1841,53 @@ StringRef normalize_path(BlockAllocator &balloc, const StringRef &path,
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) {
BlockAllocator balloc(1024, 1024);

Expand Down
6 changes: 6 additions & 0 deletions src/http2.h
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,12 @@ StringRef to_method_string(int method_token);
StringRef normalize_path(BlockAllocator &balloc, const StringRef &path,
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);

StringRef rewrite_clean_path(BlockAllocator &balloc, const StringRef &src);
Expand Down
7 changes: 5 additions & 2 deletions src/shrpx.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1877,8 +1877,11 @@ void print_help(std::ostream &out) {
affinity is enabled.
Since ";" and ":" are used as delimiter, <PATTERN> must
not contain these characters. Since ";" has special
meaning in shell, the option value must be quoted.
not contain these characters. In order to include ":"
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_DOWNSTREAM_HOST << "," << DEFAULT_DOWNSTREAM_PORT << R"(
Expand Down
6 changes: 3 additions & 3 deletions src/shrpx_config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1109,9 +1109,9 @@ int parse_mapping(Config *config, DownstreamAddrConfig &addr,
*p = '\0';
pattern = StringRef{iov.base, p};
} else {
auto path = http2::normalize_path(downstreamconf.balloc,
StringRef{slash, std::end(raw_pattern)},
StringRef{});
auto path = http2::normalize_path_colon(
downstreamconf.balloc, StringRef{slash, std::end(raw_pattern)},
StringRef{});
auto iov = make_byte_ref(downstreamconf.balloc,
std::distance(std::begin(raw_pattern), slash) +
path.size() + 1);
Expand Down

0 comments on commit 6787423

Please sign in to comment.