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_patch, | ||||||
|   lnm_http_method_delete, |   lnm_http_method_delete, | ||||||
|   lnm_http_method_head, |   lnm_http_method_head, | ||||||
|  |   lnm_http_method_total, | ||||||
| } lnm_http_method; | } lnm_http_method; | ||||||
| 
 | 
 | ||||||
| extern const char *lnm_http_status_names[][32]; | 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 | #define LNM_HTTP_ROUTER_INTERNAL | ||||||
| 
 | 
 | ||||||
| #include "lnm/common.h" | #include "lnm/common.h" | ||||||
|  | #include "lnm/http/consts.h" | ||||||
|  | #include "lnm/http/router.h" | ||||||
| 
 | 
 | ||||||
| typedef struct lnm_http_route { | struct lnm_http_route {}; | ||||||
| } lnm_http_route; |  | ||||||
| 
 | 
 | ||||||
| typedef struct lnm_http_router { | struct lnm_http_router { | ||||||
|   struct lnm_http_router *exact_children[128]; |   struct lnm_http_router *exact_children[128]; | ||||||
|   struct lnm_http_router *single_segment_child; |   struct lnm_http_router *single_segment_child; | ||||||
|   lnm_http_route *route; |   lnm_http_route *routes[lnm_http_method_total]; | ||||||
| } 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); | lnm_err lnm_http_route_init(lnm_http_route **out); | ||||||
| 
 | 
 | ||||||
| void lnm_http_route_free(lnm_http_route *route); | 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 | #endif | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| #include <string.h> | #include <string.h> | ||||||
| 
 | 
 | ||||||
| #include "lnm/common.h" | #include "lnm/common.h" | ||||||
|  | #include "lnm/http/router.h" | ||||||
| #include "lnm/http/router_internal.h" | #include "lnm/http/router_internal.h" | ||||||
| 
 | 
 | ||||||
| lnm_err lnm_http_router_init(lnm_http_router **out) { | 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, | 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)) { |   if (path[0] != '/' || !is_ascii(path)) { | ||||||
|     return lnm_err_invalid_route; |     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) { |     switch (c) { | ||||||
|     case ':': |     case ':': | ||||||
|       LNM_RES(lnm_http_router_init(&http_router->single_segment_child)); |       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
 |       // All other characters in the segment are ignored
 | ||||||
|       const char *next_slash_ptr = strchr(path, '/'); |       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; |   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