Compare commits
4 Commits
e04e6c135e
...
e230bb01c0
Author | SHA1 | Date | |
---|---|---|---|
e230bb01c0 | |||
68dcc80d1c | |||
5ee77b4628 | |||
a7f8ebea09 |
36
baked.c
36
baked.c
@ -5,6 +5,7 @@
|
||||
#include "stb/stb_ds.h"
|
||||
|
||||
#include "baked.h"
|
||||
#include "locked.h"
|
||||
|
||||
INCBIN(gpp1, "./gpp1");
|
||||
|
||||
@ -24,7 +25,17 @@ INCBIN(blog_welcome_md, "./blog/welcome.md");
|
||||
INCBIN(blog_weird_page_md, "./blog/weird-page.md");
|
||||
INCBIN(blog_curious_case_of_gebs_md, "./blog/curious-case-of-gebs.md");
|
||||
|
||||
Baked_Resource *baked_resources = NULL;
|
||||
locked(Baked_Resource *) baked_resources = locked_init(nil);
|
||||
|
||||
void lock_baked_resources(void)
|
||||
{
|
||||
lockx(&baked_resources);
|
||||
}
|
||||
|
||||
void unlock_baked_resources(void)
|
||||
{
|
||||
unlockx(&baked_resources);
|
||||
}
|
||||
|
||||
void add_baked_resource(char *key, const uchar *data, size_t size)
|
||||
{
|
||||
@ -34,11 +45,12 @@ void add_baked_resource(char *key, const uchar *data, size_t size)
|
||||
abort();
|
||||
}
|
||||
write(fd, data, size);
|
||||
shput(baked_resources, key, fd);
|
||||
shput(baked_resources.value, key, fd);
|
||||
}
|
||||
|
||||
void init_baked_resources(void)
|
||||
{
|
||||
lockx(&baked_resources);
|
||||
add_baked_resource("home.html", home_html_data, home_html_size);
|
||||
add_baked_resource("page-missing.html", page_missing_html_data, page_missing_html_size);
|
||||
add_baked_resource("template-blog.html", template_blog_html_data, template_blog_html_size);
|
||||
@ -53,30 +65,34 @@ void init_baked_resources(void)
|
||||
add_baked_resource("blog-welcome.md", blog_welcome_md_data, blog_welcome_md_size);
|
||||
add_baked_resource("blog-weird-page.md", blog_weird_page_md_data, blog_weird_page_md_size);
|
||||
add_baked_resource("blog-curious-case-of-gebs.md", blog_curious_case_of_gebs_md_data, blog_curious_case_of_gebs_md_size);
|
||||
unlockx(&baked_resources);
|
||||
}
|
||||
|
||||
void free_baked_resources(void)
|
||||
{
|
||||
for (size_t i = 0; i < shlen(baked_resources); i++) {
|
||||
close(baked_resources[i].value);
|
||||
lockx(&baked_resources);
|
||||
for (size_t i = 0; i < shlen(baked_resources.value); i++) {
|
||||
close(baked_resources.value[i].value);
|
||||
}
|
||||
shfree(baked_resources);
|
||||
shfree(baked_resources.value);
|
||||
unlockx(&baked_resources);
|
||||
}
|
||||
|
||||
bool get_baked_resource_path(char *key, char *buf, size_t size)
|
||||
{
|
||||
if (shgeti(baked_resources, key) != -1) {
|
||||
int fd = shget(baked_resources, key);
|
||||
if (shgeti(baked_resources.value, key) != -1) {
|
||||
int fd = shget(baked_resources.value, key);
|
||||
snprintf(buf, size, "/proc/%d/fd/%d", getpid(), fd);
|
||||
unlockx(&baked_resources);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void baked_resource_each(void (*f)(Baked_Resource *resource))
|
||||
void baked_resource_each(void (*f)(Baked_Resource *resource, void *udata), void *udata)
|
||||
{
|
||||
for (size_t i = 0; i < shlen(baked_resources); i++) {
|
||||
f(&baked_resources[i]);
|
||||
for (size_t i = 0; i < shlen(baked_resources.value); i++) {
|
||||
f(&baked_resources.value[i], udata);
|
||||
}
|
||||
}
|
||||
|
||||
|
4
baked.h
4
baked.h
@ -29,6 +29,8 @@ typedef struct {
|
||||
void init_baked_resources(void);
|
||||
void free_baked_resources(void);
|
||||
bool get_baked_resource_path(char *key, char *buf, size_t size);
|
||||
void baked_resource_each(void (*f)(Baked_Resource *resource));
|
||||
void baked_resource_each(void (*f)(Baked_Resource *resource, void *udata), void *udata);
|
||||
void lock_baked_resources(void);
|
||||
void unlock_baked_resources(void);
|
||||
|
||||
#endif // BAKED_H_
|
||||
|
3
build.c
3
build.c
@ -26,6 +26,7 @@ int main(int argc, char ** argv)
|
||||
"./timer.c",
|
||||
"./timer.h",
|
||||
"./CONFIG.h",
|
||||
"./locked.h",
|
||||
|
||||
"./mongoose.o",
|
||||
"./gpp1",
|
||||
@ -88,7 +89,7 @@ int main(int argc, char ** argv)
|
||||
}
|
||||
|
||||
#if MY_DEBUG
|
||||
CMD("cc", "-fPIC", "-ggdb", "-I.", "-DMY_DEBUG=1", "-D_GNU_SOURCE", "-DGEBS_NO_PREFIX",
|
||||
CMD("cc", "-fsanitize=address", "-fPIC", "-ggdb", "-I.", "-DMY_DEBUG=1", "-D_GNU_SOURCE", "-DGEBS_NO_PREFIX",
|
||||
"-DINCBIN_PREFIX=", "-DINCBIN_STYLE=INCBIN_STYLE_SNAKE", "-Wl,-z,execstack", "-o", "./aboba",
|
||||
"./main.c", "./routes.c", "./baked.c", "./timer.c", "./mongoose.o", "./cJSON/cJSON.c",
|
||||
"./md5-c/md5.c",
|
||||
|
12
locked.h
Normal file
12
locked.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef LOCKED_H_
|
||||
#define LOCKED_H_
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#define locked_init(x) { .value = (x), .lock = PTHREAD_MUTEX_INITIALIZER }
|
||||
#define locked(T) struct { T value; pthread_mutex_t lock; }
|
||||
|
||||
#define lockx(x) pthread_mutex_lock(&(x)->lock)
|
||||
#define unlockx(x) pthread_mutex_unlock(&(x)->lock)
|
||||
|
||||
#endif // LOCKED_H_
|
218
main.c
218
main.c
@ -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,11 @@
|
||||
#include "baked.h"
|
||||
#include "timer.h"
|
||||
#include "CONFIG.h"
|
||||
#include "clonestr.h"
|
||||
#include "locked.h"
|
||||
|
||||
Route *route_hashtable = NULL;
|
||||
locked(Route *) route_hashtable = locked_init(nil);
|
||||
locked(char *) etc_dump_path = locked_init(nil);
|
||||
|
||||
void run_in_thread(void *(*f)(void *), void *p)
|
||||
{
|
||||
@ -33,16 +39,49 @@ 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);
|
||||
|
||||
lockx(&etc_dump_path);
|
||||
snprintf(full_path, PATH_MAX, "%s/%s", etc_dump_path.value, file);
|
||||
unlockx(&etc_dump_path);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
char key[MG_PATH_MAX] = {0};
|
||||
strncpy(key, http_msg.uri.buf, http_msg.uri.len);
|
||||
ssize_t idx = shgeti(route_hashtable, key);
|
||||
lockx(&route_hashtable);
|
||||
ssize_t idx = shgeti(route_hashtable.value, key);
|
||||
|
||||
Route_Result result = {0};
|
||||
route_hashtable[idx].value(&http_msg, &result, route_hashtable[idx].context_data);
|
||||
route_hashtable.value[idx].value(&http_msg, &result, route_hashtable.value[idx].context_data);
|
||||
unlockx(&route_hashtable);
|
||||
mg_wakeup(data->mgr, data->conn_id, &result, sizeof(result));
|
||||
|
||||
free(data->message.buf);
|
||||
@ -80,69 +119,155 @@ 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 = malloc(MG_PATH_MAX);
|
||||
snprintf(path, MG_PATH_MAX, "/%s", resource->key);
|
||||
shput(route_hashtable.value, path, &route_generic_blog);
|
||||
route_hashtable.value[shgeti(route_hashtable.value, 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);
|
||||
lockx(&route_hashtable);
|
||||
shdefault(route_hashtable.value, &route_page_not_found);
|
||||
shput(route_hashtable.value, clonestr("/"), &route_home);
|
||||
shput(route_hashtable.value, clonestr("/page-missing"), &route_page_not_found);
|
||||
shput(route_hashtable.value, clonestr("/blog"), &route_blog);
|
||||
#if MY_DEBUG
|
||||
shput(route_hashtable, "/hotreload.js", &route_hotreload_js);
|
||||
shput(route_hashtable, "/build-id", &route_build_id);
|
||||
shput(route_hashtable.value, clonestr("/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);
|
||||
unlockx(&route_hashtable);
|
||||
}
|
||||
|
||||
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);
|
||||
lockx(&route_hashtable);
|
||||
for (size_t i = 0; i < shlen(route_hashtable.value); i++) {
|
||||
free(route_hashtable.value[i].key);
|
||||
}
|
||||
shfree(route_hashtable.value);
|
||||
unlockx(&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;
|
||||
}
|
||||
}
|
||||
shfree(route_hashtable);
|
||||
|
||||
close(input);
|
||||
close(output);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void populate_etc_dump(char *etc_dump)
|
||||
{
|
||||
static char *files[] = {
|
||||
"favicon.ico", "hotreload.js",
|
||||
"simple.css", "me.jpg",
|
||||
};
|
||||
|
||||
lock_baked_resources();
|
||||
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);
|
||||
}
|
||||
unlock_baked_resources();
|
||||
}
|
||||
|
||||
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();
|
||||
lockx(&etc_dump_path);
|
||||
if ((etc_dump_path.value = init_etc_dump()) == nil) {
|
||||
return 1;
|
||||
}
|
||||
populate_etc_dump(etc_dump_path.value);
|
||||
unlockx(&etc_dump_path);
|
||||
|
||||
mg_log_set(MG_LL_DEBUG);
|
||||
struct mg_mgr mgr;
|
||||
@ -153,13 +278,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);
|
||||
|
||||
|
||||
lockx(&etc_dump_path);
|
||||
free_etc_dump(etc_dump_path.value);
|
||||
unlockx(&etc_dump_path);
|
||||
free_baked_resources();
|
||||
|
||||
return 0;
|
||||
|
134
routes.c
134
routes.c
@ -16,7 +16,7 @@
|
||||
void make_internal_server_error(Route_Result *result)
|
||||
{
|
||||
result->status_code = 500;
|
||||
result->type = ROUTE_RESULT_TEXT;
|
||||
result->type = ROUTE_RESULT_DYNAMIC;
|
||||
list_append(&result->headers, "Content-Type: text/plain");
|
||||
sb_append_nstr(&result->body, INTERNAL_SERVER_ERROR_MSG);
|
||||
sb_finish(&result->body);
|
||||
@ -28,32 +28,19 @@ void make_application_json(Route_Result *result, int code, cJSON *root)
|
||||
defer { free(root_text); }
|
||||
|
||||
result->status_code = code;
|
||||
result->type = ROUTE_RESULT_TEXT;
|
||||
result->type = ROUTE_RESULT_DYNAMIC;
|
||||
list_append(&result->headers, clonestr("Content-Type: application/json"));
|
||||
sb_append_nstr(&result->body, root_text);
|
||||
sb_finish(&result->body);
|
||||
}
|
||||
|
||||
void make_binary(Route_Result *result, char *content_type, int code, char *data, size_t size)
|
||||
{
|
||||
char type[100];
|
||||
snprintf(type, sizeof(type), "Content-Type: %s", content_type);
|
||||
result->status_code = code;
|
||||
result->type = ROUTE_RESULT_BINARY;
|
||||
list_append(&result->headers, clonestr(type));
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
sb_append_char(&result->body, data[i]);
|
||||
}
|
||||
sb_finish(&result->body);
|
||||
}
|
||||
|
||||
void make_text(Route_Result *result, char *subtype, int code, char *in)
|
||||
{
|
||||
char type[100];
|
||||
snprintf(type, sizeof(type), "Content-Type: text/%s", subtype);
|
||||
|
||||
result->status_code = code;
|
||||
result->type = ROUTE_RESULT_TEXT;
|
||||
result->type = ROUTE_RESULT_DYNAMIC;
|
||||
list_append(&result->headers, clonestr(type));
|
||||
sb_append_nstr(&result->body, in);
|
||||
sb_finish(&result->body);
|
||||
@ -83,7 +70,7 @@ bool gpp_run(char *path, NString_List *env, String_Builder *out)
|
||||
}
|
||||
|
||||
#if MY_DEBUG
|
||||
ROUTE_HANDLER(build_id)
|
||||
void route_build_id(struct mg_http_message *msg, Route_Result *result, void *context_data)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
defer { cJSON_Delete(root); }
|
||||
@ -104,8 +91,10 @@ ROUTE_HANDLER(build_id)
|
||||
}
|
||||
#endif
|
||||
|
||||
ROUTE_HANDLER(page_not_found)
|
||||
void route_page_not_found(struct mg_http_message *msg, Route_Result *result, void *context_data)
|
||||
{
|
||||
lock_baked_resources();
|
||||
defer { unlock_baked_resources(); }
|
||||
NString_List env = {0};
|
||||
defer { list_free(&env); }
|
||||
|
||||
@ -139,84 +128,10 @@ ROUTE_HANDLER(page_not_found)
|
||||
}
|
||||
}
|
||||
|
||||
ROUTE_HANDLER(simple_css)
|
||||
{
|
||||
char path[PATH_MAX] = {0};
|
||||
if (!get_baked_resource_path("simple.css", path, sizeof(path))) {
|
||||
make_internal_server_error(result);
|
||||
return;
|
||||
}
|
||||
|
||||
String_Builder sb = {0};
|
||||
defer { sb_free(&sb); }
|
||||
if (!sb_read_file(&sb, path)) {
|
||||
make_internal_server_error(result);
|
||||
return;
|
||||
}
|
||||
sb_finish(&sb);
|
||||
|
||||
make_text(result, "css", 200, sb.items);
|
||||
}
|
||||
|
||||
ROUTE_HANDLER(me_jpg)
|
||||
{
|
||||
char path[PATH_MAX] = {0};
|
||||
if (!get_baked_resource_path("me.jpg", path, sizeof(path))) {
|
||||
make_internal_server_error(result);
|
||||
return;
|
||||
}
|
||||
|
||||
String_Builder sb = {0};
|
||||
defer { sb_free(&sb); }
|
||||
if (!sb_read_file(&sb, path)) {
|
||||
make_internal_server_error(result);
|
||||
return;
|
||||
}
|
||||
|
||||
make_binary(result, "image/jpeg", 200, sb.items, sb.count);
|
||||
}
|
||||
|
||||
ROUTE_HANDLER(favicon)
|
||||
{
|
||||
char path[PATH_MAX] = {0};
|
||||
if (!get_baked_resource_path("favicon.ico", path, sizeof(path))) {
|
||||
make_internal_server_error(result);
|
||||
return;
|
||||
}
|
||||
|
||||
String_Builder sb = {0};
|
||||
defer { sb_free(&sb); }
|
||||
if (!sb_read_file(&sb, path)) {
|
||||
make_internal_server_error(result);
|
||||
return;
|
||||
}
|
||||
|
||||
make_binary(result, "image/x-icon", 200, sb.items, sb.count);
|
||||
}
|
||||
|
||||
#if MY_DEBUG
|
||||
ROUTE_HANDLER(hotreload_js)
|
||||
{
|
||||
char path[PATH_MAX] = {0};
|
||||
if (!get_baked_resource_path("hotreload.js", path, sizeof(path))) {
|
||||
make_internal_server_error(result);
|
||||
return;
|
||||
}
|
||||
|
||||
String_Builder sb = {0};
|
||||
defer { sb_free(&sb); }
|
||||
if (!sb_read_file(&sb, path)) {
|
||||
make_internal_server_error(result);
|
||||
return;
|
||||
}
|
||||
sb_finish(&sb);
|
||||
|
||||
make_text(result, "javascript", 200, sb.items);
|
||||
}
|
||||
#endif
|
||||
|
||||
ROUTE_HANDLER(home)
|
||||
void route_home(struct mg_http_message *msg, Route_Result *result, void *context_data)
|
||||
{
|
||||
lock_baked_resources();
|
||||
defer { unlock_baked_resources(); }
|
||||
NString_List env = {0};
|
||||
defer { list_free(&env); }
|
||||
|
||||
@ -248,8 +163,10 @@ ROUTE_HANDLER(home)
|
||||
}
|
||||
}
|
||||
|
||||
ROUTE_HANDLER(generic_blog)
|
||||
void route_generic_blog(struct mg_http_message *msg, Route_Result *result, void *context_data)
|
||||
{
|
||||
lock_baked_resources();
|
||||
defer { unlock_baked_resources(); }
|
||||
NString_List env = {0};
|
||||
defer { list_free(&env); }
|
||||
|
||||
@ -323,7 +240,16 @@ ROUTE_HANDLER(generic_blog)
|
||||
}
|
||||
}
|
||||
|
||||
ROUTE_HANDLER(blog)
|
||||
void collect_blogs(Baked_Resource *resource, void *udata)
|
||||
{
|
||||
struct { Arena *tmp; String_Builder *sb; } *ud = udata;
|
||||
if ((strlen(resource->key) >= strlen("blog-"))
|
||||
&& strncmp(resource->key, "blog-", strlen("blog-")) == 0) {
|
||||
sb_append_nstr_alloc(ud->tmp, ud->sb, fmt("<li><a href=\"/%s\">%s</a></li>", resource->key, resource->key));
|
||||
}
|
||||
}
|
||||
|
||||
void route_blog(struct mg_http_message *msg, Route_Result *result, void *context_data)
|
||||
{
|
||||
NString_List env = {0};
|
||||
defer { list_free(&env); }
|
||||
@ -335,15 +261,11 @@ ROUTE_HANDLER(blog)
|
||||
defer { arena_destroy(&tmp); }
|
||||
|
||||
String_Builder sb = {0};
|
||||
void collect_blogs(Baked_Resource *resource)
|
||||
{
|
||||
if ((strlen(resource->key) >= strlen("blog-"))
|
||||
&& strncmp(resource->key, "blog-", strlen("blog-")) == 0) {
|
||||
sb_append_nstr_alloc(&tmp, &sb, fmt("<li><a href=\"/%s\">%s</a></li>", resource->key, resource->key));
|
||||
}
|
||||
}
|
||||
|
||||
baked_resource_each(&collect_blogs);
|
||||
struct { Arena *tmp; String_Builder *sb; } collect_blogs_data = {
|
||||
.tmp = &tmp,
|
||||
.sb = &sb,
|
||||
};
|
||||
baked_resource_each(&collect_blogs, &collect_blogs_data);
|
||||
sb_finish_alloc(&tmp, &sb);
|
||||
list_append(&env, fmt("-DBLOG_POSTS=%s", sb.items));
|
||||
|
||||
|
20
routes.h
20
routes.h
@ -6,8 +6,8 @@
|
||||
|
||||
typedef struct {
|
||||
enum {
|
||||
ROUTE_RESULT_TEXT,
|
||||
ROUTE_RESULT_BINARY,
|
||||
ROUTE_RESULT_DYNAMIC,
|
||||
ROUTE_RESULT_STATIC,
|
||||
} type;
|
||||
int status_code;
|
||||
NString_List headers;
|
||||
@ -28,18 +28,12 @@ typedef struct {
|
||||
void *context_data;
|
||||
} Route;
|
||||
|
||||
#define ROUTE_HANDLER(name) void route_##name(struct mg_http_message *msg, Route_Result *result, void *context_data)
|
||||
|
||||
ROUTE_HANDLER(page_not_found);
|
||||
ROUTE_HANDLER(simple_css);
|
||||
ROUTE_HANDLER(favicon);
|
||||
ROUTE_HANDLER(me_jpg);
|
||||
#if MY_DEBUG
|
||||
ROUTE_HANDLER(hotreload_js);
|
||||
ROUTE_HANDLER(build_id);
|
||||
void route_build_id(struct mg_http_message *msg, Route_Result *result, void *context_data);
|
||||
#endif
|
||||
ROUTE_HANDLER(home);
|
||||
ROUTE_HANDLER(generic_blog);
|
||||
ROUTE_HANDLER(blog);
|
||||
void route_page_not_found(struct mg_http_message *msg, Route_Result *result, void *context_data);
|
||||
void route_home(struct mg_http_message *msg, Route_Result *result, void *context_data);
|
||||
void route_generic_blog(struct mg_http_message *msg, Route_Result *result, void *context_data);
|
||||
void route_blog(struct mg_http_message *msg, Route_Result *result, void *context_data);
|
||||
|
||||
#endif // ROUTES_H_
|
||||
|
11
timer.c
11
timer.c
@ -3,22 +3,27 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "timer.h"
|
||||
#include "locked.h"
|
||||
|
||||
time_t rawtime;
|
||||
locked(time_t) rawtime;
|
||||
|
||||
void start_timer(void)
|
||||
{
|
||||
time(&rawtime);
|
||||
lockx(&rawtime);
|
||||
time(&rawtime.value);
|
||||
unlockx(&rawtime);
|
||||
}
|
||||
|
||||
void get_timer_string(char *output, size_t size)
|
||||
{
|
||||
lockx(&rawtime);
|
||||
struct tm * timeinfo;
|
||||
|
||||
timeinfo = localtime(&rawtime);
|
||||
timeinfo = localtime(&rawtime.value);
|
||||
|
||||
snprintf(output, size, "[%02d %02d %d %02d:%02d:%02d]", timeinfo->tm_mday,
|
||||
timeinfo->tm_mon + 1, timeinfo->tm_year + 1900,
|
||||
timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
|
||||
unlockx(&rawtime);
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<title>Blog</title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="stylesheet" href="/simple.css" />
|
||||
<link rel="stylesheet" href="/etc/simple.css" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Blog posts</h1>
|
||||
@ -23,7 +23,7 @@
|
||||
</footer>
|
||||
|
||||
<#ifdef HOTRELOAD>
|
||||
<script src="/hotreload.js"></script>
|
||||
<script src="/etc/hotreload.js"></script>
|
||||
<#endif>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<title>Kamil's personal website</title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="stylesheet" href="/simple.css" />
|
||||
<link rel="stylesheet" href="/etc/simple.css" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Kamil's personal website</h1>
|
||||
@ -53,7 +53,7 @@
|
||||
</ul>
|
||||
</section>
|
||||
<section>
|
||||
<img src="/me.jpg" alt="literally me" />
|
||||
<img src="/etc/me.jpg" alt="literally me" />
|
||||
</section>
|
||||
<footer>
|
||||
<div style="float: left;">
|
||||
@ -64,7 +64,7 @@
|
||||
</footer>
|
||||
|
||||
<#ifdef HOTRELOAD>
|
||||
<script src="/hotreload.js"></script>
|
||||
<script src="/etc/hotreload.js"></script>
|
||||
<#endif>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>404 - Page not found</title>
|
||||
<link rel="stylesheet" href="/simple.css" />
|
||||
<link rel="stylesheet" href="/etc/simple.css" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>The page you were looking for doesn't exist!</h1>
|
||||
@ -18,7 +18,7 @@
|
||||
</footer>
|
||||
|
||||
<#ifdef HOTRELOAD>
|
||||
<script src="/hotreload.js"></script>
|
||||
<script src="/etc/hotreload.js"></script>
|
||||
<#endif>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title><#BLOG_POST_TITLE></title>
|
||||
<link rel="stylesheet" href="/simple.css" />
|
||||
<link rel="stylesheet" href="/etc/simple.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="content"></div>
|
||||
@ -20,7 +20,7 @@
|
||||
</script>
|
||||
|
||||
<#ifdef HOTRELOAD>
|
||||
<script src="/hotreload.js"></script>
|
||||
<script src="/etc/hotreload.js"></script>
|
||||
<#endif>
|
||||
</body>
|
||||
</html>
|
||||
|
Reference in New Issue
Block a user