Mercurial
diff seobeo/s_web.c @ 226:3fa4bf481f42
[merge] Merge hg-web into default
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Sun, 02 Aug 2026 14:42:01 -0700 |
| parents | 0e7b9464248d |
| children | 543df0fe7168 |
line wrap: on
line diff
--- a/seobeo/s_web.c Sun Aug 02 08:52:13 2026 -0700 +++ b/seobeo/s_web.c Sun Aug 02 14:42:01 2026 -0700 @@ -51,6 +51,7 @@ { case HTTP_OK: status_text = "OK"; break; case HTTP_CREATED: status_text = "Created"; break; + case HTTP_NO_CONTENT: status_text = "No Content"; break; case HTTP_MOVED_PERMANENTLY: status_text = "Moved Permanently"; break; case HTTP_FOUND: status_text = "Found"; break; case HTTP_BAD_REQUEST: status_text = "Bad Request"; break; @@ -58,11 +59,13 @@ case HTTP_FORBIDDEN: status_text = "Forbidden"; break; case HTTP_NOT_FOUND: status_text = "Not Found"; break; case HTTP_INTERNAL_ERROR: status_text = "Internal Server Error"; break; + case 502: status_text = "Bad Gateway"; break; + case 504: status_text = "Gateway Timeout"; break; default: status_text = "Unknown"; break; } - sprintf( - buffer, + snprintf( + (char*)buffer, 1024, "HTTP/1.1 %d %s\r\n" "Content-Type: %s\r\n" "Content-Length: %d\r\n" @@ -774,6 +777,11 @@ Seobeo_Router_Send_Response_KeepAlive(p_handle, p_response_map, p_arena, FALSE); } +static boolean Seobeo_Response_Header_Value_Is_Safe(const char *value) +{ + return value && strchr(value, '\r') == NULL && strchr(value, '\n') == NULL; +} + void Seobeo_Router_Send_Response_KeepAlive( Seobeo_Handle *p_handle, Seobeo_Request_Entry *p_response_map, @@ -819,26 +827,63 @@ else body_length = strlen(body); - char *header = Dowa_Arena_Allocate(p_arena, 4096); - Seobeo_Web_Header_Generate_KeepAlive(header, status, content_type, body_length, keep_alive); + size_t header_capacity = 1024; for (int i = 0; i < Dowa_Array_Length(p_response_map); i++) { + const char *key = p_response_map[i].key; + const char *value = p_response_map[i].value; if ( - strstr(p_response_map[i].key, "status") || - strstr(p_response_map[i].key, "body") || - strstr(p_response_map[i].key, "content-type") || - strstr(p_response_map[i].key, "content-length") + strcasecmp(key, "status") == 0 || + strcasecmp(key, "body") == 0 || + strcasecmp(key, "content-type") == 0 || + strcasecmp(key, "content-length") == 0 + ) + continue; + if (Seobeo_Response_Header_Value_Is_Safe(key) && + Seobeo_Response_Header_Value_Is_Safe(value)) + header_capacity += strlen(key) + strlen(value) + 4; + } + + char *header = Dowa_Arena_Allocate(p_arena, header_capacity); + Seobeo_Web_Header_Generate_KeepAlive(header, status, content_type, body_length, keep_alive); + size_t header_length = strlen(header); + if (header_length < 2) + return; + header_length -= 2; + + for (int i = 0; i < Dowa_Array_Length(p_response_map); i++) + { + const char *key = p_response_map[i].key; + const char *value = p_response_map[i].value; + if ( + strcasecmp(key, "status") == 0 || + strcasecmp(key, "body") == 0 || + strcasecmp(key, "content-type") == 0 || + strcasecmp(key, "content-length") == 0 ) continue; - int32 current_header_len = strlen(header); - char *temp = malloc(sizeof(char) * 1024); - sprintf(temp, "%s: %s\r\n\r\n", p_response_map[i].key, p_response_map[i].value); - memcpy(&header[current_header_len - 2 /* \r\n */], temp, strlen(temp)); - free(temp); + if (!Seobeo_Response_Header_Value_Is_Safe(key) || + !Seobeo_Response_Header_Value_Is_Safe(value)) + { + Seobeo_Log(SEOBEO_WARNING, "Skipping unsafe response header\n"); + continue; + } + + int written = snprintf( + header + header_length, + header_capacity - header_length, + "%s: %s\r\n", + key, + value); + if (written < 0 || (size_t)written >= header_capacity - header_length) + { + Seobeo_Log(SEOBEO_ERROR, "Response header exceeded allocated capacity\n"); + return; + } + header_length += (size_t)written; } - - printf("hEADER %s\n", header); + memcpy(header + header_length, "\r\n", 3); Seobeo_Handle_Queue(p_handle, (uint8_t*)header, strlen(header)); Seobeo_Handle_Queue(p_handle, (uint8_t*)body, body_length);