Skip to content

Commit 8710866

Browse files
Make matched route accessible via Request
1 parent 37399af commit 8710866

File tree

2 files changed

+64
-2
lines changed

2 files changed

+64
-2
lines changed

httplib.h

+13-2
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,7 @@ using Ranges = std::vector<Range>;
620620
struct Request {
621621
std::string method;
622622
std::string path;
623+
const char *matched_route = nullptr;
623624
Params params;
624625
Headers headers;
625626
std::string body;
@@ -871,10 +872,16 @@ namespace detail {
871872

872873
class MatcherBase {
873874
public:
875+
MatcherBase(std::string pattern) : pattern_(pattern) {}
874876
virtual ~MatcherBase() = default;
875877

878+
const std::string &pattern() const { return pattern_; }
879+
876880
// Match request path and populate its matches and
877881
virtual bool match(Request &request) const = 0;
882+
883+
private:
884+
std::string pattern_;
878885
};
879886

880887
/**
@@ -926,7 +933,8 @@ class PathParamsMatcher final : public MatcherBase {
926933
*/
927934
class RegexMatcher final : public MatcherBase {
928935
public:
929-
RegexMatcher(const std::string &pattern) : regex_(pattern) {}
936+
RegexMatcher(const std::string &pattern)
937+
: MatcherBase(pattern), regex_(pattern) {}
930938

931939
bool match(Request &request) const override;
932940

@@ -6084,7 +6092,8 @@ inline time_t BufferStream::duration() const { return 0; }
60846092

60856093
inline const std::string &BufferStream::get_buffer() const { return buffer; }
60866094

6087-
inline PathParamsMatcher::PathParamsMatcher(const std::string &pattern) {
6095+
inline PathParamsMatcher::PathParamsMatcher(const std::string &pattern)
6096+
: MatcherBase(pattern) {
60886097
static constexpr char marker[] = "/:";
60896098

60906099
// One past the last ending position of a path param substring
@@ -6987,6 +6996,7 @@ inline bool Server::dispatch_request(Request &req, Response &res,
69876996
const auto &handler = x.second;
69886997

69896998
if (matcher->match(req)) {
6999+
req.matched_route = matcher->pattern().c_str();
69907000
handler(req, res);
69917001
return true;
69927002
}
@@ -7107,6 +7117,7 @@ inline bool Server::dispatch_request_for_content_reader(
71077117
const auto &handler = x.second;
71087118

71097119
if (matcher->match(req)) {
7120+
req.matched_route = matcher->pattern().c_str();
71107121
handler(req, res, content_reader);
71117122
return true;
71127123
}

test/test.cc

+51
Original file line numberDiff line numberDiff line change
@@ -8468,3 +8468,54 @@ TEST(ClientInThreadTest, Issue2068) {
84688468
t.join();
84698469
}
84708470
}
8471+
8472+
TEST(MatchedRouteTest, BasicAndFileRequests) {
8473+
std::vector<std::string> paths{
8474+
"/route1/1/2",
8475+
"/route1/1",
8476+
};
8477+
std::vector<std::string> routes{
8478+
"/route1/:arg1/:arg2",
8479+
"/route1/:arg1",
8480+
};
8481+
8482+
Server svr;
8483+
svr.set_mount_point("/", "./www");
8484+
svr.Get("/route1/:arg1", [&](const Request & /*req*/, Response & /*res*/) {});
8485+
svr.Get("/route1/:arg1/:arg2",
8486+
[&](const Request & /*req*/, Response & /*res*/) {});
8487+
8488+
svr.set_post_routing_handler([&](const Request &req, Response & /*res*/) {
8489+
if (!routes.empty()) {
8490+
EXPECT_EQ(req.path, paths.back());
8491+
ASSERT_EQ(req.matched_route, routes.back());
8492+
paths.pop_back();
8493+
routes.pop_back();
8494+
} else {
8495+
EXPECT_EQ(req.path, "/file");
8496+
EXPECT_EQ(req.matched_route, nullptr);
8497+
}
8498+
});
8499+
8500+
auto listen_thread = std::thread([&svr]() { svr.listen(HOST, PORT); });
8501+
auto se = detail::scope_exit([&] {
8502+
svr.stop();
8503+
8504+
listen_thread.join();
8505+
8506+
ASSERT_FALSE(svr.is_running());
8507+
});
8508+
8509+
svr.wait_until_ready();
8510+
8511+
Client cli(HOST, PORT);
8512+
8513+
auto res = cli.Get("/route1/1");
8514+
ASSERT_TRUE(res);
8515+
8516+
res = cli.Get("/route1/1/2");
8517+
ASSERT_TRUE(res);
8518+
8519+
res = cli.Get("/file");
8520+
ASSERT_TRUE(res);
8521+
}

0 commit comments

Comments
 (0)