commit dbaa680f3819391269a520637d013d145dce3177
parent f34b70f63be68595fc94039a698a51c952d8b172
Author: quantumish <freifeld.david@gmail.com>
Date: Fri, 13 Oct 2023 22:54:05 -0400
Fix hashmap bug, add test
Diffstat:
9 files changed, 83 insertions(+), 21 deletions(-)
diff --git a/Makefile b/Makefile
@@ -8,7 +8,7 @@ OBJ = $(wildcard build/*.o)
all: serv
serv: $(CLIBS) http.c
- $(CC) -o $@ $^ $(CFLAGS) $(LIBS)
+ $(CC) -o $@ $^ $(CFLAGS) $(LIBS) -O3
run: serv
sudo docker build -t bunkum-dev .
diff --git a/http/request.c b/http/request.c
@@ -17,6 +17,24 @@ enum http_method method_enum(char* p) {
return method_codes[((*(uint64_t*)p*0x1b8b6e6d) % 0x100000000) >> 28];
}
+
+/* enum parse_qvals_err { */
+/* PARSE_QVALS_SUCCESS, */
+/* PARSE_QVALS_MALFORMED, */
+/* }; */
+
+/* struct parse_qvals_res { */
+/* enum parse_qval_err err; */
+/* union { */
+/* shitvec_t items; */
+
+/* } data; */
+/* }; */
+
+/* shitvec_t parse_qvalues(char* str) { */
+
+/* } */
+
// Be careful about passing by value! if the internal hashmap resizes
// a req_free() call on the original (the one copied *from*) will be a
// double free() error
@@ -47,7 +65,9 @@ shitvec_t hdr_parse_accept(char* val) {
next = strtok(NULL, ",");
float q = 1;
char* qptr = NULL;
- if (next != NULL && (qptr = (char*)memchr(start, ';', next-start))) {
+
+ char* end = next != NULL ? next : start+strlen(start);
+ if ((qptr = (char*)memchr(start, ';', end-start))) {
sscanf(qptr, ";q=%f", &q);
}
struct req_mimetype mtype;
@@ -62,6 +82,14 @@ shitvec_t hdr_parse_accept(char* val) {
return mimetypes;
}
+struct mime_type parse_mimetype(char* str) {
+ char* slash = strchr(str, '/');
+ // if (slash == NULL) handle_error();
+ char* subtype = slash + 1;
+}
+
+
+
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);
@@ -74,7 +102,8 @@ int req_parse(request_t* req) {
char name[MAX_HEADER_NAME] = {0};
char value[MAX_HEADER_VALUE] = {0};
int matched = sscanf(start, "%32[^:]: %s", name, value);
- if (matched == 0) return 0; // No more headers;
+ // printf("%d matched. %s: %s\n", matched, 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.
@@ -133,4 +162,19 @@ void test_hdr_parse_accept() {
assert_float_eq(0.8, mtype->q);
}
+void test_bad_req_total_garbage() {
+ request_t r = req_new("this is not a request.", 23);
+ assert_int_eq(-1, req_parse(&r));
+}
+
+/* void test_bad_req_half_header() { */
+/* char bigbuf[1024] = "GET / HTTP/1.1\r\nProfile:\n"; */
+/* request_t r = req_new(bigbuf, 1024); */
+/* assert_int_eq(-1, req_parse(&r)); */
+
+/* bzero(bigbuf, 1024); */
+/* bigbuf = "GET / HTTP/1.1\r\nProfile: */
+/* } */
+
+
#endif
diff --git a/test.h b/test.h
@@ -7,6 +7,7 @@
void assert_str_eq(char* a, char* b);
void assert_float_eq(float a, float b);
void assert_size_eq(size_t a, size_t b);
+void assert_int_eq(int a, int b);
void assert_bool(bool expr);
#endif
diff --git a/testutils.c b/testutils.c
@@ -18,6 +18,13 @@ void assert_size_eq(size_t a, size_t b) {
}
}
+void assert_int_eq(int a, int b) {
+ if (a != b) {
+ printf("(%d != %d)", a, b);
+ exit(1);
+ }
+}
+
void assert_float_eq(float a, float b) {
if (a != b) {
printf("(%f != %f)", a, b);
diff --git a/utils/hashmap.c b/utils/hashmap.c
@@ -44,19 +44,19 @@ hashmap_t hashmap_new(size_t ksize, size_t vsize) {
h.k_sz = ksize;
h.v_sz = vsize;
h.len = HASHMAP_INIT_SIZE;
- h.vark = false;
+ h.vark = false;
h.filled = 0; // Store # of filled keys for load factor calculation
return h;
}
int hashmap_kcmp(hashmap_t* h, void* a, void* b) {
- if (h->vark) return strcmp(a, b);
- return memcmp(a, b, h->k_sz);
+ if (h->vark) return strcmp(a, b);
+ return memcmp(a, b, h->k_sz);
}
void* hashmap_kcpy(hashmap_t* h, void* a, void* b) {
- if (h->vark) return strcpy(a, b);
- return memcpy(a, b, h->k_sz);
+ if (h->vark) return strcpy(a, b);
+ return memcpy(a, b, h->k_sz);
}
void hashmap_resize(hashmap_t* h) {
@@ -142,7 +142,7 @@ int hashmap_del(hashmap_t* h, void* k) {
int looped_once = 0;
for (size_t off = index; off < h->len; off+=1) {
if (hashmap_kcmp(h, h->keys + (off * h->k_sz), k) == 0) {
- memset(h->keys + (off * h->v_sz), 0, h->k_sz);
+ memset(h->keys + (off * h->k_sz), 0, h->k_sz);
// No reason to delete value, will just be overwritten next time.
return 0;
}
@@ -164,15 +164,23 @@ void hashmap_free(hashmap_t* h) {
#include "../test.h"
void test_hashmap_sanity() {
- hashmap_t h = hashmap_new(16, 64);
- hashmap_set(&h, "whoo", "This is a test.");
- hashmap_set(&h, "Accept", "image/png,text/plain;q=0.5,image/jpeg");
- hashmap_resize(&h); // make sure it doesn't explode
- hashmap_set(&h, "Blah blah", "This is (another) test.");
- assert_str_eq(hashmap_get(&h, "whoo"), "This is a test.");
- assert_str_eq(hashmap_get(&h, "Accept"), "image/png,text/plain;q=0.5,image/jpeg");
- assert_str_eq(hashmap_get(&h, "Blah blah"), "This is (another) test.");
- hashmap_free(&h);
+ hashmap_t h = hashmap_new(16, 64);
+ hashmap_set(&h, "whoo", "This is a test.");
+ hashmap_set(&h, "Accept", "image/png,text/plain;q=0.5,image/jpeg");
+ hashmap_resize(&h); // make sure it doesn't explode
+ hashmap_set(&h, "Blah blah", "This is (another) test.");
+ assert_str_eq(hashmap_get(&h, "whoo"), "This is a test.");
+ assert_str_eq(hashmap_get(&h, "Accept"), "image/png,text/plain;q=0.5,image/jpeg");
+ assert_str_eq(hashmap_get(&h, "Blah blah"), "This is (another) test.");
+ hashmap_free(&h);
+}
+
+void test_hashmap_del() {
+ hashmap_t h = hashmap_new(16, 64);
+ assert_int_eq(hashmap_del(&h, "abc"), 1);
+ assert_int_eq(hashmap_set(&h, "abc", "whoo"), 0);
+ assert_int_eq(hashmap_del(&h, "abc"), 0);
+ assert_int_eq((long)hashmap_get(&h, "abc"), 0);
}
#endif
diff --git a/utils/hashmap.h b/utils/hashmap.h
@@ -17,6 +17,8 @@ typedef struct hashmap_t {
// Generates a new hashmap_t.
hashmap_t hashmap_new(size_t ksize, size_t vsize);
+#define hashmap_init(t1, t2) hashmap_new(sizeof(t1), sizeof(t2))
+
// Sets a key-value pair in the hashmap_t passed to it. Returns 0x0 for success, 0x1 for failure.
int hashmap_set(hashmap_t* h, void* k, void* v);
diff --git a/utils/profile.c b/utils/profile.c
@@ -1,3 +1,5 @@
+#define _GNU_SOURCE
+
#include <string.h>
#include <errno.h>
#include <stdio.h>
diff --git a/utils/shitvec.c b/utils/shitvec.c
@@ -1,4 +1,3 @@
-
#include <stdlib.h>
#include <string.h>
diff --git a/utils/sync.c b/utils/sync.c
@@ -1,4 +1,3 @@
-
#include "log.h"
#include "sync.h"
@@ -29,7 +28,7 @@ void* channel_pop(channel_t* chan) {
}
void* channel_recv(channel_t* chan) {
- while(__atomic_load_n(&chan->sz, __ATOMIC_RELAXED) == 0);
+ while(__atomic_load_n(&chan->sz, __ATOMIC_RELAXED) == 0);
return channel_pop(chan);
}