From f07042e798fe6d7de70309156762accae7d8cff1 Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Tue, 30 May 2023 16:00:08 +0200 Subject: [PATCH] refactor: modularize the http header files --- include/http/req.h | 46 ++++++++++++ include/http/res.h | 56 +++++++++++++++ include/{http.h => http/types.h} | 119 +++++++------------------------ include/http_loop.h | 20 ++---- src/http/http_consts.c | 12 ++-- src/http/res.c | 37 ++++++++++ src/http_loop/http_loop.c | 2 +- src/http_loop/http_loop_ctx.c | 2 +- src/http_loop/http_loop_req.c | 6 +- src/http_loop/http_loop_res.c | 2 +- src/http_loop/http_loop_tools.c | 37 ---------- src/lander/lander_get.c | 8 +-- src/lander/lander_post.c | 5 +- 13 files changed, 190 insertions(+), 162 deletions(-) create mode 100644 include/http/req.h create mode 100644 include/http/res.h rename include/{http.h => http/types.h} (62%) create mode 100644 src/http/res.c delete mode 100644 src/http_loop/http_loop_tools.c diff --git a/include/http/req.h b/include/http/req.h new file mode 100644 index 0000000..f0fad93 --- /dev/null +++ b/include/http/req.h @@ -0,0 +1,46 @@ +#ifndef LANDER_HTTP_REQ +#define LANDER_HTTP_REQ + +#include +#include +#include +#include + +#include "http/types.h" +#include "picohttpparser.h" + +#define HTTP_MAX_ALLOWED_HEADERS 16 +#define HTTP_MAX_REGEX_GROUPS 4 + +/* + * Struct representing the specific type of request + */ +typedef struct http_request { + size_t len; + int minor_version; + http_method method; + const char *path; + size_t path_len; + const char *query; + size_t query_len; + http_body_type body_type; + union { + char *buf; + FILE *file; + } body; + size_t body_len; + size_t body_received; + char *body_file_name; + regmatch_t regex_groups[HTTP_MAX_REGEX_GROUPS]; + struct phr_header headers[HTTP_MAX_ALLOWED_HEADERS]; + size_t num_headers; +} http_request; + +typedef enum http_parse_error { + http_parse_error_ok = 0, + http_parse_error_incomplete = 1, + http_parse_error_invalid = 2, + http_parse_error_unknown_method = 3 +} http_parse_error; + +#endif diff --git a/include/http/res.h b/include/http/res.h new file mode 100644 index 0000000..f7551c2 --- /dev/null +++ b/include/http/res.h @@ -0,0 +1,56 @@ +#ifndef LANDER_HTTP_RES +#define LANDER_HTTP_RES + +#include +#include + +#include "http/types.h" + +typedef struct http_response_header { + http_header type; + const char *value; + bool owned; +} http_response_header; + +typedef struct http_response { + http_status status; + const char *head; + size_t head_len; + size_t head_written; + http_body_type body_type; + union { + char *buf; + FILE *file; + } body; + size_t body_len; + size_t body_written; + // If false, the body won't be freed + bool owns_body; + http_response_header headers[4]; + size_t header_count; +} http_response; + +/* + * Set the request body to the given buffer. If owned is set to true, the body + * buffer will be free'd after the request has finished. + */ +void http_res_set_body_buf(http_response *res, const char *body, + size_t body_len, bool owned); + +/* + * Set the request body to the given filename. + */ +void http_res_set_body_file(http_response *res, const char *filename); + +/* + * Add a header to the response. + */ +void http_res_add_header(http_response *res, http_header type, + const char *value, bool owned); + +/* + * Add a Content-Type header corresponding to the mime type. + */ +void http_res_set_mime_type(http_response *res, http_mime_type mime_type); + +#endif diff --git a/include/http.h b/include/http/types.h similarity index 62% rename from include/http.h rename to include/http/types.h index fdff087..e1f4e64 100644 --- a/include/http.h +++ b/include/http/types.h @@ -1,76 +1,24 @@ -#ifndef HTTP -#define HTTP +#ifndef LANDER_HTTP_TYPES +#define LANDER_HTTP_TYPES -#include -#include -#include -#include - -#include "picohttpparser.h" - -#define HTTP_MAX_ALLOWED_HEADERS 16 -#define HTTP_MAX_REGEX_GROUPS 4 - -// Array mapping the http_response_type enum to strings -extern const char *http_response_type_names[][32]; - -// Array mapping the http_header enum to strings -extern const char *http_header_names[]; - -// Array mapping the http_mime_type enum to strings -extern const char *http_mime_type_names[][2]; +#include // Array mapping the http_request_method enum to strings -extern const char *request_method_names[]; -extern const size_t request_method_names_len; +extern const char *http_method_names[]; +extern const size_t http_method_names_len; -typedef enum http_request_method { +typedef enum http_method { http_get = 0, http_post = 1, http_put = 2, http_patch = 3, http_delete = 4 -} http_request_method; +} http_method; -typedef enum http_body_type { - http_body_buf = 0, - http_body_file = 1 -} http_body_type; +// Array mapping the http_response_type enum to strings +extern const char *http_status_names[][32]; -/* - * Struct representing the specific type of request - */ -typedef struct http_request { - size_t len; - int minor_version; - http_request_method method; - const char *path; - size_t path_len; - const char *query; - size_t query_len; - http_body_type body_type; - union { - char *buf; - FILE *file; - } body; - size_t body_len; - size_t body_received; - char *body_file_name; - regmatch_t regex_groups[HTTP_MAX_REGEX_GROUPS]; - struct phr_header headers[HTTP_MAX_ALLOWED_HEADERS]; - size_t num_headers; -} http_request; - -typedef enum http_parse_error { - http_parse_error_ok = 0, - http_parse_error_incomplete = 1, - http_parse_error_invalid = 2, - http_parse_error_unknown_method = 3 -} http_parse_error; - -/* void http_route(event_loop_conn *conn); */ - -typedef enum http_response_type { +typedef enum http_status { // 1xx http_continue = 100, http_switching_protocols = 101, @@ -135,37 +83,10 @@ typedef enum http_response_type { http_loop_detected = 508, http_not_extended = 510, http_network_authentication_required = 511 -} http_response_type; +} http_status; -typedef enum http_header { - http_header_connection = 0, - http_header_location, - http_header_content_type -} http_header; - -typedef struct http_response_header { - http_header type; - const char *value; - bool owned; -} http_response_header; - -typedef struct http_response { - http_response_type status; - const char *head; - size_t head_len; - size_t head_written; - http_body_type body_type; - union { - char *buf; - FILE *file; - } body; - size_t body_len; - size_t body_written; - // If false, the body won't be freed - bool owns_body; - http_response_header headers[4]; - size_t header_count; -} http_response; +// Array mapping the http_mime_type enum to strings +extern const char *http_mime_type_names[][2]; typedef enum http_mime_type { http_mime_aac = 0, @@ -194,4 +115,18 @@ typedef enum http_mime_type { http_mime_7z } http_mime_type; +// Array mapping the http_header enum to strings +extern const char *http_header_names[]; + +typedef enum http_header { + http_header_connection = 0, + http_header_location, + http_header_content_type +} http_header; + +typedef enum http_body_type { + http_body_buf = 0, + http_body_file = 1 +} http_body_type; + #endif diff --git a/include/http_loop.h b/include/http_loop.h index 99833b8..e1049ac 100644 --- a/include/http_loop.h +++ b/include/http_loop.h @@ -4,7 +4,9 @@ #include #include "event_loop.h" -#include "http.h" +#include "http/req.h" +#include "http/res.h" +#include "http/types.h" #include "trie.h" #define MIN(x, y) (((x) < (y)) ? (x) : (y)) @@ -17,7 +19,7 @@ typedef enum http_route_type { typedef struct http_route { http_route_type type; - http_request_method method; + http_method method; char *path; regex_t *regex; bool (*steps[5])(event_loop_conn *); @@ -94,20 +96,6 @@ void http_loop_route_request(event_loop_conn *conn); */ void http_loop_process_request(event_loop_conn *conn); -/* - * Set the request body to the given buffer. If owned is set to true, the body - * buffer will be free'd after the request has finished. - */ -void http_loop_res_set_body_buf(http_loop_ctx *ctx, const char *body, - size_t body_len, bool owned); - -void http_loop_res_set_body_file(http_loop_ctx *ctx, const char *filename); - -void http_loop_res_add_header(http_loop_ctx *ctx, http_header type, - const char *value, bool owned); - -void http_loop_res_set_mime_type(http_loop_ctx *ctx, http_mime_type mime_type); - /* * Request step that consumes the request body and stores it in a buffer */ diff --git a/src/http/http_consts.c b/src/http/http_consts.c index e693107..6a6e15c 100644 --- a/src/http/http_consts.c +++ b/src/http/http_consts.c @@ -1,13 +1,15 @@ -#include "http.h" +#include + +#include "http/types.h" // Very important that this is in the same order as http_request_method -const char *request_method_names[] = {"GET", "POST", "PUT", "PATCH", "DELETE"}; -const size_t request_method_names_len = - sizeof(request_method_names) / sizeof(request_method_names[0]); +const char *http_method_names[] = {"GET", "POST", "PUT", "PATCH", "DELETE"}; +const size_t http_method_names_len = + sizeof(http_method_names) / sizeof(http_method_names[0]); // clang-format off -const char *http_response_type_names[][32] = { +const char *http_status_names[][32] = { // 1xx { "Continue", // 100 diff --git a/src/http/res.c b/src/http/res.c new file mode 100644 index 0000000..304a460 --- /dev/null +++ b/src/http/res.c @@ -0,0 +1,37 @@ +#include + +#include "http/res.h" + +void http_res_set_body_buf(http_response *res, const char *body, + size_t body_len, bool owned) { + res->body_type = http_body_buf; + res->body.buf = (char *)body; + res->body_len = body_len; + res->owns_body = owned; +} + +void http_res_set_body_file(http_response *res, const char *filename) { + struct stat st; + stat(filename, &st); + + // TODO error handling + FILE *f = fopen(filename, "r"); + + res->body_type = http_body_file; + res->body.file = f; + res->body_len = st.st_size; +} + +void http_res_add_header(http_response *res, http_header type, + const char *value, bool owned) { + res->headers[res->header_count].type = type; + res->headers[res->header_count].value = value; + res->headers[res->header_count].owned = owned; + + res->header_count++; +} + +void http_res_set_mime_type(http_response *res, http_mime_type mime_type) { + http_res_add_header(res, http_header_content_type, + http_mime_type_names[mime_type][1], false); +} diff --git a/src/http_loop/http_loop.c b/src/http_loop/http_loop.c index 51ad32b..d6c9539 100644 --- a/src/http_loop/http_loop.c +++ b/src/http_loop/http_loop.c @@ -1,6 +1,6 @@ #include -#include "http.h" +#include "http/types.h" #include "http_loop.h" #include "log.h" diff --git a/src/http_loop/http_loop_ctx.c b/src/http_loop/http_loop_ctx.c index c138fa0..ea550e6 100644 --- a/src/http_loop/http_loop_ctx.c +++ b/src/http_loop/http_loop_ctx.c @@ -1,6 +1,6 @@ #include -#include "http.h" +#include "http/types.h" #include "http_loop.h" http_loop_gctx *http_loop_gctx_init() { diff --git a/src/http_loop/http_loop_req.c b/src/http_loop/http_loop_req.c index 154d134..09b0ed4 100644 --- a/src/http_loop/http_loop_req.c +++ b/src/http_loop/http_loop_req.c @@ -34,8 +34,8 @@ http_parse_error http_loop_parse_request(event_loop_conn *conn) { bool match = false; size_t i = 0; - for (i = 0; i < request_method_names_len; i++) { - if (strncmp(method, request_method_names[i], method_len) == 0) { + for (i = 0; i < http_method_names_len; i++) { + if (strncmp(method, http_method_names[i], method_len) == 0) { req->method = i; match = true; } @@ -88,7 +88,7 @@ void http_loop_route_request(event_loop_conn *conn) { http_loop_ctx *ctx = conn->ctx; http_loop_gctx *gctx = ctx->g; - info("%s %.*s", request_method_names[ctx->req.method], ctx->req.path_len, + info("%s %.*s", http_method_names[ctx->req.method], ctx->req.path_len, ctx->req.path); http_route *route; diff --git a/src/http_loop/http_loop_res.c b/src/http_loop/http_loop_res.c index 9b5e6f0..50d9c25 100644 --- a/src/http_loop/http_loop_res.c +++ b/src/http_loop/http_loop_res.c @@ -17,7 +17,7 @@ void http_loop_init_header(http_response *res) { } const char *response_type_name = - http_response_type_names[res->status / 100 - 1][res->status % 100]; + http_status_names[res->status / 100 - 1][res->status % 100]; // First we calculate the size of the start of the header int buf_size = snprintf(NULL, 0, http_response_format, res->status, diff --git a/src/http_loop/http_loop_tools.c b/src/http_loop/http_loop_tools.c deleted file mode 100644 index bcc8e57..0000000 --- a/src/http_loop/http_loop_tools.c +++ /dev/null @@ -1,37 +0,0 @@ -#include - -#include "http_loop.h" - -void http_loop_res_set_body_buf(http_loop_ctx *ctx, const char *body, - size_t body_len, bool owned) { - ctx->res.body_type = http_body_buf; - ctx->res.body.buf = (char *)body; - ctx->res.body_len = body_len; - ctx->res.owns_body = owned; -} - -void http_loop_res_set_body_file(http_loop_ctx *ctx, const char *filename) { - struct stat st; - stat(filename, &st); - - // TODO error handling - FILE *f = fopen(filename, "r"); - - ctx->res.body_type = http_body_file; - ctx->res.body.file = f; - ctx->res.body_len = st.st_size; -} - -void http_loop_res_add_header(http_loop_ctx *ctx, http_header type, - const char *value, bool owned) { - ctx->res.headers[ctx->res.header_count].type = type; - ctx->res.headers[ctx->res.header_count].value = value; - ctx->res.headers[ctx->res.header_count].owned = owned; - - ctx->res.header_count++; -} - -void http_loop_res_set_mime_type(http_loop_ctx *ctx, http_mime_type mime_type) { - http_loop_res_add_header(ctx, http_header_content_type, - http_mime_type_names[mime_type][1], false); -} diff --git a/src/lander/lander_get.c b/src/lander/lander_get.c index 62040e9..39a5004 100644 --- a/src/lander/lander_get.c +++ b/src/lander/lander_get.c @@ -15,8 +15,8 @@ static const char index_page[] = bool lander_get_index(event_loop_conn *conn) { http_loop_ctx *ctx = conn->ctx; - http_loop_res_set_body_buf(ctx, index_page, sizeof(index_page) - 1, false); - http_loop_res_set_mime_type(ctx, http_mime_html); + http_res_set_body_buf(&ctx->res, index_page, sizeof(index_page) - 1, false); + http_res_set_mime_type(&ctx->res, http_mime_html); conn->state = event_loop_conn_state_res; return true; @@ -35,12 +35,12 @@ bool lander_get_entry(event_loop_conn *conn) { ctx->res.status = http_not_found; } else if (entry->type == Redirect) { ctx->res.status = http_moved_permanently; - http_loop_res_add_header(ctx, http_header_location, entry->string, false); + http_res_add_header(&ctx->res, http_header_location, entry->string, false); } else if (entry->type == Paste) { char fname[8 + key_len]; sprintf(fname, "pastes/%.*s", key_len, key); - http_loop_res_set_body_file(ctx, fname); + http_res_set_body_file(&ctx->res, fname); } conn->state = event_loop_conn_state_res; diff --git a/src/lander/lander_post.c b/src/lander/lander_post.c index 7bde258..ea271ee 100644 --- a/src/lander/lander_post.c +++ b/src/lander/lander_post.c @@ -1,3 +1,4 @@ +#include "http/res.h" #include "lander.h" #include "log.h" @@ -32,7 +33,7 @@ bool lander_post_redirect(event_loop_conn *conn) { free(key); - http_loop_res_add_header(ctx, http_header_location, buf, true); + http_res_add_header(&ctx->res, http_header_location, buf, true); conn->state = event_loop_conn_state_res; @@ -63,7 +64,7 @@ bool lander_post_paste(event_loop_conn *conn) { buf[0] = '/'; buf[key_len + 1] = '\0'; - http_loop_res_add_header(ctx, http_header_location, buf, true); + http_res_add_header(&ctx->res, http_header_location, buf, true); // TODO free this char *fname = malloc(8 + key_len);