diff --git a/include/server/server.h b/include/server/server.h index dacc7a0..9e36cd6 100644 --- a/include/server/server.h +++ b/include/server/server.h @@ -9,15 +9,14 @@ #include "utils/config.h" /* Clients max queue */ -#define CWS_SERVER_BACKLOG 10 +#define CWS_SERVER_BACKLOG 128 /* Size of the epoll_event array */ -#define CWS_SERVER_EPOLL_MAXEVENTS 10 +#define CWS_SERVER_EPOLL_MAXEVENTS 64 -/* Wait forever (epoll_wait()) */ -#define CWS_SERVER_EPOLL_TIMEOUT -1 +#define CWS_SERVER_EPOLL_TIMEOUT 1000 -#define CWS_SERVER_MAX_REQUEST_SIZE (64 * 1024) /* 64 KB */ +#define CWS_SERVER_MAX_REQUEST_SIZE (16 * 1024) /* 16KB */ /* Main server loop */ extern volatile sig_atomic_t cws_server_run; diff --git a/src/http/http.c b/src/http/http.c index f118362..4967cfc 100644 --- a/src/http/http.c +++ b/src/http/http.c @@ -1,5 +1,6 @@ #include "http/http.h" +#include #include #include #include @@ -207,14 +208,16 @@ int cws_http_send_resource(cws_http *request) { FILE *file = fopen(mcl_string_cstr(request->location_path), "rb"); if (file == NULL) { cws_http_send_response(request, CWS_HTTP_NOT_FOUND); - return -1; + return 0; } /* Retrieve correct Content-Type */ char content_type[1024]; int ret = cws_http_get_content_type(request, content_type); if (ret < 0) { + fclose(file); cws_http_send_response(request, CWS_HTTP_NOT_FOUND); + return 0; } /* Retrieve file size */ @@ -227,20 +230,21 @@ int cws_http_send_resource(cws_http *request) { if (file_data == NULL) { fclose(file); CWS_LOG_ERROR("Unable to allocate file data"); - return -1; + return 0; } - /* Read 1 byte until content_length from file and put in file_data */ + /* Read file data */ size_t read_bytes = fread(file_data, 1, content_length, file); fclose(file); if (read_bytes != content_length) { free(file_data); CWS_LOG_ERROR("Partial read from file"); - return -1; + return 0; } - char conn[32]; + /* Check for keep-alive connection */ + char conn[32] = "close"; mcl_bucket *connection = mcl_hm_get(request->headers, "Connection"); if (connection && strcmp((char *)connection->value, "keep-alive") == 0) { strcpy(conn, "keep-alive"); @@ -250,12 +254,23 @@ int cws_http_send_resource(cws_http *request) { char *response = NULL; size_t response_len = cws_http_response_builder(&response, "HTTP/1.1", CWS_HTTP_OK, content_type, conn, file_data, content_length); + /* Send response in chunks to avoid blocking */ size_t bytes_sent = 0; - size_t sent; - do { - sent = send(request->sockfd, response + bytes_sent, response_len, 0); + ssize_t sent; + const size_t chunk_size = 8192; + + while (bytes_sent < response_len) { + size_t to_send = (response_len - bytes_sent > chunk_size) ? chunk_size : (response_len - bytes_sent); + sent = send(request->sockfd, response + bytes_sent, to_send, MSG_NOSIGNAL); + + if (sent <= 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + continue; + } + break; + } bytes_sent += sent; - } while (bytes_sent < response_len && sent != 0); + } free(response); free(file_data); @@ -300,17 +315,24 @@ void cws_http_send_simple_html(cws_http *request, cws_http_status status, char * "" "", title, description); - size_t body_len = strlen(body) * sizeof(char); + size_t body_len = strlen(body); char conn[32] = "close"; mcl_bucket *connection = mcl_hm_get(request->headers, "Connection"); if (connection) { - strncpy(conn, (char *)connection->value, sizeof(conn)); + strncpy(conn, (char *)connection->value, sizeof(conn) - 1); + conn[sizeof(conn) - 1] = '\0'; } char *response = NULL; 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 response with error handling */ + ssize_t sent = send(request->sockfd, response, response_len, MSG_NOSIGNAL); + if (sent < 0) { + CWS_LOG_ERROR("Failed to send response: %s", strerror(errno)); + } + free(response); } diff --git a/src/server/server.c b/src/server/server.c index a41034f..32d77c4 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -119,7 +119,6 @@ cws_server_ret cws_server_loop(int sockfd, cws_config *config) { int nfds = epoll_wait(epfd, revents, CWS_SERVER_EPOLL_MAXEVENTS, CWS_SERVER_EPOLL_TIMEOUT); if (nfds == 0) { - CWS_LOG_INFO("epoll timeout, continue..."); continue; } @@ -167,10 +166,10 @@ cws_server_ret cws_server_handle_new_client(int sockfd, int epfd, mcl_hashmap *c } cws_server_ret cws_server_handle_client_data(int client_fd, int epfd, mcl_hashmap *clients, cws_config *config) { - char tmp_data[4096]; + char tmp_data[1024]; memset(tmp_data, 0, sizeof(tmp_data)); char ip[INET_ADDRSTRLEN] = {0}; - mcl_string *data = mcl_string_new("", 4096); + mcl_string *data = mcl_string_new("", 1024); /* Incoming data */ ssize_t total_bytes = 0; @@ -184,6 +183,7 @@ cws_server_ret cws_server_handle_client_data(int client_fd, int epfd, mcl_hashma return CWS_SERVER_REQUEST_TOO_LARGE; } mcl_string_append(data, tmp_data); + memset(tmp_data, 0, sizeof(tmp_data)); } if (bytes_read < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { @@ -199,6 +199,7 @@ cws_server_ret cws_server_handle_client_data(int client_fd, int epfd, mcl_hashma mcl_bucket *client = mcl_hm_get(clients, &client_fd); if (!client) { CWS_LOG_ERROR("Client fd %d not found in hashmap", client_fd); + mcl_string_free(data); cws_epoll_del(epfd, client_fd); close(client_fd); @@ -229,7 +230,9 @@ cws_server_ret cws_server_handle_client_data(int client_fd, int epfd, mcl_hashma int keepalive = cws_http_send_resource(request); cws_http_free(request); - if (!keepalive) { + + /* Only close connection if not keep-alive */ + if (keepalive <= 0) { cws_server_close_client(epfd, client_fd, clients); }