summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSoikk2025-06-14 02:48:33 +0200
committerSoikk2025-06-14 02:48:33 +0200
commit02d02ed4ddba4d66d3f1d5ec92bfe9ec4ca182d0 (patch)
tree9ac6a83eb11455314946af54f1d3740f015c99c9 /src
parent4b87e75761cc90d6fe57dff08f8adc5559999508 (diff)
downloadsoikk-server-02d02ed4ddba4d66d3f1d5ec92bfe9ec4ca182d0.tar.xz
soikk-server-02d02ed4ddba4d66d3f1d5ec92bfe9ec4ca182d0.tar.zst
Reworked config. Added mime module. Reworked mime related functions in net module.
Diffstat (limited to 'src')
-rw-r--r--src/config/config.c285
-rw-r--r--src/config/config.h38
-rw-r--r--src/mime/mime.c59
-rw-r--r--src/mime/mime.h21
-rwxr-xr-xsrc/net/net.c55
-rwxr-xr-xsrc/net/net.h11
6 files changed, 371 insertions, 98 deletions
diff --git a/src/config/config.c b/src/config/config.c
index 5b4c6cc..3582e60 100644
--- a/src/config/config.c
+++ b/src/config/config.c
@@ -1,54 +1,281 @@
#include "config.h"
-config read_config(str cfg){
- config conf = {0};
+static void read_logs(str logs){
int off = 0;
- while(off < cfg.len){
- while(charisspace(cfg.ptr[off])) off++;
- if(cfg.ptr[off] == '#'){
- while(!charislinebreak(cfg.ptr[off])) off++;
+ while(off < logs.len){
+ while(off < logs.len && charisspace(logs.ptr[off])) off++;
+ if(logs.ptr[off] == '#'){
+ while(off < logs.len && !charislinebreak(logs.ptr[off])) off++;
continue;
}
- str key = sread_delim_f(cfg.ptr + off, charisspace, true);
- off += key.len + 1;
- while(charisspace(cfg.ptr[off])) off++;
+ int level;
+ str slevel = sread_delim_f(logs.ptr + off, charisspace, true);
+ off += slevel.len;
+ if(streq(slevel, sstr("DEBUG"))){
+ level = LOG_DEBUG;
+ }else if(streq(slevel, sstr("INFO"))){
+ level = LOG_INFO;
+ }else if(streq(slevel, sstr("WARN"))){
+ level = LOG_WARN;
+ }else if(streq(slevel, sstr("ERROR"))){
+ level = LOG_ERROR;
+ }else{
+ if(slevel.len != 0){
+ log_warn("Unexpected logging level in 'log' configuration: '%.*s'", slevel.len, slevel.ptr);
+ }
+ while(off < logs.len && !charislinebreak(logs.ptr[off])) off++;
+ continue;
+ }
+ if(log_get_files(level) >= MAX_LOGFILES){
+ log_warn("Cannot add any more files to logging level %.*s", slevel.len, slevel.ptr);
+ while(off < logs.len && !charislinebreak(logs.ptr[off])) off++;
+ continue;
+ }
+ while(off < logs.len && charisspace(logs.ptr[off])) off++;
+ str file = read_delim_f(logs.ptr + off, charisspace, true);
+ off += file.len;
+ while(off < logs.len && charisspace(logs.ptr[off])) off++;
+ str mode = read_delim_f(logs.ptr + off, charisspace, true);
+ off += mode.len;
+ if(streq(file, sstr("stderr"))){
+ int set = strtou(mode);
+ log_set_stderr(level, set);
+ }else if(streq(mode, sstr("w")) || streq(mode, sstr("a"))){
+ FILE *fp = fopen(file.ptr, mode.ptr);
+ if(fp == NULL){
+ log_warn("Error opening file '%.*s': %s", file.len, file.ptr, strerror(errno));
+ }else{
+ log_add_fp(level, fp);
+ }
+ }else{
+ log_warn("Invalid read mode for logging file '%.*s': '%.*s'. Only 'w' or 'a' permitted",
+ file.len, file.ptr, mode.len, mode.ptr);
+ }
+ free_str(&file);
+ free_str(&mode);
+ while(off < logs.len && !charislinebreak(logs.ptr[off])) off++;
+ }
+}
- if(streq(key, sstr("port"))){
- str val = sread_delim_f(cfg.ptr + off, charisspace, true);
+void rotate_logs(str logs){
+ for(int i = 0; i < LOG_LEVEL_COUNT; i++){
+ log_remove_fps(i);
+ log_set_stderr(i, 1);
+ }
+ read_logs(logs);
+}
+
+config_m master_config(char *filename){
+ config_m conf = {0};
+ conf.file = map_file(filename);
+ int off = 0;
+ while(off < conf.file.len){
+ while(off < conf.file.len && charisspace(conf.file.ptr[off])) off++;
+ if(conf.file.ptr[off] == '#'){
+ while(off < conf.file.len && !charislinebreak(conf.file.ptr[off])) off++;
+ continue;
+ }
+ str key = sread_delim_f(conf.file.ptr + off, charisspace, true);
+ off += key.len;
+ while(off < conf.file.len && charisspace(conf.file.ptr[off]) && !charislinebreak(conf.file.ptr[off])) off++;
+
+ if(streq(key, sstr("name"))){
+ conf.name = sread_delim_f(conf.file.ptr + off, charisspace, true);
+ off += conf.name.len;
+ }else if(streq(key, sstr("port"))){
+ str val = sread_delim_f(conf.file.ptr + off, charisspace, true);
off += val.len;
conf.port = (int)strtou(val);
+ }else if(streq(key, sstr("backlog"))){
+ str val = sread_delim_f(conf.file.ptr + off, charisspace, true);
+ off += val.len;
+ conf.backlog = (int)strtou(val);
+ }else if(streq(key, sstr("logs"))){
+ str val = sread_delim_f(conf.file.ptr + off, charisspace, true);
+ off += val.len;
+ str logs;
+ if(val.ptr[0] != '{'){
+ str logfile = dup_str(val);
+ logs = file_to_str(logfile.ptr);
+ free_str(&logfile);
+ }else{
+ logs = read_delim(conf.file.ptr + off, '}');
+ off += logs.len;
+ }
+ rotate_logs(logs);
+ free_str(&logs);
+ }else if(streq(key, sstr("worker"))){
+ int bcount = 1;
+ while(off < conf.file.len && bcount > 0){
+ if(conf.file.ptr[off] == '{') bcount++;
+ if(conf.file.ptr[off] == '}') bcount--;
+ off++;
+ }
+ }else if(key.len != 0){
+ log_warn("Unexpected entry in configuration: '%.*s'", key.len, key.ptr);
+ }
+ while(off < conf.file.len && !charislinebreak(conf.file.ptr[off])) off++;
+ off++;
+ };
+
+ return conf;
+}
+
+config_w worker_config(char *filename){
+ config_w conf = {0};
+ conf.file = map_file(filename);
+ init_nlist(conf.files);
+ int off = 0;
+ while(off < conf.file.len){
+ while(off < conf.file.len && charisspace(conf.file.ptr[off])) off++;
+ if(conf.file.ptr[off] == '#'){
+ while(off < conf.file.len && !charislinebreak(conf.file.ptr[off])) off++;
+ continue;
+ }
+ str key = sread_delim_f(conf.file.ptr + off, charisspace, true);
+ off += key.len;
+ while(off < conf.file.len && charisspace(conf.file.ptr[off]) && !charislinebreak(conf.file.ptr[off])) off++;
+
+ if(streq(key, sstr("name"))){
+ conf.name = sread_delim_f(conf.file.ptr + off, charisspace, true);
+ off += conf.name.len;
+ }else if(streq(key, sstr("root"))){
+ str val = sread_delim_f(conf.file.ptr + off, charisspace, true);
+ off += val.len;
+ str trailslash = val.ptr[val.len-1] == '/' ? sstr("") : sstr("/");
+ conf.root = dup_strs(val, trailslash);
+ }else if(streq(key, sstr("bundle"))){
+ conf.bundle = sread_delim_f(conf.file.ptr + off, charisspace, true);
+ off += conf.bundle.len;
+ }else if(streq(key, sstr("cert"))){
+ conf.cert = sread_delim_f(conf.file.ptr + off, charisspace, true);
+ off += conf.cert.len;
+ }else if(streq(key, sstr("key"))){
+ conf.key = sread_delim_f(conf.file.ptr + off, charisspace, true);
+ off += conf.key.len;
+ }else if(streq(key, sstr("https"))){
+ conf.secure = 1;
+ }else if(streq(key, sstr("http"))){
+ conf.secure = 0;
}else if(streq(key, sstr("ipv4"))){
conf.ipv4 = 1;
}else if(streq(key, sstr("ipv6"))){
conf.ipv6 = 1;
- }else if(streq(key, sstr("root"))){
- str val = sread_delim_f(cfg.ptr + off, charisspace, true);
- str trailslash = val.ptr[val.len-1] == '/' ? sstr("") : sstr("/");
- conf.root = dup_strs(val, trailslash);
- off += conf.root.len;
- }else{
- log_warn("Unexpected entry in configuration: '%.*s'", key.len, key.ptr);
+ }else if(streq(key, sstr("types"))){
+ str val = sread_delim_f(conf.file.ptr + off, charisspace, true);
+ off += val.len;
+ str types;
+ if(val.ptr[0] != '{'){
+ str typesfile = dup_str(val);
+ types = map_file(typesfile.ptr);
+ list_push(conf.files, types);
+ free_str(&typesfile);
+ }else{
+ types = sread_delim(conf.file.ptr + off, '}');
+ off += types.len;
+ }
+ read_mime_types(types);
+ }else if(streq(key, sstr("logs"))){
+ str val = sread_delim_f(conf.file.ptr + off, charisspace, true);
+ off += val.len;
+ str logs;
+ if(val.ptr[0] != '{'){
+ str logfile = dup_str(val);
+ logs = file_to_str(logfile.ptr);
+ free_str(&logfile);
+ }else{
+ logs = read_delim(conf.file.ptr + off, '}');
+ off += logs.len;
+ }
+ rotate_logs(logs);
+ free_str(&logs);
}
- while(!charislinebreak(cfg.ptr[off])) off++;
+ while(off < conf.file.len && !charislinebreak(conf.file.ptr[off])) off++;
off++;
};
+ return conf;
+}
+
+void free_master_config(config_m *conf){
+ conf->name = (str){0};
+ conf->port = 0;
+ conf->backlog = 0;
+ unmap_file(&conf->file);
+}
+
+void free_worker_config(config_w *conf){
+ conf->name = (str){0};
+ conf->root = (str){0};
+ conf->bundle = (str){0};
+ conf->cert = (str){0};
+ conf->key = (str){0};
+ conf->secure = 0;
+ conf->ipv4 = 0;
+ conf->ipv6 = 0;
+ free_mime_types();
+ for(int i = 0; i < list_size(conf->files); i++){
+ unmap_file(&conf->files[i]);
+ }
+ list_free(conf->files);
+ unmap_file(&conf->file);
+}
+
+void print_master_config(config_m conf){
printf(
- "CONFIGURATION:\n"
+ "MASTER CONFIGURATION:\n"
+ "\t- name: %.*s\n"
"\t- port: %d\n"
+ "\t- backlog: %d\n"
+ "\t- logs: {\n",
+ conf.name.len, conf.name.ptr,
+ conf.port,
+ conf.backlog
+ );
+ for(int i = 0; i < LOG_LEVEL_COUNT; i++){
+ switch(i){
+ case LOG_DEBUG: printf("\t\tDEBUG:\t"); break;
+ case LOG_INFO: printf("\t\tINFO:\t"); break;
+ case LOG_WARN: printf("\t\tWARN:\t"); break;
+ case LOG_ERROR: printf("\t\tERROR:\t"); break;
+ }
+ printf("%d files%s\n", log_get_files(i), log_get_stderr(i) ? " + stderr" : "");
+ }
+ printf("\t}\n");
+}
+
+void print_worker_config(config_w conf){
+ printf(
+ "WORKER CONFIGURATION:\n"
+ "\t- name: %.*s\n"
+ "\t- root: %.*s\n"
+ "\t- bundle: %.*s\n"
+ "\t- cert: %.*s\n"
+ "\t- key: %.*s\n"
"\t- secure: %s\n"
"\t- ipv4: %s\n"
- "\t- ipv6: %s\n"
- "\t- workers: %d\n"
- "\t- root: %s\n",
- conf.port,
+ "\t- ipv6: %s\n",
+ conf.name.len, conf.name.ptr,
+ conf.root.len, conf.root.ptr,
+ conf.bundle.len, conf.bundle.ptr,
+ conf.cert.len, conf.cert.ptr,
+ conf.key.len, conf.key.ptr,
conf.secure ? "yes" : "no",
conf.ipv4 ? "yes" : "no",
- conf.ipv6 ? "yes" : "no",
- conf.workers,
- conf.root.ptr
+ conf.ipv6 ? "yes" : "no"
);
-
- return conf;
+ print_mime_types();
+ printf("\t- logs: {\n");
+ for(int i = 0; i < LOG_LEVEL_COUNT; i++){
+ switch(i){
+ case LOG_DEBUG: printf("\t\tDEBUG:\t"); break;
+ case LOG_INFO: printf("\t\tINFO:\t"); break;
+ case LOG_WARN: printf("\t\tWARN:\t"); break;
+ case LOG_ERROR: printf("\t\tERROR:\t"); break;
+ }
+ printf("%d files%s\n", log_get_files(i), log_get_stderr(i) ? " + stderr" : "");
+ }
+ printf("\t}\n");
}
+
diff --git a/src/config/config.h b/src/config/config.h
index 4f04459..9a8f058 100644
--- a/src/config/config.h
+++ b/src/config/config.h
@@ -3,17 +3,39 @@
#include "str/str.h"
#include "log/log.h"
+#include "list/list.h"
+#include "mime/mime.h"
+#include <errno.h>
-typedef struct config {
+
+typedef struct config_m {
+ str file;
+ str name;
int port;
- int secure : 1;
- int ipv4 : 1;
- int ipv6 : 1;
- int workers;
+ int backlog;
+} config_m;
+
+typedef struct config_w {
+ str file;
+ str name;
str root;
-
-} config;
+ str bundle;
+ str cert;
+ str key;
+ uint secure : 1;
+ uint ipv4 : 1;
+ uint ipv6 : 1;
+ str *files;
+} config_w;
+
+
+config_m master_config(char *filename);
+config_w worker_config(char *filename);
+
+void free_master_config(config_m *conf);
+void free_worker_config(config_w *conf);
-config read_config(str cfg);
+void print_master_config(config_m conf);
+void print_worker_config(config_w conf);
#endif
diff --git a/src/mime/mime.c b/src/mime/mime.c
new file mode 100644
index 0000000..99250ea
--- /dev/null
+++ b/src/mime/mime.c
@@ -0,0 +1,59 @@
+#include "mime.h"
+
+
+// look into making this a BST or something more efficient
+static mime_type *types;
+
+void add_mime_type(mime_type mt){
+ list_push(types, mt);
+}
+
+void read_mime_types(str file){
+ if(types == NULL){
+ init_nlist(types);
+ }
+ int off = 0;
+ while(off < file.len){
+ while(off < file.len && charisspace(file.ptr[off])) off++;
+ if(file.ptr[off] == '#'){
+ while(off < file.len && !charislinebreak(file.ptr[off])) off++;
+ continue;
+ }
+ mime_type mt;
+ mt.desc = sread_delim_f(file.ptr + off, charisspace, true);
+ off += mt.desc.len;
+ while(off < file.len && charisspace(file.ptr[off])) off++;
+ mt.ext = sread_delim_f(file.ptr + off, charisspace, true);
+ off += mt.ext.len;
+ while(off < file.len && !charislinebreak(file.ptr[off])) off++;
+ if(mt.desc.len == 0 || mt.ext.len == 0){
+ continue;
+ }
+ add_mime_type(mt);
+ }
+}
+
+str get_mime_type(str ext){
+ int size = list_size(types);
+ for(int i = 0; i < size; i++){
+ if(streq(types[i].ext, ext)){
+ return types[i].desc;
+ }
+ }
+ return (str){0};
+}
+
+void free_mime_types(void){
+ list_free(types);
+}
+
+void print_mime_types(void){
+ int size = list_size(types);
+ printf("\t- types: {\n");
+ for(int i = 0; i < size; i++){
+ printf("\t\t%.*s\t%.*s\n",
+ types[i].desc.len, types[i].desc.ptr, types[i].ext.len, types[i].ext.ptr);
+ }
+ printf("\t}\n");
+}
+
diff --git a/src/mime/mime.h b/src/mime/mime.h
new file mode 100644
index 0000000..dada0a3
--- /dev/null
+++ b/src/mime/mime.h
@@ -0,0 +1,21 @@
+#ifndef MIME_H
+#define MIME_H
+
+#include "str/str.h"
+#include "list/list.h"
+
+
+typedef struct mime_type {
+ str desc;
+ str ext;
+} mime_type;
+
+
+void add_mime_type(mime_type mt);
+void read_mime_types(str file);
+str get_mime_type(str ext);
+void free_mime_types(void);
+
+void print_mime_types(void);
+
+#endif
diff --git a/src/net/net.c b/src/net/net.c
index e7c5981..3e70cef 100755
--- a/src/net/net.c
+++ b/src/net/net.c
@@ -12,47 +12,6 @@ str response_headers[] = {
sstr("Transfer-Encoding"),
};
-struct {
- str fmt;
- str type;
-} mime_types[] = {
- {.fmt = sstr("avif"), .type = sstr("image/avif")},
- {.fmt = sstr("bmp"), .type = sstr("image/bmp")},
- {.fmt = sstr("css"), .type = sstr("text/css")},
- {.fmt = sstr("csv"), .type = sstr("text/csv")},
- {.fmt = sstr("eot"), .type = sstr("application/vnd.ms-fontobject")},
- {.fmt = sstr("gz"), .type = sstr("application/gzip")},
- {.fmt = sstr("gif"), .type = sstr("image/gif")},
- {.fmt = sstr("html"), .type = sstr("text/html")},
- {.fmt = sstr("ico"), .type = sstr("image/vnd.microsoft.icon")},
- {.fmt = sstr("jpg"), .type = sstr("image/jpeg")},
- {.fmt = sstr("jpeg"), .type = sstr("image/jpeg")},
- {.fmt = sstr("js"), .type = sstr("text/javascript")},
- {.fmt = sstr("json"), .type = sstr("application/json")},
- {.fmt = sstr("midi"), .type = sstr("audio/midi")},
- {.fmt = sstr("mp3"), .type = sstr("audio/mpeg")},
- {.fmt = sstr("mp4"), .type = sstr("video/mp4")},
- {.fmt = sstr("mpeg"), .type = sstr("video/mpeg")},
- {.fmt = sstr("png"), .type = sstr("image/png")},
- {.fmt = sstr("pdf"), .type = sstr("application/pdf")},
- {.fmt = sstr("php"), .type = sstr("application/x-httpd-php")},
- {.fmt = sstr("rar"), .type = sstr("application/vnd.rar")},
- {.fmt = sstr("svg"), .type = sstr("image/svg+xml")},
- {.fmt = sstr("tiff"), .type = sstr("image/tiff")},
- {.fmt = sstr("ts"), .type = sstr("video/mp2t")},
- {.fmt = sstr("ttf"), .type = sstr("font/ttf")},
- {.fmt = sstr("txt"), .type = sstr("text/plain")},
- {.fmt = sstr("wav"), .type = sstr("audio/wav")},
- {.fmt = sstr("weba"), .type = sstr("audio/webm")},
- {.fmt = sstr("webm"), .type = sstr("video/webm")},
- {.fmt = sstr("webp"), .type = sstr("image/webp")},
- {.fmt = sstr("woff"), .type = sstr("font/woff")},
- {.fmt = sstr("woff2"), .type = sstr("font/woff2")},
- {.fmt = sstr("xml"), .type = sstr("application/xml")},
- {.fmt = sstr("zip"), .type = sstr("application/zip")},
- {.fmt = sstr("7z"), .type = sstr("application/x-7z-compressed")},
-};
-
LIST(struct uri_mod) uri_rewrites = NULL;
static int pleasesslgivemetheerror(int ssl_get_error){
@@ -597,20 +556,14 @@ void send_file(http_worker *hw, str filename){
}
log_info("sending '%.*s'", filename.len, filename.ptr);
- enum mime_type type = TXT;
- str fmt = dstr(get_extension(filename.ptr));
- for(int i = 0; i < sizeof(mime_types)/sizeof(mime_types[0]); i++){
- if(strncmp(fmt.ptr, mime_types[i].fmt.ptr, fmt.len) == 0){
- type = i;
- break;
- }
- }
- free_str(&fmt);
+ str ext = dsstr(get_extension(filename.ptr));
+ str type = get_mime_type(ext);
+ if(type.len == 0) type = sstr("text/plain");
struct http_message hm = {
.resp_ver = sstr("HTTP/1.1"), .status = sstr("200"), .reason = sstr("OK"),
.hlen = 2, .headers = {
- { .name = response_headers[CONTENT_TYPE], .value = mime_types[type].type },
+ { .name = response_headers[CONTENT_TYPE], .value = type },
{ .name = response_headers[CONTENT_LENGTH], .value = utostr(fsize, 10) }
},
.body = {0},
diff --git a/src/net/net.h b/src/net/net.h
index 79886df..dc7c147 100755
--- a/src/net/net.h
+++ b/src/net/net.h
@@ -19,6 +19,7 @@
#include "list/list.h"
#include "files/files.h"
#include "log/log.h"
+#include "mime/mime.h"
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <poll.h>
@@ -34,16 +35,6 @@ typedef enum http_method {
} http_method;
-
-enum mime_type {
- AVIF, BMP, CSS, CSV, GZ, GIF, HTML,
- ICO, JPG, JPEG, JS, JSON, MIDI, MP3,
- MP4, MPEG, PNG, PDF, PHP, RAR, TIFF, TS,
- TXT, WAV, WEBA, WEBM, WEBP, XML, ZIP,
- _7Z,
-};
-
-
struct uri {
str path;
str query;