Mercurial
diff seobeo/tests/seobeo_http_timeout_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_timeout_test.c Sun Aug 02 09:01:24 2026 -0700 @@ -0,0 +1,82 @@ +#include "seobeo/seobeo.h" + +#include <arpa/inet.h> +#include <pthread.h> +#include <stdio.h> +#include <string.h> +#include <time.h> + +typedef struct { + int listener; +} Timeout_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_stalled_response(void *argument) +{ + Timeout_Server *server = argument; + int client = accept(server->listener, NULL, NULL); + if (client >= 0) { + char request[1024]; + (void)read(client, request, sizeof(request)); + usleep(250000); + 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; + } + + Timeout_Server server = {.listener = listener}; + pthread_t thread; + if (pthread_create(&thread, NULL, serve_stalled_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, 50); + + int64_t started = monotonic_milliseconds(); + Seobeo_Client_Response *response = Seobeo_Client_Request_Execute(request); + int64_t elapsed = monotonic_milliseconds() - started; + + int failed = response != NULL || elapsed < 40 || elapsed > 2000; + if (failed) + fprintf(stderr, "Expected a bounded timeout; response=%p elapsed=%lldms\n", + (void *)response, (long long)elapsed); + + Seobeo_Client_Response_Destroy(response); + Seobeo_Client_Request_Destroy(request); + pthread_join(thread, NULL); + close(listener); + return failed; +}