From 3ae1b62dd0a25dfb57bb3fc7694b75f60888fed5 Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Sun, 25 Feb 2024 21:50:51 +0100 Subject: [PATCH] feat(routing): make path segments easily accessible from request struct --- example/routing.c | 6 ++- include/lnm/http/loop.h | 62 +--------------------------- include/lnm/http/req.h | 12 ++++++ include/lnm/http/route.h | 69 ++++++++++++++++++++++++++++++++ src/http/lnm_http_loop_process.c | 5 ++- src/http/lnm_http_req.c | 16 ++++++++ 6 files changed, 105 insertions(+), 65 deletions(-) create mode 100644 include/lnm/http/route.h diff --git a/example/routing.c b/example/routing.c index 47d02b3..19d64e1 100644 --- a/example/routing.c +++ b/example/routing.c @@ -1,5 +1,6 @@ #include +#include "lnm/http/req.h" #include "lnm/log.h" #include "lnm/loop.h" #include "lnm/http/loop.h" @@ -16,8 +17,9 @@ void ctx_free(void *c_ctx) {} lnm_http_step_err print_step(lnm_http_conn *conn) { lnm_http_loop_ctx *ctx = conn->ctx; - const lnm_http_route_match_segment *seg = lnm_http_route_match_get(&ctx->match, "key"); - lnm_linfo("main", "key: %.*s", seg->len, ctx->req.buf.s + ctx->req.path.o + seg->start); + const char *key; + size_t key_len = lnm_http_req_route_segment(&key, &ctx->req, "key") ; + lnm_linfo("main", "key: %.*s", key_len, key); return lnm_http_step_err_done; } diff --git a/include/lnm/http/loop.h b/include/lnm/http/loop.h index 3731f34..ba4337b 100644 --- a/include/lnm/http/loop.h +++ b/include/lnm/http/loop.h @@ -6,17 +6,7 @@ #include "lnm/common.h" #include "lnm/http/req.h" #include "lnm/http/res.h" - -#define LNM_HTTP_MAX_KEY_SEGMENTS 4 - -typedef enum lnm_http_step_err { - lnm_http_step_err_done = 0, - lnm_http_step_err_io_needed, - lnm_http_step_err_close, - lnm_http_step_err_res, -} lnm_http_step_err; - -typedef lnm_http_step_err (*lnm_http_step_fn)(lnm_http_conn *conn); +#include "lnm/http/route.h" typedef lnm_err (*lnm_http_ctx_init_fn)(void **c_ctx, void *gctx); @@ -24,55 +14,6 @@ typedef void (*lnm_http_ctx_reset_fn)(void *c_ctx); typedef void (*lnm_http_ctx_free_fn)(void *c_ctx); -typedef struct lnm_http_route lnm_http_route; - -typedef struct lnm_http_route_match_segment { - size_t start; - size_t len; -} lnm_http_route_match_segment; - -typedef struct lnm_http_route_match { - const lnm_http_route *route; - lnm_http_method method; - lnm_http_route_match_segment key_segments[LNM_HTTP_MAX_KEY_SEGMENTS]; -} lnm_http_route_match; - -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(lnm_http_route_match *out, - const lnm_http_router *router, - lnm_http_method method, - const char *path); - -const lnm_http_route_match_segment * -lnm_http_route_match_get(lnm_http_route_match *match, const char *key); - -lnm_err lnm_http_route_step_append(lnm_http_route *route, lnm_http_step_fn fn, - bool blocking); - /** * Initialize a new `lnm_http_loop`. * @@ -130,7 +71,6 @@ typedef struct lnm_http_loop_ctx { lnm_http_loop_state state; lnm_http_req req; lnm_http_res res; - lnm_http_route_match match; lnm_http_step *cur_step; lnm_http_loop_gctx *g; void *c; diff --git a/include/lnm/http/req.h b/include/lnm/http/req.h index 06f2743..1c32972 100644 --- a/include/lnm/http/req.h +++ b/include/lnm/http/req.h @@ -9,6 +9,7 @@ #include "lnm/common.h" #include "lnm/http/consts.h" +#include "lnm/http/route.h" #define LNM_HTTP_MAX_REQ_HEADERS 32 #define LNM_HTTP_MAX_REGEX_GROUPS 4 @@ -35,6 +36,7 @@ typedef struct lnm_http_req { } buf; int minor_version; lnm_http_method method; + lnm_http_route_match route_match; struct { size_t o; size_t len; @@ -108,4 +110,14 @@ lnm_err lnm_http_req_header_get(const char **out, size_t *out_len, lnm_err lnm_http_req_header_get_s(const char **out, size_t *out_len, lnm_http_req *req, const char *name); +/** + * Retrieve a named key segment from the matched route. + * + * @param out where to write pointer to string + * @param key key of the segment + * @return length of the outputted char buffer, or 0 if the key doesn't exist + */ +size_t lnm_http_req_route_segment(const char **out, lnm_http_req *req, + const char *key); + #endif diff --git a/include/lnm/http/route.h b/include/lnm/http/route.h new file mode 100644 index 0000000..f121b96 --- /dev/null +++ b/include/lnm/http/route.h @@ -0,0 +1,69 @@ +#ifndef LNM_HTTP_ROUTE +#define LNM_HTTP_ROUTE + +#include + +#include "lnm/common.h" +#include "lnm/http/consts.h" + +#define LNM_HTTP_MAX_KEY_SEGMENTS 4 + +typedef enum lnm_http_step_err { + lnm_http_step_err_done = 0, + lnm_http_step_err_io_needed, + lnm_http_step_err_close, + lnm_http_step_err_res, +} lnm_http_step_err; + +typedef lnm_http_step_err (*lnm_http_step_fn)(lnm_http_conn *conn); + +typedef struct lnm_http_route lnm_http_route; + +typedef struct lnm_http_route_match_segment { + size_t start; + size_t len; +} lnm_http_route_match_segment; + +typedef struct lnm_http_route_match { + const lnm_http_route *route; + lnm_http_method method; + lnm_http_route_match_segment key_segments[LNM_HTTP_MAX_KEY_SEGMENTS]; +} lnm_http_route_match; + +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(lnm_http_route_match *out, + const lnm_http_router *router, + lnm_http_method method, + const char *path); + +const lnm_http_route_match_segment * +lnm_http_route_match_get(lnm_http_route_match *match, const char *key); + +lnm_err lnm_http_route_step_append(lnm_http_route *route, lnm_http_step_fn fn, + bool blocking); + +#endif diff --git a/src/http/lnm_http_loop_process.c b/src/http/lnm_http_loop_process.c index 91b9254..ea690ce 100644 --- a/src/http/lnm_http_loop_process.c +++ b/src/http/lnm_http_loop_process.c @@ -58,10 +58,11 @@ void lnm_http_loop_process_route(lnm_http_conn *conn) { lnm_http_loop_ctx *ctx = conn->ctx; const lnm_http_loop_gctx *gctx = ctx->g; - switch (lnm_http_router_route(&ctx->match, gctx->router, ctx->req.method, + switch (lnm_http_router_route(&ctx->req.route_match, gctx->router, + ctx->req.method, ctx->req.buf.s + ctx->req.path.o)) { case lnm_http_route_err_match: - ctx->cur_step = ctx->match.route->step; + ctx->cur_step = ctx->req.route_match.route->step; ctx->state = lnm_http_loop_state_parse_headers; break; case lnm_http_route_err_unknown_method: diff --git a/src/http/lnm_http_req.c b/src/http/lnm_http_req.c index 50be3af..a612b02 100644 --- a/src/http/lnm_http_req.c +++ b/src/http/lnm_http_req.c @@ -112,3 +112,19 @@ lnm_err lnm_http_req_header_get_s(const char **out, size_t *out_len, return lnm_err_not_found; } + +size_t lnm_http_req_route_segment(const char **out, lnm_http_req *req, + const char *key) { + const lnm_http_route_match_segment *segment = + lnm_http_route_match_get(&req->route_match, key); + + if (segment == NULL) { + return 0; + } + + if (out != NULL) { + *out = req->buf.s + req->path.o + segment->start; + } + + return segment->len; +}