diff --git a/httplib.h b/httplib.h index a8bc856938..1b00586ce3 100644 --- a/httplib.h +++ b/httplib.h @@ -840,7 +840,6 @@ class PathParamsMatcher final : public MatcherBase { bool match(Request &request) const override; private: - 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 @@ -5887,6 +5886,8 @@ inline socket_t BufferStream::socket() const { return 0; } inline const std::string &BufferStream::get_buffer() const { return buffer; } inline PathParamsMatcher::PathParamsMatcher(const std::string &pattern) { + static constexpr char marker[] = "/:"; + // One past the last ending position of a path param substring std::size_t last_param_end = 0; @@ -5899,13 +5900,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 +5969,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