Mercurial
diff seobeo/s_web.c @ 175:71ad34a8bc9a hg-web
[HgWeb] Can stream hg response now. Added react page for hg web since we use json anyway.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Tue, 20 Jan 2026 06:06:47 -0800 |
| parents | 827c6ac504cd |
| children | 8cf4ec5e2191 |
line wrap: on
line diff
--- a/seobeo/s_web.c Mon Jan 19 18:59:23 2026 -0800 +++ b/seobeo/s_web.c Tue Jan 20 06:06:47 2026 -0800 @@ -96,13 +96,14 @@ // Recording IP to see who is ddosing or any web scrappers... void *p_real_ip_kv = Dowa_HashMap_Get_Ptr(p_req_map, "X-Real-IP"); const char *real_ip = p_real_ip_kv ? ((Seobeo_Request_Entry*)p_real_ip_kv)->value : NULL; + // Fallback if (!real_ip) { void *p_forwarded_kv = Dowa_HashMap_Get_Ptr(p_req_map, "X-Forwarded-For"); real_ip = p_forwarded_kv ? ((Seobeo_Request_Entry*)p_forwarded_kv)->value : NULL; } - // Fallback + if (!real_ip) real_ip = p_cli_handle->host; @@ -137,7 +138,7 @@ // --- Check for WebSocket upgrade request --- #ifdef SEOBEO_WEBSOCKET_SERVER - Seobeo_Log(SEOBEO_DEBUG, "Web soceket path \n"); + Seobeo_Log(SEOBEO_DEBUG, "Web socket path \n"); if (Seobeo_WebSocket_Server_Handle_Upgrade(p_cli_handle, p_req_map, path)) { Seobeo_Log(SEOBEO_INFO, "WebSocket connection established\n"); @@ -149,7 +150,15 @@ } #endif - // --- Try to match API route first --- + // --- Try to match streaming route first --- + Seobeo_Stream_Handler stream_handler = Seobeo_Router_Find_Stream_Handler(method, path, &p_req_map, p_request_arena); + if (stream_handler != NULL) + { + stream_handler(p_cli_handle, p_req_map, p_response_arena); + goto clean_up; + } + + // --- Try to match API route --- Seobeo_Route_Handler handler = Seobeo_Router_Find_Handler(method, path, &p_req_map, p_request_arena); if (handler != NULL) { @@ -293,7 +302,10 @@ break; if (r == 0) - return 1; // EAGAIN, try again later TODO: Add this as part of Handle struct. + { + Seobeo_Log(SEOBEO_INFO, "Waiting?\n"); + continue; // EAGAIN, try again later TODO: Add this as part of Handle struct. + } } // "METHOD SP PATH SP VERSION CRLF" @@ -408,7 +420,6 @@ char *next = strstr(line, "\r\n"); if (!next) break; - // split at colon char *colon = memchr(line, ':', next - line); if (colon) { @@ -432,7 +443,6 @@ memcpy(val, val_start, value_len); val[value_len] = '\0'; - // Both key and value are arena-allocated, hashmap will use them Dowa_HashMap_Push_Arena(*pp_map, key, val, p_arena); } @@ -450,7 +460,6 @@ Seobeo_Log(SEOBEO_DEBUG, "Content-Length=%zu, reading body in chunks...\n", body_len); - // Allocate buffer for entire body char *body = Dowa_Arena_Allocate(p_arena, body_len + 1); if (!body) { @@ -567,6 +576,7 @@ char *method; // "GET", "POST", "PUT", "DELETE" char *path_pattern; // "/v1/users/:id/posts/:post_id" Seobeo_Route_Handler handler; + Seobeo_Stream_Handler stream_handler; // For streaming responses // Pre-parsed path segments for efficient matching char **path_segments; // ["v1", "users", ":id", "posts", ":post_id"] @@ -588,6 +598,25 @@ route.method = strdup(method); route.path_pattern = strdup(path_pattern); route.handler = handler; + route.stream_handler = NULL; + route.path_segments = Dowa_String_Split(path_pattern, "/", strlen(path_pattern), 1, NULL); + route.segment_count = Dowa_Array_Length(route.path_segments); + route.is_param = (boolean*)malloc(sizeof(boolean) * route.segment_count); + + for (size_t i = 0; i < route.segment_count; i++) + route.is_param[i] = (route.path_segments[i][0] == ':'); + + Dowa_Array_Push(g_routes, route); +} + +void Seobeo_Router_Register_Stream(const char *method, const char *path_pattern, Seobeo_Stream_Handler handler) +{ + Seobeo_Route route = {0}; + + route.method = strdup(method); + route.path_pattern = strdup(path_pattern); + route.handler = NULL; + route.stream_handler = handler; route.path_segments = Dowa_String_Split(path_pattern, "/", strlen(path_pattern), 1, NULL); route.segment_count = Dowa_Array_Length(route.path_segments); route.is_param = (boolean*)malloc(sizeof(boolean) * route.segment_count); @@ -670,6 +699,29 @@ return NULL; } +Seobeo_Stream_Handler Seobeo_Router_Find_Stream_Handler( + const char *method, + const char *path, + Seobeo_Request_Entry **pp_request_map, + Dowa_Arena *p_arena) +{ + if (g_routes == NULL || method == NULL || path == NULL) + return NULL; + + size_t route_count = Dowa_Array_Length(g_routes); + for (size_t i = 0; i < route_count; i++) + { + Seobeo_Route *route = &g_routes[i]; + if (strcmp(route->method, method) != 0) + continue; + + if (route->stream_handler && match_route_and_extract(route, path, pp_request_map, p_arena)) + return route->stream_handler; + } + + return NULL; +} + void Seobeo_Router_Send_Response( Seobeo_Handle *p_handle, Seobeo_Request_Entry *p_response_map, @@ -696,24 +748,23 @@ const char *body = ""; void *p_body_kv = Dowa_HashMap_Get_Ptr(p_response_map, "body"); if (p_body_kv) - { body = ((Seobeo_Request_Entry*)p_body_kv)->value; - } const char *content_type = "text/html"; void *p_content_type_kv = Dowa_HashMap_Get_Ptr(p_response_map, "content-type"); if (p_content_type_kv) - { content_type = ((Seobeo_Request_Entry*)p_content_type_kv)->value; - } - size_t body_length = strlen(body); + // TODO: Update this to be integer + size_t body_length; void *p_content_length_kv = Dowa_HashMap_Get_Ptr(p_response_map, "content-length"); if (p_content_length_kv) { const char *content_length_str = ((Seobeo_Request_Entry*)p_content_length_kv)->value; body_length = atoi(content_length_str); } + else + body_length = strlen(body); char *header = Dowa_Arena_Allocate(p_arena, 4096); Seobeo_Web_Header_Generate(header, status, content_type, body_length); @@ -734,6 +785,8 @@ free(temp); } + printf("hEADER %s\n", header); + Seobeo_Handle_Queue(p_handle, (uint8_t*)header, strlen(header)); Seobeo_Handle_Queue(p_handle, (uint8_t*)body, body_length); Seobeo_Handle_Flush(p_handle);