feat(config): use toml config file
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
+2
-1
@@ -6,7 +6,8 @@ port = "3030"
|
||||
root = "www"
|
||||
|
||||
[[virtual_hosts]]
|
||||
domain = "localhost"
|
||||
# "default" domain is required
|
||||
domain = "default"
|
||||
root = "www"
|
||||
|
||||
[[virtual_hosts.pages]]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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.");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user