Mercurial
comparison seobeo/s_web.c @ 251:117c4d53c9a4
[ui] Add HTML-first Web Component system
Co-authored-by: Copilot <[email protected]>
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Tue, 04 Aug 2026 09:14:57 -0700 |
| parents | b8aa08503378 |
| children | 609d3c6aff4e |
comparison
equal
deleted
inserted
replaced
| 250:745fd127b2a1 | 251:117c4d53c9a4 |
|---|---|
| 1 #include "seobeo/seobeo.h" | 1 #include "seobeo/seobeo.h" |
| 2 #include <strings.h> | 2 #include <strings.h> |
| 3 #include <time.h> | 3 #include <time.h> |
| 4 | 4 |
| 5 static char g_folder_path[512] = "."; | 5 static char g_folder_path[512] = "."; |
| 6 | |
| 7 static boolean Seobeo_Static_Path_Is_Safe(const char *path) | |
| 8 { | |
| 9 if (!path || strchr(path, '\\')) | |
| 10 return FALSE; | |
| 11 const char *segment = path; | |
| 12 while (*segment) | |
| 13 { | |
| 14 while (*segment == '/') | |
| 15 segment++; | |
| 16 const char *end = segment; | |
| 17 while (*end && *end != '/') | |
| 18 end++; | |
| 19 if ((size_t)(end - segment) == 2 && | |
| 20 segment[0] == '.' && | |
| 21 segment[1] == '.') | |
| 22 return FALSE; | |
| 23 segment = end; | |
| 24 } | |
| 25 return TRUE; | |
| 26 } | |
| 6 | 27 |
| 7 static char *canonical_request_header(char *header) | 28 static char *canonical_request_header(char *header) |
| 8 { | 29 { |
| 9 if (strcasecmp(header, "content-length") == 0) return "Content-Length"; | 30 if (strcasecmp(header, "content-length") == 0) return "Content-Length"; |
| 10 if (strcasecmp(header, "content-type") == 0) return "Content-Type"; | 31 if (strcasecmp(header, "content-type") == 0) return "Content-Type"; |
| 239 } | 260 } |
| 240 | 261 |
| 241 // --- Static files fallback for GET (use original large arena logic) --- | 262 // --- Static files fallback for GET (use original large arena logic) --- |
| 242 if (strcmp(method, "GET") == 0) | 263 if (strcmp(method, "GET") == 0) |
| 243 { | 264 { |
| 265 if (!Seobeo_Static_Path_Is_Safe(path)) | |
| 266 { | |
| 267 Seobeo_Web_Header_Generate_KeepAlive( | |
| 268 p_response_header, | |
| 269 HTTP_BAD_REQUEST, | |
| 270 "text/plain", | |
| 271 0, | |
| 272 should_keep_alive); | |
| 273 Seobeo_Handle_Queue( | |
| 274 p_cli_handle, | |
| 275 (const uint8 *)p_response_header, | |
| 276 (uint32)strlen(p_response_header)); | |
| 277 Seobeo_Handle_Flush(p_cli_handle); | |
| 278 goto clean_up_arenas; | |
| 279 } | |
| 280 | |
| 244 char *file_path = Dowa_Arena_Allocate(p_response_arena, (size_t)5 * 1024); | 281 char *file_path = Dowa_Arena_Allocate(p_response_arena, (size_t)5 * 1024); |
| 245 | 282 |
| 246 if (!path || strcmp(path, "/") == 0) | 283 if (!path || strcmp(path, "/") == 0) |
| 247 { | 284 { |
| 248 strcpy(file_path, "index.html"); | 285 strcpy(file_path, "index.html"); |
| 259 } | 296 } |
| 260 else | 297 else |
| 261 strcpy(file_path, path); | 298 strcpy(file_path, path); |
| 262 } | 299 } |
| 263 | 300 |
| 264 void *p_file_kv = Dowa_HashMap_Get_Ptr(p_html_cache, file_path); | 301 char *file_content = NULL; |
| 265 const char *file_content = NULL; | |
| 266 size_t body_size = 0; | 302 size_t body_size = 0; |
| 267 | 303 (void)p_html_cache; |
| 268 if (p_file_kv) | 304 file_content = Seobeo_Web_LoadFile(file_path, &body_size); |
| 269 { | |
| 270 Seobeo_Cached_File *cached = ((Seobeo_Cache_Entry*)p_file_kv)->value; | |
| 271 file_content = cached->content; | |
| 272 body_size = cached->size; | |
| 273 } | |
| 274 else | |
| 275 { | |
| 276 file_content = Seobeo_Web_LoadFile(file_path, &body_size); | |
| 277 if (file_content) | |
| 278 { | |
| 279 Seobeo_Cached_File *cached = malloc(sizeof(Seobeo_Cached_File)); | |
| 280 cached->content = (char*)file_content; | |
| 281 cached->size = body_size; | |
| 282 Dowa_HashMap_Push(p_html_cache, file_path, cached); | |
| 283 } | |
| 284 } | |
| 285 | 305 |
| 286 if (!file_content) | 306 if (!file_content) |
| 287 { | 307 { |
| 288 Seobeo_Web_Header_Generate_KeepAlive(p_response_header, | 308 Seobeo_Web_Header_Generate_KeepAlive(p_response_header, |
| 289 HTTP_NOT_FOUND, | 309 HTTP_NOT_FOUND, |
| 334 (uint32)strlen(p_response_header)); | 354 (uint32)strlen(p_response_header)); |
| 335 Seobeo_Handle_Queue(p_cli_handle, | 355 Seobeo_Handle_Queue(p_cli_handle, |
| 336 (const uint8*)file_content, | 356 (const uint8*)file_content, |
| 337 (uint32)body_size); | 357 (uint32)body_size); |
| 338 Seobeo_Handle_Flush(p_cli_handle); | 358 Seobeo_Handle_Flush(p_cli_handle); |
| 359 free(file_content); | |
| 339 } | 360 } |
| 340 else | 361 else |
| 341 { | 362 { |
| 342 Seobeo_Web_Header_Generate_KeepAlive(p_response_header, | 363 Seobeo_Web_Header_Generate_KeepAlive(p_response_header, |
| 343 HTTP_NOT_FOUND, | 364 HTTP_NOT_FOUND, |
| 598 const char *folder_path, | 619 const char *folder_path, |
| 599 const char *port, | 620 const char *port, |
| 600 Seobeo_ServerMode mode, | 621 Seobeo_ServerMode mode, |
| 601 int thread_count) | 622 int thread_count) |
| 602 { | 623 { |
| 624 return Seobeo_Web_Server_Start_On( | |
| 625 NULL, | |
| 626 folder_path, | |
| 627 port, | |
| 628 mode, | |
| 629 thread_count); | |
| 630 } | |
| 631 | |
| 632 int Seobeo_Web_Server_Start_On( | |
| 633 const char *host, | |
| 634 const char *folder_path, | |
| 635 const char *port, | |
| 636 Seobeo_ServerMode mode, | |
| 637 int thread_count) | |
| 638 { | |
| 603 if (folder_path) | 639 if (folder_path) |
| 604 strncpy(g_folder_path, folder_path, sizeof(g_folder_path) - 1); | 640 strncpy(g_folder_path, folder_path, sizeof(g_folder_path) - 1); |
| 605 | 641 |
| 606 Seobeo_Cache_Entry *p_html_cache = NULL; | 642 Seobeo_Cache_Entry *p_html_cache = NULL; |
| 607 | 643 |
| 608 Seobeo_Handle *p_server_handle = | 644 Seobeo_Handle *p_server_handle = |
| 609 Seobeo_Stream_Handle_Server_Create(NULL, port); | 645 Seobeo_Stream_Handle_Server_Create(host, port); |
| 610 if (p_server_handle->socket < 0) return 1; | 646 if (!p_server_handle || p_server_handle->socket < 0) |
| 647 { | |
| 648 if (p_server_handle) | |
| 649 Seobeo_Handle_Destroy(p_server_handle); | |
| 650 return 1; | |
| 651 } | |
| 611 | 652 |
| 612 Seobeo_Log(SEOBEO_INFO, "Listening on port %s\n", port); | 653 Seobeo_Log(SEOBEO_INFO, "Listening on port %s\n", port); |
| 613 | 654 |
| 614 if (mode == SEOBEO_MODE_FORK) | 655 if (mode == SEOBEO_MODE_FORK) |
| 615 { | 656 { |