Mercurial
diff seobeo/tests/seobeo_http_content_length_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_content_length_test.c Sun Aug 02 09:01:24 2026 -0700 @@ -0,0 +1,91 @@ +#include "seobeo/seobeo.h" + +#include <arpa/inet.h> +#include <pthread.h> +#include <stdio.h> +#include <string.h> +#include <time.h> + +typedef struct { + int listener; +} Content_Length_Server; + +static int64_t monotonic_milliseconds(void) +{ + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + return (int64_t)now.tv_sec * 1000 + now.tv_nsec / 1000000; +} + +static void *serve_lowercase_content_length(void *argument) +{ + Content_Length_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-length: 4\r\n" + "Connection: keep-alive\r\n" + "\r\n" + "done"; + (void)write(client, response, sizeof(response) - 1); + usleep(500000); + 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; + } + + Content_Length_Server server = {.listener = listener}; + pthread_t thread; + if (pthread_create(&thread, NULL, serve_lowercase_content_length, &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); + int64_t started = monotonic_milliseconds(); + Seobeo_Client_Response *response = Seobeo_Client_Request_Execute(request); + int64_t elapsed = monotonic_milliseconds() - started; + + int failed = !response || + response->body_length != 4 || + memcmp(response->body, "done", 4) != 0 || + elapsed > 300; + if (failed) + fprintf(stderr, "Case-insensitive Content-Length was not honored (%lldms)\n", + (long long)elapsed); + + Seobeo_Client_Response_Destroy(response); + Seobeo_Client_Request_Destroy(request); + pthread_join(thread, NULL); + close(listener); + return failed; +}