Skip to content

Commit 97e8099

Browse files
committed
Make "*" method actually catch all methods, tweak priority order a bit
1 parent 85c6f0f commit 97e8099

File tree

3 files changed

+36
-22
lines changed

3 files changed

+36
-22
lines changed

src/HttpContext.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ struct HttpContext {
426426
/* Todo: This is ugly, fix */
427427
std::vector<std::string> methods;
428428
if (method == "*") {
429-
methods = httpContextData->currentRouter->upperCasedMethods;
429+
methods = {"*"};
430430
} else {
431431
methods = {method};
432432
}

src/HttpRouter.h

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@ namespace uWS {
3535

3636
template <class USERDATA>
3737
struct HttpRouter {
38-
/* These are public for now */
39-
std::vector<std::string> upperCasedMethods = {"GET", "POST", "HEAD", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE", "PATCH"};
38+
static constexpr std::string_view ANY_METHOD_TOKEN = "*";
4039
static const uint32_t HIGH_PRIORITY = 0xd0000000, MEDIUM_PRIORITY = 0xe0000000, LOW_PRIORITY = 0xf0000000;
4140

4241
private:
@@ -46,9 +45,6 @@ struct HttpRouter {
4645
/* Handler ids are 32-bit */
4746
static const uint32_t HANDLER_MASK = 0x0fffffff;
4847

49-
/* Methods and their respective priority */
50-
std::map<std::string, int> priority;
51-
5248
/* List of handlers */
5349
std::vector<MoveOnlyFunction<bool(HttpRouter *)>> handlers;
5450

@@ -245,10 +241,8 @@ struct HttpRouter {
245241

246242
public:
247243
HttpRouter() {
248-
int p = 0;
249-
for (std::string &method : upperCasedMethods) {
250-
priority[method] = p++;
251-
}
244+
/* Always have ANY route */
245+
getNode(&root, std::string(ANY_METHOD_TOKEN.data(), ANY_METHOD_TOKEN.length()), false);
252246
}
253247

254248
std::pair<int, std::string_view *> getParameters() {
@@ -269,12 +263,16 @@ struct HttpRouter {
269263
for (auto &p : root.children) {
270264
if (p->name == method) {
271265
/* Then route the url */
272-
return executeHandlers(p.get(), 0, userData);
266+
if (executeHandlers(p.get(), 0, userData)) {
267+
return true;
268+
} else {
269+
break;
270+
}
273271
}
274272
}
275273

276-
/* We did not find any handler for this method and url */
277-
return false;
274+
/* Always test any route last */
275+
return executeHandlers(root.children.back().get(), 0, userData);
278276
}
279277

280278
/* Adds the corresponding entires in matching tree and handler list */
@@ -299,6 +297,22 @@ struct HttpRouter {
299297
std::cerr << "Error: Internal routing error" << std::endl;
300298
std::abort();
301299
}
300+
301+
/* ANY method must be last, GET must be first */
302+
std::sort(root.children.begin(), root.children.end(), [](const auto &a, const auto &b) {
303+
/* Assuming the list of methods is unique, non-repeating */
304+
if (a->name == "GET") {
305+
return true;
306+
} else if (b->name == "GET") {
307+
return false;
308+
} else if (a->name == ANY_METHOD_TOKEN) {
309+
return false;
310+
} else if (b->name == ANY_METHOD_TOKEN) {
311+
return true;
312+
} else {
313+
return a->name < b->name;
314+
}
315+
});
302316
}
303317

304318
bool cullNode(Node *parent, Node *node, uint32_t handler) {

tests/HttpRouter.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ void testMethodPriority() {
88
uWS::HttpRouter<int> r;
99
std::string result;
1010

11-
r.add(r.upperCasedMethods, "/static/route", [&result](auto *) {
11+
r.add({"*"}, "/static/route", [&result](auto *) {
1212
std::cout << "ANY static route" << std::endl;
1313
result += "AS";
1414
return true;
@@ -26,9 +26,9 @@ void testMethodPriority() {
2626
return true;
2727
});
2828

29-
assert(r.route("nonsense", "/static/route") == false);
29+
assert(r.route("nonsense", "/static/route") == true);
3030
assert(r.route("GET", "/static") == false);
31-
assert(result == "");
31+
assert(result == "AS");
3232

3333
/* Should end up directly in ANY handler */
3434
result.clear();
@@ -51,7 +51,7 @@ void testPatternPriority() {
5151
uWS::HttpRouter<int> r;
5252
std::string result;
5353

54-
r.add(r.upperCasedMethods, "/a/b/c", [&result](auto *) {
54+
r.add({"*"}, "/a/b/c", [&result](auto *) {
5555
std::cout << "ANY static route" << std::endl;
5656
result += "AS";
5757
return false;
@@ -81,18 +81,18 @@ void testPatternPriority() {
8181
return false;
8282
});
8383

84-
r.add(r.upperCasedMethods, "/a/:b/c", [&result](auto *) {
84+
r.add({"*"}, "/a/:b/c", [&result](auto *) {
8585
std::cout << "ANY parameter route" << std::endl;
8686
result += "AP";
8787
return false;
8888
}, r.LOW_PRIORITY);
8989

9090
assert(r.route("POST", "/a/b/c") == false);
91-
assert(result == "ASPPAP");
91+
assert(result == "PPASAP");
9292

9393
result.clear();
9494
assert(r.route("GET", "/a/b/c") == false);
95-
assert(result == "GSASGPAPGW");
95+
assert(result == "GSGPGWASAP");
9696
}
9797

9898
void testUpgrade() {
@@ -224,7 +224,7 @@ void testBugReports() {
224224
}, r.MEDIUM_PRIORITY);
225225

226226
/* ANY on /* */
227-
r.add(r.upperCasedMethods, "/*", [&result](auto *) {
227+
r.add({"*"}, "/*", [&result](auto *) {
228228
result += "AW";
229229
return false;
230230
}, r.LOW_PRIORITY);
@@ -256,7 +256,7 @@ void testBugReports() {
256256
}, r.MEDIUM_PRIORITY);
257257

258258
/* ANY on /* */
259-
r.add(r.upperCasedMethods, "/*", [&result](auto *) {
259+
r.add({"*"}, "/*", [&result](auto *) {
260260
result += "AW";
261261
return false;
262262
}, r.LOW_PRIORITY);

0 commit comments

Comments
 (0)