Repository navigation
Application
Header: <cwist/app.h> (wraps <cwist/sys/app/app.h>)
A cwist_app owns everything a server needs: the route table, the middleware
chain, protocol settings (TLS, HTTP/2, HTTP/3, WebTransport), attached
services (database, pools, scheduler, gRPC routes, assets) and caches. A
program usually creates one app, configures it, calls cwist_app_listen(),
and destroys it after the server stops.
#include <cwist/app.h>
int main(void) {
cwist_app *app = cwist_app_create();
if (!app) return 1;
cwist_app_use_db(app, "app.db");
cwist_app_enable_metrics(app);
cwist_app_enable_healthz(app);
cwist_app_get(app, "/", index_handler);
int rc = cwist_app_listen(app, 8080); /* blocks */
cwist_app_destroy(app);
return rc == 0 ? 0 : 1;
}| Function | Description |
|---|---|
cwist_app *cwist_app_create(void) |
Allocate an app with default settings. Returns NULL on allocation failure. |
void cwist_app_destroy(cwist_app *app) |
Free the app and everything it owns: routes (running route-context destructors), middleware contexts, pools, the scheduler, caches. |
int cwist_app_listen(cwist_app *app, int port) |
Serve until SIGTERM, SIGINT or cwist_shutdown_request(). Same as cwist_app_listen_ex(app, port, 0, -1). |
int cwist_app_listen_ex(cwist_app *app, int port, int workers_override, int c1m_override) |
workers_override > 0 sets the worker process count (1 = no fork); c1m_override is 1 reactor, 0 classic pool, negative reads CWIST_C1M_MODE. Returns 0 after a graceful shutdown, -1 if the server could not start. |
void cwist_apply_profile(void) |
Apply CWIST_PROFILE defaults to the environment; called by cwist_app_listen(). |
void cwist_app_set_max_memspace(cwist_app *app, size_t size) |
Capacity of the static-file memory pool (default: twice the size of the files found). Use CWIST_MIB(64) and friends from <cwist/core/macros.h>. |
cwist_app_listen() forks worker processes (one per core unless
CWIST_WORKERS says otherwise), raises the open-file limit, binds TCP (and
UDP for HTTP/3) with SO_REUSEPORT, installs SIGTERM/SIGINT handlers for the
duration of the call, and drains connections on shutdown. With more than one
worker it returns in each worker process. See Server Modes and
Graceful Shutdown.
Routes are covered in Routing. Summary:
cwist_app_get(app, "/users/:id", get_user); /* plain handler */
cwist_app_post_ex(app, "/items", create_item, ctx, cwist_free); /* handler with context */
cwist_app_get_opt(app, "/download/:id", download, CWIST_ENDPOINT_FILE);
cwist_app_get_named(app, "/posts/:id", "post", show_post); /* for cwist_url_for() */
cwist_app_ws(app, "/chat", chat_handler); /* blocking WebSocket */
cwist_app_ws_async(app, "/live", on_message, NULL); /* reactor WebSocket */
cwist_app_static(app, "/static", "./public");cwist_app_use(app, cwist_mw_access_log(CWIST_LOG_JSON));
cwist_app_use_ex(app, NULL, my_mw_ex, ctx, ctx_destroy);See Middleware.
| Function | Description |
|---|---|
cwist_error_t cwist_app_use_https(cwist_app *app, const char *cert_path, const char *key_path) |
Serve TLS with the given PEM certificate and key. TLS 1.3+ only. |
void cwist_app_use_pqc_layer(cwist_app *app, bool enabled) |
Force the hybrid post-quantum group list X25519MLKEM768:X25519:P-256 and TLS 1.3 minimum. |
void cwist_app_set_tls_groups(cwist_app *app, const char *groups) |
Explicit colon-separated TLS group list; NULL restores automatic selection. |
cwist_error_t cwist_app_use_https2(cwist_app *app, bool enabled) |
Negotiate HTTP/2 (h2) over TLS through ALPN. |
cwist_error_t cwist_app_use_http2(cwist_app *app, bool enabled) |
Accept cleartext HTTP/2 (h2c, prior knowledge) on the plain TCP port. |
cwist_error_t cwist_app_use_https3(cwist_app *app, bool enabled) |
Serve HTTP/3 over QUIC with the HTTPS certificate, on UDP at the same port number. |
cwist_error_t cwist_app_use_http3(cwist_app *app, bool enabled) |
Serve HTTP/3 with an ephemeral self-signed certificate (no TLS setup; for development and tests). |
void cwist_app_use_webtransport(cwist_app *app, cwist_webtransport_handler_func handler) |
Accept WebTransport sessions; also needs HTTP/3 enabled. |
cwist_error_t cwist_app_use_ech(cwist_app *app, const char *ech_key, const char *ech_dir) |
Declared in <cwist/security/tls/ech.h>. With the bundled BoringSSL this is currently a no-op that returns success; the key and directory arguments are not used yet. |
Convenience macros cwist_use_https2(enabled), cwist_use_https3(enabled),
cwist_use_http2(enabled) and cwist_use_http3(enabled) call the functions
above on a variable named app.
Details: HTTPS and TLS, HTTP/2, HTTP/3 and QUIC, WebTransport.
| Function | Description |
|---|---|
cwist_error_t cwist_app_use_db(cwist_app *app, const char *db_path) |
Open a SQLite database and expose it to every request as req->db. |
cwist_error_t cwist_app_use_nuke_db(cwist_app *app, const char *db_path, int sync_interval_ms) |
Use Nuke DB (in-memory reads, synced to disk) as the app database. |
cwist_db *cwist_app_get_db(cwist_app *app) |
The app database handle. |
cwist_error_t cwist_app_use_db_pool(cwist_app *app, const char *db_path, size_t max_conns) |
Attach a SQLite connection pool. |
cwist_db_pool_t *cwist_app_get_db_pool(cwist_app *app) |
The pool, or NULL. |
cwist_error_t cwist_app_use_redis(cwist_app *app, const char *host, int port, size_t max_conns) |
Attach a Redis connection pool. |
cwist_redis_pool_t *cwist_app_get_redis_pool(cwist_app *app) |
The Redis pool, or NULL. |
cwist_error_t cwist_app_use_scheduler(cwist_app *app, size_t worker_count, size_t queue_capacity) |
Attach a background job scheduler. |
cwist_scheduler_t *cwist_app_get_scheduler(cwist_app *app) |
The scheduler, or NULL. |
bool cwist_app_auto_rdbms(cwist_app *app, int port) |
Probe 127.0.0.1:port for PostgreSQL, MySQL or MariaDB by wire protocol and record the result in app->rdbms. |
void cwist_app_enable_metrics(cwist_app *app) |
Add GET /metrics (Prometheus text format). |
void cwist_app_enable_healthz(cwist_app *app) |
Add GET /healthz, /live and /ready. |
void cwist_app_enable_swagger(cwist_app *app, const char *mount_path, const char *openapi_json_path) |
Serve Swagger UI at mount_path for the given openapi.json. |
int cwist_app_use_session(cwist_app *app, const char *secret) |
Enable signed cookie sessions; see Sessions and Flash. |
Pages: Database, Redis, Scheduler, Metrics and Health, OpenAPI.
cwist_rdbms_probe_port(port) connects to 127.0.0.1:port. It sends a
PostgreSQL StartupMessage, or reads a MySQL handshake packet and tells MySQL
from MariaDB by its version string. cwist_app_auto_rdbms() stores the
detected provider and port in app->rdbms (cwist_rdbms_runtime, with
ready = true). It does not open a client connection: CWIST has no
PostgreSQL or MySQL driver. Use the result to choose the
ORM SQL dialect or to configure your own driver.
| Function | Description |
|---|---|
void cwist_app_set_error_handler(cwist_app *app, cwist_error_handler_func handler) |
Fallback handler. |
void cwist_app_register_error_handler(cwist_app *app, cwist_http_status_t status, cwist_error_handler_func handler) |
Handler for one status code; replaces an earlier one for the same code. |
typedef void (*cwist_error_handler_func)(cwist_http_request *req,
cwist_http_response *res,
cwist_http_status_t status);The dispatcher calls these when no route, asset or static file matches the
request: the handler registered for 404, or else the fallback handler, runs
with status = CWIST_HTTP_NOT_FOUND. Without either, CWIST answers
404 Not Found with a plain-text body. Other statuses set by handlers are sent
as the handler wrote them. See Error Handling.
cwist_app_configure_bdr(app, max_bytes, max_entry_age_sec, revalidate_hits)
sets the guard rails of the app's Big Dumb Reply cache. See
Big Dumb Reply Cache and, for
CWIST_ENDPOINT_FIXED, FIXED Endpoint Cache.
| Function | Description |
|---|---|
void cwist_app_dispatch(cwist_app *app, cwist_http_request *req, cwist_http_response *res) |
Run an already-parsed request through middleware and routing. Used by the test client. |
int cwist_app_dispatch_memory(cwist_app *app, const char *req_buf, size_t req_len, char **res_buf, size_t *res_len) |
Parse a raw HTTP/1.x request from memory, dispatch it, and serialize the response into a new buffer (free with cwist_free() from <cwist/core/mem/alloc.h>). Connection: close semantics. Returns -1 for a malformed request or a body that cannot be serialized (file streams). |
int cwist_app_dispatch_stream(cwist_app *app, const char *req_buf, size_t req_len, cwist_stream_write_fn write_fn, void *write_ctx) |
Like dispatch_memory but delivers the response through a chunk callback. |
char *out; size_t out_len;
const char *raw = "GET /users/7 HTTP/1.1\r\nHost: x\r\n\r\n";
if (cwist_app_dispatch_memory(app, raw, strlen(raw), &out, &out_len) == 0) {
fwrite(out, 1, out_len, stdout);
cwist_free(out);
}These entry points serve embedded hosts (WASM, Service Workers) and tests. The incremental-request and streaming variants are on Streaming Responses.
cwist_app_multiport() serves one app on a public port plus a list of extra
ports, each of which can be detached into its own tunable sub-app. See
Multiport.
- Handlers and middleware run on several threads at once (and, with more than one worker, in several processes). Shared state needs its own synchronization; per-process state is not shared between workers.
- The framework owns the
cwist_http_requestandcwist_http_responsepassed to a handler. Do not destroy them. - Strings returned by getters such as
cwist_http_header_get()andcwist_query_map_get()are borrowed from the request; copy them to keep them after the handler returns. - Objects you create with a
_createfunction are yours to_destroy. -
req->appandreq->dbgive handlers the app and its database without globals; route contexts (_exroutes) bind per-route state.
cwist_app is a public struct (include/cwist/sys/app/app.h). Read its
fields only when no accessor exists (for example app->rdbms); configure the
app through the functions above.
CWIST wiki, written against the dev branch of c4punks/CWIST. Pages marked "Source:" are generated from files under docs/; fix those in the repository. Questions: Discord.
Getting started
- Installation
- Quick Start
- Linking
- Server Modes
- Configuration and Environment
- Project CLI
- Tutorial / Korean
- Examples and Tutorials
Guides
Core
- API Reference
- Application
- Routing
- Middleware
- Requests and Responses
- Async Handlers
- Streaming Responses
- Error Handling
- Graceful Shutdown
- Multiport
Protocols
- HTTPS and TLS
- HTTP/2
- HTTP/3 and QUIC
- WebTransport
- WebSocket
- Server-Sent Events
- gRPC Server
- gRPC Client
- Protobuf and Codegen
- GraphQL
- WebRTC DataChannels
- HTTP Clients
Web features
- Static Files and Assets
- Big Dumb Reply Cache
- Compression
- Cookies
- Sessions and Flash
- Query Maps
- Multipart Uploads
- HTML Components
- Templates
- JSON
- Validation
- OpenAPI
Security
Data
Runtime
- Memory Management
- Full GC
- Async GC Ownership
- SString
- Reactor and I/O
- Metrics and Health
- Logging
- Testing
Platforms
Performance notes
- Benchmark Methodology
- C1M File Limits
- Reactor Fairness
- Cooperative Queuing
- Classic Pool Starvation
- Reactor Wakeup
- wrk Dual Histogram
- FIXED Endpoint Cache
- ADR-0001
- Durable Queue Gate
- Mux References
Project