diff --git a/README.md b/README.md index 5f1b33c..61ec847 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ meson compile -C build ## Usage -1. Copy `config.yaml` and `www/` directory to your working directory +1. Copy `config.toml` and `www/` directory to your working directory 2. Run `./build/cws` 3. Open `http://localhost:3030` in your browser diff --git a/config.toml b/config.toml index 1de6d3e..06c3ff3 100644 --- a/config.toml +++ b/config.toml @@ -6,7 +6,8 @@ port = "3030" root = "www" [[virtual_hosts]] -domain = "localhost" +# "default" domain is required +domain = "default" root = "www" [[virtual_hosts.pages]] diff --git a/include/http/handler.h b/include/http/handler.h index 0c319d9..9fc78b5 100644 --- a/include/http/handler.h +++ b/include/http/handler.h @@ -4,17 +4,11 @@ #include "http/request.h" #include "http/response.h" -/* Configuration for static file serving */ typedef struct cws_handler_config { - const char *root_dir; - const char *index_file; + char *root; + char *domain; } cws_handler_config_s; -/* Static file handler */ cws_response_s *cws_handler_static_file(cws_request_s *request, cws_handler_config_s *config); -/* Error handlers */ -cws_response_s *cws_handler_not_found(cws_request_s *request); -cws_response_s *cws_handler_not_implemented(cws_request_s *request); - #endif diff --git a/include/http/request.h b/include/http/request.h index a77e7df..f3a22a8 100644 --- a/include/http/request.h +++ b/include/http/request.h @@ -12,6 +12,7 @@ typedef struct cws_request { cws_http_method_e method; + string_s *host; string_s *path; string_s *query_string; string_s *http_version; @@ -21,6 +22,8 @@ typedef struct cws_request { cws_request_s *cws_http_parse(string_s *request_str); +char *cws_http_get_host(cws_request_s *request); + void cws_http_free(cws_request_s *request); #endif diff --git a/meson.build b/meson.build index f55eb60..11fa6a5 100644 --- a/meson.build +++ b/meson.build @@ -2,9 +2,11 @@ project( 'cws', 'c', version: '0.1.0', - default_options: ['c_std=c11', 'warning_level=3'], + default_options: ['c_std=gnu23', 'warning_level=3'], ) +add_global_arguments('-Wno-pedantic', language: 'c') + cc = meson.get_compiler('c') subdir('src') diff --git a/src/config/config.c b/src/config/config.c index 67fef17..d211f1e 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -72,6 +72,17 @@ static bool parse_vhosts(cws_config_s *config, toml_result_t result) { return true; } +static bool find_default(cws_config_s *config) { + for (unsigned i = 0; i < config->virtual_hosts_count; ++i) { + cws_vhost_s *vh = config->virtual_hosts; + if (!strcmp(vh[i].domain, "default")) { + return true; + } + } + + return false; +} + static bool parse_toml(cws_config_s *config) { const char *path = "config.toml"; @@ -104,7 +115,7 @@ static bool parse_toml(cws_config_s *config) { toml_free(result); - return true; + return find_default(config); } cws_config_s *cws_config_init(void) { @@ -113,7 +124,9 @@ cws_config_s *cws_config_init(void) { return NULL; } - parse_toml(config); + if (!parse_toml(config)) { + return NULL; + } return config; } @@ -156,5 +169,7 @@ void cws_config_free(cws_config_s *config) { } } - free(config); + if (config) { + free(config); + } } diff --git a/src/core/worker.c b/src/core/worker.c index 963a96b..c55c8e7 100644 --- a/src/core/worker.c +++ b/src/core/worker.c @@ -27,7 +27,19 @@ static void worker_close_client(int epfd, int client_fd) { close(client_fd); } -static cws_return worker_handle_client_data(int epfd, int client_fd) { +static cws_vhost_s *get_vhost(cws_config_s *config, char *host) { + for (unsigned i = 0; i < config->virtual_hosts_count; ++i) { + cws_vhost_s *vh = config->virtual_hosts; + if (!strcmp(vh[i].domain, host)) { + return vh; + } + } + + /* ?? */ + return NULL; +} + +static cws_return worker_handle_client_data(int epfd, int client_fd, cws_config_s *config) { string_s *data = string_new("", 4096); /* Read data from socket */ @@ -55,14 +67,15 @@ static cws_return worker_handle_client_data(int epfd, int client_fd) { } /* Configure handler */ - /* TODO: use vhosts */ - cws_handler_config_s config = { - .root_dir = "www", - .index_file = "index.html", + char *host = cws_http_get_host(request); + cws_vhost_s *vh = get_vhost(config, host); + cws_handler_config_s conf = { + .domain = vh->domain, + .root = vh->root, }; /* Handle request and generate response */ - cws_response_s *response = cws_handler_static_file(request, &config); + cws_response_s *response = cws_handler_static_file(request, &conf); /* Send response */ if (response) { @@ -81,7 +94,7 @@ static cws_return worker_handle_client_data(int epfd, int client_fd) { /* Worker thread: process events on its epoll instance */ static void *cws_worker_loop(void *arg) { - cws_worker_s *worker = arg; + cws_worker_s *worker = (cws_worker_s *)arg; struct epoll_event events[64]; while (cws_server_run) { @@ -94,7 +107,7 @@ static void *cws_worker_loop(void *arg) { for (int i = 0; i < nfds; ++i) { int client_fd = events[i].data.fd; - worker_handle_client_data(worker->epfd, client_fd); + worker_handle_client_data(worker->epfd, client_fd, worker->config); } } diff --git a/src/http/handler.c b/src/http/handler.c index 136cca5..ca998c2 100644 --- a/src/http/handler.c +++ b/src/http/handler.c @@ -6,11 +6,12 @@ /* Sanitize and resolve file path */ static string_s *resolve_file_path(const char *url_path, cws_handler_config_s *config) { - string_s *full_path = string_new(config->root_dir, 256); + string_s *full_path = string_new(config->root, 256); if (strcmp(url_path, "/") == 0) { string_append(full_path, "/"); - string_append(full_path, config->index_file); + /* Use vhost index file */ + string_append(full_path, "index.html"); return full_path; } @@ -24,13 +25,21 @@ static bool file_exists(const char *filepath) { return stat(filepath, &st) == 0 && S_ISREG(st.st_mode); } +static cws_response_s *cws_handler_not_found(void) { + return cws_response_error(HTTP_NOT_FOUND, "The requested resource was not found."); +} + +static cws_response_s *cws_handler_not_implemented(void) { + return cws_response_error(HTTP_NOT_IMPLEMENTED, "Method not implemented."); +} + cws_response_s *cws_handler_static_file(cws_request_s *request, cws_handler_config_s *config) { if (!request || !config) { return cws_response_error(HTTP_INTERNAL_ERROR, "Invalid request or configuration"); } if (request->method != HTTP_GET) { - return cws_handler_not_implemented(request); + return cws_handler_not_implemented(); } string_s *filepath = resolve_file_path(string_cstr(request->path), config); @@ -38,7 +47,7 @@ cws_response_s *cws_handler_static_file(cws_request_s *request, cws_handler_conf if (!file_exists(path)) { string_free(filepath); - return cws_handler_not_found(request); + return cws_handler_not_found(); } cws_response_s *response = cws_response_new(HTTP_OK); @@ -53,13 +62,3 @@ cws_response_s *cws_handler_static_file(cws_request_s *request, cws_handler_conf return response; } - -cws_response_s *cws_handler_not_found(cws_request_s *request) { - (void)request; - return cws_response_error(HTTP_NOT_FOUND, "The requested resource was not found."); -} - -cws_response_s *cws_handler_not_implemented(cws_request_s *request) { - (void)request; - return cws_response_error(HTTP_NOT_IMPLEMENTED, "Method not implemented."); -} diff --git a/src/http/request.c b/src/http/request.c index 742061a..52a0e08 100644 --- a/src/http/request.c +++ b/src/http/request.c @@ -183,6 +183,15 @@ cws_request_s *cws_http_parse(string_s *request_str) { return request; } +char *cws_http_get_host(cws_request_s *request) { + bucket_s *host = hm_get(request->headers, "Host"); + if (!host) { + return "default"; + } + + return (char *)host->value; +} + void cws_http_free(cws_request_s *request) { if (!request) { return; diff --git a/src/main.c b/src/main.c index 33790e6..a16be4d 100644 --- a/src/main.c +++ b/src/main.c @@ -22,6 +22,7 @@ int main(void) { cws_config_s *config = cws_config_init(); if (!config) { + cws_log_error("Unable to parse config"); cws_log_shutdown(); return EXIT_FAILURE; }