diff seobeo/tests/seobeo_http_framing_test.c @ 221:ce7f4400c2de hg-web

[hg-web] Harden forge and add changeset UI
author MrJuneJune <me@mrjunejune.com>
date Sun, 02 Aug 2026 09:01:24 -0700
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/seobeo/tests/seobeo_http_framing_test.c	Sun Aug 02 09:01:24 2026 -0700
@@ -0,0 +1,79 @@
+#include "seobeo/seobeo.h"
+
+#include <arpa/inet.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+
+typedef struct {
+  int listener;
+} Framing_Server;
+
+static void *serve_close_delimited_response(void *argument)
+{
+  Framing_Server *server = argument;
+  int client = accept(server->listener, NULL, NULL);
+  if (client >= 0) {
+    char request[1024];
+    (void)read(client, request, sizeof(request));
+    const char response[] =
+        "HTTP/1.1 200 OK\r\n"
+        "Content-Type: text/plain\r\n"
+        "Connection: close\r\n"
+        "\r\n"
+        "buffered-body";
+    (void)write(client, response, sizeof(response) - 1);
+    close(client);
+  }
+  return NULL;
+}
+
+int main(void)
+{
+  int listener = socket(AF_INET, SOCK_STREAM, 0);
+  if (listener < 0)
+    return 1;
+
+  struct sockaddr_in address = {
+    .sin_family = AF_INET,
+    .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
+    .sin_port = 0,
+  };
+  if (bind(listener, (struct sockaddr *)&address, sizeof(address)) != 0 ||
+      listen(listener, 1) != 0) {
+    close(listener);
+    return 1;
+  }
+
+  socklen_t address_length = sizeof(address);
+  if (getsockname(listener, (struct sockaddr *)&address, &address_length) != 0) {
+    close(listener);
+    return 1;
+  }
+
+  Framing_Server server = {.listener = listener};
+  pthread_t thread;
+  if (pthread_create(&thread, NULL, serve_close_delimited_response, &server) != 0) {
+    close(listener);
+    return 1;
+  }
+
+  char url[128];
+  snprintf(url, sizeof(url), "http://127.0.0.1:%u/", ntohs(address.sin_port));
+  Seobeo_Client_Request *request = Seobeo_Client_Request_Create(url);
+  Seobeo_Client_Request_Set_Timeout_Milliseconds(request, 1000);
+  Seobeo_Client_Response *response = Seobeo_Client_Request_Execute(request);
+
+  int failed = !response ||
+               response->status_code != 200 ||
+               response->body_length != strlen("buffered-body") ||
+               memcmp(response->body, "buffered-body", strlen("buffered-body")) != 0;
+  if (failed)
+    fprintf(stderr, "Close-delimited response body was not preserved\n");
+
+  Seobeo_Client_Response_Destroy(response);
+  Seobeo_Client_Request_Destroy(request);
+  pthread_join(thread, NULL);
+  close(listener);
+  return failed;
+}