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