Mercurial
view seobeo/tests/seobeo_http_framing_test.c @ 281:c57149ad216e default tip
Copilot-Session: f68442b1-fa8f-46a0-9689-81710613bbd4
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Tue, 18 Aug 2026 22:18:15 -0700 |
| parents | b3b547563ec7 |
| children |
line wrap: on
line source
#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; for (int response_index = 0; response_index < 2; response_index++) { int client = accept(server->listener, NULL, NULL); if (client < 0) continue; char request[1024]; (void)read(client, request, sizeof(request)); if (response_index == 0) { 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); } else { const char response[] = "HTTP/1.1 200 OK\r\n" "Content-Type: application/json\r\n" "Transfer-Encoding: chunked\r\n" "Connection: close\r\n" "\r\n" "7;sample=yes\r\n" "{\"ok\":t\r\n" "4\r\n" "rue}\r\n" "0\r\n" "X-Trailer: ignored\r\n" "\r\n"; (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/close", 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); snprintf( url, sizeof(url), "http://127.0.0.1:%u/chunked", ntohs(address.sin_port)); request = Seobeo_Client_Request_Create(url); Seobeo_Client_Request_Set_Timeout_Milliseconds(request, 1000); response = Seobeo_Client_Request_Execute(request); int chunked_failed = !response || response->status_code != 200 || response->body_length != strlen("{\"ok\":true}") || memcmp(response->body, "{\"ok\":true}", strlen("{\"ok\":true}")) != 0; if (chunked_failed) fprintf(stderr, "Chunked response body was not decoded\n"); failed = failed || chunked_failed; Seobeo_Client_Response_Destroy(response); Seobeo_Client_Request_Destroy(request); pthread_join(thread, NULL); close(listener); return failed; }