From a90330dd6e9e0d366cf47583eb3753c5785481f2 Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Sun, 28 May 2023 09:09:46 +0200 Subject: [PATCH] feat: parse method into enum value --- include/http.h | 12 +++++++++--- src/http_loop/http_loop.c | 6 ++++++ src/http_loop/http_loop_consts.c | 8 ++++++++ src/http_loop/http_loop_route.c | 31 ++++++++++++++++++++++++------- src/http_loop/http_loop_util.c | 3 +++ 5 files changed, 50 insertions(+), 10 deletions(-) diff --git a/include/http.h b/include/http.h index 80352c2..4d38f07 100644 --- a/include/http.h +++ b/include/http.h @@ -15,6 +15,8 @@ extern const char http_405[]; extern const size_t http_405_len; extern const char http_500[]; extern const size_t http_500_len; +extern const char http_501[]; +extern const size_t http_501_len; typedef enum http_request_method { http_request_method_get = 0, @@ -24,14 +26,16 @@ typedef enum http_request_method { http_request_method_delete = 4 } http_request_method; +extern const char *request_method_names[]; +extern const size_t request_method_names_len; + /* * Struct representing the specific type of request */ typedef struct http_request { size_t len; int minor_version; - const char *method; - size_t method_len; + http_request_method method; const char *path; size_t path_len; const char *query; @@ -43,13 +47,15 @@ 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 { http_not_found = 404, - http_method_not_allowed = 405 + http_method_not_allowed = 405, + http_method_not_implemented = 501 } http_response_type; void http_write_standard_response(event_loop_conn *conn, diff --git a/src/http_loop/http_loop.c b/src/http_loop/http_loop.c index 058d631..d74cca1 100644 --- a/src/http_loop/http_loop.c +++ b/src/http_loop/http_loop.c @@ -36,6 +36,12 @@ bool http_loop_handle_request(event_loop_conn *conn) { return false; } + // It's fun to respond with extremely specific error messages + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/501 + else if (res == http_parse_error_unknown_method) { + http_write_standard_response(conn, 501); + return false; + } conn->rbuf_read += res; diff --git a/src/http_loop/http_loop_consts.c b/src/http_loop/http_loop_consts.c index 9190d0a..a58cf48 100644 --- a/src/http_loop/http_loop_consts.c +++ b/src/http_loop/http_loop_consts.c @@ -11,3 +11,11 @@ const size_t http_405_len = sizeof(http_405) - 1; const char http_500[] = "HTTP/1.1 500 Internal Server Error\n" "Content-Length: 0\n\n"; const size_t http_500_len = sizeof(http_500) - 1; +const char http_501[] = "HTTP/1.1 501 Not Implemented\n" + "Content-Length: 0\n\n"; +const size_t http_501_len = sizeof(http_501) - 1; + +// 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]); diff --git a/src/http_loop/http_loop_route.c b/src/http_loop/http_loop_route.c index 8ba1a4a..5d61ced 100644 --- a/src/http_loop/http_loop_route.c +++ b/src/http_loop/http_loop_route.c @@ -10,11 +10,13 @@ http_parse_error http_loop_parse_request(event_loop_conn *conn) { size_t num_headers = HTTP_MAX_ALLOWED_HEADERS; http_request *req = &ctx->req; - int res = - phr_parse_request((const char *)&conn->rbuf[conn->rbuf_read], - conn->rbuf_size - conn->rbuf_read, &req->method, - &req->method_len, &req->path, &req->path_len, - &req->minor_version, req->headers, &num_headers, 0); + const char *method; + size_t method_len; + + int res = phr_parse_request( + (const char *)&conn->rbuf[conn->rbuf_read], + conn->rbuf_size - conn->rbuf_read, &method, &method_len, &req->path, + &req->path_len, &req->minor_version, req->headers, &num_headers, 0); if (res == -1) { return http_parse_error_invalid; @@ -24,8 +26,23 @@ http_parse_error http_loop_parse_request(event_loop_conn *conn) { req->len = res; - // Split path into path & query + // Try to parse the method type + 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) { + req->method = i; + match = true; + } + } + + if (!match) { + return http_parse_error_unknown_method; + } + + // Split path into path & query + i = 0; bool no_query = true; while (no_query && i < req->path_len) { @@ -77,7 +94,7 @@ bool http_loop_route_request(event_loop_conn *conn) { http_loop_ctx *ctx = conn->ctx; http_loop_gctx *gctx = ctx->g; - info("%.*s %.*s", ctx->req.method_len, ctx->req.method, ctx->req.path_len, + info("%s %.*s", request_method_names[ctx->req.method], ctx->req.path_len, ctx->req.path); http_route *route; diff --git a/src/http_loop/http_loop_util.c b/src/http_loop/http_loop_util.c index 0289b62..69389c6 100644 --- a/src/http_loop/http_loop_util.c +++ b/src/http_loop/http_loop_util.c @@ -14,6 +14,9 @@ void http_write_standard_response(event_loop_conn *conn, case 405: s = http_405; len = http_405_len; + case 501: + s = http_501; + len = http_501_len; } memcpy(conn->wbuf, s, len);