Compare commits
No commits in common. "cf4451740f24f6a1a9fcff50fcd8dd7c089a7ca8" and "6eb965adcd90f80fefae53b8c07919ad22d87c20" have entirely different histories.
cf4451740f
...
6eb965adcd
|
@ -49,23 +49,11 @@ lnm_err lnm_http_router_add(lnm_http_route **out, lnm_http_router *http_router,
|
||||||
lnm_http_method method, const char *path);
|
lnm_http_method method, const char *path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether the two routers have any conflicting parts.
|
* Add all of the child router's routes to the parent router, under the given
|
||||||
|
* route prefix.
|
||||||
*/
|
*/
|
||||||
bool lnm_http_router_conflicts(const lnm_http_router *r1,
|
lnm_err lnm_http_router_nest(lnm_http_router *parent,
|
||||||
const lnm_http_router *r2);
|
const lnm_http_router *child, const char *prefix);
|
||||||
|
|
||||||
/**
|
|
||||||
* Merge two routers, with the result ending up in r1. This is equivalent to
|
|
||||||
* nesting a router on '/'.
|
|
||||||
*/
|
|
||||||
lnm_err lnm_http_router_merge(lnm_http_router *r1, lnm_http_router *r2);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Integrate the child router into the parent routing, mounting its paths on the
|
|
||||||
* given prefix.
|
|
||||||
*/
|
|
||||||
lnm_err lnm_http_router_nest(lnm_http_router *parent, lnm_http_router *child,
|
|
||||||
const char *prefix);
|
|
||||||
|
|
||||||
lnm_http_route_err lnm_http_router_route(lnm_http_route_match *out,
|
lnm_http_route_err lnm_http_router_route(lnm_http_route_match *out,
|
||||||
const lnm_http_router *router,
|
const lnm_http_router *router,
|
||||||
|
|
|
@ -28,7 +28,6 @@ void lnm_http_router_free(lnm_http_router *router) {
|
||||||
|
|
||||||
for (size_t i = 0; i < lnm_http_method_total; i++) {
|
for (size_t i = 0; i < lnm_http_method_total; i++) {
|
||||||
lnm_http_route_free(router->routes[i]);
|
lnm_http_route_free(router->routes[i]);
|
||||||
lnm_http_route_free(router->multi_segment_routes[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(router);
|
free(router);
|
||||||
|
@ -288,95 +287,3 @@ lnm_http_route_match_get(lnm_http_route_match *match, const char *key) {
|
||||||
|
|
||||||
return &match->key_segments[trie->index];
|
return &match->key_segments[trie->index];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lnm_http_router_conflicts(const lnm_http_router *r1,
|
|
||||||
const lnm_http_router *r2) {
|
|
||||||
// First check the literal routes for the routers
|
|
||||||
for (lnm_http_method m = 0; m < lnm_http_method_total; m++) {
|
|
||||||
if ((r1->routes[m] != NULL && r2->routes[m] != NULL) ||
|
|
||||||
(r1->multi_segment_routes[m] != NULL &&
|
|
||||||
r2->multi_segment_routes[m] != NULL)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((r1->single_segment_child != NULL && r2->single_segment_child != NULL) &&
|
|
||||||
lnm_http_router_conflicts(r1->single_segment_child,
|
|
||||||
r2->single_segment_child)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned char c = 0; c < 128; c++) {
|
|
||||||
if ((r1->exact_children[c] != NULL && r2->exact_children[c] != NULL) &&
|
|
||||||
lnm_http_router_conflicts(r1->exact_children[c],
|
|
||||||
r2->exact_children[c])) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void __lnm_http_router_merge(lnm_http_router *r1, lnm_http_router *r2) {
|
|
||||||
for (lnm_http_method m = 0; m < lnm_http_method_total; m++) {
|
|
||||||
if (r2->routes[m] != NULL) {
|
|
||||||
r1->routes[m] = r2->routes[m];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r2->multi_segment_routes[m] != NULL) {
|
|
||||||
r1->multi_segment_routes[m] = r2->multi_segment_routes[m];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r1->single_segment_child != NULL && r2->single_segment_child != NULL) {
|
|
||||||
__lnm_http_router_merge(r1->single_segment_child, r2->single_segment_child);
|
|
||||||
} else if (r2->single_segment_child != NULL) {
|
|
||||||
r1->single_segment_child = r2->single_segment_child;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned char c = 0; c < 128; c++) {
|
|
||||||
if (r1->exact_children[c] != NULL && r2->exact_children[c] != NULL) {
|
|
||||||
__lnm_http_router_merge(r1->exact_children[c], r2->exact_children[c]);
|
|
||||||
} else if (r2->exact_children[c] != NULL) {
|
|
||||||
r1->exact_children[c] = r2->exact_children[c];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
r1->represents_route = r1->represents_route || r2->represents_route;
|
|
||||||
|
|
||||||
free(r2);
|
|
||||||
}
|
|
||||||
|
|
||||||
lnm_err lnm_http_router_merge(lnm_http_router *r1, lnm_http_router *r2) {
|
|
||||||
if (lnm_http_router_conflicts(r1, r2)) {
|
|
||||||
return lnm_err_overlapping_route;
|
|
||||||
}
|
|
||||||
|
|
||||||
__lnm_http_router_merge(r1, r2);
|
|
||||||
|
|
||||||
return lnm_err_ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
lnm_err lnm_http_router_nest(lnm_http_router *parent, lnm_http_router *child,
|
|
||||||
const char *prefix) {
|
|
||||||
if (!is_ascii(prefix) || prefix[0] != '/') {
|
|
||||||
return lnm_err_invalid_route;
|
|
||||||
}
|
|
||||||
|
|
||||||
lnm_http_router *router = parent;
|
|
||||||
|
|
||||||
// The child router's routes are also mounted on '/', so we stop one earlier
|
|
||||||
// as we need to merge it with the router representing the '/'
|
|
||||||
while (*prefix != '\0') {
|
|
||||||
unsigned char c = *prefix;
|
|
||||||
|
|
||||||
if (router->exact_children[c] == NULL) {
|
|
||||||
LNM_RES(lnm_http_router_init(&router->exact_children[c]));
|
|
||||||
}
|
|
||||||
|
|
||||||
router = router->exact_children[c];
|
|
||||||
prefix++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return lnm_http_router_merge(router, child);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
#include "lnm/common.h"
|
|
||||||
#include "lnm/http/route.h"
|
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
|
|
||||||
#include "lnm/http/loop.h"
|
#include "lnm/http/loop.h"
|
||||||
|
@ -53,56 +51,10 @@ void test_routing_star() {
|
||||||
TEST_CHECK(lnm_http_router_route(&match, router, lnm_http_method_get, "/hello/world") == lnm_http_route_err_match);
|
TEST_CHECK(lnm_http_router_route(&match, router, lnm_http_method_get, "/hello/world") == lnm_http_route_err_match);
|
||||||
TEST_CHECK(match.key_segments[0].start == 1);
|
TEST_CHECK(match.key_segments[0].start == 1);
|
||||||
TEST_CHECK(match.key_segments[0].len == 11);
|
TEST_CHECK(match.key_segments[0].len == 11);
|
||||||
|
|
||||||
lnm_http_router_free(router);
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_routing_merge() {
|
|
||||||
lnm_http_router *rtr1, *rtr2;
|
|
||||||
lnm_http_route *rt1, *rt2;
|
|
||||||
lnm_http_route_match match;
|
|
||||||
|
|
||||||
TEST_CHECK(lnm_http_router_init(&rtr1) == lnm_err_ok);
|
|
||||||
TEST_CHECK(lnm_http_router_init(&rtr2) == lnm_err_ok);
|
|
||||||
|
|
||||||
TEST_CHECK(lnm_http_router_add(&rt1, rtr1, lnm_http_method_get, "/*key") == lnm_err_ok);
|
|
||||||
TEST_CHECK(lnm_http_router_add(NULL, rtr1, lnm_http_method_get, "/:key/hello") == lnm_err_ok);
|
|
||||||
TEST_CHECK(lnm_http_router_add(&rt2, rtr2, lnm_http_method_get, "/test2") == lnm_err_ok);
|
|
||||||
TEST_CHECK(lnm_http_router_add(NULL, rtr2, lnm_http_method_get, "/:key/hello2") == lnm_err_ok);
|
|
||||||
|
|
||||||
TEST_CHECK(lnm_http_router_merge(rtr1, rtr2) == lnm_err_ok);
|
|
||||||
|
|
||||||
TEST_CHECK(lnm_http_router_route(&match, rtr1, lnm_http_method_get, "/some/thing") == lnm_http_route_err_match);
|
|
||||||
TEST_CHECK(match.route == rt1);
|
|
||||||
|
|
||||||
TEST_CHECK(lnm_http_router_route(&match, rtr1, lnm_http_method_get, "/test2") == lnm_http_route_err_match);
|
|
||||||
TEST_CHECK(match.route == rt2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_routing_nest() {
|
|
||||||
lnm_http_router *r1, *r2;
|
|
||||||
lnm_http_route_match match;
|
|
||||||
|
|
||||||
TEST_CHECK(lnm_http_router_init(&r1) == lnm_err_ok);
|
|
||||||
TEST_CHECK(lnm_http_router_init(&r2) == lnm_err_ok);
|
|
||||||
|
|
||||||
TEST_CHECK(lnm_http_router_add(NULL, r1, lnm_http_method_get, "/*key") == lnm_err_ok);
|
|
||||||
TEST_CHECK(lnm_http_router_add(NULL, r2, lnm_http_method_get, "/test/test2") == lnm_err_ok);
|
|
||||||
|
|
||||||
TEST_CHECK(lnm_http_router_nest(r2, r1, "/test") == lnm_err_ok);
|
|
||||||
|
|
||||||
TEST_CHECK(lnm_http_router_route(&match, r2, lnm_http_method_get, "/test/test_var/secondvar") == lnm_http_route_err_match);
|
|
||||||
TEST_CHECK(match.key_segments[0].start == 6);
|
|
||||||
TEST_CHECK(match.key_segments[0].len == 18);
|
|
||||||
|
|
||||||
TEST_CHECK(lnm_http_router_route(&match, r2, lnm_http_method_get, "/test/test2") == lnm_http_route_err_match);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_LIST = {
|
TEST_LIST = {
|
||||||
{ "routing simple", test_routing_simple },
|
{ "routing simple", test_routing_simple },
|
||||||
{ "routing star", test_routing_star },
|
{ "routing star", test_routing_star },
|
||||||
{ "routing merge", test_routing_merge },
|
|
||||||
{ "routing nest", test_routing_nest },
|
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue