improve error handling

This commit is contained in:
2025-08-02 00:28:24 +02:00
parent c7ad5d7874
commit fa964b2620
6 changed files with 42 additions and 111 deletions

View File

@@ -49,7 +49,7 @@ typedef struct cws_http_t {
cws_http *cws_http_parse(char *request_str, int sockfd, cws_config *config); cws_http *cws_http_parse(char *request_str, int sockfd, cws_config *config);
int cws_http_parse_method(cws_http *request, const char *method); 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); 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_response(cws_http *request, cws_http_status status);
void cws_http_send_resource(cws_http *request); 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); void cws_http_free(cws_http *request);

View File

@@ -13,5 +13,3 @@ add_global_arguments('-DUSE_COLORS', language : 'c')
add_global_arguments('-DEVELOPER', language : 'c') add_global_arguments('-DEVELOPER', language : 'c')
executable('cws', server, include_directories : incdir, dependencies : deps) executable('cws', server, include_directories : incdir, dependencies : deps)
executable('testbuild', test, include_directories : incdir)

View File

@@ -22,6 +22,7 @@ cws_http *cws_http_parse(char *request_str, int sockfd, cws_config *config) {
char *request_str_cpy = strdup(request_str); char *request_str_cpy = strdup(request_str);
if (!request_str_cpy) { if (!request_str_cpy) {
free(request); free(request);
return NULL; return NULL;
} }
@@ -37,13 +38,16 @@ cws_http *cws_http_parse(char *request_str, int sockfd, cws_config *config) {
return NULL; return NULL;
} }
CWS_LOG_DEBUG("method: %s", pch); CWS_LOG_DEBUG("method: %s", pch);
int ret = cws_http_parse_method(request, pch); int ret = cws_http_parse_method(request, pch);
if (ret < 0) { if (ret < 0) {
/* Not implemented */ /* Not implemented */
cws_http_free(request); cws_http_free(request);
free(request_str_cpy); 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 */ /* Parse location */
@@ -61,6 +65,10 @@ cws_http *cws_http_parse(char *request_str, int sockfd, cws_config *config) {
if (strcmp(request->location, "/") == 0) { if (strcmp(request->location, "/") == 0) {
snprintf(request->location_path, CWS_HTTP_LOCATION_PATH_LEN, "%s/index.html", config->www); snprintf(request->location_path, CWS_HTTP_LOCATION_PATH_LEN, "%s/index.html", config->www);
} else { } 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); snprintf(request->location_path, CWS_HTTP_LOCATION_PATH_LEN, "%s%s", config->www, request->location);
} }
CWS_LOG_DEBUG("location path: %s", request->location_path); 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; size_t total_len = header_len + body_len_bytes;
*response = (char *)malloc(total_len); *response = malloc(total_len);
if (*response == NULL) { if (*response == NULL) {
return 0; return 0;
} }
@@ -173,11 +181,11 @@ void cws_http_send_response(cws_http *request, cws_http_status status) {
case CWS_HTTP_OK: case CWS_HTTP_OK:
break; break;
case CWS_HTTP_NOT_FOUND: { 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; break;
} }
case CWS_HTTP_NOT_IMPLEMENTED: { 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; break;
} }
} }
@@ -192,7 +200,10 @@ void cws_http_send_resource(cws_http *request) {
/* Retrieve correct Content-Type */ /* Retrieve correct Content-Type */
char content_type[1024]; 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 */ /* Retrieve file size */
fseek(file, 0, SEEK_END); fseek(file, 0, SEEK_END);
@@ -213,13 +224,18 @@ void cws_http_send_resource(cws_http *request) {
if (read_bytes != content_length) { if (read_bytes != content_length) {
free(file_data); free(file_data);
CWS_LOG_ERROR("Partial read from file."); CWS_LOG_ERROR("Partial read from file");
return; 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; 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); size_t response_len = cws_http_response_builder(&response, "HTTP/1.1", CWS_HTTP_OK, content_type, conn, file_data, content_length);
CWS_LOG_DEBUG("%s", response);
size_t bytes_sent = 0; size_t bytes_sent = 0;
do { do {
@@ -231,15 +247,14 @@ void cws_http_send_resource(cws_http *request) {
free(file_data); 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, '.'); char *ptr = strrchr(request->location_path, '.');
if (ptr == NULL) { if (ptr == NULL) {
cws_http_send_error_page(request, CWS_HTTP_NOT_FOUND, "404 Not Found", "404 Not Found."); return -1;
return;
} }
ptr += 1; ptr += 1;
char ct[32]; char ct[32] = {0};
/* TODO: Improve content_type (used to test) */ /* TODO: Improve content_type (used to test) */
if (strcmp(ptr, "html") == 0 || strcmp(ptr, "css") == 0 || strcmp(ptr, "javascript") == 0) { 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); 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]; char body[512];
memset(body, 0, sizeof(body)); 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); title, description);
size_t body_len = strlen(body) * sizeof(char); 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; 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); send(request->sockfd, response, response_len, 0);
free(response); free(response);
} }

View File

@@ -1,6 +1,3 @@
server = files('main.c', 'server/server.c') server = files('main.c', 'server/server.c')
server += files('utils/utils.c', 'utils/hashmap.c', 'utils/config.c') server += files('utils/utils.c', 'utils/hashmap.c', 'utils/config.c')
server += files('http/http.c') server += files('http/http.c')
test = files('../test/hashmap_test.c')
test += files('utils/hashmap.c')

View File

@@ -108,7 +108,7 @@ int cws_server_loop(int sockfd, cws_config *config) {
return -1; 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) { if (!revents) {
mcl_hm_free(clients); mcl_hm_free(clients);
close(epfd); close(epfd);
@@ -160,8 +160,8 @@ int cws_server_loop(int sockfd, cws_config *config) {
if (bytes_read < 0) { if (bytes_read < 0) {
if (errno != EAGAIN && errno != EWOULDBLOCK) { if (errno != EAGAIN && errno != EWOULDBLOCK) {
/* Error during read, handle it (close client) */ /* Error during read, handle it (close client) */
cws_epoll_del(epfd, client_fd); CWS_LOG_INFO("Client (%s) disconnected (error)", ip);
close(client_fd); cws_server_close_client(epfd, client_fd, clients);
} }
continue; continue;
} }
@@ -175,8 +175,6 @@ int cws_server_loop(int sockfd, cws_config *config) {
} }
cws_http_send_resource(request); cws_http_send_resource(request);
CWS_LOG_INFO("Client (%s) disconnected", ip);
cws_server_close_client(epfd, client_fd, clients);
cws_http_free(request); cws_http_free(request);
/* Clear str */ /* Clear str */

View File

@@ -1,85 +0,0 @@
#include "utils/hashmap.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
}