commit 2f6ca9c766f9d7e01fae84de7cc997ea39a872a5
parent 060e65d3ae7e844e7ae0745948c5f82f4daea6d4
Author: quantumish <freifeld.david@gmail.com>
Date: Mon, 10 Apr 2023 23:06:53 -0700
Actually correctly parse Accept header
Diffstat:
6 files changed, 55 insertions(+), 53 deletions(-)
diff --git a/http.c b/http.c
@@ -24,31 +24,6 @@
#include "http/response.h"
#include "http/request.h"
-void scuffed_htmlescape(char* dst, char* src, size_t sz) {
- strcpy(dst, "<pre>\n");
- int offset = 6;
- int i;
- for (i = 0; i < sz; i++) {
- switch (src[i]) {
- case '<':
- strcpy(dst+i+offset, "&lt;");
- offset += 3;
- break;
- case '>':
- strcpy(dst+i+offset, "&gt;");
- offset += 3;
- break;
- case '&':
- strcpy(dst+i+offset, "&amp;");
- offset += 4;
- break;
- default:
- dst[i+offset] = src[i];
- }
- }
- strcpy(dst+i+offset, "\n</pre>");
-}
-
shitvec_t paths;
response_t serve_file(request_t req) {
@@ -71,13 +46,7 @@ response_t serve_file(request_t req) {
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);
@@ -88,6 +57,7 @@ response_t serve_file(request_t req) {
buf = cbuf;
bufsize = clen;
}
+
resp_add_content(&r, buf, bufsize);
free(buf);
return r;
@@ -117,8 +87,15 @@ void* handle_conn(void* ctxt) {
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);
+ if (strcmp(hdr.name, "Accept") == 0) {
+ shitvec_t mtypes = hdr_parse_accept(hdr.value);
+ for (size_t j = 0; j < mtypes.vec_sz; j++) {
+ struct req_mimetype mtype = *(struct req_mimetype*)shitvec_get(&mtypes, j);
+ log_info("Allowed type %s with q=%f", mtype.item, mtype.q);
+ }
+ }
}
-
+
log_info("Got request for %s", req.path);
if (shitvec_check(&paths, req.path, (int(*)(void*,void*))strcmp)) {
diff --git a/http/request.c b/http/request.c
@@ -2,6 +2,7 @@
#include <string.h>
#include <stdint.h>
+#include "../utils/log.h"
#include "../utils/shitvec.h"
#include "request.h"
@@ -30,25 +31,36 @@ request_t req_new(char* reqbuf, size_t bufsize) {
return req;
}
-struct qual_item {
- float q;
- char item[8];
+int cmp_r_mimetype(const void* a, const void* b) {
+ struct req_mimetype* aa = (struct req_mimetype*)a;
+ struct req_mimetype* bb = (struct req_mimetype*)b;
+ if (aa->q > bb->q) return -1;
+ else if (aa->q == bb->q) return 0;
+ else if (aa->q < bb->q) return 1;
}
-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);
- }
+// TODO handle parse errors
+shitvec_t hdr_parse_accept(char* val) {
+ shitvec_t mimetypes = shitvec_new(sizeof(struct req_mimetype));
+ char* start = strtok(val, ",");
+ char* next;
+ do {
+ next = strtok(NULL, ",");
+ float q = 1;
+ char* qptr = NULL;
+ if ((qptr = (char*)memchr(start, ';', next-start))) {
+ sscanf(qptr, ";q=%f", &q);
+ }
+ struct req_mimetype mtype;
+ mtype.q = q;
+ memset(mtype.item, 0, MAX_MIMETYPE_LEN);
+ if (qptr != NULL) strncpy(mtype.item, start, qptr-start);
+ else if (next != NULL) strncpy(mtype.item, start, next-start);
+ else strcpy(mtype.item, start);
+ shitvec_push(&mimetypes, &mtype);
+ } while ((start = next));
+ shitvec_sort(&mimetypes, cmp_r_mimetype);
+ return mimetypes;
}
int req_parse(request_t* req) {
@@ -60,7 +72,7 @@ int req_parse(request_t* req) {
req->headers = shitvec_new(sizeof(header_line_t));
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) {
- header_line_t hdr;
+ header_line_t hdr = header_line_new();
int matched = sscanf(start, "%32[^:]: %s", hdr.name, hdr.value);
if (matched == 0) return 0; // No more headers;
else if (matched == 1) {
@@ -70,10 +82,10 @@ int req_parse(request_t* req) {
shitvec_push(&req->headers, &hdr);
start = memchr(start, '\n', MAX_HEADER_NAME+MAX_HEADER_VALUE)+1;
}
-
return 0;
}
void req_free(request_t* req) {
shitvec_free(&req->headers);
}
+
diff --git a/http/request.h b/http/request.h
@@ -18,12 +18,20 @@ 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_MIMETYPE_LEN 32
+
+struct req_mimetype {
+ float q;
+ char item[MAX_MIMETYPE_LEN];
+};
typedef struct header_line {
char name[MAX_HEADER_NAME];
char value[MAX_HEADER_VALUE];
} header_line_t;
+shitvec_t hdr_parse_accept(char* val);
+
typedef struct request {
char* buf;
size_t bufsize;
diff --git a/http/response.c b/http/response.c
@@ -43,7 +43,7 @@ void resp_add_content(response_t* r, char* content, size_t content_len) {
void resp_set_ctype(response_t* r, char* ext) {
if (ext == NULL) {
- resp_add_hdr(r, "Content-Type", "text/html");
+ resp_add_hdr(r, "Content-Type", "text/plain");
} else if (strcmp(ext+1, "html") == 0) {
resp_add_hdr(r, "Content-Type", "text/html");
} else if (strcmp(ext+1, "png") == 0) {
diff --git a/utils/shitvec.c b/utils/shitvec.c
@@ -46,6 +46,10 @@ bool shitvec_check(shitvec_t* sv, void* item, int(cmp)(void*, void*)) {
return false;
}
+void shitvec_sort(shitvec_t* sv, int(*cmp)(const void*, const void*)) {
+ qsort(sv->arr, sv->vec_sz, sv->e_sz, cmp);
+}
+
void shitvec_free(shitvec_t* sv) {
free(sv->arr);
}
diff --git a/utils/shitvec.h b/utils/shitvec.h
@@ -18,6 +18,7 @@ void* shitvec_get(shitvec_t* sv, size_t index);
void shitvec_push(shitvec_t* sv, void* item);
void shitvec_subpush(shitvec_t* sv, void* item, size_t sz);
bool shitvec_check(shitvec_t* sv, void* item, int(cmp)(void*, void*));
+void shitvec_sort(shitvec_t* sv, int(*cmp)(const void*, const void*));
void shitvec_free(shitvec_t* sv);
#endif