From fbf6557c0534deb5185ea208299177f4ee55b5f2 Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Fri, 3 Nov 2023 13:22:25 +0100 Subject: [PATCH] feat(http): add step for parsing content-length header --- include/http_loop.h | 9 ++++++++- src/http_loop/http_loop_req.c | 1 + src/http_loop/http_loop_steps.c | 35 ++++++++++++++++++++++++++++++++- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/include/http_loop.h b/include/http_loop.h index c25becf..4737301 100644 --- a/include/http_loop.h +++ b/include/http_loop.h @@ -166,6 +166,13 @@ bool http_loop_step_body_to_buf(event_loop_conn *conn); */ bool http_loop_step_body_to_file(event_loop_conn *conn); +/** + * Try to parse the Content-Length header. + * + * @param conn connection to process + */ +bool http_loop_step_parse_content_length(event_loop_conn *conn); + /** * Authenticate the request using the X-Api-Key header. * @@ -201,7 +208,7 @@ bool http_loop_step_write_body(event_loop_conn *conn); * Initialize a new http loop. * * @param routes array of routes that should be served - * @parma route_count how many elements are in `routes` + * @param route_count how many elements are in `routes` * @param custom_gctx the application's custom global context; can be NULL * @param custom_ctx_init function to initialize a new custom context * @param custom_ctx_reset function to reset a custom context diff --git a/src/http_loop/http_loop_req.c b/src/http_loop/http_loop_req.c index 76e15d5..a8cd841 100644 --- a/src/http_loop/http_loop_req.c +++ b/src/http_loop/http_loop_req.c @@ -144,5 +144,6 @@ void http_loop_process_request(event_loop_conn *conn) { if ((conn->state != event_loop_conn_state_req) || (ctx->route->steps[ctx->current_step] == NULL)) { ctx->current_step = 0; + conn->state = event_loop_conn_state_res; } } diff --git a/src/http_loop/http_loop_steps.c b/src/http_loop/http_loop_steps.c index 474cb72..dfa8c96 100644 --- a/src/http_loop/http_loop_steps.c +++ b/src/http_loop/http_loop_steps.c @@ -1,5 +1,6 @@ #include +#include "http_loop.h" #include "lander.h" /* @@ -22,12 +23,44 @@ static bool string_to_num(size_t *res, const char *s, size_t len) { return true; } +bool http_loop_step_parse_content_length(event_loop_conn *conn) { + http_loop_ctx *ctx = conn->ctx; + + for (size_t i = 0; i < ctx->req.num_headers; i++) { + struct phr_header *header = &ctx->req.headers[i]; + + if (strncmp(header->name, "Content-Length", header->name_len) == 0) { + // If the content length header is present but contains an invalid + // number, we return a bad request error + if (!string_to_num(&ctx->req.body.expected_len, header->value, + header->value_len)) { + ctx->res.status = http_bad_request; + conn->state = event_loop_conn_state_res; + + return true; + } + // The content length was actually 0, so we can instantly return here + else if (ctx->req.body.expected_len == 0) { + return true; + } + } + } + + // A zero here means there's no content length header + if (ctx->req.body.expected_len == 0) { + ctx->res.status = http_length_required; + conn->state = event_loop_conn_state_res; + } + + return true; +} + /* * Try to find and parse the Content-Length header. This function returns true * if it was successful. If false is returned, the underlying step should * immediately exit. */ -static bool try_parse_content_length(event_loop_conn *conn) { +bool try_parse_content_length(event_loop_conn *conn) { http_loop_ctx *ctx = conn->ctx; for (size_t i = 0; i < ctx->req.num_headers; i++) {