diff seobeo/s_web.c @ 231:09a96dcb2b4c hg-web

[merge] Join existing hg-web branch head
author MrJuneJune <me@mrjunejune.com>
date Sun, 02 Aug 2026 16:50:48 -0700
parents 0e7b9464248d
children 543df0fe7168
line wrap: on
line diff
--- a/seobeo/s_web.c	Sun Jan 25 10:44:04 2026 -0800
+++ b/seobeo/s_web.c	Sun Aug 02 16:50:48 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);