HTTP client and networking library for C.
Features
- HTTP/HTTPS client
- SSL/TLS support
- Async networking with libuv
- Joinable/detached tasks and bounded worker pools
- Server-Sent Events routes and event framing
- Snapshot testing utilities
Files
| File | Description |
|---|---|
seobeo.h |
Public API header |
seobeo_internal.h |
Internal declarations |
s_http_client.c |
HTTP client implementation |
s_network.c |
Network utilities |
s_sse.c |
Server-Sent Events framing and stream lifecycle |
s_ssl.c |
SSL/TLS handling |
s_logging.c |
Logging utilities |
s_worker.c |
Thread and worker-pool implementation |
seobeo_worker.h |
Public worker API |
snapshot_creator.c/h |
Snapshot testing |
docs/ |
Documentation |
examples/ |
Usage examples |
tests/ |
Unit tests |
os/ |
OS-specific code |
Usage
#include "seobeo/seobeo.h"
// Make HTTP request
HttpResponse* resp = http_get("https://example.com");
// handle response...
http_response_free(resp);
Building
bazel build //seobeo:seobeo
bazel test //seobeo:seobeo_test
Background workers
Use a detached task for simple fire-and-forget work:
void Convert_Image(void *p_context)
{
Conversion *p_conversion = p_context;
Run_FFmpeg(p_conversion);
}
Seobeo_Worker_Result result =
Seobeo_Thread_Start_Detached(
Convert_Image,
p_conversion,
free);
if (result != SEOBEO_WORKER_OK)
free(p_conversion);
Use a bounded pool when requests can enqueue expensive work:
Seobeo_Worker_Pool *p_pool =
Seobeo_Worker_Pool_Create(2, 16);
Seobeo_Worker_Result result =
Seobeo_Worker_Pool_Submit(
p_pool,
Convert_Image,
p_conversion,
free);
Seobeo_Worker_Pool_Shutdown(p_pool, TRUE);
Seobeo_Worker_Pool_Destroy(p_pool);
Submitting transfers context ownership only when it returns
SEOBEO_WORKER_OK. Cleanup runs after successful work and for queued tasks
discarded by a non-draining shutdown. User callbacks never run while the pool
mutex is held.
Server-Sent Events
Register an SSE route separately from ordinary response and stream handlers:
static void Build_Events(
Seobeo_SSE_Stream *p_stream,
Seobeo_Request_Entry *p_request,
Dowa_Arena *p_arena)
{
(void)p_request;
(void)p_arena;
Seobeo_SSE_Event event = {
.event = "build",
.id = "42",
.data = "started\ncompiling",
.retry_ms = 2000,
};
Seobeo_SSE_Send(p_stream, &event);
Seobeo_SSE_Send_Comment(p_stream, "heartbeat");
}
Seobeo_Router_Register_SSE("/events/builds", Build_Events);
SSE handlers run once when a client connects and must return promptly so edge
workers remain available. Call Seobeo_SSE_Retain before storing a stream for
later work and pair it with Seobeo_SSE_Release; use
Seobeo_SSE_Is_Open before sending. Do not retain the request map or arena
after the handler returns. A return value of 1 means the record was retained
behind socket backpressure and Seobeo_SSE_Flush should be retried later.
SEOBEO_SSE_BACKPRESSURE means the bounded pending queue is full and the new
record was not accepted. Events are bounded by the handle write-buffer
capacity so one record is queued atomically; larger records return
SEOBEO_SSE_EVENT_TOO_LARGE.
Dependencies
- libuv (via //third_party/libuv)
- OpenSSL