Mercurial
comparison seobeo/s_web.c @ 92:655ea0b661fd
[Seobeo] Added few endpoints for handling files. [Dowa] Added few functions for random number and generating uuids
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Fri, 02 Jan 2026 17:47:10 -0800 |
| parents | 19cccf6e866a |
| children | 70401cf61e97 |
comparison
equal
deleted
inserted
replaced
| 91:19cccf6e866a | 92:655ea0b661fd |
|---|---|
| 102 void *p_response_header = Dowa_Arena_Allocate(p_response_arena, (size_t)1024*5); // 5Kb | 102 void *p_response_header = Dowa_Arena_Allocate(p_response_arena, (size_t)1024*5); // 5Kb |
| 103 if (!p_response_header) { perror("Dowa_Arena_Allocate"); goto clean_up; } | 103 if (!p_response_header) { perror("Dowa_Arena_Allocate"); goto clean_up; } |
| 104 | 104 |
| 105 // Parse request headers into hashmap using arena | 105 // Parse request headers into hashmap using arena |
| 106 Seobeo_Request_Entry *p_req_map = NULL; | 106 Seobeo_Request_Entry *p_req_map = NULL; |
| 107 if (Seobeo_Web_Header_Parse(p_cli_handle, &p_req_map, p_request_arena) != 0) | 107 int parse_result = Seobeo_Web_Header_Parse(p_cli_handle, &p_req_map, p_request_arena); |
| 108 { | 108 |
| 109 // Treat EAGAIN (return code 1) as success - headers were parsed, body may still be coming | |
| 110 if (parse_result != 0 && parse_result != 1) | |
| 111 { | |
| 112 printf("ERROR: Seobeo_Web_Header_Parse failed with code %d\n", parse_result); | |
| 113 fflush(stdout); | |
| 109 Seobeo_Web_Header_Generate(p_response_header, | 114 Seobeo_Web_Header_Generate(p_response_header, |
| 110 HTTP_BAD_REQUEST, | 115 HTTP_BAD_REQUEST, |
| 111 "text/plain", 0); | 116 "text/plain", 0); |
| 112 Seobeo_Handle_Queue(p_cli_handle, | 117 Seobeo_Handle_Queue(p_cli_handle, |
| 113 (const uint8*)p_response_header, | 118 (const uint8*)p_response_header, |
| 114 (uint32)strlen(p_response_header)); | 119 (uint32)strlen(p_response_header)); |
| 115 Seobeo_Handle_Flush(p_cli_handle); | 120 Seobeo_Handle_Flush(p_cli_handle); |
| 116 goto clean_up; | 121 goto clean_up; |
| 117 } | 122 } |
| 118 | 123 |
| 124 printf("DEBUG: Parse completed with code %d\n", parse_result); | |
| 125 fflush(stdout); | |
| 126 | |
| 119 // Extract method (GET, POST, etc.) | 127 // Extract method (GET, POST, etc.) |
| 120 void *p_method_kv = Dowa_HashMap_Get_Ptr(p_req_map, "HTTP_Method"); | 128 void *p_method_kv = Dowa_HashMap_Get_Ptr(p_req_map, "HTTP_Method"); |
| 121 const char *method = p_method_kv ? ((Seobeo_Request_Entry*)p_method_kv)->value : NULL; | 129 const char *method = p_method_kv ? ((Seobeo_Request_Entry*)p_method_kv)->value : NULL; |
| 122 | 130 |
| 131 printf("DEBUG: Parsed request, method=%s\n", method ? method : "NULL"); | |
| 132 fflush(stdout); | |
| 133 | |
| 123 if (!method) | 134 if (!method) |
| 124 { | 135 { |
| 136 printf("ERROR: No HTTP method found in request\n"); | |
| 137 fflush(stdout); | |
| 125 Seobeo_Web_Header_Generate(p_response_header, | 138 Seobeo_Web_Header_Generate(p_response_header, |
| 126 HTTP_BAD_REQUEST, | 139 HTTP_BAD_REQUEST, |
| 127 "text/plain", 0); | 140 "text/plain", 0); |
| 128 Seobeo_Handle_Queue(p_cli_handle, | 141 Seobeo_Handle_Queue(p_cli_handle, |
| 129 (const uint8*)p_response_header, | 142 (const uint8*)p_response_header, |
| 275 // 2) Parse request‐line "METHOD SP PATH SP VERSION CRLF" | 288 // 2) Parse request‐line "METHOD SP PATH SP VERSION CRLF" |
| 276 char *buf = (char*)p_handle->read_buffer; | 289 char *buf = (char*)p_handle->read_buffer; |
| 277 char *hdr_end = strstr(buf, "\r\n\r\n"); | 290 char *hdr_end = strstr(buf, "\r\n\r\n"); |
| 278 size_t hdr_len = hdr_end - buf + 4; | 291 size_t hdr_len = hdr_end - buf + 4; |
| 279 | 292 |
| 293 // Debug: Print the first line of the request | |
| 294 char *first_line_end = strstr(buf, "\r\n"); | |
| 295 if (first_line_end) | |
| 296 { | |
| 297 size_t first_line_len = first_line_end - buf; | |
| 298 printf("DEBUG: Request line (first %zu bytes): '", first_line_len > 200 ? 200 : first_line_len); | |
| 299 fwrite(buf, 1, first_line_len > 200 ? 200 : first_line_len, stdout); | |
| 300 printf("'\n"); | |
| 301 fflush(stdout); | |
| 302 } | |
| 303 | |
| 280 // This seems kinda bad ? | 304 // This seems kinda bad ? |
| 281 char method[16], path[256], version[16]; | 305 char method[16], path[256], version[16]; |
| 282 if (sscanf(buf, "%15s %255s %15s", method, path, version) != 3) | 306 int scan_result = sscanf(buf, "%15s %255s %15s", method, path, version); |
| 283 { | 307 printf("DEBUG: sscanf returned %d (method='%s', path='%s', version='%s')\n", |
| 308 scan_result, | |
| 309 scan_result >= 1 ? method : "N/A", | |
| 310 scan_result >= 2 ? path : "N/A", | |
| 311 scan_result >= 3 ? version : "N/A"); | |
| 312 fflush(stdout); | |
| 313 | |
| 314 if (scan_result != 3) | |
| 315 { | |
| 316 printf("ERROR: Failed to parse request line\n"); | |
| 317 fflush(stdout); | |
| 284 return -1; | 318 return -1; |
| 285 } | 319 } |
| 286 | 320 |
| 287 // Copy strings to arena and store in hashmap | 321 // Copy strings to arena and store in hashmap |
| 322 printf("DEBUG: Allocating method_copy\n"); | |
| 323 fflush(stdout); | |
| 288 char *method_copy = Dowa_Arena_Allocate(p_arena, strlen(method) + 1); | 324 char *method_copy = Dowa_Arena_Allocate(p_arena, strlen(method) + 1); |
| 289 if (!method_copy) return -1; | 325 if (!method_copy) { printf("ERROR: Failed to allocate method_copy\n"); return -1; } |
| 290 strcpy(method_copy, method); | 326 strcpy(method_copy, method); |
| 291 | 327 |
| 328 printf("DEBUG: Allocating version_copy\n"); | |
| 329 fflush(stdout); | |
| 292 char *version_copy = Dowa_Arena_Allocate(p_arena, strlen(version) + 1); | 330 char *version_copy = Dowa_Arena_Allocate(p_arena, strlen(version) + 1); |
| 293 if (!version_copy) return -1; | 331 if (!version_copy) { printf("ERROR: Failed to allocate version_copy\n"); return -1; } |
| 294 strcpy(version_copy, version); | 332 strcpy(version_copy, version); |
| 295 | 333 |
| 334 printf("DEBUG: Pushing HTTP_Method and Version to map\n"); | |
| 335 fflush(stdout); | |
| 296 Dowa_HashMap_Push_Arena(*pp_map, "HTTP_Method", method_copy, p_arena); | 336 Dowa_HashMap_Push_Arena(*pp_map, "HTTP_Method", method_copy, p_arena); |
| 297 Dowa_HashMap_Push_Arena(*pp_map, "Version", version_copy, p_arena); | 337 Dowa_HashMap_Push_Arena(*pp_map, "Version", version_copy, p_arena); |
| 338 printf("DEBUG: Map now has %zu entries\n", Dowa_Array_Length(*pp_map)); | |
| 339 fflush(stdout); | |
| 298 | 340 |
| 299 // 1) Separate raw path and query string | 341 // 1) Separate raw path and query string |
| 300 char *raw_path = path; | 342 char *raw_path = path; |
| 301 char *query_start = strchr(raw_path, '?'); | 343 char *query_start = strchr(raw_path, '?'); |
| 302 char *query_str = NULL; | 344 char *query_str = NULL; |
| 392 void *p_cl_kv = Dowa_HashMap_Get_Ptr(*pp_map, "Content-Length"); | 434 void *p_cl_kv = Dowa_HashMap_Get_Ptr(*pp_map, "Content-Length"); |
| 393 if (p_cl_kv) | 435 if (p_cl_kv) |
| 394 { | 436 { |
| 395 const char *content_length_str = ((Seobeo_Request_Entry*)p_cl_kv)->value; | 437 const char *content_length_str = ((Seobeo_Request_Entry*)p_cl_kv)->value; |
| 396 size_t body_len = atoi(content_length_str); | 438 size_t body_len = atoi(content_length_str); |
| 397 while (p_handle->read_buffer_len < body_len) | 439 |
| 398 { | 440 printf("DEBUG: Content-Length=%zu, reading body in chunks...\n", body_len); |
| 399 int r = Seobeo_Handle_Read(p_handle); | 441 fflush(stdout); |
| 400 if (r < 0) return -1; | 442 |
| 401 if (r == 0) return 1; // wait for more data | 443 // Allocate buffer for entire body |
| 402 } | |
| 403 | |
| 404 char *body = Dowa_Arena_Allocate(p_arena, body_len + 1); | 444 char *body = Dowa_Arena_Allocate(p_arena, body_len + 1); |
| 405 if (!body) return -1; | 445 if (!body) |
| 406 memcpy(body, p_handle->read_buffer, body_len); | 446 { |
| 447 printf("ERROR: Failed to allocate %zu bytes for body\n", body_len); | |
| 448 fflush(stdout); | |
| 449 return -1; | |
| 450 } | |
| 451 | |
| 452 size_t total_read = 0; | |
| 453 | |
| 454 // Read body in chunks | |
| 455 while (total_read < body_len) | |
| 456 { | |
| 457 // Copy what's currently in the read buffer | |
| 458 size_t available = p_handle->read_buffer_len; | |
| 459 size_t to_copy = (body_len - total_read) < available ? (body_len - total_read) : available; | |
| 460 | |
| 461 if (to_copy > 0) | |
| 462 { | |
| 463 memcpy(body + total_read, p_handle->read_buffer, to_copy); | |
| 464 total_read += to_copy; | |
| 465 Seobeo_Handle_Consume(p_handle, (uint32)to_copy); | |
| 466 | |
| 467 printf("DEBUG: Copied %zu bytes, total %zu/%zu\n", to_copy, total_read, body_len); | |
| 468 fflush(stdout); | |
| 469 } | |
| 470 | |
| 471 // If we still need more data, read another chunk | |
| 472 if (total_read < body_len) | |
| 473 { | |
| 474 int r = Seobeo_Handle_Read(p_handle); | |
| 475 if (r < 0) | |
| 476 { | |
| 477 printf("ERROR: Read failed with %d\n", r); | |
| 478 fflush(stdout); | |
| 479 return -1; | |
| 480 } | |
| 481 if (r == 0) | |
| 482 { | |
| 483 // No data available yet, continue waiting | |
| 484 // printf("DEBUG: Waiting for more data... (have %zu/%zu bytes)\n", total_read, body_len); | |
| 485 fflush(stdout); | |
| 486 continue; | |
| 487 } | |
| 488 } | |
| 489 } | |
| 490 | |
| 407 body[body_len] = '\0'; | 491 body[body_len] = '\0'; |
| 492 printf("DEBUG: Body fully received (%zu bytes)\n", body_len); | |
| 493 fflush(stdout); | |
| 408 | 494 |
| 409 // Body is arena-allocated | 495 // Body is arena-allocated |
| 410 Dowa_HashMap_Push_Arena(*pp_map, "Body", body, p_arena); | 496 Dowa_HashMap_Push_Arena(*pp_map, "Body", body, p_arena); |
| 411 | |
| 412 Seobeo_Handle_Consume(p_handle, (uint32)body_len); | |
| 413 } | 497 } |
| 414 | 498 |
| 415 return 0; // success; map now holds Method, Path, Version, headers, and optional Body | 499 return 0; // success; map now holds Method, Path, Version, headers, and optional Body |
| 416 } | 500 } |
| 417 | 501 |