Skip to content

Commit b5744db

Browse files
committed
fix: router endpoint match
1 parent 9c85f7b commit b5744db

File tree

3 files changed

+50
-17
lines changed

3 files changed

+50
-17
lines changed

src/router/router.cpp

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,25 +21,34 @@ Router::Router(const std::map<std::string, RouteConfig>& routes)
2121
{
2222
}
2323

24-
// Returns the length of the matching prefix between request_path and route_path
25-
static size_t prefix_length(const std::string& request_path, const std::string& route_path)
24+
static bool route_matches(const std::string& request_path, const std::string& route)
2625
{
27-
if (route_path == "/")
28-
return 1;
26+
if (route == "/")
27+
return true;
2928

30-
if (request_path.size() < route_path.size())
31-
return 0;
29+
if (request_path.size() < route.size())
30+
return false;
31+
32+
// Check if prefix matches
33+
if (request_path.compare(0, route.size(), route) != 0)
34+
return false;
3235

33-
if (request_path.compare(0, route_path.size(), route_path) != 0)
34-
return 0;
36+
// Check for exact match
37+
if (request_path.size() == route.size())
38+
return true;
3539

36-
if (request_path.size() == route_path.size())
37-
return route_path.size();
40+
assert(route[0] == '/');
41+
assert(route.size() > 1 && "At this point we must have matched more than just '/'");
3842

39-
if (request_path[route_path.size()] == '/')
40-
return route_path.size();
43+
// Directory match
44+
if (route[route.size() - 1] == '/')
45+
return true;
4146

42-
return 0;
47+
// Endpoint match, ensure boundary
48+
if (request_path[route.size()] == '/')
49+
return true;
50+
51+
return false;
4352
}
4453

4554
// for the moment it takes some static input
@@ -54,7 +63,9 @@ const RouteConfig& Router::find_best_route(const std::string& request_path) cons
5463
for (std::map<std::string, RouteConfig>::const_iterator it = routes_.begin();
5564
it != routes_.end();
5665
++it) {
57-
size_t match_len = prefix_length(request_path, it->first);
66+
67+
std::string route_path = it->second.path;
68+
size_t match_len = route_matches(request_path, route_path) ? route_path.size() : 0;
5869
if (match_len > best_len) {
5970
best_len = match_len;
6071
best = &it->second;
@@ -68,15 +79,13 @@ const RouteConfig& Router::find_best_route(const std::string& request_path) cons
6879
// This seems to be valid in some cases but we ignore it right now.
6980
static bool is_cgi_request(const HttpRequest& request, const RouteConfig& route)
7081
{
71-
LOG(DEBUG) << "shared.ext" << route.shared.cgi.extension;
7282
if (route.shared.cgi.extension.empty())
7383
return false;
7484

7585
size_t dot = request.path.find_last_of(".");
7686
if (dot == std::string::npos)
7787
return false;
78-
std::string ext = request.path.substr(dot);
79-
LOG(DEBUG) << "ext = " << ext;
88+
std::string ext = request.path.substr(dot);
8089
return request.path.substr(dot) == route.shared.cgi.extension;
8190
}
8291

tests/config/router_unittest.conf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,8 @@ server {
2222
allow_uploads on;
2323
upload_store /tmp/store;
2424
}
25+
26+
location /cgi-bin/ {
27+
cgi_allow_methods GET POST;
28+
}
2529
}

tests/router_unittest.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,26 @@ UTEST(RouterTest, MatchesDirectoryWithTrailingSlash)
7171
ASSERT_STREQ("/files", result.c_str());
7272
}
7373

74+
UTEST(RouterTest, MatchesSubdirectory)
75+
{
76+
HttpConfig conf = make_unittest_config();
77+
Router router(conf.servers[0].locations);
78+
std::string request_path = "/cgi-bin/upload.php";
79+
std::string result = router.find_best_route(request_path).path;
80+
81+
ASSERT_STREQ("/cgi-bin/", result.c_str());
82+
}
83+
84+
UTEST(RouterTest, DoesNotMatchEndpointWithoutBoundary)
85+
{
86+
HttpConfig conf = make_unittest_config();
87+
Router router(conf.servers[0].locations);
88+
std::string request_path = "/uploading/file.txt";
89+
std::string result = router.find_best_route(request_path).path;
90+
91+
ASSERT_STREQ("/", result.c_str());
92+
}
93+
7494
UTEST(RouterTest, MatchesDirectoryWithMutlipleLeadingSlashes)
7595
{
7696
UTEST_SKIP("TODO: IMPLEMENT THIS FEATURE");

0 commit comments

Comments
 (0)