From 77b62825a6c2da2837673e76328871f015f48bcf Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Thu, 30 Nov 2023 21:04:13 +0100 Subject: [PATCH] feat(lnm): more request processing code --- lnm/include/lnm/http/loop.h | 30 +++++-- lnm/include/lnm/http/res.h | 30 +++++++ .../http/{loop_ctx.c => lnm_http_loop_ctx.c} | 0 ...loop_process.c => lnm_http_loop_process.c} | 79 ++++++++++++++++--- lnm/src/http/{req.c => lnm_http_req.c} | 0 5 files changed, 120 insertions(+), 19 deletions(-) create mode 100644 lnm/include/lnm/http/res.h rename lnm/src/http/{loop_ctx.c => lnm_http_loop_ctx.c} (100%) rename lnm/src/http/{loop_process.c => lnm_http_loop_process.c} (51%) rename lnm/src/http/{req.c => lnm_http_req.c} (100%) diff --git a/lnm/include/lnm/http/loop.h b/lnm/include/lnm/http/loop.h index 20d746b..de0edcd 100644 --- a/lnm/include/lnm/http/loop.h +++ b/lnm/include/lnm/http/loop.h @@ -5,6 +5,7 @@ #include "lnm/common.h" #include "lnm/http/req.h" +#include "lnm/http/res.h" typedef struct lnm_loop lnm_http_loop; @@ -14,14 +15,14 @@ typedef struct lnm_http_step lnm_http_step; typedef struct lnm_http_route lnm_http_route; -typedef enum lnm_step_err { - lnm_step_err_done = 0, - lnm_step_err_io_needed, - lnm_step_err_close, - lnm_step_err_res, -} lnm_step_err; +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_step_err (*lnm_http_step_fn)(lnm_http_conn *conn); +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); @@ -84,9 +85,22 @@ void lnm_http_loop_route_add(lnm_http_loop *hl, lnm_http_route *route); * Represents what state an HTTP loop request is currently in. */ typedef enum lnm_http_loop_state { + // Parse the HTTP request lnm_http_loop_state_parse_req = 0, + // Route the request lnm_http_loop_state_route, + // Parse specific headers (e.g. Content-Length) + lnm_http_loop_state_parse_headers, + // Execute the various steps defined for the route lnm_http_loop_state_steps, + // Write the response status line + lnm_http_loop_state_write_status_line, + // Write the various response headers + lnm_http_loop_state_write_headers, + // Write the request body + lnm_http_loop_state_write_body, + // Clean up the request and reset the state for a next request + lnm_http_loop_state_finish, } lnm_http_loop_state; typedef struct lnm_http_loop_gctx { @@ -103,7 +117,9 @@ typedef struct lnm_http_loop_gctx { typedef struct lnm_http_loop_ctx { lnm_http_loop_state state; lnm_http_req req; + lnm_http_res res; lnm_http_route *route; + lnm_http_step *cur_step; lnm_http_loop_gctx *g; void *c; } lnm_http_loop_ctx; diff --git a/lnm/include/lnm/http/res.h b/lnm/include/lnm/http/res.h new file mode 100644 index 0000000..18ae914 --- /dev/null +++ b/lnm/include/lnm/http/res.h @@ -0,0 +1,30 @@ +#ifndef LNM_HTTP_RES +#define LNM_HTTP_RES + +#include + +#include "lnm/http/consts.h" + +typedef struct lnm_http_res_header { + struct { + char *s; + size_t len; + bool owned; + } name; + struct { + char *s; + size_t len; + bool owned; + } value; + struct lnm_http_res_header *next; +} lnm_http_res_header; + +typedef struct lnm_http_res { + lnm_http_status status; + struct { + lnm_http_res_header *head; + lnm_http_res_header *current; + } headers; +} lnm_http_res; + +#endif diff --git a/lnm/src/http/loop_ctx.c b/lnm/src/http/lnm_http_loop_ctx.c similarity index 100% rename from lnm/src/http/loop_ctx.c rename to lnm/src/http/lnm_http_loop_ctx.c diff --git a/lnm/src/http/loop_process.c b/lnm/src/http/lnm_http_loop_process.c similarity index 51% rename from lnm/src/http/loop_process.c rename to lnm/src/http/lnm_http_loop_process.c index 5568647..5fa4f21 100644 --- a/lnm/src/http/loop_process.c +++ b/lnm/src/http/lnm_http_loop_process.c @@ -1,12 +1,18 @@ #include #include +#include "lnm/http/consts.h" #include "lnm/http/loop.h" #include "lnm/http/loop_internal.h" #include "lnm/http/req.h" #include "lnm/loop.h" #include "lnm/loop_internal.h" +/* static const lnm_http_loop_state lnm_http_loop_state_first_req = + * lnm_http_loop_state_parse_req; */ +static const lnm_http_loop_state lnm_http_loop_state_first_res = + lnm_http_loop_state_write_headers; + void lnm_http_loop_process_parse_req(lnm_http_conn *conn) { lnm_http_loop_ctx *ctx = conn->ctx; @@ -16,7 +22,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; + ctx->state = lnm_http_loop_state_route; break; case lnm_http_parse_err_incomplete: // If the request is already the size of the read buffer, we close the @@ -29,8 +35,8 @@ void lnm_http_loop_process_parse_req(lnm_http_conn *conn) { conn->state = lnm_loop_state_end; break; case lnm_http_parse_err_unknown_method: - // TODO set status code here - conn->state = lnm_loop_state_end; + ctx->res.status = lnm_http_status_method_not_implemented; + ctx->state = lnm_http_loop_state_first_res; break; } } @@ -65,31 +71,80 @@ void lnm_http_loop_process_route(lnm_http_conn *conn) { match_level = match_level < new_match_level ? new_match_level : match_level; } - ctx->route = match_level == 2 ? route : NULL; + switch (match_level) { + case 0: + ctx->res.status = lnm_http_status_not_found; + ctx->state = lnm_http_loop_state_first_res; + break; + case 1: + ctx->res.status = lnm_http_status_method_not_allowed; + ctx->state = lnm_http_loop_state_first_res; + break; + case 2: + ctx->route = route; + ctx->cur_step = route->step; + ctx->state = lnm_http_loop_state_parse_headers; + break; + } +} + +void lnm_http_loop_process_parse_headers(lnm_http_conn *conn) { + lnm_http_loop_ctx *ctx = conn->ctx; + + // TODO + + ctx->state = lnm_http_loop_state_steps; } void lnm_http_loop_process_steps(lnm_http_conn *conn) { - /* lnm_http_loop_ctx *ctx = conn->ctx; */ + lnm_http_loop_ctx *ctx = conn->ctx; + lnm_http_step *step; - /* while () */ + do { + step = ctx->cur_step; + + switch (step->fn(conn)) { + case lnm_http_step_err_done: + ctx->cur_step = ctx->cur_step->next; + break; + case lnm_http_step_err_io_needed: + break; + case lnm_http_step_err_close: + conn->state = lnm_loop_state_end; + break; + case lnm_http_step_err_res: + ctx->state = lnm_http_loop_state_first_res; + break; + } + } while ((step != ctx->cur_step) && (ctx->cur_step != NULL)); + + if (ctx->cur_step == NULL) { + ctx->state = lnm_http_loop_state_write_headers; + } } void (*process_fns[])(lnm_http_conn *conn) = { lnm_http_loop_process_parse_req, lnm_http_loop_process_route, + lnm_http_loop_process_parse_headers, lnm_http_loop_process_steps, }; void lnm_http_loop_process(lnm_http_conn *conn) { lnm_http_loop_ctx *ctx = conn->ctx; - lnm_http_loop_state cur_state; + lnm_http_loop_state http_loop_state; + lnm_loop_state loop_state; - // As long as the processing is able to advance to a next state, we keep - // progressing + // We stop processing if: + // - the event loop state has changed, as we need to switch to the other I/O + // loop + // - the process fn returned without changing the HTTP loop state, indicating + // it's waiting for I/O do { - cur_state = ctx->state; + http_loop_state = ctx->state; + loop_state = conn->state; - process_fns[cur_state](conn); - } while (conn->state == lnm_loop_state_req && cur_state != ctx->state); + process_fns[http_loop_state](conn); + } while ((conn->state == loop_state) && (http_loop_state != ctx->state)); } diff --git a/lnm/src/http/req.c b/lnm/src/http/lnm_http_req.c similarity index 100% rename from lnm/src/http/req.c rename to lnm/src/http/lnm_http_req.c