feat(routing): multi-segment wildcard matches
							parent
							
								
									3ae1b62dd0
								
							
						
					
					
						commit
						115bf74456
					
				|  | @ -23,6 +23,25 @@ lnm_http_step_err print_step(lnm_http_conn *conn) { | |||
|   return lnm_http_step_err_done; | ||||
| } | ||||
| 
 | ||||
| lnm_http_step_err print_step2(lnm_http_conn *conn) { | ||||
|   lnm_http_loop_ctx *ctx = conn->ctx; | ||||
| 
 | ||||
|   const char *key; | ||||
|   size_t key_len = lnm_http_req_route_segment(&key, &ctx->req, "key") ; | ||||
|   lnm_linfo("main", "yuhh key: %.*s", key_len, key); | ||||
|   return lnm_http_step_err_done; | ||||
| } | ||||
| 
 | ||||
| lnm_http_step_err print_step3(lnm_http_conn *conn) { | ||||
|   lnm_http_loop_ctx *ctx = conn->ctx; | ||||
| 
 | ||||
|   const char *key; | ||||
|   size_t key_len = lnm_http_req_route_segment(&key, &ctx->req, "cool") ; | ||||
|   lnm_linfo("main", "cool: %.*s", key_len, key); | ||||
|   return lnm_http_step_err_done; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main() { | ||||
|   lnm_http_loop *hl; | ||||
| 
 | ||||
|  | @ -34,8 +53,13 @@ int main() { | |||
|   lnm_http_router_init(&router); | ||||
| 
 | ||||
|   lnm_http_route *route; | ||||
|   lnm_http_router_add(&route, router, lnm_http_method_get, "/emma"); | ||||
|   lnm_http_router_add(&route, router, lnm_http_method_get, "/:key"); | ||||
|   lnm_http_route_step_append(route, print_step, false); | ||||
|   lnm_http_router_add(&route, router, lnm_http_method_get, "/:key/two"); | ||||
|   lnm_http_route_step_append(route, print_step2, false); | ||||
|   lnm_http_router_add(&route, router, lnm_http_method_get, "/*cool"); | ||||
|   lnm_http_route_step_append(route, print_step3, false); | ||||
| 
 | ||||
|   lnm_http_loop_router_set(hl, router); | ||||
| 
 | ||||
|  |  | |||
|  | @ -5,19 +5,25 @@ | |||
| 
 | ||||
| #include "lnm/http/loop.h" | ||||
| 
 | ||||
| struct lnm_http_router { | ||||
|   struct lnm_http_router *exact_children[128]; | ||||
|   struct lnm_http_router *single_segment_child; | ||||
|   lnm_http_route *routes[lnm_http_method_total]; | ||||
|   bool represents_route; | ||||
| }; | ||||
| 
 | ||||
| typedef struct lnm_http_route_segment_trie { | ||||
|   struct lnm_http_route_segment_trie *children[128]; | ||||
|   size_t index; | ||||
|   bool represents_segment; | ||||
| } lnm_http_route_segment_trie; | ||||
| 
 | ||||
| struct lnm_http_route { | ||||
|   lnm_http_route_segment_trie *key_segments; | ||||
|   lnm_http_step *step; | ||||
| }; | ||||
| 
 | ||||
| struct lnm_http_router { | ||||
|   struct lnm_http_router *exact_children[128]; | ||||
|   struct lnm_http_router *single_segment_child; | ||||
|   lnm_http_route *multi_segment_routes[lnm_http_method_total]; | ||||
|   lnm_http_route *routes[lnm_http_method_total]; | ||||
|   bool represents_route; | ||||
| }; | ||||
| 
 | ||||
| lnm_err lnm_http_route_segment_trie_init(lnm_http_route_segment_trie **out); | ||||
| 
 | ||||
| void lnm_http_route_segment_trie_free(lnm_http_route_segment_trie *trie); | ||||
|  | @ -39,11 +45,6 @@ typedef struct lnm_http_step { | |||
|  */ | ||||
| lnm_err lnm_http_step_init(lnm_http_step **out); | ||||
| 
 | ||||
| struct lnm_http_route { | ||||
|   lnm_http_route_segment_trie *key_segments; | ||||
|   lnm_http_step *step; | ||||
| }; | ||||
| 
 | ||||
| lnm_err lnm_http_route_init(lnm_http_route **out); | ||||
| 
 | ||||
| void lnm_http_route_free(lnm_http_route *route); | ||||
|  |  | |||
|  | @ -93,9 +93,42 @@ lnm_err lnm_http_router_add(lnm_http_route **out, lnm_http_router *http_router, | |||
|       http_router = http_router->single_segment_child; | ||||
|       path = new_path; | ||||
|     } break; | ||||
|     case '*': | ||||
|       // TODO multi-segment wildcard
 | ||||
|       break; | ||||
|     case '*': { | ||||
|       const char *next_slash_ptr = strchr(path + 1, '/'); | ||||
| 
 | ||||
|       // Star match should be at end of route
 | ||||
|       if (next_slash_ptr != NULL) { | ||||
|         res = lnm_err_invalid_route; | ||||
| 
 | ||||
|         goto end; | ||||
|       } | ||||
| 
 | ||||
|       const char *end = strchr(path + 1, '\0'); | ||||
|       size_t key_len = end - (path + 1); | ||||
| 
 | ||||
|       if (key_len == 0) { | ||||
|         res = lnm_err_invalid_route; | ||||
| 
 | ||||
|         goto end; | ||||
|       } | ||||
| 
 | ||||
|       res = lnm_http_route_key_segment_insert(route, path + 1, key_len, | ||||
|                                               key_segments_count); | ||||
| 
 | ||||
|       if (res != lnm_err_ok) { | ||||
|         goto end; | ||||
|       } | ||||
| 
 | ||||
|       key_segments_count++; | ||||
| 
 | ||||
|       if (http_router->multi_segment_routes[method] != NULL) { | ||||
|         res = lnm_err_overlapping_route; | ||||
|       } | ||||
| 
 | ||||
|       http_router->multi_segment_routes[method] = route; | ||||
|       goto end; | ||||
| 
 | ||||
|     } break; | ||||
|     default: | ||||
|       if (http_router->exact_children[c] == NULL) { | ||||
|         res = lnm_http_router_init(&http_router->exact_children[c]); | ||||
|  | @ -107,6 +140,7 @@ lnm_err lnm_http_router_add(lnm_http_route **out, lnm_http_router *http_router, | |||
| 
 | ||||
|       http_router = http_router->exact_children[c]; | ||||
|       path++; | ||||
| 
 | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
|  | @ -195,6 +229,26 @@ static lnm_http_route_err __lnm_http_router_route(lnm_http_route_match *out, | |||
|     } | ||||
|   } | ||||
| 
 | ||||
|   const lnm_http_route *multi_segment_route = | ||||
|       router->multi_segment_routes[method]; | ||||
| 
 | ||||
|   if (multi_segment_route != NULL) { | ||||
|     const char *end_ptr = strchr(path + path_index, '\0'); | ||||
|     size_t segment_len = end_ptr - (path + path_index); | ||||
| 
 | ||||
|     // TODO do 405's make sense for star matches?
 | ||||
| 
 | ||||
|     if (segment_len > 0) { | ||||
|       if (out != NULL) { | ||||
|         out->route = multi_segment_route; | ||||
|         out->key_segments[matched_key_segments].start = path_index; | ||||
|         out->key_segments[matched_key_segments].len = segment_len; | ||||
|       } | ||||
| 
 | ||||
|       return lnm_http_route_err_match; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return res; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue