Compare commits

...

2 Commits

Author SHA1 Message Date
francesco 93d09ae9df refactor(doxygen): remove doxygen 2026-02-25 19:12:22 +01:00
francesco 825c02b626 feat(config): use toml config file 2026-02-25 19:06:52 +01:00
12 changed files with 73 additions and 2912 deletions
-3
View File
@@ -1,3 +0,0 @@
[submodule "doxygen-awesome-css"]
path = doxygen-awesome-css
url = https://github.com/jothepro/doxygen-awesome-css.git
-2864
View File
File diff suppressed because it is too large Load Diff
+1 -10
View File
@@ -19,19 +19,10 @@ 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
## Documentation
```bash
git submodule update --init
doxygen
```
Then open `docs/html/index.html`.
## Roadmap
- [ ] Virtual hosts support
+2 -1
View File
@@ -6,7 +6,8 @@ port = "3030"
root = "www"
[[virtual_hosts]]
domain = "localhost"
# "default" domain is required
domain = "default"
root = "www"
[[virtual_hosts.pages]]
+2 -8
View File
@@ -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
+3
View File
@@ -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
+3 -1
View File
@@ -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')
+18 -3
View File
@@ -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);
}
}
+21 -8
View File
@@ -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);
}
}
+13 -14
View File
@@ -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.");
}
+9
View File
@@ -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;
+1
View File
@@ -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;
}