Mercurial
comparison seobeo/s_web.c @ 18:fa2b8af609d9
[Seobeo] Fixed a bug with pathing. Support SSL.
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Mon, 06 Oct 2025 08:21:34 -0700 |
| parents | d97ec3ded2ae |
| children | 875bb6e10db7 |
comparison
equal
deleted
inserted
replaced
| 17:d97ec3ded2ae | 18:fa2b8af609d9 |
|---|---|
| 6 return sprintf( | 6 return sprintf( |
| 7 buffer, | 7 buffer, |
| 8 "GET %s HTTP/1.1\r\n" | 8 "GET %s HTTP/1.1\r\n" |
| 9 "Host: %s\r\n" | 9 "Host: %s\r\n" |
| 10 "Connection: close\r\n" | 10 "Connection: close\r\n" |
| 11 "accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\n" | |
| 12 "accept-language: en-GB,en;q=0.9,en-US;q=0.8,ko;q=0.7\r\n" | |
| 13 "if-modified-since: Sat, 02 Aug 2025 22:51:58 GMT\r\n" | |
| 14 "if-none-match: W/\"688e968e-5700\"\r\n" | |
| 15 "priority: u=0, i\r\n" | |
| 16 "sec-ch-ua: \"Chromium\";v=\"140\", \"Not=A?Brand\";v=\"24\", \"Google Chrome\";v=\"140\"\r\n" | |
| 17 "sec-ch-ua-mobile: 0\r\n" | |
| 18 "sec-ch-ua-platform: \"macOS\"\r\n" | |
| 19 "sec-fetch-dest: document\r\n" | |
| 20 "sec-fetch-mode: navigate\r\n" | |
| 21 "sec-fetch-site: none\r\n" | |
| 22 "sec-fetch-user: 1\r\n" | |
| 23 "upgrade-insecure-requests: 1\r\n" | |
| 11 "\r\n", | 24 "\r\n", |
| 12 path, host | 25 path, host |
| 13 ); | 26 ); |
| 14 } | 27 } |
| 15 | 28 |
| 31 default: status_text = "Unknown"; break; | 44 default: status_text = "Unknown"; break; |
| 32 } | 45 } |
| 33 | 46 |
| 34 sprintf( | 47 sprintf( |
| 35 buffer, | 48 buffer, |
| 36 "HTTP/2.2 %d %s\r\n" | 49 "HTTP/1.1 %d %s\r\n" |
| 37 "Content-Type: %s\r\n" | 50 "Content-Type: %s\r\n" |
| 38 "Content-Length: %d\r\n" | 51 "Content-Length: %d\r\n" |
| 39 "Connection: close\r\n" | 52 "Connection: close\r\n" |
| 40 "\r\n", | 53 "\r\n", |
| 41 status, status_text, content_type, content_length | 54 status, status_text, content_type, content_length |
| 69 (uint32)strlen(p_response_header)); | 82 (uint32)strlen(p_response_header)); |
| 70 Seobeo_Handle_Flush(p_cli_handle); | 83 Seobeo_Handle_Flush(p_cli_handle); |
| 71 goto clean_up; | 84 goto clean_up; |
| 72 } | 85 } |
| 73 | 86 |
| 74 Dowa_HashMap_Print(p_req_map); | 87 // DEBUG |
| 88 // Dowa_HashMap_Print(p_req_map); | |
| 75 | 89 |
| 76 const char *path = (const char*)Dowa_HashMap_Get(p_req_map, "Path"); | 90 const char *path = (const char*)Dowa_HashMap_Get(p_req_map, "Path"); |
| 77 | |
| 78 char *file_path = Dowa_Arena_Allocate(p_response_arena, (size_t)512); | 91 char *file_path = Dowa_Arena_Allocate(p_response_arena, (size_t)512); |
| 79 | 92 |
| 80 if (!path || strcmp(path, "/") == 0) | 93 if (!path || strcmp(path, "/") == 0) |
| 81 { | 94 { |
| 82 strcpy(file_path, "index.html"); | 95 strcpy(file_path, "index.html"); |
| 83 } | 96 }else |
| 84 else | |
| 85 { | 97 { |
| 86 size_t L = strlen(path); | 98 size_t L = strlen(path); |
| 87 // strip leading '/' | 99 // strip leading '/' |
| 88 if (path[0] == '/') | 100 if (path[0] == '/') |
| 89 { | 101 { |
| 90 if (strchr(path, '.') == NULL) | 102 if (strchr(path, '.') == NULL) |
| 91 snprintf(file_path, 512, "%.*s/index.html", (int)(L-1), path+1); | 103 snprintf(file_path, 512, "%.*s/index.html", (int)(L-1), path+1); |
| 92 else | 104 else |
| 93 snprintf(file_path, 512, "%.*s", (int)(L-1), path+1); | 105 snprintf(file_path, 512, "%.*s", (int)(L-1), path+1); |
| 94 } | 106 }else |
| 95 else | |
| 96 { | 107 { |
| 97 // Probably never get here? | 108 // Probably never get here? |
| 98 strcpy(file_path, path); | 109 strcpy(file_path, path); |
| 99 } | 110 } |
| 100 } | 111 } |
| 101 | 112 |
| 113 // DEBUG | |
| 102 // printf("\n\nfile_path: %s\n", file_path); | 114 // printf("\n\nfile_path: %s\n", file_path); |
| 103 | 115 |
| 104 // Recursively go though the path until it gets to a file | 116 // Recursively go though the path until it gets to a file |
| 105 while ((slash = strchr(file_path, '/'))) | 117 while ((slash = strchr(file_path, '/'))) |
| 106 { | 118 { |
| 107 *slash = '\0'; // e.g. file_path="foo", slash+1="index.html" | 119 *slash = '\0'; // e.g. file_path="foo", slash+1="index.html" |
| 108 char *dir = file_path; // "foo" | 120 char *dir = file_path; // "foo" |
| 109 file_path = slash + 1; // "index.html" | 121 file_path = slash + 1; // "index.html" |
| 110 | 122 |
| 123 printf("\n\nDirectory: %s\n\n", dir); | |
| 124 | |
| 111 p_current = Dowa_HashMap_Get(p_current, dir); | 125 p_current = Dowa_HashMap_Get(p_current, dir); |
| 112 if (!p_current) { perror("No value"); goto clean_up; } | 126 if (!p_current) |
| 127 { | |
| 128 fprintf(stderr, "No value in hashmap key: %s\n\n", dir); | |
| 129 Seobeo_Web_GenerateResponseHeader(p_response_header, | |
| 130 HTTP_NOT_FOUND, | |
| 131 "text/html", 0); | |
| 132 Seobeo_Handle_Queue(p_cli_handle, | |
| 133 (const uint8*)p_response_header, | |
| 134 (uint32)strlen(p_response_header)); | |
| 135 Seobeo_Handle_Flush(p_cli_handle); | |
| 136 goto clean_up; | |
| 137 } | |
| 113 } | 138 } |
| 114 | 139 |
| 115 size_t pos = Dowa_HashMap_GetPosition(p_current, file_path); | 140 size_t pos = Dowa_HashMap_GetPosition(p_current, file_path); |
| 116 entry = p_current->entries[pos]; | 141 entry = p_current->entries[pos]; |
| 117 | 142 |
| 139 else if (strstr(file_path, ".svg")) mime = "image/svg+xml"; | 164 else if (strstr(file_path, ".svg")) mime = "image/svg+xml"; |
| 140 else if (strstr(file_path, ".ico")) mime = "image/x-icon"; | 165 else if (strstr(file_path, ".ico")) mime = "image/x-icon"; |
| 141 else if (strstr(file_path, ".json")) mime = "application/json"; | 166 else if (strstr(file_path, ".json")) mime = "application/json"; |
| 142 | 167 |
| 143 size_t body_size = entry->capacity; | 168 size_t body_size = entry->capacity; |
| 169 printf("key: %s\n\n", entry->key); | |
| 170 printf("Body Size: %zu\n\n", body_size); | |
| 144 Seobeo_Web_GenerateResponseHeader(p_response_header, | 171 Seobeo_Web_GenerateResponseHeader(p_response_header, |
| 145 HTTP_OK, | 172 HTTP_OK, |
| 146 mime, | 173 mime, |
| 147 body_size); | 174 body_size); |
| 175 | |
| 176 printf("response header: %s, data: %d\n\n", p_response_header, (uint32)strlen(p_response_header)); | |
| 148 Seobeo_Handle_Queue(p_cli_handle, | 177 Seobeo_Handle_Queue(p_cli_handle, |
| 149 (const uint8*)p_response_header, | 178 (const uint8*)p_response_header, |
| 150 (uint32)strlen(p_response_header)); | 179 (uint32)strlen(p_response_header)); |
| 180 | |
| 181 printf("response body data: %d\n\n", (uint32)body_size); | |
| 151 Seobeo_Handle_Queue(p_cli_handle, | 182 Seobeo_Handle_Queue(p_cli_handle, |
| 152 (const uint8*)entry->buffer, | 183 (const uint8*)entry->buffer, |
| 153 (uint32)body_size); | 184 (uint32)body_size); |
| 154 Seobeo_Handle_Flush(p_cli_handle); | 185 Seobeo_Handle_Flush(p_cli_handle); |
| 155 | 186 |
| 284 perror("Dowa_Cache_Folder"); | 315 perror("Dowa_Cache_Folder"); |
| 285 return -1; | 316 return -1; |
| 286 } | 317 } |
| 287 | 318 |
| 288 Seobeo_PHandle p_server_handle = | 319 Seobeo_PHandle p_server_handle = |
| 289 Seobeo_Stream_Handle_Create(NULL, port); | 320 Seobeo_Stream_Handle_Server_Create(NULL, port); |
| 290 if (p_server_handle->socket < 0) return 1; | 321 if (p_server_handle->socket < 0) return 1; |
| 322 | |
| 291 printf("Listening on port %s\n", port); | 323 printf("Listening on port %s\n", port); |
| 292 | 324 |
| 293 // Fork‐based fallback | 325 // Fork‐based fallback |
| 294 if (mode == SEOBEO_MODE_FORK) | 326 if (mode == SEOBEO_MODE_FORK) |
| 295 { | 327 { |
| 328 printf("FORK MODE\n"); | |
| 296 struct sigaction sa; | 329 struct sigaction sa; |
| 297 sa.sa_handler = SigchildHandler; | 330 sa.sa_handler = SigchildHandler; |
| 298 sigemptyset(&sa.sa_mask); | 331 sigemptyset(&sa.sa_mask); |
| 299 sa.sa_flags = SA_RESTART; | 332 sa.sa_flags = SA_RESTART; |
| 300 sigaction(SIGCHLD, &sa, NULL); | 333 sigaction(SIGCHLD, &sa, NULL); |
| 314 } | 347 } |
| 315 } | 348 } |
| 316 | 349 |
| 317 if (mode == SEOBEO_MODE_EDGE) | 350 if (mode == SEOBEO_MODE_EDGE) |
| 318 { | 351 { |
| 352 printf("EDGE MODE\n"); | |
| 319 Seobeo_Web_Edge(p_server_handle, thread_count, p_html_cache); | 353 Seobeo_Web_Edge(p_server_handle, thread_count, p_html_cache); |
| 320 } | 354 } |
| 321 | 355 |
| 322 return -1; | 356 return -1; |
| 323 } | 357 } |
| 325 | 359 |
| 326 int Seobeo_Web_ClientGet(const char *host, | 360 int Seobeo_Web_ClientGet(const char *host, |
| 327 const char *port, | 361 const char *port, |
| 328 const char *path) | 362 const char *path) |
| 329 { | 363 { |
| 330 Seobeo_PHandle h = Seobeo_Stream_Handle_Create(host, port); | 364 Seobeo_PHandle h = Seobeo_Stream_Handle_Client_Create(host, port, TRUE); |
| 331 if (!h || h->socket < 0) | 365 if (!h || h->socket < 0) |
| 332 { | 366 { |
| 333 if (h) Seobeo_Handle_Destroy(h); | 367 if (h) |
| 368 Seobeo_Handle_Destroy(h); | |
| 334 return -1; | 369 return -1; |
| 335 } | 370 } |
| 336 | 371 |
| 337 Dowa_PArena p_request_arena = Dowa_Arena_Create(1 * 1024 * 1024); | 372 Dowa_PArena p_request_arena = Dowa_Arena_Create(1 * 1024 * 1024); |
| 338 if (!p_request_arena) | 373 if (!p_request_arena) { perror("Dowa_Arena_Create"); return -1; } |
| 339 { | 374 |
| 340 perror("Dowa_Arena_Create"); | |
| 341 return -1; | |
| 342 } | |
| 343 void *p_request_header = Dowa_Arena_Allocate(p_request_arena, 4096); | 375 void *p_request_header = Dowa_Arena_Allocate(p_request_arena, 4096); |
| 344 if (!p_request_header) | 376 if (!p_request_header) { perror("Dowa_Arena_Allocate"); return -1; } |
| 345 { | |
| 346 perror("Dowa_Arena_Allocate"); | |
| 347 return -1; | |
| 348 } | |
| 349 | 377 |
| 350 int request_len = Seobeo_Web_GenerateRequestHeader(p_request_header, host, path); | 378 int request_len = Seobeo_Web_GenerateRequestHeader(p_request_header, host, path); |
| 351 printf("request: %s\n", (char *)p_request_header); | 379 // DEBUG |
| 380 // printf("request: %s\n", (char *)p_request_header); | |
| 352 Seobeo_Handle_Queue(h, (uint8 *)p_request_header, (uint32)request_len); | 381 Seobeo_Handle_Queue(h, (uint8 *)p_request_header, (uint32)request_len); |
| 353 | |
| 354 if (Seobeo_Handle_Flush(h) < 0) | 382 if (Seobeo_Handle_Flush(h) < 0) |
| 355 { | 383 { |
| 356 perror("Seobeo_Handle_Flush"); | 384 perror("Seobeo_Handle_Flush"); |
| 357 Seobeo_Handle_Destroy(h); | 385 Seobeo_Handle_Destroy(h); |
| 358 return -1; | 386 return -1; |
| 359 } | 387 } |
| 360 | 388 |
| 389 // Response | |
| 361 size_t cap = 1024*8, used = 0; | 390 size_t cap = 1024*8, used = 0; |
| 362 char *p_request_body = Dowa_Arena_Allocate(p_request_arena, cap); | 391 char *p_request_body = Dowa_Arena_Allocate(p_request_arena, cap); |
| 363 if (!p_request_body) { Seobeo_Handle_Destroy(h); return -1; } | 392 if (!p_request_body) { Seobeo_Handle_Destroy(h); return -1; } |
| 364 | 393 |
| 365 while (1) { | 394 while (1) |
| 395 { | |
| 366 int n = Seobeo_Handle_Read(h); | 396 int n = Seobeo_Handle_Read(h); |
| 397 printf("Size: %d\n", n); | |
| 367 if (n > 0) | 398 if (n > 0) |
| 368 { | 399 { |
| 400 // TODO: Maybe directly use arena inside of the struct? idk if that is useful or not... | |
| 369 memcpy(p_request_body + used, h->read_buffer, h->read_buffer_len); | 401 memcpy(p_request_body + used, h->read_buffer, h->read_buffer_len); |
| 370 used += h->read_buffer_len; | 402 used += h->read_buffer_len; |
| 371 Seobeo_Handle_Consume(h, (uint32)h->read_buffer_len); | 403 Seobeo_Handle_Consume(h, (uint32)h->read_buffer_len); |
| 372 } | 404 }else if (n == 0) |
| 373 else if (n == 0) | 405 { |
| 374 { | 406 // Wait |
| 375 // non-blocking mode and no data right now → keep looping or break? | |
| 376 // For a simple blocking client, you could block instead: | |
| 377 continue; | 407 continue; |
| 378 } | 408 }else if (n == -2) |
| 379 else if (n == -2) | 409 { |
| 380 { | 410 // Debug |
| 381 // peer closed; we’ve got everything | 411 // peer closed; we’ve got everything |
| 412 printf("\n\nCLOSED\n\n"); | |
| 382 break; | 413 break; |
| 383 } | 414 }else |
| 384 else | |
| 385 { | 415 { |
| 386 Dowa_Arena_Free(p_request_arena); | 416 Dowa_Arena_Free(p_request_arena); |
| 387 Seobeo_Handle_Destroy(h); | 417 Seobeo_Handle_Destroy(h); |
| 388 return -1; | 418 return -1; |
| 389 } | 419 } |
| 390 } | 420 } |
| 391 | 421 |
| 392 printf("%s\n\n", p_request_body); | 422 printf("%s", p_request_body); |
| 393 Dowa_Arena_Free(p_request_arena); | 423 Dowa_Arena_Free(p_request_arena); |
| 394 Seobeo_Handle_Destroy(h); | 424 Seobeo_Handle_Destroy(h); |
| 395 return 0; | 425 return 0; |
| 396 } | 426 } |