improve error handling
This commit is contained in:
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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')
|
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user