feat: add initial routing function
							parent
							
								
									0e1d5d3f23
								
							
						
					
					
						commit
						386d83ec93
					
				|  | @ -13,6 +13,7 @@ typedef enum lnm_http_method { | |||
|   lnm_http_method_patch, | ||||
|   lnm_http_method_delete, | ||||
|   lnm_http_method_head, | ||||
|   lnm_http_method_total, | ||||
| } lnm_http_method; | ||||
| 
 | ||||
| extern const char *lnm_http_status_names[][32]; | ||||
|  |  | |||
|  | @ -0,0 +1,39 @@ | |||
| #ifndef LNM_HTTP_ROUTER | ||||
| #define LNM_HTTP_ROUTER | ||||
| 
 | ||||
| #include "lnm/common.h" | ||||
| #include "lnm/http/consts.h" | ||||
| 
 | ||||
| typedef struct lnm_http_route lnm_http_route; | ||||
| 
 | ||||
| typedef struct lnm_http_router lnm_http_router; | ||||
| 
 | ||||
| typedef enum lnm_http_route_err { | ||||
|   lnm_http_route_err_match = 0, | ||||
|   lnm_http_route_err_unknown_route = 1, | ||||
|   lnm_http_route_err_unknown_method = 2, | ||||
| } lnm_http_route_err; | ||||
| 
 | ||||
| /**
 | ||||
|  * 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_router_add(lnm_http_route **out, lnm_http_router *http_router, | ||||
|                             lnm_http_method method, 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); | ||||
| 
 | ||||
| lnm_http_route_err lnm_http_router_route(const lnm_http_route **out, | ||||
|                                          const lnm_http_router *router, | ||||
|                                          lnm_http_method method, | ||||
|                                          const char *path); | ||||
| 
 | ||||
| #endif | ||||
|  | @ -2,35 +2,19 @@ | |||
| #define LNM_HTTP_ROUTER_INTERNAL | ||||
| 
 | ||||
| #include "lnm/common.h" | ||||
| #include "lnm/http/consts.h" | ||||
| #include "lnm/http/router.h" | ||||
| 
 | ||||
| typedef struct lnm_http_route { | ||||
| } lnm_http_route; | ||||
| struct lnm_http_route {}; | ||||
| 
 | ||||
| typedef struct lnm_http_router { | ||||
| 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_http_route *routes[lnm_http_method_total]; | ||||
| }; | ||||
| 
 | ||||
| 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 | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| #include <string.h> | ||||
| 
 | ||||
| #include "lnm/common.h" | ||||
| #include "lnm/http/router.h" | ||||
| #include "lnm/http/router_internal.h" | ||||
| 
 | ||||
| lnm_err lnm_http_router_init(lnm_http_router **out) { | ||||
|  | @ -40,7 +41,7 @@ static bool is_ascii(const char *s) { | |||
| } | ||||
| 
 | ||||
| lnm_err lnm_http_router_add(lnm_http_route **out, lnm_http_router *http_router, | ||||
|                             const char *path) { | ||||
|                             lnm_http_method method, const char *path) { | ||||
|   if (path[0] != '/' || !is_ascii(path)) { | ||||
|     return lnm_err_invalid_route; | ||||
|   } | ||||
|  | @ -51,6 +52,7 @@ lnm_err lnm_http_router_add(lnm_http_route **out, lnm_http_router *http_router, | |||
|     switch (c) { | ||||
|     case ':': | ||||
|       LNM_RES(lnm_http_router_init(&http_router->single_segment_child)); | ||||
|       http_router = http_router->single_segment_child; | ||||
| 
 | ||||
|       // All other characters in the segment are ignored
 | ||||
|       const char *next_slash_ptr = strchr(path, '/'); | ||||
|  | @ -67,7 +69,60 @@ lnm_err lnm_http_router_add(lnm_http_route **out, lnm_http_router *http_router, | |||
|     } | ||||
|   } | ||||
| 
 | ||||
|   LNM_RES(lnm_http_route_init(out)); | ||||
|   if (http_router->routes[method] != NULL) { | ||||
|     return lnm_err_overlapping_route; | ||||
|   } | ||||
| 
 | ||||
|   LNM_RES(lnm_http_route_init(&http_router->routes[method])); | ||||
|   *out = http_router->routes[method]; | ||||
| 
 | ||||
|   return lnm_err_ok; | ||||
| } | ||||
| 
 | ||||
| lnm_http_route_err lnm_http_router_route(const lnm_http_route **out, | ||||
|                                          const lnm_http_router *router, | ||||
|                                          lnm_http_method method, | ||||
|                                          const char *path) { | ||||
|   if (!is_ascii(path)) { | ||||
|     return lnm_http_route_err_unknown_route; | ||||
|   } | ||||
| 
 | ||||
|   if (*path == '\0') { | ||||
|     *out = router->routes[method]; | ||||
| 
 | ||||
|     return *out == NULL ? lnm_http_route_err_unknown_method | ||||
|                         : lnm_http_route_err_match; | ||||
|   } | ||||
| 
 | ||||
|   lnm_http_route_err res = lnm_http_route_err_unknown_route; | ||||
|   lnm_http_router *exact_router = router->exact_children[(unsigned char)*path]; | ||||
| 
 | ||||
|   if (exact_router != NULL) { | ||||
|     lnm_http_route_err sub_res = | ||||
|         lnm_http_router_route(out, exact_router, method, path + 1); | ||||
| 
 | ||||
|     if (sub_res == lnm_http_route_err_match) { | ||||
|       return lnm_http_route_err_match; | ||||
|     } | ||||
| 
 | ||||
|     res = LNM_MAX(res, sub_res); | ||||
|   } | ||||
| 
 | ||||
|   lnm_http_router *single_segment_router = router->single_segment_child; | ||||
| 
 | ||||
|   if (single_segment_router != NULL) { | ||||
|     const char *next_slash_ptr = strchr(path, '/'); | ||||
|     path = next_slash_ptr == NULL ? strchr(path, '\0') : next_slash_ptr; | ||||
| 
 | ||||
|     lnm_http_route_err sub_res = | ||||
|         lnm_http_router_route(out, exact_router, method, path); | ||||
| 
 | ||||
|     if (sub_res == lnm_http_route_err_match) { | ||||
|       return lnm_http_route_err_match; | ||||
|     } | ||||
| 
 | ||||
|     res = LNM_MAX(res, sub_res); | ||||
|   } | ||||
| 
 | ||||
|   return res; | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue