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:
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;
+}