From 74643c8c97d9badbdc7c86f2d472803ec8d401f7 Mon Sep 17 00:00:00 2001 From: Bogdan Guliaev Date: Fri, 6 Sep 2024 09:45:42 +0300 Subject: [PATCH] Only match path params that span full path segment --- httplib.h | 11 ++++++----- test/test.cc | 12 ++++++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/httplib.h b/httplib.h index a8bc856938..9e59534dda 100644 --- a/httplib.h +++ b/httplib.h @@ -840,7 +840,7 @@ class PathParamsMatcher final : public MatcherBase { bool match(Request &request) const override; private: - static constexpr char marker = ':'; + static constexpr char marker[] = "/:"; // Treat segment separators as the end of path parameter capture // Does not need to handle query parameters as they are parsed before path // matching @@ -5899,13 +5899,14 @@ inline PathParamsMatcher::PathParamsMatcher(const std::string &pattern) { #endif while (true) { - const auto marker_pos = pattern.find(marker, last_param_end); + const auto marker_pos = pattern.find( + marker, last_param_end == 0 ? last_param_end : last_param_end - 1); if (marker_pos == std::string::npos) { break; } static_fragments_.push_back( - pattern.substr(last_param_end, marker_pos - last_param_end)); + pattern.substr(last_param_end, marker_pos - last_param_end + 1)); - const auto param_name_start = marker_pos + 1; + const auto param_name_start = marker_pos + 2; auto sep_pos = pattern.find(separator, param_name_start); if (sep_pos == std::string::npos) { sep_pos = pattern.length(); } @@ -5967,7 +5968,7 @@ inline bool PathParamsMatcher::match(Request &request) const { request.path_params.emplace( param_name, request.path.substr(starting_pos, sep_pos - starting_pos)); - // Mark everythin up to '/' as matched + // Mark everything up to '/' as matched starting_pos = sep_pos + 1; } // Returns false if the path is longer than the pattern diff --git a/test/test.cc b/test/test.cc index b42463408d..5c6ceefe06 100644 --- a/test/test.cc +++ b/test/test.cc @@ -7599,6 +7599,18 @@ TEST(PathParamsTest, SequenceOfParams) { EXPECT_EQ(request.path_params, expected_params); } +TEST(PathParamsTest, SemicolonInTheMiddleIsNotAParam) { + const auto pattern = "/prefix:suffix"; + detail::PathParamsMatcher matcher(pattern); + + Request request; + request.path = "/prefix:suffix"; + ASSERT_TRUE(matcher.match(request)); + + const std::unordered_map expected_params = {}; + EXPECT_EQ(request.path_params, expected_params); +} + TEST(UniversalClientImplTest, Ipv6LiteralAddress) { // If ipv6 regex working, regex match codepath is taken. // else port will default to 80 in Client impl