A compact REST layer for C: an HTTP server built on libmicrohttpd with a flat, verb-indexed service table and fast wildcard URL matching, plus a full HTTP client (blocking, parallel-multi, connection-pooled, TLS). It is the transport layer under the coraine NGSI-LD context broker, but has no NGSI-LD dependency of its own.
- Version: 0.1.0
- Language: C
- License: Apache License 2.0 — Copyright 2026 Seamware
- Service table — register a flat array of
(verb, url, routine)services; the library splits them by HTTP method into per-verb vectors at init. - Fast URL matching — character-sum hashing and pre-computed wildcard offsets
avoid
strcmpon the hot path; supports single (*) and greedy (**) wildcards. - Per-request state — a thread-local request context (
corRest) bound for the duration of a connection. - HTTP client — request builder, JSON bodies, per-request timeouts, response header access.
- Parallel multi-client — fire N requests and harvest them together (used for distributed-operation fan-out).
- Connection pool + TLS — keep-alive pooling per host and an OpenSSL transport.
The umbrella header pulls in the whole API:
#include "corRest/corRest.h"// HTTP method — also the index into the per-verb service vectors (CorRestVerb.h)
typedef enum CorRestVerb {
CorVerbGet = 0, CorVerbPut, CorVerbPost, CorVerbDelete,
CorVerbPatch, CorVerbHead, CorVerbOptions
} CorRestVerb;
// A service routine returns true on success (CorRestService.h)
typedef bool (*CorRestServiceRoutine)(void);
// One service entry, as authored by the embedding app/plugin
typedef struct CorRestServiceSimplified {
CorRestVerb verb;
const char* url; // path pattern, may contain * / **
CorRestServiceRoutine serviceRoutine;
uint64_t supportedParams; // bitmask of accepted URL params
uint64_t ldOp; // atomic-op bit (0 for non-NGSI-LD routes)
CorRestServiceRoutine payloadCheck; // optional body validator (NULL = none)
} CorRestServiceSimplified;
// URL-param name → bitmask bit (for supportedParams)
typedef struct CorRestParam { const char* name; uint64_t bit; } CorRestParam;int corRestInit(CorRestServiceSimplified serviceV[], int services,
unsigned short port, int poolSize);
void corRestStop(void);
void corRestStateInit(struct MHD_Connection* connection, const char* url, const char* method);
void corRestStateRelease(void);corRestInit expands the flat service array into per-verb vectors and starts the
microhttpd listener on port. corRestStateInit / corRestStateRelease manage the
thread-local per-request state.
int corRestClientInit(int maxIdleConns, int idleTimeoutSec, const char* userAgent);
// Request builder
void corRestClientRequestInit(CorRestClientRequest* req, CorRestVerb verb, const char* url, CorAlloc* allocP);
void corRestClientRequestHeader(CorRestClientRequest* req, const char* name, const char* value);
void corRestClientRequestBody(CorRestClientRequest* req, const char* body, int bodyLen);
void corRestClientRequestTimeout(CorRestClientRequest* req, int connectMs, int requestMs);
int corRestClientSend(CorRestClientRequest* req, CorRestClientResponse* resp);
const char* corRestClientResponseHeader(CorRestClientResponse* resp, const char* name);A default per-request timeout is exposed as int corRestClientDefaultRequestTimeoutMs.
A response holds its own copy of what was read: its status text, headers and body
stay valid after the connection has gone back to the pool or been closed. The copy
comes from the request's allocator and lives as long as it; without an allocator it
is malloc'd and released by corRestClientResponseCleanup (corRestClientMultiDestroy
for a response of the multi engine). The body is zero-terminated.
CorRestClientMulti* corRestClientMultiCreate(int capacity);
int corRestClientMultiAdd(CorRestClientMulti* multi, CorRestVerb verb, const char* url, /* … */);
int corRestClientMultiPerform(CorRestClientMulti* multi, int timeoutMs);
CorRestClientResponse* corRestClientMultiResponse(CorRestClientMulti* multi, int index);
void corRestClientMultiDestroy(CorRestClientMulti* multi);A connection pool (corRestClientPool*) and an OpenSSL TLS transport
(corRestClientTls*) sit underneath for keep-alive and https://.
#include "corRest/corRest.h"
static bool pingGet(void)
{
// … build the response via the CorRestOut API …
return true;
}
static CorRestServiceSimplified services[] =
{
{ CorVerbGet, "/ping", pingGet, 0, 0, NULL },
{ CorVerbGet, "/things/*", thingGet, 0, 0, NULL }, // single-wildcard
};
int main(void)
{
if (corRestInit(services, sizeof(services)/sizeof(services[0]), 1026, 16) != 0)
return 1;
// … serve until shutdown …
corRestStop();
return 0;
}make # build libcorRest.a (+ .so) and the test binary
make ci # clean + install
make di # debug + install
make clientLifetimeTest # the lifetime of a client response, under AddressSanitizerlibcorRest.a links statically into its consumers. Sibling repos must be
present (the build references ../<lib>/lib<lib>.a).
Sibling repos (one .a each):
corAlloc— arena allocator (CorAlloc)corTree— the tree (CorNode)corJson— JSON parsing and renderingcorBase— core utilities and the library log (COR_LIB_*)corLog— logging and trace levels
System libraries: libmicrohttpd (HTTP server), openssl (ssl/crypto, TLS
client), pthread, m.