feat: initial trie routing structure
							parent
							
								
									1f63f06e0c
								
							
						
					
					
						commit
						71cf5a5981
					
				|  | @ -32,6 +32,8 @@ typedef enum lnm_err { | |||
|   lnm_err_not_setup, | ||||
|   lnm_err_bad_regex, | ||||
|   lnm_err_not_found, | ||||
|   lnm_err_invalid_route, | ||||
|   lnm_err_overlapping_route, | ||||
| } lnm_err; | ||||
| 
 | ||||
| typedef struct lnm_loop lnm_http_loop; | ||||
|  |  | |||
|  | @ -0,0 +1,36 @@ | |||
| #ifndef LNM_HTTP_ROUTER_INTERNAL | ||||
| #define LNM_HTTP_ROUTER_INTERNAL | ||||
| 
 | ||||
| #include "lnm/common.h" | ||||
| 
 | ||||
| typedef struct lnm_http_route { | ||||
| } lnm_http_route; | ||||
| 
 | ||||
| typedef struct lnm_http_router { | ||||
|   struct lnm_http_router *exact_children[128]; | ||||
|   struct lnm_http_router *single_segment_child; | ||||
|   lnm_http_route *route; | ||||
| } lnm_http_router; | ||||
| 
 | ||||
| /**
 | ||||
|  * Allocate and initialize a new http_router. | ||||
|  */ | ||||
| lnm_err lnm_http_router_init(lnm_http_router **out); | ||||
| 
 | ||||
| void lnm_http_router_free(lnm_http_router *router); | ||||
| 
 | ||||
| lnm_err lnm_http_route_init(lnm_http_route **out); | ||||
| 
 | ||||
| void lnm_http_route_free(lnm_http_route *route); | ||||
| 
 | ||||
| lnm_err lnm_http_router_add(lnm_http_route **out, lnm_http_router *http_router, | ||||
|                             const char *path); | ||||
| 
 | ||||
| /**
 | ||||
|  * Add all of the child router's routes to the parent router, under the given | ||||
|  * route prefix. | ||||
|  */ | ||||
| lnm_err lnm_http_router_nest(lnm_http_router *parent, | ||||
|                              const lnm_http_router *child, const char *prefix); | ||||
| 
 | ||||
| #endif | ||||
|  | @ -0,0 +1,73 @@ | |||
| #include <string.h> | ||||
| 
 | ||||
| #include "lnm/common.h" | ||||
| #include "lnm/http/router_internal.h" | ||||
| 
 | ||||
| lnm_err lnm_http_router_init(lnm_http_router **out) { | ||||
|   lnm_http_router *router = calloc(1, sizeof(lnm_http_router)); | ||||
| 
 | ||||
|   if (router == NULL) { | ||||
|     return lnm_err_failed_alloc; | ||||
|   } | ||||
| 
 | ||||
|   *out = router; | ||||
| 
 | ||||
|   return lnm_err_ok; | ||||
| } | ||||
| 
 | ||||
| lnm_err lnm_http_route_init(lnm_http_route **out) { | ||||
|   lnm_http_route *route = calloc(1, sizeof(lnm_http_route)); | ||||
| 
 | ||||
|   if (route == NULL) { | ||||
|     return lnm_err_failed_alloc; | ||||
|   } | ||||
| 
 | ||||
|   *out = route; | ||||
| 
 | ||||
|   return lnm_err_ok; | ||||
| } | ||||
| 
 | ||||
| static bool is_ascii(const char *s) { | ||||
|   while (*s != '0') { | ||||
|     if (*s > 127) { | ||||
|       return false; | ||||
|     } | ||||
| 
 | ||||
|     s++; | ||||
|   } | ||||
| 
 | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| lnm_err lnm_http_router_add(lnm_http_route **out, lnm_http_router *http_router, | ||||
|                             const char *path) { | ||||
|   if (path[0] != '/' || !is_ascii(path)) { | ||||
|     return lnm_err_invalid_route; | ||||
|   } | ||||
| 
 | ||||
|   while (*path != '\0') { | ||||
|     unsigned char c = *path; | ||||
| 
 | ||||
|     switch (c) { | ||||
|     case ':': | ||||
|       LNM_RES(lnm_http_router_init(&http_router->single_segment_child)); | ||||
| 
 | ||||
|       // All other characters in the segment are ignored
 | ||||
|       const char *next_slash_ptr = strchr(path, '/'); | ||||
|       path = next_slash_ptr == NULL ? strchr(path, '\0') : next_slash_ptr; | ||||
|       break; | ||||
|     case '*': | ||||
|       // TODO multi-segment wildcard
 | ||||
|       break; | ||||
|     default: | ||||
|       LNM_RES(lnm_http_router_init(&http_router->exact_children[c])); | ||||
|       http_router = http_router->exact_children[c]; | ||||
|       path++; | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   LNM_RES(lnm_http_route_init(out)); | ||||
| 
 | ||||
|   return lnm_err_ok; | ||||
| } | ||||
		Loading…
	
		Reference in New Issue