feat(routing): make path segments easily accessible from request struct

routing
Jef Roosens 2024-02-25 21:50:51 +01:00
parent fbd41f7e4e
commit 3ae1b62dd0
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
6 changed files with 105 additions and 65 deletions

View File

@ -1,5 +1,6 @@
#include <unistd.h> #include <unistd.h>
#include "lnm/http/req.h"
#include "lnm/log.h" #include "lnm/log.h"
#include "lnm/loop.h" #include "lnm/loop.h"
#include "lnm/http/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_step_err print_step(lnm_http_conn *conn) {
lnm_http_loop_ctx *ctx = conn->ctx; lnm_http_loop_ctx *ctx = conn->ctx;
const lnm_http_route_match_segment *seg = lnm_http_route_match_get(&ctx->match, "key"); const char *key;
lnm_linfo("main", "key: %.*s", seg->len, ctx->req.buf.s + ctx->req.path.o + seg->start); 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; return lnm_http_step_err_done;
} }

View File

@ -6,17 +6,7 @@
#include "lnm/common.h" #include "lnm/common.h"
#include "lnm/http/req.h" #include "lnm/http/req.h"
#include "lnm/http/res.h" #include "lnm/http/res.h"
#include "lnm/http/route.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 lnm_err (*lnm_http_ctx_init_fn)(void **c_ctx, void *gctx); 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 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`. * Initialize a new `lnm_http_loop`.
* *
@ -130,7 +71,6 @@ typedef struct lnm_http_loop_ctx {
lnm_http_loop_state state; lnm_http_loop_state state;
lnm_http_req req; lnm_http_req req;
lnm_http_res res; lnm_http_res res;
lnm_http_route_match match;
lnm_http_step *cur_step; lnm_http_step *cur_step;
lnm_http_loop_gctx *g; lnm_http_loop_gctx *g;
void *c; void *c;

View File

@ -9,6 +9,7 @@
#include "lnm/common.h" #include "lnm/common.h"
#include "lnm/http/consts.h" #include "lnm/http/consts.h"
#include "lnm/http/route.h"
#define LNM_HTTP_MAX_REQ_HEADERS 32 #define LNM_HTTP_MAX_REQ_HEADERS 32
#define LNM_HTTP_MAX_REGEX_GROUPS 4 #define LNM_HTTP_MAX_REGEX_GROUPS 4
@ -35,6 +36,7 @@ typedef struct lnm_http_req {
} buf; } buf;
int minor_version; int minor_version;
lnm_http_method method; lnm_http_method method;
lnm_http_route_match route_match;
struct { struct {
size_t o; size_t o;
size_t len; 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_err lnm_http_req_header_get_s(const char **out, size_t *out_len,
lnm_http_req *req, const char *name); 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 #endif

View File

@ -0,0 +1,69 @@
#ifndef LNM_HTTP_ROUTE
#define LNM_HTTP_ROUTE
#include <stdlib.h>
#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

View File

@ -58,10 +58,11 @@ void lnm_http_loop_process_route(lnm_http_conn *conn) {
lnm_http_loop_ctx *ctx = conn->ctx; lnm_http_loop_ctx *ctx = conn->ctx;
const lnm_http_loop_gctx *gctx = ctx->g; 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)) { ctx->req.buf.s + ctx->req.path.o)) {
case lnm_http_route_err_match: 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; ctx->state = lnm_http_loop_state_parse_headers;
break; break;
case lnm_http_route_err_unknown_method: case lnm_http_route_err_unknown_method:

View File

@ -112,3 +112,19 @@ lnm_err lnm_http_req_header_get_s(const char **out, size_t *out_len,
return lnm_err_not_found; 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;
}