Mercurial
comparison seobeo/tests/seobeo_http_content_length_test.c @ 226:3fa4bf481f42
[merge] Merge hg-web into default
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Sun, 02 Aug 2026 14:42:01 -0700 |
| parents | ce7f4400c2de |
| children |
comparison
equal
deleted
inserted
replaced
| 220:eb8b4230fdb9 | 226:3fa4bf481f42 |
|---|---|
| 1 #include "seobeo/seobeo.h" | |
| 2 | |
| 3 #include <arpa/inet.h> | |
| 4 #include <pthread.h> | |
| 5 #include <stdio.h> | |
| 6 #include <string.h> | |
| 7 #include <time.h> | |
| 8 | |
| 9 typedef struct { | |
| 10 int listener; | |
| 11 } Content_Length_Server; | |
| 12 | |
| 13 static int64_t monotonic_milliseconds(void) | |
| 14 { | |
| 15 struct timespec now; | |
| 16 clock_gettime(CLOCK_MONOTONIC, &now); | |
| 17 return (int64_t)now.tv_sec * 1000 + now.tv_nsec / 1000000; | |
| 18 } | |
| 19 | |
| 20 static void *serve_lowercase_content_length(void *argument) | |
| 21 { | |
| 22 Content_Length_Server *server = argument; | |
| 23 int client = accept(server->listener, NULL, NULL); | |
| 24 if (client >= 0) { | |
| 25 char request[1024]; | |
| 26 (void)read(client, request, sizeof(request)); | |
| 27 const char response[] = | |
| 28 "HTTP/1.1 200 OK\r\n" | |
| 29 "content-length: 4\r\n" | |
| 30 "Connection: keep-alive\r\n" | |
| 31 "\r\n" | |
| 32 "done"; | |
| 33 (void)write(client, response, sizeof(response) - 1); | |
| 34 usleep(500000); | |
| 35 close(client); | |
| 36 } | |
| 37 return NULL; | |
| 38 } | |
| 39 | |
| 40 int main(void) | |
| 41 { | |
| 42 int listener = socket(AF_INET, SOCK_STREAM, 0); | |
| 43 if (listener < 0) | |
| 44 return 1; | |
| 45 | |
| 46 struct sockaddr_in address = { | |
| 47 .sin_family = AF_INET, | |
| 48 .sin_addr.s_addr = htonl(INADDR_LOOPBACK), | |
| 49 .sin_port = 0, | |
| 50 }; | |
| 51 if (bind(listener, (struct sockaddr *)&address, sizeof(address)) != 0 || | |
| 52 listen(listener, 1) != 0) { | |
| 53 close(listener); | |
| 54 return 1; | |
| 55 } | |
| 56 | |
| 57 socklen_t address_length = sizeof(address); | |
| 58 if (getsockname(listener, (struct sockaddr *)&address, &address_length) != 0) { | |
| 59 close(listener); | |
| 60 return 1; | |
| 61 } | |
| 62 | |
| 63 Content_Length_Server server = {.listener = listener}; | |
| 64 pthread_t thread; | |
| 65 if (pthread_create(&thread, NULL, serve_lowercase_content_length, &server) != 0) { | |
| 66 close(listener); | |
| 67 return 1; | |
| 68 } | |
| 69 | |
| 70 char url[128]; | |
| 71 snprintf(url, sizeof(url), "http://127.0.0.1:%u/", ntohs(address.sin_port)); | |
| 72 Seobeo_Client_Request *request = Seobeo_Client_Request_Create(url); | |
| 73 Seobeo_Client_Request_Set_Timeout_Milliseconds(request, 1000); | |
| 74 int64_t started = monotonic_milliseconds(); | |
| 75 Seobeo_Client_Response *response = Seobeo_Client_Request_Execute(request); | |
| 76 int64_t elapsed = monotonic_milliseconds() - started; | |
| 77 | |
| 78 int failed = !response || | |
| 79 response->body_length != 4 || | |
| 80 memcmp(response->body, "done", 4) != 0 || | |
| 81 elapsed > 300; | |
| 82 if (failed) | |
| 83 fprintf(stderr, "Case-insensitive Content-Length was not honored (%lldms)\n", | |
| 84 (long long)elapsed); | |
| 85 | |
| 86 Seobeo_Client_Response_Destroy(response); | |
| 87 Seobeo_Client_Request_Destroy(request); | |
| 88 pthread_join(thread, NULL); | |
| 89 close(listener); | |
| 90 return failed; | |
| 91 } |