diff --git a/lnm/include/lnm/http/loop.h b/lnm/include/lnm/http/loop.h index 550d046..20d746b 100644 --- a/lnm/include/lnm/http/loop.h +++ b/lnm/include/lnm/http/loop.h @@ -56,7 +56,8 @@ lnm_err lnm_http_step_append(lnm_http_step **out, lnm_http_step *step, * @param path literal path to match * @param step step to process request with */ -lnm_err lnm_http_route_init_literal(lnm_http_route **out, const char *path, +lnm_err lnm_http_route_init_literal(lnm_http_route **out, + lnm_http_method method, const char *path, lnm_http_step *step); /** @@ -67,8 +68,9 @@ lnm_err lnm_http_route_init_literal(lnm_http_route **out, const char *path, * @param regex_group_count how many regex groups are contained in the pattern * @param step step to process request with */ -lnm_err lnm_http_route_init_regex(lnm_http_route **out, const char *pattern, - int regex_group_count, lnm_http_step *step); +lnm_err lnm_http_route_init_regex(lnm_http_route **out, lnm_http_method method, + const char *pattern, int regex_group_count, + lnm_http_step *step); /** * Add a new route to the HTTP route. @@ -101,6 +103,7 @@ typedef struct lnm_http_loop_gctx { typedef struct lnm_http_loop_ctx { lnm_http_loop_state state; lnm_http_req req; + lnm_http_route *route; lnm_http_loop_gctx *g; void *c; } lnm_http_loop_ctx; diff --git a/lnm/include/lnm/http/req.h b/lnm/include/lnm/http/req.h index 35bd21a..def3ad7 100644 --- a/lnm/include/lnm/http/req.h +++ b/lnm/include/lnm/http/req.h @@ -1,6 +1,7 @@ #ifndef LNM_HTTP_REQ #define LNM_HTTP_REQ +#include #include #include "picohttpparser.h" @@ -8,6 +9,7 @@ #include "lnm/http/consts.h" #define LNM_HTTP_MAX_REQ_HEADERS 32 +#define LNM_HTTP_MAX_REGEX_GROUPS 4 /** * Represents the parsed HTTP request @@ -19,6 +21,7 @@ typedef struct lnm_http_req { struct { const char *s; size_t len; + regmatch_t groups[LNM_HTTP_MAX_REGEX_GROUPS]; } path; struct { const char *s; diff --git a/lnm/src/_include/lnm/http/loop_internal.h b/lnm/src/_include/lnm/http/loop_internal.h index c6bc128..4d9e865 100644 --- a/lnm/src/_include/lnm/http/loop_internal.h +++ b/lnm/src/_include/lnm/http/loop_internal.h @@ -20,6 +20,7 @@ typedef struct lnm_http_route { regex_t *regex; const char *s; } route; + lnm_http_method method; lnm_http_route_type type; int regex_group_count; lnm_http_step *step; @@ -63,4 +64,6 @@ void lnm_http_loop_ctx_reset(lnm_http_loop_ctx *ctx); void lnm_http_loop_ctx_free(lnm_http_loop_ctx *ctx); +void lnm_http_loop_process(lnm_http_conn *conn); + #endif diff --git a/lnm/src/http/lnm_http_loop.c b/lnm/src/http/lnm_http_loop.c index 024da9d..e79d3c3 100644 --- a/lnm/src/http/lnm_http_loop.c +++ b/lnm/src/http/lnm_http_loop.c @@ -19,6 +19,7 @@ lnm_err lnm_http_loop_init(lnm_http_loop **out, void *c_gctx, ctx_init, ctx_reset, ctx_free), free(hl)); + hl->data_read = lnm_http_loop_process; *out = hl; return lnm_err_ok; @@ -58,19 +59,22 @@ lnm_err lnm_http_route_init(lnm_http_route **out) { return lnm_err_ok; } -lnm_err lnm_http_route_init_literal(lnm_http_route **out, const char *path, +lnm_err lnm_http_route_init_literal(lnm_http_route **out, + lnm_http_method method, const char *path, lnm_http_step *step) { LNM_RES(lnm_http_route_init(out)); (*out)->type = lnm_http_route_type_literal; + (*out)->method = method; (*out)->route.s = path; (*out)->step = step; return lnm_err_ok; } -lnm_err lnm_http_route_init_regex(lnm_http_route **out, const char *pattern, - int regex_group_count, lnm_http_step *step) { +lnm_err lnm_http_route_init_regex(lnm_http_route **out, lnm_http_method method, + const char *pattern, int regex_group_count, + lnm_http_step *step) { regex_t *regex = calloc(1, sizeof(regex_t)); if (regex == NULL) { @@ -84,6 +88,7 @@ lnm_err lnm_http_route_init_regex(lnm_http_route **out, const char *pattern, LNM_RES2(lnm_http_route_init(out), free(regex)); + (*out)->method = method; (*out)->type = lnm_http_route_type_regex; (*out)->route.regex = regex; (*out)->regex_group_count = regex_group_count; diff --git a/lnm/src/http/loop_process.c b/lnm/src/http/loop_process.c index e93aca7..5568647 100644 --- a/lnm/src/http/loop_process.c +++ b/lnm/src/http/loop_process.c @@ -1,3 +1,6 @@ +#include +#include + #include "lnm/http/loop.h" #include "lnm/http/loop_internal.h" #include "lnm/http/req.h" @@ -12,6 +15,7 @@ void lnm_http_loop_process_parse_req(lnm_http_conn *conn) { switch (res) { case lnm_http_parse_err_ok: + conn->r.read += ctx->req.len; ctx->state = lnm_http_loop_state_steps; break; case lnm_http_parse_err_incomplete: @@ -31,7 +35,38 @@ void lnm_http_loop_process_parse_req(lnm_http_conn *conn) { } } -void lnm_http_loop_process_route(lnm_http_conn *conn) {} +void lnm_http_loop_process_route(lnm_http_conn *conn) { + lnm_http_loop_ctx *ctx = conn->ctx; + lnm_http_loop_gctx *gctx = ctx->g; + + // 0: no match + // 1: matched route, but not method + // 2: fully matched route + int match_level = 0; + lnm_http_route *route; + + for (size_t i = 0; i < gctx->routes.len && match_level < 2; i++) { + route = gctx->routes.arr[i]; + bool matched_path; + + switch (route->type) { + case lnm_http_route_type_literal: + matched_path = + strncmp(route->route.s, ctx->req.path.s, ctx->req.path.len) == 0; + break; + case lnm_http_route_type_regex: + matched_path = + regexec(route->route.regex, ctx->req.path.s, + LNM_HTTP_MAX_REGEX_GROUPS, ctx->req.path.groups, 0) == 0; + } + + // Remember the previous match levels + int new_match_level = matched_path + (route->method == ctx->req.method); + match_level = match_level < new_match_level ? new_match_level : match_level; + } + + ctx->route = match_level == 2 ? route : NULL; +} void lnm_http_loop_process_steps(lnm_http_conn *conn) { /* lnm_http_loop_ctx *ctx = conn->ctx; */