From c58e53eb2a7674ec469933cabfce19d9baab8e51 Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Thu, 25 May 2023 12:01:20 +0200 Subject: [PATCH] feat: start of http part of server --- .gitignore | 1 + include/http.h | 39 +++++++++++++++++ src/event_loop/event_loop_conn.c | 43 +++++++++---------- src/event_loop/event_loop_http.c | 0 src/event_loop/event_loop_internal.h | 5 --- .../http_consts.c} | 2 +- src/http/http_parse.c | 30 +++++++++++++ 7 files changed, 91 insertions(+), 29 deletions(-) create mode 100644 include/http.h create mode 100644 src/event_loop/event_loop_http.c rename src/{event_loop/event_loop_consts.c => http/http_consts.c} (95%) create mode 100644 src/http/http_parse.c diff --git a/.gitignore b/.gitignore index 1537245..240d06c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ compile_commands.json # Data files lander.data pastes/ +.cache/ diff --git a/include/http.h b/include/http.h new file mode 100644 index 0000000..e1bb2fe --- /dev/null +++ b/include/http.h @@ -0,0 +1,39 @@ +#ifndef HTTP +#define HTTP + +#include + +extern const char http_404[]; +extern const size_t http_404_len; +extern const char http_500[]; +extern const size_t http_500_len; + +typedef enum http_request_entity { + event_loop_request_type_unknown = 0 +} http_request_entity; + +typedef enum http_request_method { + http_request_method_get = 0, + http_request_method_post = 1, + http_request_method_put = 2, + http_request_method_patch = 3, + http_request_method_delete = 4 +} http_request_method; + +/* + * Struct representing the specific type of request + */ +typedef struct http_request { + http_request_method type; + http_request_entity entity; +} 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; + +http_parse_error http_parse_request(http_request *req, const char *path, size_t path_len); + +#endif diff --git a/src/event_loop/event_loop_conn.c b/src/event_loop/event_loop_conn.c index 0cca6aa..bcf2dc9 100644 --- a/src/event_loop/event_loop_conn.c +++ b/src/event_loop/event_loop_conn.c @@ -74,34 +74,31 @@ bool event_loop_handle_request(event_loop_conn *conn) { &minor_version, headers, &num_headers, 0); if (res > 0) { - /* conn->close_after_write = true; */ - // TODO allow HTTP pipelining - /* conn->close_after_write = true; */ - for (int i = 0; i < num_headers; i++) { - /* printf("%.*s: ", headers[i].name_len, headers[i].name); */ - /* printf("%.*s\n", headers[i].value_len, headers[i].value); */ - if (strncmp("Connection", headers[i].name, headers[i].name_len) == 0) { - if (strncmp("close", headers[i].value, headers[i].value_len) == 0) { - conn->close_after_write = true; - break; - } - } - } + /* for (size_t i = 0; i < num_headers; i++) { */ + /* /1* printf("%.*s: ", headers[i].name_len, headers[i].name); *1/ */ + /* /1* printf("%.*s\n", headers[i].value_len, headers[i].value); *1/ */ + /* if (strncmp("Connection", headers[i].name, headers[i].name_len) == 0) { */ + /* if (strncmp("close", headers[i].value, headers[i].value_len) == 0) { */ + /* conn->close_after_write = true; */ + /* break; */ + /* } */ + /* } */ + /* } */ - memcpy(conn->wbuf, http_200_ok, sizeof(http_200_ok) - 1); + /* memcpy(conn->wbuf, http_500, http_500_len); */ - // Move the new request up to the front of the read buffer - memmove(conn->rbuf, &conn->rbuf[res], conn->rbuf_size - res); - conn->rbuf_size -= res; + /* // Move the new request up to the front of the read buffer */ + /* memmove(conn->rbuf, &conn->rbuf[res], conn->rbuf_size - res); */ + /* conn->rbuf_size -= res; */ - conn->state = event_loop_conn_state_res; - conn->wbuf_size = sizeof(http_200_ok) - 1; - conn->wbuf_sent = 0; + /* conn->state = event_loop_conn_state_res; */ + /* conn->wbuf_size = http_500_len; */ + /* conn->wbuf_sent = 0; */ - event_loop_conn_io_res(conn); + /* /1* event_loop_conn_io_res(conn); *1/ */ - // End the connection if the http request is invalid, or when the response - // is too large to fit into a single read buffer + /* // End the connection if the http request is invalid, or when the response */ + /* // is too large to fit into a single read buffer */ } else if (res == -1 || (res == -2 && conn->rbuf_size == EVENT_LOOP_BUFFER_SIZE)) { conn->state = event_loop_conn_state_end; diff --git a/src/event_loop/event_loop_http.c b/src/event_loop/event_loop_http.c new file mode 100644 index 0000000..e69de29 diff --git a/src/event_loop/event_loop_internal.h b/src/event_loop/event_loop_internal.h index 34c22b3..ef10191 100644 --- a/src/event_loop/event_loop_internal.h +++ b/src/event_loop/event_loop_internal.h @@ -53,9 +53,4 @@ int event_loop_accept(event_loop *loop, int fd); void event_loop_conn_io(event_loop_conn *conn); -extern const char http_404[]; -extern const size_t http_404_len; -extern const char http_500[]; -extern const size_t http_500_len; - #endif diff --git a/src/event_loop/event_loop_consts.c b/src/http/http_consts.c similarity index 95% rename from src/event_loop/event_loop_consts.c rename to src/http/http_consts.c index 87419e7..b84fba5 100644 --- a/src/event_loop/event_loop_consts.c +++ b/src/http/http_consts.c @@ -1,4 +1,4 @@ -#include +#include "http.h" const char http_404[] = "HTTP/1.1 404 Not Found\n" "Connection: close\n" diff --git a/src/http/http_parse.c b/src/http/http_parse.c new file mode 100644 index 0000000..1d3c4e8 --- /dev/null +++ b/src/http/http_parse.c @@ -0,0 +1,30 @@ +#include "http.h" +#include "picohttpparser.h" + +/* + * given the HTTP path, parse the request + */ +http_parse_error http_parse_request(http_request *req, const char *buf, size_t buf_size) { + // First we try to parse the incoming HTTP request + const char *method, *path; + struct phr_header headers[16]; + size_t method_len, path_len, num_headers; + int minor_version; + + int res = phr_parse_request(buf, buf_size, + &method, &method_len, &path, &path_len, + &minor_version, headers, &num_headers, 0); + + if (res == -2) { + return http_parse_error_incomplete; + } else if (res < 0) { + return http_parse_error_invalid; + } + + // Next, we parse the HTTP request as a lander-specific request + if (path_len == 0 || path[0] != '/') { + return http_parse_error_invalid; + } + + return http_parse_error_ok; +}