bunkum

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

commit 060e65d3ae7e844e7ae0745948c5f82f4daea6d4
parent 586aad6f4b555fe36ac570531f6652f9c235c0b5
Author: quantumish <freifeld.david@gmail.com>
Date:   Mon, 10 Apr 2023 20:35:58 -0700

Clean up code, add beginnings of Accept-Encoding handling

Diffstat:
Mhttp.c | 89+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Mhttp/request.c | 21+++++++++++++++++++++
Autils/compression.c | 32++++++++++++++++++++++++++++++++
3 files changed, 101 insertions(+), 41 deletions(-)

diff --git a/http.c b/http.c @@ -51,6 +51,48 @@ void scuffed_htmlescape(char* dst, char* src, size_t sz) { shitvec_t paths; +response_t serve_file(request_t req) { + char path[128+8] = "./public"; + strcat(path, req.path); + int fd = open(path, O_RDONLY); // TODO handle + response_t r = resp_new(OK); + + struct stat st; + fstat(fd, &st); + 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... + resp_set_ctype(&r, ext); + + char datebuf[32]; + time_to_str(st.st_mtim.tv_sec, datebuf); + resp_add_hdr(&r, "Last-Modified", datebuf); + + char* buf = fbuf; // buffer to be written + size_t bufsize = st.st_size; + + if (ext == NULL) { + bufsize = st.st_size * 2; + buf = malloc(bufsize); // FIXME dubious assumption + scuffed_htmlescape(buf, fbuf, st.st_size); + free(fbuf); + } + if (ext == NULL || strcmp(ext, ".png") != 0) { + resp_add_hdr(&r, "Content-Encoding", "deflate"); + size_t clen = compressBound(st.st_size); + char* cbuf = malloc(clen); + compress((Bytef*)cbuf, &clen, (Bytef*)buf, bufsize); + free(buf); + + buf = cbuf; + bufsize = clen; + } + resp_add_content(&r, buf, bufsize); + free(buf); + return r; +} + // TODO actually respect requests // TODO handle gzip // TODO list dirs @@ -65,59 +107,23 @@ void* handle_conn(void* ctxt) { return 0x0; } gettimeofday(&before, NULL); - if (strlen(msgbuf) > 0) { + if (msgbuf[0] != 0) { request_t req = req_new(msgbuf, 1024); int err = req_parse(&req); if (err < 0) log_error("Failed to parse incoming request."); + log_debug("Req: %s, %s, %f", method_name(req.method), req.path, req.ver); + for (size_t i = 0; i < req.headers.vec_sz; i++) { header_line_t hdr = *(header_line_t*)shitvec_get(&req.headers, i); log_debug("Header '%s: %s'", hdr.name, hdr.value); } log_info("Got request for %s", req.path); - - // TODO split up logic here + if (shitvec_check(&paths, req.path, (int(*)(void*,void*))strcmp)) { - char path[128+8] = "./public"; - strcat(path, req.path); - int fd = open(path, O_RDONLY); // TODO handle - response_t r = resp_new(OK); - - struct stat st; - fstat(fd, &st); - 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... - resp_set_ctype(&r, ext); - - char datebuf[32]; - time_to_str(st.st_mtim.tv_sec, datebuf); - resp_add_hdr(&r, "Last-Modified", datebuf); - - char* buf = fbuf; // buffer to be written - size_t bufsize = st.st_size; - - if (ext == NULL) { - bufsize = st.st_size * 2; - buf = malloc(bufsize); // FIXME dubious assumption - scuffed_htmlescape(buf, fbuf, st.st_size); - free(fbuf); - } - if (ext == NULL || strcmp(ext, ".png") != 0) { - resp_add_hdr(&r, "Content-Encoding", "deflate"); - size_t clen = compressBound(st.st_size); - char* cbuf = malloc(clen); - compress((Bytef*)cbuf, &clen, (Bytef*)buf, bufsize); - free(buf); - - buf = cbuf; - bufsize = clen; - } - resp_add_content(&r, buf, bufsize); + response_t r = serve_file(req); send(ns, r.content, r.sz, 0); - free(buf); free(r.content); } else { response_t r = __resp_new(NotFound, "Fuck off."); @@ -126,6 +132,7 @@ void* handle_conn(void* ctxt) { send(ns, r.content, r.sz, 0); free(r.content); } + gettimeofday(&after, NULL); timersub(&after, &before, &tdiff); log_info("Handled request for %s in %ld.%06ld sec", req.path, tdiff.tv_sec, tdiff.tv_usec); diff --git a/http/request.c b/http/request.c @@ -30,6 +30,27 @@ request_t req_new(char* reqbuf, size_t bufsize) { return req; } +struct qual_item { + float q; + char item[8]; +} + +shitvec_t parse_accept(char* value) { + shitvec_t items = shitvec_new(16); + char* start = strtok(value, ","); + while (start != NULL) { + struct qual_item i; + strtok(NULL, ","); + + /* strncpy(i.item, start, */ + strchr(start, ';'); + + sscanf(strchr(start, ';'), "q=%f", &i.q); + + printf("%s", start); + } +} + int req_parse(request_t* req) { char method[8] = {0}; int matched = sscanf(req->buf, "%s %s HTTP/%f\r\n", (char*)method, (char*)req->path, &req->ver); diff --git a/utils/compression.c b/utils/compression.c @@ -0,0 +1,32 @@ +#include <stdlib.h> + +#include "zlib.h" + +char* zlib_compress(char* buf, size_t bufsize) { + size_t clen = compressBound(bufsize); + char* cbuf = malloc(clen); + compress((Bytef*)cbuf, &clen, (Bytef*)buf, bufsize); + return cbuf; +} + +char* gzip_compress(char* buf, size_t bufsize) { + size_t clen = compressBound(bufsize); + char* cbuf = malloc(clen); + z_stream zs; + zs.zalloc = Z_NULL; + zs.zfree = Z_NULL; + zs.opaque = Z_NULL; + zs.avail_in = (uInt)bufsize; + zs.next_in = (Bytef *)buf; + zs.avail_out = (uInt)clen; + zs.next_out = (Bytef *)cbuf; + + // "Add 16 to windowBits to write a simple gzip header and trailer around the compressed data instead of a zlib wrapper" + deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 | 16, 8, Z_DEFAULT_STRATEGY); + deflate(&zs, Z_FINISH); + deflateEnd(&zs); + + // zs.total_out + + return cbuf; +}