bunkum

an old and silly c99 web server with some fun features
Log | Files | Refs | README

commit ec4d9dcdef6e1be313614e40af9f38947dea07c7
parent d7d48e8ddff7914d7cc26366cc97643888a58d4e
Author: quantumish <freifeld.david@gmail.com>
Date:   Thu, 13 Apr 2023 16:50:45 -0700

Fix various bugs, improve MIME type mapping

Diffstat:
MMakefile | 2+-
Mhttp.c | 27++++++++++++++++-----------
Mhttp/request.c | 4++--
Mhttp/request.h | 2+-
Mhttp/response.c | 23++++++++++++++---------
Mutils/log.c | 2+-
6 files changed, 35 insertions(+), 25 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,4 +1,4 @@ -CFLAGS?=-O2 -g +CFLAGS?= -g LIBS:=-lz -lpthread CLIBS = $(wildcard utils/*.c) $(wildcard http/*.c) OBJ = $(wildcard build/*.o) diff --git a/http.c b/http.c @@ -25,7 +25,6 @@ #include "http/response.h" #include "http/request.h" - response_t serve_error(enum StatusCode c) { response_t r = resp_new(c); resp_add_hdr(&r, "Content-Type", "text/html"); @@ -37,6 +36,13 @@ response_t serve_error(enum StatusCode c) { shitvec_t paths; +char* get_file_ext(char* filename) { + char* ext = strtok(filename, "."); + char* next; + while ((next = strtok(NULL, "."))) ext = next; + return ext; +} + response_t serve_file(request_t req) { char path[128+8] = "./public"; strcat(path, req.path); @@ -48,7 +54,8 @@ response_t serve_file(request_t req) { char* fbuf = malloc(st.st_size); // TODO what if file larger than memory? for (size_t i = 0; read(fd, fbuf+(i*4096), 4096) > 0; i++); - char* ext = strchr(req.path, '.'); // NOTE breaks if there's a dir with a dot... + + char* ext = get_file_ext(req.path); resp_set_ctype(&r, ext); @@ -56,12 +63,10 @@ response_t serve_file(request_t req) { char* mtype = (char*)ext_to_mtype(ext); char* hdr; if ((hdr = hashmap_get(&req.headers, "Accept"))) { - log_debug("Handling Accept header"); ok = false; shitvec_t mtypes = hdr_parse_accept(hdr); for (int j = 0; j < mtypes.vec_sz; j++) { struct req_mimetype* a_mtype = shitvec_get(&mtypes, j); - log_debug("%s", a_mtype->item); // TODO doesn't handle stuff like image/* (is that even allowed?) if (strcmp(a_mtype->item, mtype) == 0 || strcmp(a_mtype->item, "*/*") == 0) { ok = true; @@ -69,17 +74,15 @@ response_t serve_file(request_t req) { } } } - + char* buf = fbuf; // buffer to be written size_t bufsize = st.st_size; if (ok && (hdr = hashmap_get(&req.headers, "Accept-Encoding"))) { - log_debug("Handling Accept-Encoding header"); ok = false; shitvec_t mtypes = hdr_parse_accept(hdr); // abuse of this func for (int j = 0; j < mtypes.vec_sz; j++) { struct req_mimetype* a_mtype = shitvec_get(&mtypes, j); - log_debug("%s", a_mtype->item); if (strcmp(a_mtype->item, "gzip") == 0) { resp_add_hdr(&r, "Content-Encoding", "gzip"); buf = gzip_compress(buf, &bufsize); @@ -97,10 +100,12 @@ response_t serve_file(request_t req) { } } if (!ok) return serve_error(NotAcceptable); - - /* char datebuf[64]; */ - /* time_to_str(st.st_mtim.tv_sec, datebuf); */ - /* resp_add_hdr(&r, "Last-Modified", datebuf); */ + + #ifndef __APPLE__ + char datebuf[64]; + time_to_str(st.st_mtim.tv_sec, datebuf); + resp_add_hdr(&r, "Last-Modified", datebuf); + #endif resp_add_content(&r, buf, bufsize); free(buf); diff --git a/http/request.c b/http/request.c @@ -63,17 +63,17 @@ int req_parse(request_t* req) { req->headers = hashmap_new(MAX_HEADER_NAME, MAX_HEADER_VALUE); req->headers.vark = true; + // FIXME if start is null this causes problems char* start = memchr(req->buf, '\n', MAX_HEADER_NAME+MAX_HEADER_VALUE)+1; while (start+MAX_HEADER_NAME+MAX_HEADER_VALUE < req->buf+req->bufsize) { char name[MAX_HEADER_NAME] = {0}; - char value[MAX_HEADER_VALUE] = {0}; + char value[MAX_HEADER_VALUE] = {0}; int matched = sscanf(start, "%32[^:]: %s", name, value); if (matched == 0) return 0; // No more headers; else if (matched == 1) { if (name[0] == '\r') return 0; // TODO sketch return -1; // Uhh... half a header. NOTE doesn't even seem to work. fun. } - log_debug("Inserting '%s' (len %d) -> '%s'", name, strlen(name), value); hashmap_set(&req->headers, name, value); start = memchr(start, '\n', MAX_HEADER_NAME+MAX_HEADER_VALUE)+1; } diff --git a/http/request.h b/http/request.h @@ -18,7 +18,7 @@ const char* method_name(enum http_method m); #define MAX_PATH_LEN 128 #define MAX_HEADER_NAME 32 -#define MAX_HEADER_VALUE 128 +#define MAX_HEADER_VALUE 512 #define MAX_MIMETYPE_LEN 32 struct req_mimetype { diff --git a/http/response.c b/http/response.c @@ -3,6 +3,7 @@ #include <stdlib.h> #include <stdio.h> +#include "../utils/log.h" #include "../utils/hashmap.h" #include "../utils/time.h" #include "response.h" @@ -28,7 +29,7 @@ void resp_add_hdr(response_t* r, char* hdr, char* val) { } void resp_add_content(response_t* r, char* content, size_t content_len) { - char length[8]; + char length[32]; sprintf(length, "%ld", content_len); resp_add_hdr(r, "Content-Length", length); @@ -41,19 +42,23 @@ void resp_add_content(response_t* r, char* content, size_t content_len) { memcpy(r->content+header_len, content, content_len); } +const char* exts[] = {"html", "css", "js", "png", "gif", "jpeg", "svg", "ttf", "woff", "woff2", NULL}; // TODO sentinel sketchy +const char* mtypes[] = {"text/html", "text/css", "text/javascript", "image/png", + "image/gif", "image/jpeg", "image/svg+xml", "font/ttf", "font/woff", "font/woff2"}; + +// TODO find cleaner way of doing this +// two lists and loop const char* ext_to_mtype(char* ext) { if (ext == NULL) { return"text/plain"; - } else if (strcmp(ext+1, "html") == 0) { - return"text/html"; - } else if (strcmp(ext+1, "png") == 0) { - return"image/png"; - } else if (strcmp(ext+1, "svg") == 0) { - return "image/svg+xml"; - } else if (strcmp(ext+1, "jpeg") == 0) { - return "image/jpeg"; } + for (size_t i = 0; exts[i] != NULL; i++) { + if (strcmp(ext, exts[i]) == 0) return mtypes[i]; + } + + log_warn("Giving up on mapping %s extension to a MIME type!", ext); + return "text/plain"; } void resp_set_ctype(response_t* r, char* ext) { diff --git a/utils/log.c b/utils/log.c @@ -11,7 +11,7 @@ #include "log.h" -#define LOG_MAX_MSGLEN 128 +#define LOG_MAX_MSGLEN 1024 #define ANSI_RED "\x1b[31m" #define ANSI_BOLDRED "\x1b[1;31m"