Skip to content
This repository was archived by the owner on Jul 4, 2025. It is now read-only.

Commit 54465b7

Browse files
committed
fix: better comparision for two url paths
1 parent 13d8341 commit 54465b7

File tree

3 files changed

+82
-4
lines changed

3 files changed

+82
-4
lines changed

engine/main.cc

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ void RunServer(std::optional<std::string> host, std::optional<int> port,
325325
auto handlers = drogon::app().getHandlersInfo();
326326
bool has_ep = [req, &handlers]() {
327327
for (auto const& h : handlers) {
328-
if (req->path() == std::get<0>(h))
328+
if (string_utils::AreUrlPathsEqual(req->path(), std::get<0>(h)))
329329
return true;
330330
}
331331
return false;
@@ -340,9 +340,12 @@ void RunServer(std::optional<std::string> host, std::optional<int> port,
340340
std::string supported_methods = [req, &handlers]() {
341341
std::string methods;
342342
for (auto const& h : handlers) {
343-
if (req->path() == std::get<0>(h)) {
344-
methods += drogon::to_string_view(std::get<1>(h));
345-
methods += ", ";
343+
if (string_utils::AreUrlPathsEqual(req->path(), std::get<0>(h))) {
344+
auto m = drogon::to_string_view(std::get<1>(h));
345+
if (methods.find(m) == std::string::npos) {
346+
methods += drogon::to_string_view(std::get<1>(h));
347+
methods += ", ";
348+
}
346349
}
347350
}
348351
if (methods.size() < 2)

engine/test/components/test_string_utils.cc

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,3 +289,50 @@ TEST_F(StringUtilsTestSuite, LargeInputPerformance) {
289289
}
290290

291291

292+
TEST_F(StringUtilsTestSuite, UrlPaths_SimilarStrings) {
293+
std::string str1 = "/v1/threads/{1}/messages/{2}";
294+
std::string str2 = "/v1/threads/xxx/messages/yyy";
295+
EXPECT_TRUE( AreUrlPathsEqual(str1, str2));
296+
}
297+
298+
TEST_F(StringUtilsTestSuite, UrlPaths_DifferentPaths) {
299+
std::string str1 = "/v1/threads/{1}/messages/{2}";
300+
std::string str2 = "/v1/threads/xxx/messages/yyy/extra";
301+
EXPECT_FALSE(AreUrlPathsEqual(str1, str2));
302+
}
303+
304+
TEST_F(StringUtilsTestSuite, UrlPaths_DifferentPlaceholderCounts) {
305+
std::string str1 = "/v1/threads/{1}/messages/{2}";
306+
std::string str2 = "/v1/threads/{1}/messages/{2}/{3}";
307+
EXPECT_FALSE(AreUrlPathsEqual(str1, str2));
308+
}
309+
310+
TEST_F(StringUtilsTestSuite, UrlPaths_NoPlaceholders) {
311+
std::string str1 = "/v1/threads/1/messages/2";
312+
std::string str2 = "/v1/threads/xxx/messages/yyy";
313+
EXPECT_FALSE(AreUrlPathsEqual(str1, str2));
314+
}
315+
316+
TEST_F(StringUtilsTestSuite, UrlPaths_EmptyStrings) {
317+
std::string str1 = "";
318+
std::string str2 = "";
319+
EXPECT_TRUE(AreUrlPathsEqual(str1, str2));
320+
}
321+
322+
TEST_F(StringUtilsTestSuite, UrlPaths_SinglePlaceholder) {
323+
std::string str1 = "/v1/threads/{1}";
324+
std::string str2 = "/v1/threads/xxx";
325+
EXPECT_TRUE(AreUrlPathsEqual(str1, str2));
326+
}
327+
328+
TEST_F(StringUtilsTestSuite, UrlPaths_MultiplePlaceholdersSameFormat) {
329+
std::string str1 = "/v1/threads/{1}/messages/{2}/comments/{3}";
330+
std::string str2 = "/v1/threads/xxx/messages/yyy/comments/zzz";
331+
EXPECT_TRUE(AreUrlPathsEqual(str1, str2));
332+
}
333+
334+
TEST_F(StringUtilsTestSuite, UrlPaths_NonPlaceholderDifferences) {
335+
std::string str1 = "/v1/threads/{1}/messages/{2}";
336+
std::string str2 = "/v2/threads/xxx/messages/yyy";
337+
EXPECT_FALSE(AreUrlPathsEqual(str1, str2));
338+
}

engine/utils/string_utils.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <cctype>
55
#include <chrono>
66
#include <iomanip>
7+
#include <regex>
78
#include <sstream>
89
#include <string>
910
#include <vector>
@@ -200,4 +201,31 @@ inline std::string EscapeJson(const std::string& s) {
200201
}
201202
return o.str();
202203
}
204+
205+
// Add a method to compares two url paths
206+
inline bool AreUrlPathsEqual(const std::string& path1,
207+
const std::string& path2) {
208+
auto has_placeholder = [](const std::string& s) {
209+
if (s.empty())
210+
return false;
211+
return s.find_first_of('{') < s.find_last_of('}');
212+
};
213+
std::vector<std::string> parts1 = SplitBy(path1, "/");
214+
std::vector<std::string> parts2 = SplitBy(path2, "/");
215+
216+
// Check if both strings have the same number of parts
217+
if (parts1.size() != parts2.size()) {
218+
return false;
219+
}
220+
221+
for (size_t i = 0; i < parts1.size(); ++i) {
222+
if (has_placeholder(parts1[i]) || has_placeholder(parts2[i]))
223+
continue;
224+
if (parts1[i] != parts2[i]) {
225+
return false;
226+
}
227+
}
228+
229+
return true;
230+
}
203231
} // namespace string_utils

0 commit comments

Comments
 (0)