Static assets finally

This commit is contained in:
kamkow1
2025-06-22 14:57:24 +02:00
parent e04e6c135e
commit a7f8ebea09
7 changed files with 185 additions and 60 deletions

200
main.c
View File

@ -1,5 +1,8 @@
#include <libgen.h>
#include <pthread.h>
#include <ftw.h>
#include <signal.h>
#include <sys/sendfile.h>
#define GEBS_IMPLEMENTATION
#include "gebs/gebs.h"
@ -11,8 +14,14 @@
#include "baked.h"
#include "timer.h"
#include "CONFIG.h"
#include "clonestr.h"
Route *route_hashtable = NULL;
Route *route_hashtable = nil;
/* char *etc_dump_path = nil; */
struct { char *value; pthread_mutex_t lock; } etc_dump_path = {
.value = nil,
.lock = PTHREAD_MUTEX_INITIALIZER,
};
void run_in_thread(void *(*f)(void *), void *p)
{
@ -33,7 +42,38 @@ void *route_thread_function(void *param)
if (r <= 0) {
Route_Result result = {0};
result.status_code = 400;
result.type = ROUTE_RESULT_DYNAMIC;
/* list_append(&result.headers, clonestr("Content-Type: text/plain")); */
sb_append_nstr(&result.body, "Could not parse HTTP request");
sb_finish(&result.body);
mg_wakeup(data->mgr, data->conn_id, &result, sizeof(result));
free(data->message.buf);
free(data);
return nil;
}
if (mg_match(http_msg.uri, mg_str("/etc/*"), nil)) {
Route_Result result = {0};
result.type = ROUTE_RESULT_STATIC;
char *p = malloc(http_msg.uri.len+1);
strncpy(p, http_msg.uri.buf, http_msg.uri.len);
p[http_msg.uri.len] = 0;
char *file = basename(p);
char *full_path = malloc(PATH_MAX);
pthread_mutex_lock(&etc_dump_path.lock);
snprintf(full_path, PATH_MAX, "%s/%s", etc_dump_path.value, file);
pthread_mutex_unlock(&etc_dump_path.lock);
sb_append_nstr(&result.body, full_path);
sb_finish(&result.body);
free(full_path);
free(p);
mg_wakeup(data->mgr, data->conn_id, &result, sizeof(result));
free(data->message.buf);
free(data);
return nil;
}
@ -80,69 +120,146 @@ void event_handler(struct mg_connection *conn, int ev, void *ev_data)
}
sb_finish(&sb);
if (result->type == ROUTE_RESULT_TEXT) {
if (result->type == ROUTE_RESULT_DYNAMIC) {
mg_http_reply(conn, result->status_code, sb.items, "%s", result->body.items);
} else if (result->type == ROUTE_RESULT_BINARY) {
char *reply = fmt(
"HTTP/1.1 %d OK\r\n"
"%s"
"Content-Length: %zu\r\n"
"\r\n",
result->status_code,
sb.items,
result->body.count
);
printf("%s\n", reply);
mg_printf(conn, "%s", reply);
mg_send(conn, result->body.items, result->body.count);
} else if (result->type == ROUTE_RESULT_STATIC) {
char *path = result->body.items;
mg_http_serve_file(conn, ev_data, path, &(struct mg_http_serve_opts){0});
}
}
}
void route_hashtable_put_blogs(Baked_Resource *resource, void *udata)
{
if ((strlen(resource->key) >= strlen("blog-"))
&& strncmp(resource->key, "blog-", strlen("blog-")) == 0) {
char path[MG_PATH_MAX];
snprintf(path, MG_PATH_MAX, "/%s", resource->key);
shput(route_hashtable, path, &route_generic_blog);
route_hashtable[shgeti(route_hashtable, path)].context_data = (void *)resource;
}
}
void init_route_hashtable(void)
{
shdefault(route_hashtable, &route_page_not_found);
shput(route_hashtable, "/", &route_home);
shput(route_hashtable, "/page-missing", &route_page_not_found);
shput(route_hashtable, "/simple.css", &route_simple_css);
shput(route_hashtable, "/favicon.ico", &route_favicon);
shput(route_hashtable, "/blog", &route_blog);
#if MY_DEBUG
shput(route_hashtable, "/hotreload.js", &route_hotreload_js);
shput(route_hashtable, "/build-id", &route_build_id);
#endif
shput(route_hashtable, "/me.jpg", &route_me_jpg);
shput(route_hashtable, "/blog", &route_blog);
void put_blogs(Baked_Resource *resource)
{
if ((strlen(resource->key) >= strlen("blog-"))
&& strncmp(resource->key, "blog-", strlen("blog-")) == 0) {
char *path = malloc(MG_PATH_MAX);
snprintf(path, MG_PATH_MAX, "/%s", resource->key);
shput(route_hashtable, path, &route_generic_blog);
route_hashtable[shgeti(route_hashtable, path)].context_data = (void *)resource;
}
}
baked_resource_each(&put_blogs);
baked_resource_each(&route_hashtable_put_blogs, nil);
}
void free_route_hashtable(void)
{
for (size_t i = 0; i < shlen(route_hashtable); i++) {
if (strlen(route_hashtable[i].key) >= strlen("blog-")
&& strncmp(route_hashtable[i].key, "blog-", strlen("blog-")) == 0) {
free(route_hashtable[i].key);
}
}
shfree(route_hashtable);
}
char *init_etc_dump(void)
{
char template[] = "/tmp/aboba-etc.XXXXXX";
char *etc_dump1 = mkdtemp(template);
char *etc_dump = malloc(strlen(etc_dump1)+1);
strcpy(etc_dump, etc_dump1);
if (etc_dump == nil) {
LOGE("Could not create etc dump\n");
return nil;
}
LOGI("etc dump dir is %s\n", etc_dump);
return etc_dump;
}
int etc_dump_rm_cb(const char *path,
discard const struct stat *st,
discard int type,
discard struct FTW *ftw)
{
return remove(path);
}
bool free_etc_dump(char *etc_dump)
{
LOGI("Removing etc dump %s\n", etc_dump);
bool ok = nftw(etc_dump, etc_dump_rm_cb, FOPEN_MAX, FTW_DEPTH | FTW_MOUNT | FTW_PHYS) != -1;
if (!ok) {
LOGE("Could not remove %s\n", etc_dump);
}
free(etc_dump);
return ok;
}
// https://stackoverflow.com/questions/2180079/how-can-i-copy-a-file-on-unix-using-c
int cp(const char* source, const char* destination)
{
int result = 0;
int input, output;
if ((input = open(source, O_RDONLY)) == -1)
{
return -1;
}
if ((output = creat(destination, 0660)) == -1)
{
close(input);
return -1;
}
// sendfile will work with non-socket output (i.e. regular file) under
// Linux 2.6.33+ and some other unixy systems.
struct stat file_stat = {0};
result = fstat(input, &file_stat);
off_t copied = 0;
while (result == 0 && copied < file_stat.st_size) {
ssize_t written = sendfile(output, input, &copied, SSIZE_MAX);
copied += written;
if (written == -1) {
result = -1;
}
}
close(input);
close(output);
return result;
}
void populate_etc_dump(char *etc_dump)
{
static char *files[] = {
"favicon.ico", "hotreload.js",
"simple.css", "me.jpg",
};
for (size_t i = 0; i < sizeof(files)/sizeof(files[0]); i++) {
char path[PATH_MAX];
get_baked_resource_path(files[i], path, sizeof(path));
char dest[PATH_MAX];
snprintf(dest, sizeof(dest), "%s/%s", etc_dump, files[i]);
cp(path, dest);
}
}
volatile bool alive = true;
void graceful_shutdown(int no) { alive = false; }
int main(int argc, char ** argv)
{
signal(SIGINT, &graceful_shutdown);
start_timer();
init_baked_resources();
pthread_mutex_lock(&etc_dump_path.lock);
if ((etc_dump_path.value = init_etc_dump()) == nil) {
return 1;
}
populate_etc_dump(etc_dump_path.value);
pthread_mutex_unlock(&etc_dump_path.lock);
mg_log_set(MG_LL_DEBUG);
struct mg_mgr mgr;
@ -153,13 +270,16 @@ int main(int argc, char ** argv)
mg_wakeup_init(&mgr);
mg_http_listen(&mgr, CONFIG_LISTEN_URL, &event_handler, NULL);
for (;;) {
while (alive) {
mg_mgr_poll(&mgr, 1000);
scratch_arena_reset();
}
mg_mgr_free(&mgr);
pthread_mutex_lock(&etc_dump_path.lock);
free_etc_dump(etc_dump_path.value);
pthread_mutex_unlock(&etc_dump_path.lock);
free_baked_resources();
return 0;