From 32687e0b49fddbed6869851cbc8f594e8a020fa1 Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Thu, 25 May 2023 14:28:53 +0200 Subject: [PATCH] feat: only memmove read buffer on read --- include/http.h | 3 +- src/event_loop/event_loop_conn.c | 53 +++++++++++++++------------- src/event_loop/event_loop_internal.h | 1 + src/http/http_parse.c | 9 ++--- 4 files changed, 37 insertions(+), 29 deletions(-) diff --git a/include/http.h b/include/http.h index e1bb2fe..06de7ca 100644 --- a/include/http.h +++ b/include/http.h @@ -34,6 +34,7 @@ typedef enum http_parse_error { http_parse_error_invalid = 2, } http_parse_error; -http_parse_error http_parse_request(http_request *req, const char *path, size_t path_len); +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 bcf2dc9..de5b6cb 100644 --- a/src/event_loop/event_loop_conn.c +++ b/src/event_loop/event_loop_conn.c @@ -11,6 +11,7 @@ #include #include "picohttpparser.h" +#include "http.h" #include "event_loop_internal.h" @@ -54,7 +55,7 @@ void event_loop_conn_io_res(event_loop_conn *conn) { bool event_loop_handle_request(event_loop_conn *conn) { // Prevents the request handler function from looping indefinitely without // ever consuming new data - if (conn->rbuf_size == 0) { + if (conn->rbuf_size - conn->rbuf_read == 0) { return false; } @@ -69,7 +70,7 @@ bool event_loop_handle_request(event_loop_conn *conn) { num_headers = sizeof(headers) / sizeof(headers[0]); - int res = phr_parse_request((const char *)conn->rbuf, conn->rbuf_size, + int res = phr_parse_request((const char *)&conn->rbuf[conn->rbuf_read], conn->rbuf_size - conn->rbuf_read, &method, &method_len, &path, &path_len, &minor_version, headers, &num_headers, 0); @@ -77,27 +78,33 @@ bool event_loop_handle_request(event_loop_conn *conn) { /* 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) { */ + /* 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_500, http_500_len); */ + // Advance the read buffer + conn->rbuf_read += res; - /* // Move the new request up to the front of the read buffer */ + memcpy(conn->wbuf, http_404, http_404_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; */ - /* conn->state = event_loop_conn_state_res; */ - /* conn->wbuf_size = http_500_len; */ - /* conn->wbuf_sent = 0; */ + conn->state = event_loop_conn_state_res; + conn->wbuf_size = http_404_len; + conn->wbuf_sent = 0; - /* /1* event_loop_conn_io_res(conn); *1/ */ + event_loop_conn_io_res(conn); - /* // End the connection if the http request is invalid, or when the response */ + /* // 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)) { @@ -114,7 +121,12 @@ bool event_loop_handle_request(event_loop_conn *conn) { * Returns whether the function should be retried immediately or not. */ void event_loop_conn_io_req(event_loop_conn *conn) { - while (1) { + do { + // Move remaining data to start of buffer + memmove(conn->rbuf, &conn->rbuf[conn->rbuf_read], conn->rbuf_size - conn->rbuf_read); + conn->rbuf_size -= conn->rbuf_read; + conn->rbuf_read = 0; + ssize_t res; size_t cap = EVENT_LOOP_BUFFER_SIZE - conn->rbuf_size; @@ -153,19 +165,12 @@ void event_loop_conn_io_req(event_loop_conn *conn) { conn->rbuf_size += (size_t)res; - /* assert(conn->rbuf_size <= sizeof(conn->rbuf)); */ - - // Try to process requests one by one. - // Try to process requests one by one. - // Why is there a loop? Please read the explanation of "pipelining". - while (event_loop_handle_request(conn)) { - }; - - // We can keep reading as long as we're in request mode - if (conn->state != event_loop_conn_state_req) { - return; - }; + // This loop allows processing multiple requests from a single read buffer + while (event_loop_handle_request(conn)) + ; } + // We can keep reading as long as we're in request mode + while (conn->state == event_loop_conn_state_req); } void event_loop_conn_io(event_loop_conn *conn) { diff --git a/src/event_loop/event_loop_internal.h b/src/event_loop/event_loop_internal.h index ef10191..cf72eb3 100644 --- a/src/event_loop/event_loop_internal.h +++ b/src/event_loop/event_loop_internal.h @@ -12,6 +12,7 @@ typedef struct event_loop_conn { event_loop_conn_state state; // buffer for reading size_t rbuf_size; + size_t rbuf_read; uint8_t rbuf[EVENT_LOOP_BUFFER_SIZE]; // buffer for writing size_t wbuf_size; diff --git a/src/http/http_parse.c b/src/http/http_parse.c index 1d3c4e8..bdd1f46 100644 --- a/src/http/http_parse.c +++ b/src/http/http_parse.c @@ -4,16 +4,17 @@ /* * given the HTTP path, parse the request */ -http_parse_error http_parse_request(http_request *req, const char *buf, size_t buf_size) { +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); + 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;