view seobeo/tests/seobeo_http_content_length_test.c @ 235:38bd030ebea4

[resume] Strengthen Microsoft impact and skills
author MrJuneJune <me@mrjunejune.com>
date Sun, 02 Aug 2026 19:26:55 -0700
parents ce7f4400c2de
children
line wrap: on
line source

#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;
}