Mercurial
changeset 22:947b81010aba
[Dowa & Seobeo] Updated so that Dowa hashmaps can use arena and not be broken. Split up web so taht it can handle different paths. Also fixes issues with hash collisions which was pain in the ass.
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Tue, 07 Oct 2025 07:11:02 -0700 |
| parents | 09def63429b9 |
| children | 2d0d0b6c8906 |
| files | README.md dowa/BUILD dowa/d_memory.c dowa/dowa.h dowa/dowa_test.c seobeo/s_linux_network.c seobeo/s_web.c |
| diffstat | 7 files changed, 442 insertions(+), 182 deletions(-) [+] |
line wrap: on
line diff
--- a/README.md Mon Oct 06 10:57:30 2025 -0700 +++ b/README.md Tue Oct 07 07:11:02 2025 -0700 @@ -13,3 +13,13 @@ ``` And run whatever your favoriate debugging tools + +```bash +bazel run //dowa:dowa_test --run_under="valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes" +``` + + +brew install valgrind +# or use the unofficial ARM build: +arch -x86_64 brew install valgrind +arch -x86_64 valgrind ./test
--- a/dowa/BUILD Mon Oct 06 10:57:30 2025 -0700 +++ b/dowa/BUILD Tue Oct 07 07:11:02 2025 -0700 @@ -23,4 +23,6 @@ data = glob([ "test_folder/**", ]), + copts = ["-fsanitize=address", "-g"], + linkopts = ["-fsanitize=address"], )
--- a/dowa/d_memory.c Mon Oct 06 10:57:30 2025 -0700 +++ b/dowa/d_memory.c Tue Oct 07 07:11:02 2025 -0700 @@ -28,12 +28,24 @@ void Dowa_Arena_Destroy(Dowa_PArena p_arena) { - if (p_arena) - { - if (p_arena->buffer) - free(p_arena->buffer); - free(p_arena); - } + if (!p_arena) return; + + if (p_arena->buffer) + free(p_arena->buffer); + free(p_arena); +} + +void *Dowa_Arena_Copy(Dowa_PArena p_arena, const void *src, size_t size) +{ + if (p_arena == NULL || src == NULL || size == 0) + return NULL; + + void *dest = Dowa_Arena_Allocate(p_arena, size); + if (!dest) + return NULL; + + memcpy(dest, src, size); + return dest; } // --- HashMap --- // @@ -53,14 +65,17 @@ } p_hash_map->capacity = capacity; p_hash_map->current_capacity = 0; + p_hash_map->p_arena = NULL; return p_hash_map; } Dowa_PHashMap Dowa_HashMap_Create_With_Arena(size_t capacity, Dowa_PArena p_arena) { if (p_arena == NULL) + { printf("Arena is NULL\n"); return Dowa_HashMap_Create(capacity); + } Dowa_PHashMap p_hash_map; p_hash_map = Dowa_Arena_Allocate(p_arena, sizeof(Dowa_HashMap)); @@ -69,6 +84,7 @@ return NULL; } p_hash_map->entries = Dowa_Arena_Allocate(p_arena, sizeof(*p_hash_map->entries) * capacity); + memset(p_hash_map->entries, 0, capacity * sizeof *p_hash_map->entries); if (p_hash_map->entries == NULL) { free(p_hash_map); @@ -85,7 +101,11 @@ if (!p_hash_map) return; if (p_hash_map->p_arena) - Dowa_Arena_Destroy(p_hash_map->p_arena); + { + // Free arena instead of the map... + // Dowa_Arena_Destroy(p_hash_map->p_arena); + return; + } else { Dowa_PHashEntry entry; @@ -120,37 +140,66 @@ void *Dowa_HashMap_Get(Dowa_PHashMap p_hash_map, const char *key) { - int idx_foo = Dowa_HashMap_Get_Position(p_hash_map, key); - void *value = p_hash_map->entries[idx_foo]; - if (value == NULL || strcmp(((Dowa_PHashEntry) value)->key, key) != 0) + int idx = Dowa_HashMap_Get_Position(p_hash_map, key); + Dowa_PHashEntry entry = p_hash_map->entries[idx]; + + while (entry) { - return NULL; + if (strcmp(entry->key, key) == 0) + { + return entry->buffer; + } + entry = entry->next; } - return ((Dowa_PHashEntry) value)->buffer; + + return NULL; } + int32 Dowa_HashMap_Push_Value_With_Type_NoCopy(Dowa_PHashMap p_hash_map, const char *key, void *value, size_t value_size, Dowa_HashMap_ValueType type) { int idx = Dowa_HashMap_Get_Position(p_hash_map, key); Dowa_PHashEntry entry = p_hash_map->entries[idx]; - if (entry) - free(entry->buffer); - else + Dowa_PHashEntry prev = NULL; + + // Old key + while (entry) { - entry = p_hash_map->p_arena ? - Dowa_Arena_Allocate(p_hash_map->p_arena, sizeof(Dowa_HashEntry)) : - malloc(sizeof(Dowa_HashEntry)); - if (entry == NULL) { perror("malloc or arena alloc"); return -1; } + if (strcmp(entry->key, key) == 0) + { + if (!p_hash_map->p_arena && entry->buffer) + free(entry->buffer); + entry->buffer = value; + entry->capacity = value_size; + entry->type = type; + return 0; + } + prev = entry; + entry = entry->next; + } - p_hash_map->entries[idx] = entry; - p_hash_map->current_capacity++; - entry->key = strdup(key); - } + // New Key + entry = p_hash_map->p_arena ? + Dowa_Arena_Allocate(p_hash_map->p_arena, sizeof(Dowa_HashEntry)) : + malloc(sizeof(Dowa_HashEntry)); + if (!entry) { perror("malloc or arena alloc"); return -1; } + + entry->key = p_hash_map->p_arena ? + Dowa_Arena_Copy(p_hash_map->p_arena, key, strlen(key) + 1 /* \0 */) : + strdup(key); entry->buffer = value; entry->capacity = value_size; entry->type = type; + entry->next = NULL; + + if (prev) + prev->next = entry; + else + p_hash_map->entries[idx] = entry; + + p_hash_map->current_capacity++; return 0; } @@ -160,27 +209,57 @@ { int idx = Dowa_HashMap_Get_Position(p_hash_map, key); Dowa_PHashEntry entry = p_hash_map->entries[idx]; - if (entry) - free(entry->buffer); - else + Dowa_PHashEntry prev = NULL; + + // Check for existing key + while (entry) { - entry = p_hash_map->p_arena ? - Dowa_Arena_Allocate(p_hash_map->p_arena, sizeof(Dowa_HashEntry)) : - malloc(sizeof(Dowa_HashEntry)); - if (entry == NULL) { perror("malloc or arena alloc"); return -1; } + if (strcmp(entry->key, key) == 0) + { + if (!p_hash_map->p_arena && entry->buffer) + free(entry->buffer); + + entry->buffer = p_hash_map->p_arena ? + Dowa_Arena_Allocate(p_hash_map->p_arena, value_size) : + malloc(value_size); + if (!entry->buffer) { perror("malloc or arena alloc"); return -1; } - p_hash_map->entries[idx] = entry; - p_hash_map->current_capacity++; - entry->key = strdup(key); + memcpy(entry->buffer, value, value_size); + entry->capacity = value_size; + entry->type = type; + return 0; + } + prev = entry; + entry = entry->next; } - entry->buffer = p_hash_map->p_arena ? + + // New Key + entry = p_hash_map->p_arena ? + Dowa_Arena_Allocate(p_hash_map->p_arena, sizeof(Dowa_HashEntry)) : + malloc(sizeof(Dowa_HashEntry)); + if (!entry) { perror("malloc or arena alloc"); return -1; } + + entry->key = p_hash_map->p_arena ? + Dowa_Arena_Copy(p_hash_map->p_arena, key, strlen(key) + 1 /* \0 */) : + strdup(key); + if (!entry->key) { perror("strdup"); return -1; } + + entry->buffer = p_hash_map->p_arena ? Dowa_Arena_Allocate(p_hash_map->p_arena, value_size) : malloc(value_size); + if (!entry->buffer) { perror("malloc or arena alloc"); return -1; } - if (entry->buffer == NULL) { perror("malloc or arena alloc"); return -1; } + memcpy(entry->buffer, value, value_size); entry->capacity = value_size; entry->type = type; - memcpy(entry->buffer, value, value_size); + entry->next = NULL; + + if (prev) + prev->next = entry; + else + p_hash_map->entries[idx] = entry; + + p_hash_map->current_capacity++; return 0; } @@ -193,7 +272,7 @@ { int idx = Dowa_HashMap_Get_Position(p_hash_map, key); Dowa_PHashEntry entry = p_hash_map->entries[idx]; - if (entry) + if (entry && !(p_hash_map->p_arena)) { free(entry->key); free(entry->buffer); @@ -212,39 +291,43 @@ for (size_t i = 0; i < map->capacity; ++i) { Dowa_PHashEntry e = map->entries[i]; - if (!e) continue; - printf("%s: ", e->key); - switch (e->type) + while (e) { - case DOWA_HASH_MAP_TYPE_BUFFER: - { - unsigned char *p = e->buffer; - for (size_t j = 0; j < e->capacity; ++j) - { - printf("%02x", p[j]); - } - printf("\n"); - } - break; - case DOWA_HASH_MAP_TYPE_STRING: + if (!e) break; + printf("%s: ", e->key); + switch (e->type) { - printf("%s\n", (char*)e->buffer); - } - break; - case DOWA_HASH_MAP_TYPE_HASHMAP: - { - printf("This is a hashmap with size of %zu, and pointer %p\n", (Dowa_PHashMap)e->capacity, (void *)e); + case DOWA_HASH_MAP_TYPE_BUFFER: + { + unsigned char *p = e->buffer; + for (size_t j = 0; j < e->capacity; ++j) + { + printf("%02x", p[j]); + } + printf("\n"); + } + break; + case DOWA_HASH_MAP_TYPE_STRING: + { + printf("%s\n", (char*)e->buffer); + } + break; + case DOWA_HASH_MAP_TYPE_HASHMAP: + { + printf("This is a hashmap with size of %zu, and pointer %p\n", e->capacity, (void *)e); + } + break; + case DOWA_HASH_MAP_TYPE_INT: + { + printf("%d\n", *(int32*)e->buffer); + } + break; + default: + { + printf("<unknown type>\n"); + } } - break; - case DOWA_HASH_MAP_TYPE_INT: - { - printf("%d\n", *(int32*)e->buffer); - } - break; - default: - { - printf("<unknown type>\n"); - } + e = e->next; } } printf("-----------\n"); @@ -277,24 +360,29 @@ if (!f) { perror("fopen"); continue; } void *buf = p_hash_map->p_arena ? - Dowa_Arena_Allocate(p_hash_map->p_arena, size) : - malloc(size); + Dowa_Arena_Allocate(p_hash_map->p_arena, size+1) : + malloc(size+1); if (!buf) { perror("malloc"); fclose(f); closedir(dir); return -1; } + if (fread(buf, 1, size, f) != size) { perror("fread"); - free(buf); + if (!p_hash_map->p_arena) free(buf); fclose(f); continue; } fclose(f); - Dowa_HashMap_Push_Value_With_Type(p_hash_map, entry->d_name, buf, size, DOWA_HASH_MAP_TYPE_STRING); + // null-terminate since the files don't do this and we need this for print. + ((unsigned char*)buf)[size] = '\0'; + + Dowa_HashMap_Push_Value_With_Type(p_hash_map, entry->d_name, buf, size + 1, DOWA_HASH_MAP_TYPE_STRING); free(buf); // Dowa_HashMap_PushValue made its own copy } else if (S_ISDIR(st.st_mode)) { + // TODO: Adjust the sizes of the recursive map? Dowa_PHashMap p_child_map = Dowa_HashMap_Create_With_Arena(100, p_hash_map->p_arena); if (!p_child_map) {
--- a/dowa/dowa.h Mon Oct 06 10:57:30 2025 -0700 +++ b/dowa/dowa.h Tue Oct 07 07:11:02 2025 -0700 @@ -34,9 +34,9 @@ // --- Arena Allocator --- // typedef struct { - char *buffer; - size_t offset; - size_t capacity; + char *buffer; + size_t offset; + size_t capacity; } Dowa_Arena, *Dowa_PArena; /* Creates a new arena with the specified capacity (in bytes). Returns a pointer to the arena, or NULL on failure. */ @@ -45,21 +45,24 @@ extern void *Dowa_Arena_Allocate(Dowa_PArena arena, size_t size); /* Destroys the arena and frees its underlying memory block.*/ extern void Dowa_Arena_Destroy(Dowa_PArena arena); +/* Strdup but saves within the arena */ +extern void *Dowa_Arena_Copy(Dowa_PArena p_arena, const void *src, size_t size); // --- HashMap --- // typedef enum { - DOWA_HASH_MAP_TYPE_BUFFER, // Raw byte buffer - DOWA_HASH_MAP_TYPE_STRING, // Null-terminated string - DOWA_HASH_MAP_TYPE_HASHMAP, // Nested hashmap - DOWA_HASH_MAP_TYPE_INT // Integer value + DOWA_HASH_MAP_TYPE_BUFFER, // Raw byte buffer + DOWA_HASH_MAP_TYPE_STRING, // Null-terminated string + DOWA_HASH_MAP_TYPE_HASHMAP, // Nested hashmap + DOWA_HASH_MAP_TYPE_INT // Integer value } Dowa_HashMap_ValueType; typedef struct { - char *key; - void *buffer; - size_t capacity; - Dowa_HashMap_ValueType type; + char *key; + void *buffer; + size_t capacity; + Dowa_HashMap_ValueType type; + struct Dowa_HashEntry *next; } Dowa_HashEntry, *Dowa_PHashEntry; typedef struct {
--- a/dowa/dowa_test.c Mon Oct 06 10:57:30 2025 -0700 +++ b/dowa/dowa_test.c Tue Oct 07 07:11:02 2025 -0700 @@ -96,17 +96,20 @@ Dowa_HashMap_Print(map2); Dowa_HashMap_Destroy(map2); + printf("[Map2] destroyed (no change)\n\n"); Dowa_Arena_Destroy(mapArena); - printf("[Map2 & Arena] destroyed\n\n"); + printf("[Arena] destroyed (all null)\n\n"); // --- Test Cache_Folder --- // Ensure there is a directory "./dowa/test_folder" with some files for this test to succeed. int cache_result = Dowa_HashMap_Cache_Folder(map, "dowa/test_folder"); printf("[Cache_Folder] returned %d\n", cache_result); - if (cache_result == 0) { + if (cache_result == 0) + { printf("=== Map After Caching 'dowa/test_folder' ===\n"); Dowa_HashMap_Print(map); - } else { + }else + { printf("Cache_Folder failed (ensure 'dowa/test_folder' exists with files)\n"); }
--- a/seobeo/s_linux_network.c Mon Oct 06 10:57:30 2025 -0700 +++ b/seobeo/s_linux_network.c Tue Oct 07 07:11:02 2025 -0700 @@ -298,7 +298,7 @@ if (errno == EINTR || errno == EAGAIN) { // DEBUG - printf("Partial write, returning early (offset=%d)\n", offset); + // printf("Partial write, returning early (offset=%d)\n", offset); continue; } if (errno == EAGAIN) return 1;
--- a/seobeo/s_web.c Mon Oct 06 10:57:30 2025 -0700 +++ b/seobeo/s_web.c Tue Oct 07 07:11:02 2025 -0700 @@ -62,125 +62,191 @@ Dowa_PHashMap p_current = p_html_cache; char *slash; - Dowa_PArena p_response_arena = Dowa_Arena_Create(8192); + Dowa_PArena p_response_arena = Dowa_Arena_Create(1*1024*1024); if (!p_response_arena) { perror("Dowa_Arena_Initialize"); goto clean_up; } void *p_response_header = Dowa_Arena_Allocate(p_response_arena, (size_t)2048); if (!p_response_header) { perror("Dowa_Arena_Allocate"); goto clean_up; } - Dowa_PHashMap p_req_map = Dowa_HashMap_Create_With_Arena(32, p_response_arena); + // Parse request headers into hashmap + Dowa_PHashMap p_req_map = Dowa_HashMap_Create_With_Arena(100, p_response_arena); if (Seobeo_Web_Header_Parse(p_cli_handle, p_req_map) != 0) { - // malformed request or closed — respond 400 Seobeo_Web_Header_Generate(p_response_header, - HTTP_BAD_REQUEST, - "text/plain", 0); + HTTP_BAD_REQUEST, + "text/plain", 0); Seobeo_Handle_Queue(p_cli_handle, - (const uint8*)p_response_header, - (uint32)strlen(p_response_header)); + (const uint8*)p_response_header, + (uint32)strlen(p_response_header)); + Seobeo_Handle_Flush(p_cli_handle); + goto clean_up; + } + + Dowa_HashMap_Print(p_req_map); + + // Extract method (GET, POST, etc.) + const char *method = (const char*)Dowa_HashMap_Get(p_req_map, "HTTP_Method"); + printf("Method: %s Pointer %p\n\n", method, p_req_map); + if (!method) + { + printf("?? wtf\n\n"); + Seobeo_Web_Header_Generate(p_response_header, + HTTP_BAD_REQUEST, + "text/plain", 0); + Seobeo_Handle_Queue(p_cli_handle, + (const uint8*)p_response_header, + (uint32)strlen(p_response_header)); Seobeo_Handle_Flush(p_cli_handle); goto clean_up; } - // DEBUG - // Dowa_HashMap_Print(p_req_map); - - const char *path = (const char*)Dowa_HashMap_Get(p_req_map, "Path"); - char *file_path = Dowa_Arena_Allocate(p_response_arena, (size_t)512); - - if (!path || strcmp(path, "/") == 0) - { - strcpy(file_path, "index.html"); - }else + // --- Separate GET map for caching or routing --- + Dowa_PHashMap p_get_map = Dowa_HashMap_Create(64); + if (!p_get_map) { - size_t L = strlen(path); - // strip leading '/' - if (path[0] == '/') - { - if (strchr(path, '.') == NULL) - snprintf(file_path, 512, "%.*s/index.html", (int)(L-1), path+1); - else - snprintf(file_path, 512, "%.*s", (int)(L-1), path+1); - }else - { - // Probably never get here? - strcpy(file_path, path); - } + perror("Dowa_HashMap_Create (p_get_map)"); + goto clean_up; } - // DEBUG - // printf("\n\nfile_path: %s\n", file_path); + // --- Handle different HTTP methods --- + if (strcmp(method, "GET") == 0) + { + const char *path = (const char*)Dowa_HashMap_Get(p_req_map, "Path"); + char *file_path = Dowa_Arena_Allocate(p_response_arena, (size_t)512); - // Recursively go though the path until it gets to a file - while ((slash = strchr(file_path, '/'))) - { - *slash = '\0'; // e.g. file_path="foo", slash+1="index.html" - char *dir = file_path; // "foo" - file_path = slash + 1; // "index.html" + if (!path || strcmp(path, "/") == 0) + { + strcpy(file_path, "index.html"); + } + else + { + size_t L = strlen(path); + if (path[0] == '/') + { + if (strchr(path, '.') == NULL) + snprintf(file_path, 512, "%.*s/index.html", (int)(L-1), path+1); + else + snprintf(file_path, 512, "%.*s", (int)(L-1), path+1); + } + else + { + strcpy(file_path, path); + } + } + + // Store path for GET handling map + Dowa_HashMap_Push_Value(p_get_map, "Path", file_path, strlen(file_path) + 1); - printf("\n\nDirectory: %s\n\n", dir); + // Walk through nested maps to find content + while ((slash = strchr(file_path, '/'))) + { + *slash = '\0'; + char *dir = file_path; + file_path = slash + 1; + + printf("Directory: %s\n", dir); - p_current = Dowa_HashMap_Get(p_current, dir); - if (!p_current) - { - fprintf(stderr, "No value in hashmap key: %s\n\n", dir); + p_current = Dowa_HashMap_Get(p_current, dir); + if (!p_current) + { + fprintf(stderr, "No value in hashmap key: %s\n\n", dir); + Seobeo_Web_Header_Generate(p_response_header, + HTTP_NOT_FOUND, + "text/html", 0); + Seobeo_Handle_Queue(p_cli_handle, + (const uint8*)p_response_header, + (uint32)strlen(p_response_header)); + Seobeo_Handle_Flush(p_cli_handle); + goto clean_up; + } + } + + size_t pos = Dowa_HashMap_Get_Position(p_current, file_path); + entry = p_current->entries[pos]; + + if (!entry) + { Seobeo_Web_Header_Generate(p_response_header, - HTTP_NOT_FOUND, - "text/html", 0); + HTTP_NOT_FOUND, + "text/html", 0); Seobeo_Handle_Queue(p_cli_handle, - (const uint8*)p_response_header, - (uint32)strlen(p_response_header)); + (const uint8*)p_response_header, + (uint32)strlen(p_response_header)); Seobeo_Handle_Flush(p_cli_handle); goto clean_up; } - } - size_t pos = Dowa_HashMap_Get_Position(p_current, file_path); - entry = p_current->entries[pos]; + const char *mime = "application/octet-stream"; + if (strstr(file_path, ".html")) mime = "text/html; charset=utf-8"; + else if (strstr(file_path, ".css")) mime = "text/css"; + else if (strstr(file_path, ".js")) mime = "application/javascript"; + else if (strstr(file_path, ".png")) mime = "image/png"; + else if (strstr(file_path, ".jpg") || strstr(file_path, ".jpeg")) mime = "image/jpeg"; + else if (strstr(file_path, ".gif")) mime = "image/gif"; + else if (strstr(file_path, ".svg")) mime = "image/svg+xml"; + else if (strstr(file_path, ".ico")) mime = "image/x-icon"; + else if (strstr(file_path, ".json")) mime = "application/json"; - // Missing so 404 - if (!entry) - { + size_t body_size = entry->capacity; + printf("key: %s\nBody Size: %zu\n", entry->key, body_size); + Seobeo_Web_Header_Generate(p_response_header, - HTTP_NOT_FOUND, - "text/html", 0); - Seobeo_Handle_Queue(p_cli_handle, - (const uint8*)p_response_header, - (uint32)strlen(p_response_header)); - Seobeo_Handle_Flush(p_cli_handle); - goto clean_up; - } - + HTTP_OK, + mime, + body_size); - const char *mime = "application/octet-stream"; // Default binary - if (strstr(file_path, ".html")) mime = "text/html; charset=utf-8"; - else if (strstr(file_path, ".css")) mime = "text/css"; - else if (strstr(file_path, ".js")) mime = "application/javascript"; - else if (strstr(file_path, ".png")) mime = "image/png"; - else if (strstr(file_path, ".jpg") || strstr(file_path, ".jpeg")) mime = "image/jpeg"; - else if (strstr(file_path, ".gif")) mime = "image/gif"; - else if (strstr(file_path, ".svg")) mime = "image/svg+xml"; - else if (strstr(file_path, ".ico")) mime = "image/x-icon"; - else if (strstr(file_path, ".json")) mime = "application/json"; - - size_t body_size = entry->capacity; - printf("key: %s\n\n", entry->key); - printf("Body Size: %zu\n\n", body_size); - Seobeo_Web_Header_Generate(p_response_header, - HTTP_OK, - mime, - body_size); - - printf("response header: %s, data: %d\n\n", p_response_header, (uint32)strlen(p_response_header)); - Seobeo_Handle_Queue(p_cli_handle, - (const uint8*)p_response_header, - (uint32)strlen(p_response_header)); - - printf("response body data: %d\n\n", (uint32)body_size); - Seobeo_Handle_Queue(p_cli_handle, - (const uint8*)entry->buffer, - (uint32)body_size); - Seobeo_Handle_Flush(p_cli_handle); + Seobeo_Handle_Queue(p_cli_handle, + (const uint8*)p_response_header, + (uint32)strlen(p_response_header)); + Seobeo_Handle_Queue(p_cli_handle, + (const uint8*)entry->buffer, + (uint32)body_size); + Seobeo_Handle_Flush(p_cli_handle); + } + else if (strcmp(method, "POST") == 0) + { + // --- TODO: Add POST logic here --- + Seobeo_Web_Header_Generate(p_response_header, + HTTP_NOT_FOUND, + "text/plain", 0); + Seobeo_Handle_Queue(p_cli_handle, + (const uint8*)p_response_header, + (uint32)strlen(p_response_header)); + Seobeo_Handle_Flush(p_cli_handle); + } + else if (strcmp(method, "PUT") == 0) + { + // --- TODO: Add PUT logic here --- + Seobeo_Web_Header_Generate(p_response_header, + HTTP_NOT_FOUND, + "text/plain", 0); + Seobeo_Handle_Queue(p_cli_handle, + (const uint8*)p_response_header, + (uint32)strlen(p_response_header)); + Seobeo_Handle_Flush(p_cli_handle); + } + else if (strcmp(method, "DELETE") == 0) + { + // --- TODO: Add DELETE logic here --- + Seobeo_Web_Header_Generate(p_response_header, + HTTP_NOT_FOUND, + "text/plain", 0); + Seobeo_Handle_Queue(p_cli_handle, + (const uint8*)p_response_header, + (uint32)strlen(p_response_header)); + Seobeo_Handle_Flush(p_cli_handle); + } + else + { + // Unknown or unsupported method + Seobeo_Web_Header_Generate(p_response_header, + HTTP_FORBIDDEN, + "text/plain", 0); + Seobeo_Handle_Queue(p_cli_handle, + (const uint8*)p_response_header, + (uint32)strlen(p_response_header)); + Seobeo_Handle_Flush(p_cli_handle); + } clean_up: if (p_cli_handle) @@ -189,6 +255,7 @@ Dowa_Arena_Destroy(p_response_arena); } + int Seobeo_Web_Header_Parse(Seobeo_PHandle p_handle, Dowa_PHashMap map) { // 1) Fill read_buffer until we see "\r\n\r\n" @@ -211,16 +278,97 @@ char *hdr_end = strstr(buf, "\r\n\r\n"); size_t hdr_len = hdr_end - buf + 4; + // This seems kinda bad ? char method[16], path[256], version[16]; if (sscanf(buf, "%15s %255s %15s", method, path, version) != 3) { return -1; } - Dowa_HashMap_Push_Value_With_Type(map, "Method", method, strlen(method) + 1, DOWA_HASH_MAP_TYPE_STRING); - Dowa_HashMap_Push_Value_With_Type(map, "Path", path, strlen(path) + 1, DOWA_HASH_MAP_TYPE_STRING); + Dowa_HashMap_Push_Value_With_Type(map, "HTTP_Method", method, strlen(method) + 1, DOWA_HASH_MAP_TYPE_STRING); + printf("Method: %s Pointer %p\n\n", Dowa_HashMap_Get(map, "HTTP_Method"), map); Dowa_HashMap_Push_Value_With_Type(map, "Version", version, strlen(version) + 1, DOWA_HASH_MAP_TYPE_STRING); + // 1) Separate raw path and query string + char *raw_path = path; + char *query_start = strchr(raw_path, '?'); + char *query_str = NULL; + + if (query_start) + { + *query_start = '\0'; // now raw_path ends before '?' + query_str = query_start + 1; + } + + // push only the clean path + Dowa_HashMap_Push_Value_With_Type( + map, + "Path", + raw_path, + strlen(raw_path) + 1, + DOWA_HASH_MAP_TYPE_STRING); + + // 2) If there *is* a query, tokenize into a sub-map + if (query_str && *query_str) + { + // create nested map for GET params + Dowa_PHashMap p_query_map = Dowa_HashMap_Create_With_Arena(100, map->p_arena); + + char *cur = query_str; + while (cur && *cur) + { + // find the next '&' + char *next_amp = strchr(cur, '&'); + // if none, treat end-of-string as the boundary + char *pair_end = next_amp ? next_amp : cur + strlen(cur); + + // find '=' in [cur, pair_end) + char *eq = memchr(cur, '=', pair_end - cur); + if (eq) { + size_t key_len = eq - cur; + size_t val_len = pair_end - (eq + 1); + + // extract key + char key_buf[key_len + 1]; + memcpy(key_buf, cur, key_len); + key_buf[key_len] = '\0'; + + // extract value + char val_buf[val_len + 1]; + memcpy(val_buf, eq + 1, val_len); + val_buf[val_len] = '\0'; + + printf("key: '%s', value: '%s'\n", key_buf, val_buf); + // push into map with strlen(val_buf)+1 to include '\0' + Dowa_HashMap_Push_Value_With_Type( + p_query_map, + key_buf, + val_buf, + (uint32_t)(val_len + 1), + DOWA_HASH_MAP_TYPE_STRING); + } + + // advance past '&' if present, else end loop + cur = next_amp ? next_amp + 1 : NULL; + } + if ( + Dowa_HashMap_Push_Value_With_Type_NoCopy( + map, + "QueryParams", + p_query_map, + sizeof(p_query_map), + DOWA_HASH_MAP_TYPE_HASHMAP) == -1 + ) + { + printf("Something went wrong...\n\n"); + } + } + + // int qp = Dowa_HashMap_Get_Position(map, "QueryParams"); + // Dowa_PHashEntry p_qp_entry = map->entries[qp]; + // printf("query param key: %s\n", p_qp_entry->key); + // printf("query param value: %s\n",(char *)Dowa_HashMap_Get(p_qp_entry->buffer, "hello")); + // 3) Parse each header line until the blank line char *line = buf + strlen(method) + 1 + strlen(path) + 1 + strlen(version) + 2; while (line < hdr_end) @@ -230,7 +378,8 @@ // split at colon char *colon = memchr(line, ':', next - line); - if (colon) { + if (colon) + { size_t key_len = colon - line; size_t value_len = next - colon - 1; @@ -249,7 +398,11 @@ memcpy(val, val_start, value_len); val[value_len] = '\0'; - Dowa_HashMap_Push_Value(map, key, val, value_len + 1); + Dowa_HashMap_Push_Value_With_Type(map, key, val, value_len + 1, DOWA_HASH_MAP_TYPE_STRING); + + printf("Capacity: %d, Length: %d ", (int)map->p_arena->capacity, (int)map->p_arena->offset); + printf("value_len: %d, key: %s value %s position: %d\n\n", (int)value_len + 1, key, val, Dowa_HashMap_Get_Position(map, key)); + printf("Method: %s Position: %d Pointer %p\n\n", Dowa_HashMap_Get(map, "HTTP_Method"), Dowa_HashMap_Get_Position(map, "HTTP_Method"), map); free(key); free(val); @@ -414,7 +567,8 @@ } } - printf("%s", p_request_body); + // Debug + printf("Request body %s", p_request_body); Dowa_Arena_Destroy(p_request_arena); Seobeo_Handle_Destroy(h); return 0;