From fa964b2620b32097431363518bbc4c81164411c8 Mon Sep 17 00:00:00 2001 From: Francesco Date: Sat, 2 Aug 2025 00:28:24 +0200 Subject: [PATCH] improve error handling --- include/http/http.h | 4 +-- meson.build | 2 -- src/http/http.c | 51 +++++++++++++++++++-------- src/meson.build | 3 -- src/server/server.c | 8 ++--- test/hashmap_test.c | 85 --------------------------------------------- 6 files changed, 42 insertions(+), 111 deletions(-) delete mode 100644 test/hashmap_test.c diff --git a/include/http/http.h b/include/http/http.h index 13daaf3..914cb21 100644 --- a/include/http/http.h +++ b/include/http/http.h @@ -49,7 +49,7 @@ typedef struct cws_http_t { cws_http *cws_http_parse(char *request_str, int sockfd, cws_config *config); int cws_http_parse_method(cws_http *request, const char *method); -void cws_http_get_content_type(cws_http *request, char *content_type); +int cws_http_get_content_type(cws_http *request, char *content_type); char *cws_http_status_string(cws_http_status status); /** @@ -62,7 +62,7 @@ size_t cws_http_response_builder(char **response, char *http_version, cws_http_s void cws_http_send_response(cws_http *request, cws_http_status status); void cws_http_send_resource(cws_http *request); -void cws_http_send_error_page(cws_http *request, cws_http_status status, char *title, char *description); +void cws_http_send_simple_html(cws_http *request, cws_http_status status, char *title, char *description); void cws_http_free(cws_http *request); diff --git a/meson.build b/meson.build index 2a4db60..df1ba8f 100644 --- a/meson.build +++ b/meson.build @@ -13,5 +13,3 @@ add_global_arguments('-DUSE_COLORS', language : 'c') add_global_arguments('-DEVELOPER', language : 'c') executable('cws', server, include_directories : incdir, dependencies : deps) - -executable('testbuild', test, include_directories : incdir) diff --git a/src/http/http.c b/src/http/http.c index d8e9584..0f87dc6 100644 --- a/src/http/http.c +++ b/src/http/http.c @@ -22,6 +22,7 @@ cws_http *cws_http_parse(char *request_str, int sockfd, cws_config *config) { char *request_str_cpy = strdup(request_str); if (!request_str_cpy) { free(request); + return NULL; } @@ -37,13 +38,16 @@ cws_http *cws_http_parse(char *request_str, int sockfd, cws_config *config) { return NULL; } CWS_LOG_DEBUG("method: %s", pch); + int ret = cws_http_parse_method(request, pch); if (ret < 0) { /* Not implemented */ cws_http_free(request); free(request_str_cpy); - cws_http_send_error_page(request, CWS_HTTP_NOT_IMPLEMENTED, "501 Not Implemented", "501 Not Implemented"); + cws_http_send_response(request, CWS_HTTP_NOT_IMPLEMENTED); + + return NULL; } /* Parse location */ @@ -61,6 +65,10 @@ cws_http *cws_http_parse(char *request_str, int sockfd, cws_config *config) { if (strcmp(request->location, "/") == 0) { snprintf(request->location_path, CWS_HTTP_LOCATION_PATH_LEN, "%s/index.html", config->www); } else { + size_t location_path_len = strlen(request->location); + if (location_path_len > CWS_HTTP_LOCATION_PATH_LEN) { + request->location[location_path_len - 1] = '\0'; + } snprintf(request->location_path, CWS_HTTP_LOCATION_PATH_LEN, "%s%s", config->www, request->location); } CWS_LOG_DEBUG("location path: %s", request->location_path); @@ -155,7 +163,7 @@ size_t cws_http_response_builder(char **response, char *http_version, cws_http_s size_t total_len = header_len + body_len_bytes; - *response = (char *)malloc(total_len); + *response = malloc(total_len); if (*response == NULL) { return 0; } @@ -173,11 +181,11 @@ void cws_http_send_response(cws_http *request, cws_http_status status) { case CWS_HTTP_OK: break; case CWS_HTTP_NOT_FOUND: { - cws_http_send_error_page(request, CWS_HTTP_NOT_FOUND, "404 Not Found", "Resource not found, 404."); + cws_http_send_simple_html(request, CWS_HTTP_NOT_FOUND, "404 Not Found", "Resource not found, 404."); break; } case CWS_HTTP_NOT_IMPLEMENTED: { - cws_http_send_error_page(request, CWS_HTTP_NOT_IMPLEMENTED, "501 Not Implemented", "Method not implemented, 501."); + cws_http_send_simple_html(request, CWS_HTTP_NOT_IMPLEMENTED, "501 Not Implemented", "Method not implemented, 501."); break; } } @@ -192,7 +200,10 @@ void cws_http_send_resource(cws_http *request) { /* Retrieve correct Content-Type */ char content_type[1024]; - cws_http_get_content_type(request, content_type); + int ret = cws_http_get_content_type(request, content_type); + if (ret < 0) { + cws_http_send_response(request, CWS_HTTP_NOT_FOUND); + } /* Retrieve file size */ fseek(file, 0, SEEK_END); @@ -213,13 +224,18 @@ void cws_http_send_resource(cws_http *request) { if (read_bytes != content_length) { free(file_data); - CWS_LOG_ERROR("Partial read from file."); + CWS_LOG_ERROR("Partial read from file"); return; } + char conn[32] = "close"; + mcl_bucket *connection = mcl_hm_get(request->headers, "Connection"); + if (connection) { + strncpy(conn, (char *)connection->value, sizeof(conn)); + } + char *response = NULL; - size_t response_len = cws_http_response_builder(&response, "HTTP/1.1", CWS_HTTP_OK, content_type, "close", file_data, content_length); - CWS_LOG_DEBUG("%s", response); + size_t response_len = cws_http_response_builder(&response, "HTTP/1.1", CWS_HTTP_OK, content_type, conn, file_data, content_length); size_t bytes_sent = 0; do { @@ -231,15 +247,14 @@ void cws_http_send_resource(cws_http *request) { free(file_data); } -void cws_http_get_content_type(cws_http *request, char *content_type) { +int cws_http_get_content_type(cws_http *request, char *content_type) { char *ptr = strrchr(request->location_path, '.'); if (ptr == NULL) { - cws_http_send_error_page(request, CWS_HTTP_NOT_FOUND, "404 Not Found", "404 Not Found."); - return; + return -1; } ptr += 1; - char ct[32]; + char ct[32] = {0}; /* TODO: Improve content_type (used to test) */ if (strcmp(ptr, "html") == 0 || strcmp(ptr, "css") == 0 || strcmp(ptr, "javascript") == 0) { @@ -251,9 +266,11 @@ void cws_http_get_content_type(cws_http *request, char *content_type) { } snprintf(content_type, 1024, "%s/%s", ct, ptr); + + return 0; } -void cws_http_send_error_page(cws_http *request, cws_http_status status, char *title, char *description) { +void cws_http_send_simple_html(cws_http *request, cws_http_status status, char *title, char *description) { char body[512]; memset(body, 0, sizeof(body)); @@ -269,8 +286,14 @@ void cws_http_send_error_page(cws_http *request, cws_http_status status, char *t title, description); size_t body_len = strlen(body) * sizeof(char); + char conn[32] = "close"; + mcl_bucket *connection = mcl_hm_get(request->headers, "Connection"); + if (connection) { + strncpy(conn, (char *)connection->value, sizeof(conn)); + } + char *response = NULL; - size_t response_len = cws_http_response_builder(&response, "HTTP/1.1", status, "text/html", "close", body, body_len); + size_t response_len = cws_http_response_builder(&response, "HTTP/1.1", status, "text/html", conn, body, body_len); send(request->sockfd, response, response_len, 0); free(response); } diff --git a/src/meson.build b/src/meson.build index 2a44c6f..59f2b66 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,6 +1,3 @@ server = files('main.c', 'server/server.c') server += files('utils/utils.c', 'utils/hashmap.c', 'utils/config.c') server += files('http/http.c') - -test = files('../test/hashmap_test.c') -test += files('utils/hashmap.c') diff --git a/src/server/server.c b/src/server/server.c index 54d1e8f..dfe7d5a 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -108,7 +108,7 @@ int cws_server_loop(int sockfd, cws_config *config) { return -1; } - struct epoll_event *revents = (struct epoll_event *)malloc(CWS_SERVER_EPOLL_MAXEVENTS * sizeof(struct epoll_event)); + struct epoll_event *revents = malloc(CWS_SERVER_EPOLL_MAXEVENTS * sizeof(struct epoll_event)); if (!revents) { mcl_hm_free(clients); close(epfd); @@ -160,8 +160,8 @@ int cws_server_loop(int sockfd, cws_config *config) { if (bytes_read < 0) { if (errno != EAGAIN && errno != EWOULDBLOCK) { /* Error during read, handle it (close client) */ - cws_epoll_del(epfd, client_fd); - close(client_fd); + CWS_LOG_INFO("Client (%s) disconnected (error)", ip); + cws_server_close_client(epfd, client_fd, clients); } continue; } @@ -175,8 +175,6 @@ int cws_server_loop(int sockfd, cws_config *config) { } cws_http_send_resource(request); - CWS_LOG_INFO("Client (%s) disconnected", ip); - cws_server_close_client(epfd, client_fd, clients); cws_http_free(request); /* Clear str */ diff --git a/test/hashmap_test.c b/test/hashmap_test.c deleted file mode 100644 index 430dcd8..0000000 --- a/test/hashmap_test.c +++ /dev/null @@ -1,85 +0,0 @@ -#include "utils/hashmap.h" - -#include -#include -#include - -#include "utils/colors.h" - -int my_hash_fn(void *key) { - char *key_str = (char *)key; - size_t key_len = strlen(key_str); - - int total = 0; - - for (size_t i = 0; i < key_len; ++i) { - total += (int)key_str[i]; - } - - return total % 2069; -} - -bool my_equal_fn(void *a, void *b) { - if (strcmp((char *)a, (char *)b) == 0) { - return true; - } - - return false; -} - -void my_free_fn(void *value) { free(value); } - -int main(void) { - bool ret; - cws_hashmap *str_hashmap = cws_hm_init(my_hash_fn, my_equal_fn, my_free_fn, my_free_fn); - - char *key = strdup("test1"); - if (key == NULL) { - CWS_LOG_ERROR("strdup() key"); - - return 1; - } - - char *value = strdup("value1"); - if (value == NULL) { - CWS_LOG_ERROR("strdup() value"); - free(key); - - return 1; - } - - /* Add a new key-value */ - ret = cws_hm_set(str_hashmap, (void *)key, (void *)value); - if (!ret) { - CWS_LOG_WARNING("Unable to set %s:%s", key, value); - } - - /* Get the added key-value */ - cws_bucket *bucket = cws_hm_get(str_hashmap, key); - CWS_LOG_DEBUG("Set %s:%s", (char *)bucket->key, (char *)bucket->value); - - /* Update the value */ - char *another_value = strdup("another value1"); - ret = cws_hm_set(str_hashmap, (void *)key, (void *)another_value); - if (!ret) { - CWS_LOG_WARNING("Unable to set %s:%s", key, another_value); - } - - bucket = cws_hm_get(str_hashmap, key); - CWS_LOG_DEBUG("Set %s:%s", (char *)bucket->key, (char *)bucket->value); - - /* Remove the key-value */ - ret = cws_hm_remove(str_hashmap, (void *)key); - if (ret) { - CWS_LOG_DEBUG("test1 removed"); - } - /* Can't use key, it has been freed */ - bucket = cws_hm_get(str_hashmap, (void *)"test1"); - if (bucket == NULL) { - CWS_LOG_DEBUG("test1 not found"); - } - - cws_hm_free(str_hashmap); - - return 0; -}