feat(routing): implement router nesting
parent
2ce49a3347
commit
cf4451740f
|
@ -359,74 +359,24 @@ lnm_err lnm_http_router_merge(lnm_http_router *r1, lnm_http_router *r2) {
|
||||||
|
|
||||||
lnm_err lnm_http_router_nest(lnm_http_router *parent, lnm_http_router *child,
|
lnm_err lnm_http_router_nest(lnm_http_router *parent, lnm_http_router *child,
|
||||||
const char *prefix) {
|
const char *prefix) {
|
||||||
size_t prefix_len = strlen(prefix);
|
if (!is_ascii(prefix) || prefix[0] != '/') {
|
||||||
|
|
||||||
if (!is_ascii(prefix) || prefix[0] != '/' || prefix[prefix_len - 1] == '/') {
|
|
||||||
return lnm_err_invalid_route;
|
return lnm_err_invalid_route;
|
||||||
}
|
}
|
||||||
|
|
||||||
lnm_http_router *merge_target = parent;
|
lnm_http_router *router = parent;
|
||||||
|
|
||||||
// The child router's routes are also mounted on '/', so we stop one earlier
|
// 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 '/'
|
// as we need to merge it with the router representing the '/'
|
||||||
while (*(prefix + 1) != '\0') {
|
while (*prefix != '\0') {
|
||||||
unsigned char c = *prefix;
|
unsigned char c = *prefix;
|
||||||
|
|
||||||
if (merge_target->exact_children[c] == NULL) {
|
if (router->exact_children[c] == NULL) {
|
||||||
LNM_RES(lnm_http_router_init(&merge_target->exact_children[c]));
|
LNM_RES(lnm_http_router_init(&router->exact_children[c]));
|
||||||
}
|
}
|
||||||
|
|
||||||
merge_target = merge_target->exact_children[c];
|
router = router->exact_children[c];
|
||||||
prefix++;
|
prefix++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We check whether there are any conflicts between the child and the existing
|
return lnm_http_router_merge(router, child);
|
||||||
// router
|
|
||||||
bool conflicting = merge_target->single_segment_child != NULL &&
|
|
||||||
child->single_segment_child != NULL;
|
|
||||||
|
|
||||||
for (lnm_http_method m = 0; !conflicting && m < lnm_http_method_total; m++) {
|
|
||||||
conflicting =
|
|
||||||
conflicting ||
|
|
||||||
(merge_target->routes[m] != NULL && child->routes[m] != NULL) ||
|
|
||||||
(merge_target->multi_segment_routes[m] != NULL &&
|
|
||||||
child->multi_segment_routes[m] != NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned char c = 0; !conflicting && c < 128; c++) {
|
|
||||||
conflicting = conflicting || (merge_target->exact_children[c] != NULL &&
|
|
||||||
child->exact_children[c] != NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (conflicting) {
|
|
||||||
return lnm_err_overlapping_route;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge routers
|
|
||||||
merge_target->represents_route =
|
|
||||||
merge_target->represents_route || child->represents_route;
|
|
||||||
|
|
||||||
if (child->single_segment_child != NULL) {
|
|
||||||
merge_target->single_segment_child = child->single_segment_child;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (lnm_http_method m = 0; m < lnm_http_method_total; m++) {
|
|
||||||
if (child->routes[m] != NULL) {
|
|
||||||
merge_target->routes[m] = child->routes[m];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (child->multi_segment_routes[m] != NULL) {
|
|
||||||
merge_target->multi_segment_routes[m] = child->multi_segment_routes[m];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned char c = 0; c < 128; c++) {
|
|
||||||
if (child->exact_children[c] != NULL) {
|
|
||||||
merge_target->exact_children[c] = child->exact_children[c];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(child);
|
|
||||||
|
|
||||||
return lnm_err_ok;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,18 +80,17 @@ void test_routing_merge() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_routing_nest() {
|
void test_routing_nest() {
|
||||||
lnm_http_router *r1;
|
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(&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, r1, lnm_http_method_get, "/*key") == lnm_err_ok);
|
||||||
|
|
||||||
lnm_http_router *r2;
|
|
||||||
TEST_CHECK(lnm_http_router_init(&r2) == 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_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_nest(r2, r1, "/test") == lnm_err_ok);
|
||||||
|
|
||||||
lnm_http_route_match match;
|
|
||||||
TEST_CHECK(lnm_http_router_route(&match, r2, lnm_http_method_get, "/test/test_var/secondvar") == lnm_http_route_err_match);
|
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].start == 6);
|
||||||
TEST_CHECK(match.key_segments[0].len == 18);
|
TEST_CHECK(match.key_segments[0].len == 18);
|
||||||
|
@ -104,6 +103,6 @@ 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 merge", test_routing_merge },
|
||||||
/* { "routing nest", test_routing_nest }, */
|
{ "routing nest", test_routing_nest },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue