From cfaae5529e9f02e365ecc0fe5180969d264dccd7 Mon Sep 17 00:00:00 2001 From: Francesco Date: Tue, 10 Feb 2026 00:23:17 +0100 Subject: [PATCH] refactor(config): use toml file --- README.md | 2 +- config.toml | 22 +++++ config.yaml | 17 ---- include/config/config.h | 13 +-- meson.build | 5 +- src/config/config.c | 185 ++++++++++++++++++++++++++++------------ src/core/server.c | 6 +- src/http/response.c | 1 + src/main.c | 2 +- 9 files changed, 167 insertions(+), 86 deletions(-) create mode 100644 config.toml delete mode 100644 config.yaml diff --git a/README.md b/README.md index 3fa00c8..5f1b33c 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ A minimal HTTP web server written in C. ## Requirements -- [libcyaml](https://github.com/tlsa/libcyaml) - myclib (on my profile) +- [tomlc17](https://github.com/cktan/tomlc17) - [doxygen](https://www.doxygen.nl/) (optional, for documentation only - requires `dot`) ## Build diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..1de6d3e --- /dev/null +++ b/config.toml @@ -0,0 +1,22 @@ +# Default server values +[server] +host = "localhost" +port = "3030" +# Root folder in case there are no virtual hosts +root = "www" + +[[virtual_hosts]] +domain = "localhost" +root = "www" + +[[virtual_hosts.pages]] +status = "404" +path = "www/pages/404.html" + +[[virtual_hosts.pages]] +status = "505" +path = "www/pages/505.html" + +[[virtual_hosts]] +domain = "example.com" +root = "example_site" diff --git a/config.yaml b/config.yaml deleted file mode 100644 index a65ad58..0000000 --- a/config.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# Default hostname -hostname: localhost - -# Running port -port: 3030 - -# Virtual hosts setup -virtual_hosts: - - domain: localhost - # Root folder - root: www - # Custom pages - error_pages: - - method: 404 - path: pages/404.html - - method: 500 - path: pages/500.html diff --git a/include/config/config.h b/include/config/config.h index df277f9..275605d 100644 --- a/include/config/config.h +++ b/include/config/config.h @@ -3,21 +3,22 @@ #include -typedef struct cws_error_page { - unsigned method; - const char *path; -} cws_error_page; +typedef struct cws_page { + char *status; + char *path; +} cws_page_s; typedef struct cws_vhost { char *domain; char *root; - cws_error_page *error_pages; + cws_page_s *error_pages; unsigned error_pages_count; } cws_vhost_s; typedef struct cws_config { - char *hostname; + char *host; char *port; + char *root; cws_vhost_s *virtual_hosts; unsigned virtual_hosts_count; } cws_config_s; diff --git a/meson.build b/meson.build index b2a5b7a..7e18d31 100644 --- a/meson.build +++ b/meson.build @@ -11,12 +11,11 @@ subdir('src') incdir = include_directories('include') -libyaml = dependency('yaml-0.1') -libcyaml = dependency('libcyaml') +libtomlc17 = dependency('libtomlc17', required: true) libmath = cc.find_library('m', required: true) libmyclib = cc.find_library('myclib', required: true) -deps = [libyaml, libcyaml, libmath, libmyclib] +deps = [libtomlc17, libmath, libmyclib] add_global_arguments('-DUSE_COLORS', language: 'c') add_global_arguments('-DEVELOPER', language: 'c') diff --git a/src/config/config.c b/src/config/config.c index 634a65d..67fef17 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -1,85 +1,160 @@ #include "config/config.h" -#include +#include #include +#include #include "utils/debug.h" -static const cyaml_config_t cyaml_config = { - .log_fn = cyaml_log, - .mem_fn = cyaml_mem, - .log_level = CYAML_LOG_WARNING, -}; +static char *cws_strdup(const char *str) { + if (!str) { + return NULL; + } -static const cyaml_schema_field_t error_page_fields[] = { - CYAML_FIELD_INT("method", CYAML_FLAG_DEFAULT, cws_error_page, method), - CYAML_FIELD_STRING_PTR("path", CYAML_FLAG_POINTER, cws_error_page, path, 0, CYAML_UNLIMITED), - CYAML_FIELD_END, -}; + size_t len = strlen(str) + 1; + char *copy = malloc(sizeof *copy * len); + if (!copy) { + return NULL; + } -static cyaml_schema_value_t error_page_schema = { - CYAML_VALUE_MAPPING(CYAML_FLAG_DEFAULT, cws_error_page, error_page_fields), -}; + memcpy(copy, str, len); -static const cyaml_schema_field_t virtual_hosts_fields[] = { - CYAML_FIELD_STRING_PTR("domain", CYAML_FLAG_POINTER, struct cws_vhost, domain, 0, CYAML_UNLIMITED), - CYAML_FIELD_STRING_PTR("root", CYAML_FLAG_POINTER, struct cws_vhost, root, 0, CYAML_UNLIMITED), - CYAML_FIELD_SEQUENCE("error_pages", CYAML_FLAG_POINTER | CYAML_FLAG_OPTIONAL, struct cws_vhost, error_pages, - &error_page_schema, 0, CYAML_UNLIMITED), - CYAML_FIELD_END, -}; + return copy; +} -static cyaml_schema_value_t virtual_hosts_schema = { - CYAML_VALUE_MAPPING(CYAML_FLAG_DEFAULT, struct cws_vhost, virtual_hosts_fields), -}; +static bool parse_vhosts(cws_config_s *config, toml_result_t result) { + toml_datum_t vhosts = toml_seek(result.toptab, "virtual_hosts"); + config->virtual_hosts_count = vhosts.u.arr.size; + config->virtual_hosts = malloc(sizeof *config->virtual_hosts * config->virtual_hosts_count); + if (!config->virtual_hosts) { + return false; + } -static const cyaml_schema_field_t top_schema_fields[] = { - CYAML_FIELD_STRING_PTR("hostname", CYAML_FLAG_POINTER, struct cws_config, hostname, 0, CYAML_UNLIMITED), - CYAML_FIELD_STRING_PTR("port", CYAML_FLAG_POINTER, struct cws_config, port, 0, CYAML_UNLIMITED), - CYAML_FIELD_SEQUENCE("virtual_hosts", CYAML_FLAG_POINTER, struct cws_config, virtual_hosts, &virtual_hosts_schema, - 0, CYAML_UNLIMITED), - CYAML_FIELD_END, -}; + for (int i = 0; i < vhosts.u.arr.size; ++i) { + cws_vhost_s *vh = &config->virtual_hosts[i]; + toml_datum_t elem = vhosts.u.arr.elem[i]; + toml_datum_t domain = toml_seek(elem, "domain"); + vh->domain = cws_strdup(domain.u.str.ptr); + if (!vh->domain) { + return false; + } -static cyaml_schema_value_t top_schema = { - CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, struct cws_config, top_schema_fields), -}; + toml_datum_t root = toml_seek(elem, "root"); + vh->root = cws_strdup(root.u.str.ptr); + if (!vh->root) { + return false; + } -static bool find_default_hostname(cws_config_s *config) { - for (unsigned i = 0; i < config->virtual_hosts_count; ++i) { - if (strcmp(config->hostname, config->virtual_hosts[i].domain) == 0) { - return true; + /* Pages */ + toml_datum_t pages = toml_seek(elem, "pages"); + vh->error_pages_count = pages.u.arr.size; + vh->error_pages = malloc(sizeof *vh->error_pages * vh->error_pages_count); + if (!vh->error_pages) { + return false; + } + + for (int j = 0; j < pages.u.arr.size; ++j) { + toml_datum_t page = pages.u.arr.elem[i]; + toml_datum_t status = toml_seek(page, "status"); + vh->error_pages[i].status = cws_strdup(status.u.str.ptr); + if (!vh->error_pages[i].status) { + return false; + } + + toml_datum_t path = toml_seek(page, "path"); + vh->error_pages[i].path = cws_strdup(path.u.str.ptr); + if (!vh->error_pages[i].path) { + return false; + } } } - return false; + return true; +} + +static bool parse_toml(cws_config_s *config) { + const char *path = "config.toml"; + + toml_result_t result = toml_parse_file_ex(path); + if (!result.ok) { + cws_log_error("Unable to parse config.toml"); + + return false; + } + + toml_datum_t host = toml_seek(result.toptab, "server.host"); + config->host = cws_strdup(host.u.str.ptr); + if (!config->host) { + return false; + } + + toml_datum_t port = toml_seek(result.toptab, "server.port"); + config->port = cws_strdup(port.u.str.ptr); + if (!config->port) { + return false; + } + + toml_datum_t root = toml_seek(result.toptab, "server.root"); + config->root = cws_strdup(root.u.str.ptr); + if (!config->root) { + return false; + } + + parse_vhosts(config, result); + + toml_free(result); + + return true; } cws_config_s *cws_config_init(void) { - const char *path = "config.yaml"; - cws_config_s *config; - - cyaml_err_t err = cyaml_load_file(path, &cyaml_config, &top_schema, (cyaml_data_t **)&config, NULL); - if (err != CYAML_OK) { - cws_log_error("%s", cyaml_strerror(err)); - + cws_config_s *config = malloc(sizeof *config); + if (!config) { return NULL; } - bool found = find_default_hostname(config); - if (!found) { - cws_log_error("Default hostname not found in config.yaml"); - cws_config_free(config); - - return NULL; - } + parse_toml(config); return config; } void cws_config_free(cws_config_s *config) { - cyaml_err_t err = cyaml_free(&cyaml_config, &top_schema, config, 0); - if (err != CYAML_OK) { + if (!config) { return; } + + if (config->host) { + free(config->host); + } + + if (config->port) { + free(config->port); + } + + if (config->root) { + free(config->root); + } + + for (unsigned i = 0; i < config->virtual_hosts_count; ++i) { + cws_vhost_s *vh = &config->virtual_hosts[i]; + if (vh->domain) { + free(vh->domain); + } + + if (vh->root) { + free(vh->root); + } + + for (unsigned j = 0; j < vh->error_pages_count; ++j) { + if (vh->error_pages[i].path) { + free(vh->error_pages[i].path); + } + + if (vh->error_pages[i].status) { + free(vh->error_pages[i].status); + } + } + } + + free(config); } diff --git a/src/core/server.c b/src/core/server.c index 2dab184..1165c27 100644 --- a/src/core/server.c +++ b/src/core/server.c @@ -41,7 +41,7 @@ static cws_return cws_server_setup_epoll(int server_fd, int *epfd_out) { } cws_return cws_server_setup(cws_server_s *server, cws_config_s *config) { - if (!config || !config->hostname || !config->port) { + if (!config || !config->host || !config->port) { return CWS_CONFIG_ERROR; } @@ -49,9 +49,9 @@ cws_return cws_server_setup(cws_server_s *server, cws_config_s *config) { struct addrinfo hints; struct addrinfo *res; - cws_server_setup_hints(&hints, config->hostname); + cws_server_setup_hints(&hints, config->host); - int status = getaddrinfo(config->hostname, config->port, &hints, &res); + int status = getaddrinfo(config->host, config->port, &hints, &res); if (status != 0) { cws_log_error("getaddrinfo() error: %s", gai_strerror(status)); return CWS_GETADDRINFO_ERROR; diff --git a/src/http/response.c b/src/http/response.c index bb13892..03339bc 100644 --- a/src/http/response.c +++ b/src/http/response.c @@ -30,6 +30,7 @@ cws_response_s *cws_response_new(cws_http_status_e status) { resp->body_file = NULL; resp->content_length = 0; + /* TODO: get the value from connection */ cws_response_set_header(resp, "Connection", "close"); return resp; diff --git a/src/main.c b/src/main.c index 31b4fea..5aa4375 100644 --- a/src/main.c +++ b/src/main.c @@ -38,7 +38,7 @@ int main(void) { return EXIT_FAILURE; } - cws_log_info("Running cws on http://%s:%s", config->hostname, config->port); + cws_log_info("Running cws on http://%s:%s", config->host, config->port); ret = cws_server_start(&server); if (ret != CWS_OK) { cws_log_error("Unable to start web server: %s", cws_error_str(ret));