cwist
Modern C web framework with libttak runtime
Loading...
Searching...
No Matches
Framework & App API

Header: <cwist/sys/app/app.h> (Proposed)

High-level abstractions for building web applications quickly.

cwist_app_create

Main Application Context.
Definition app.h:155
cwist_app * cwist_app_create(void)
Creates a new CWIST application instance.
Definition app.c:1292

Initializes a new web application instance with default security settings.

cwist_app_use_https

cwist_error_t cwist_app_use_https(cwist_app *app, const char *cert_path, const char *key_path);
Integrated error structure used throughout the system.
Definition cwist_err.h:72
cwist_error_t cwist_app_use_https(cwist_app *app, const char *cert_path, const char *key_path)
Enable TLS for the application using the supplied certificate pair.
Definition app.c:1646

Enables HTTPS for the application.

cwist_app_use_https2 / cwist_use_https2

// Convenience macro when your app variable is named `app`
cwist_error_t cwist_app_use_https2(cwist_app *app, bool enabled)
Definition app.c:1760
#define cwist_use_https2(enabled)
Definition app.h:464

Keeps the default HTTPS request path in legacy HTTP/1.1 mode unless explicitly enabled. When enabled, CWIST rebuilds the TLS context with an HTTP/2-compatible TLS profile, negotiates h2 through ALPN, and swaps in the HTTPS/2 request-handler slot for the app. The HTTP/2 handler feeds decoded requests into the existing routing/middleware stack, so handler code does not need to change. The current implementation is intentionally narrow: one request stream is handled at a time per TLS connection, with support for the standard client preface, SETTINGS, HEADERS, CONTINUATION, DATA, PING, and GOAWAY.

cwist_app_use_pqc_layer

void cwist_app_use_pqc_layer(cwist_app *app, bool enabled);
void cwist_app_use_pqc_layer(cwist_app *app, bool enabled)
Enable Post-Quantum Cryptography (PQC) hybrid key exchange layer.
Definition app.c:1744

Enables the post-quantum cryptography (PQC) hybrid TLS layer. When enabled is true, CWIST forces X25519MLKEM768:X25519:P-256 as the key-exchange group list, sets TLS 1.3 as the minimum version, and disables all legacy TLSv1.0–1.2 cipher suites. This provides transport-layer quantum resistance via the NIST-standard ML-KEM-768 (Kyber) hybridized with classical X25519 ECDH, without requiring any OpenSSL knowledge from the application. Application code never touches BoringSSL directly.

cwist_app_use_db

cwist_error_t cwist_app_use_db(cwist_app *app, const char *db_path);
Wrapper for Database Operations. Currently uses SQLite3.
Definition sql.h:21
cwist_error_t cwist_app_use_db(cwist_app *app, const char *db_path)
Open a SQLite database and attach it as the shared application handle.
Definition app.c:1851
cwist_db * cwist_app_get_db(cwist_app *app)
Return the active shared database wrapper for the application.
Definition app.c:1948

Opens (or reopens) a SQLite database and keeps the handle on the cwist_app. Each incoming request automatically receives the pointer via req->db, so handlers can run queries without wiring globals:

cJSON *rows = NULL;
if (cwist_db_query(req->db, "SELECT name FROM profiles LIMIT 1", &rows).error.err_i16 == 0) {
char *json = cJSON_PrintUnformatted(rows);
free(json);
cJSON_Delete(rows);
}
}
cwist_error_t cwist_db_query(cwist_db *db, const char *sql, cJSON **result)
Execute a SQL query and collect every row into a cJSON array.
Definition db.c:374
cwist_error_t cwist_sstring_assign(cwist_sstring *str, const char *data)
Assign a C string.
Definition sstring.c:504
size_t cap
Definition otel.c:56
__prim_cwist_error_t error
Definition cwist_err.h:74
cwist_db * db
Shared database handle from cwist_app.
Definition http.h:177
HTTP Response Object. Supports standard string body or Zero-Copy pointer body.
Definition http.h:82
cwist_sstring * body
Definition http.h:87

Routing

cwist_app_get / cwist_app_post

Registers standard HTTP handlers. Supports path parameters using :name syntax.

// ...
}
cwist_app_get(app, "/users/:id", user_handler);
const char * cwist_query_map_get(cwist_query_map *map, const char *key)
Get a value by key.
Definition query.c:196
cwist_query_map * path_params
Parsed path parameters (e.g. :id)
Definition http.h:70
void cwist_app_get(cwist_app *app, const char *path, cwist_handler_func handler)
Registers a GET route handler.
Definition app.c:2216

cwist_app_get_ex / _post_ex / _put_ex / _delete_ex / _patch_ex

Register a route whose handler also receives a context pointer, so state can be bound to a route without globals (for example a closure from a language binding). Matching, :param paths, middleware and every transport behave exactly as for cwist_app_get().

typedef void (*cwist_handler_ex_func)(void *user_ctx, cwist_http_request *req,
typedef void (*cwist_handler_ctx_destroy_func)(void *user_ctx);
void *user_ctx, cwist_handler_ctx_destroy_func destroy);
void(* cwist_handler_ctx_destroy_func)(void *user_ctx)
Releases a route's user context once the route no longer needs it.
Definition app.h:50
void(* cwist_handler_ex_func)(void *user_ctx, cwist_http_request *req, cwist_http_response *res)
Route handler that also receives the context it was registered with.
Definition app.h:43
cwist_error_t cwist_app_get_ex(cwist_app *app, const char *path, cwist_handler_ex_func handler, void *user_ctx, cwist_handler_ctx_destroy_func destroy)
Registers a GET route whose handler receives a user context.
Definition app.c:2180

Ownership of user_ctx passes to the app on every call. If destroy is not NULL it runs exactly once with user_ctx:

  • when the app is destroyed;
  • when the same method and path (one without :param segments) is registered again, by any routing function, unless the new registration passes the same non-NULL user_ctx;
  • immediately, when the registration fails. The function then returns INT16 -1; success is INT16 0.

Multiport sub-apps share the context without owning it. Pass destroy = NULL to keep ownership with the caller. The handler can run on several worker threads at once, so a shared context needs its own synchronization.

typedef struct { const char *greeting; } greeter;
static void greet(void *user_ctx, cwist_http_request *req, cwist_http_response *res) {
const greeter *g = user_ctx;
(void)req;
cwist_sstring_assign(res->body, g->greeting);
}
greeter *g = cwist_alloc(sizeof(*g));
g->greeting = "hello";
cwist_app_get_ex(app, "/greet", greet, g, cwist_free);
void cwist_free(void *ptr)
Free memory obtained via cwist_alloc/cwist_strdup/etc.
Definition alloc.c:52
void * cwist_alloc(size_t size)
Allocate zeroed memory tracked by libttak.
Definition alloc.c:17

cwist_app_dispatch_memory

Runs the full router/middleware/handler pipeline on a raw HTTP/1.x request held in a memory buffer — no socket, thread, or event loop involved. The response is serialized (status line + headers + body) into a freshly allocated buffer the caller frees with cwist_free(). One-shot Connection: close semantics; this is the in-memory entry point for embedded transports such as WASM hosts.

char *res_buf;
size_t res_len;
const char *req = "GET /users/7 HTTP/1.1\r\nHost: x\r\n\r\n";
if (cwist_app_dispatch_memory(app, req, strlen(req), &res_buf, &res_len) == 0) {
}
int cwist_app_dispatch_memory(cwist_app *app, const char *req_buf, size_t req_len, char **res_buf, size_t *res_len)
Run the full router/middleware/handler pipeline on a raw HTTP/1.x request held in a memory buffer,...
Definition app.c:2523

cwist_app_ws

Registers a WebSocket handler.

void cwist_app_ws(cwist_app *app, const char *path, cwist_ws_handler_func handler);
void(* cwist_ws_handler_func)(cwist_websocket *ws)
Function pointer type for WebSocket handlers.
Definition app.h:56
void cwist_app_ws(cwist_app *app, const char *path, cwist_ws_handler_func handler)
Register a WebSocket upgrade endpoint with default options.
Definition app.c:2309

Routes without parameters are stored in a hash table for O(1) lookups while parameterized patterns fall back to sequential matching.

cwist_endpoint_opt_t

Each route can be annotated with a bitmask of behavioral flags:

Flag Description
CWIST_DYNAMIC Default dynamic handler behavior.
CWIST_ENDPOINT_FIXED Hint that the route's response is request-invariant. Does not activate caching in the current revision — every request is dispatched normally. See docs/fixed-cache-status.md.
CWIST_ENDPOINT_FILE Hint that the endpoint streams files, enabling Linux/BSD sendfile fast paths.

Use the _opt helpers to set these flags:

"/download/:id",
#define CWIST_ENDPOINT_FILE
#define CWIST_DYNAMIC
#define CWIST_ENDPOINT_FIXED
void cwist_app_get_opt(cwist_app *app, const char *path, cwist_handler_func handler, cwist_endpoint_opt_t opts)
Register a GET handler with explicit endpoint options.
Definition app.c:2363

Flags may be OR-ed together to combine behaviors (e.g., fixed + file).

Static Assets

cwist_app_static

cwist_error_t cwist_app_static(cwist_app *app, const char *url_prefix, const char *dir);
cwist_error_t cwist_app_static(cwist_app *app, const char *url_prefix, const char *directory)
Serves a directory of static files at a URL prefix. Files are loaded into the fixed memory pool for Z...
Definition app.c:2057

Mounts a directory (path normalization + traversal guards) at a URL prefix. Static responses still pass through the middleware chain and use cwist_http_response_send_file for MIME detection, traversal protection, and HEAD-aware Content-Length.

Error Handling

cwist_app_set_error_handler

Registers a global error handler for status codes >= 400 (e.g., 404 Not Found).

void(* cwist_error_handler_func)(cwist_http_request *req, cwist_http_response *res, cwist_http_status_t status)
Function pointer type for error handlers.
Definition app.h:61
void cwist_app_set_error_handler(cwist_app *app, cwist_error_handler_func handler)
Install a custom HTTP error callback.
Definition app.c:1411

Unused Variables

Use the CWIST_UNUSED() macro to suppress compiler warnings for unused handler parameters.

cwist_sstring_assign(res->body, "Hello");
}
#define CWIST_UNUSED(x)
Mark an intentionally unused variable to silence compiler warnings.
Definition macros.h:23

Concurrency & Thread-Safety

  • Multithreading: cwist_app_listen starts a multithreaded server (one thread per request). Handlers and middleware MUST be thread-safe.
  • Global State: Avoid using global variables in your handlers. If you need shared state, ensure it is protected by appropriate synchronization primitives (e.g., pthread_mutex_t).
  • Context Passing: Each handler receives req->app/req->db for shared infrastructure, while req->private_data remains available for middleware-to-middleware communication.

Memory Ownership Rules

  • Framework-Owned: cwist_http_request and cwist_http_response objects passed to handlers are owned by the framework. Do NOT destroy them inside the handler.
  • Borrowed Strings: Strings returned by cwist_http_header_get or cwist_json_get_raw are borrowed. If you need to keep them after the builder or request is destroyed, you must copy them.
  • Explicit Destruction: Objects created with _create (e.g., cwist_json_builder_create, cwist_websocket_upgrade) MUST be destroyed by the caller using the corresponding _destroy function.

cwist_app_listen

int cwist_app_listen(cwist_app *app, int port);
int cwist_app_listen(cwist_app *app, int port)
Serve app on port until SIGTERM, SIGINT or cwist_shutdown_request(); blocks the calling thread.
Definition app.c:4628

Starts the server loop on the specified port.

In-Memory Test Client

Header: <cwist/sys/app/test_client.h>

cwist_test_client dispatches synthetic HTTP requests directly through the app's router and middleware without opening a socket, so integration tests run in-process with no ports and no teardown race.

cwist_test_client_create / cwist_test_client_destroy

void cwist_test_client_destroy(cwist_test_client *client)
Destroy a test client.
cwist_test_client * cwist_test_client_create(cwist_app *app)
Create a test client for an app.

Creates and destroys a test client bound to app. The client keeps a per-instance cookie jar that is carried automatically on subsequent requests.

Request helpers

const char *body, const char *content_type);
const char *json_body);
const char *body, const char *content_type);
const char *body, const char *content_type);
cwist_http_response * cwist_test_client_post_json(cwist_test_client *client, const char *path, const char *json_body)
Perform a POST request with JSON content-type.
cwist_http_response * cwist_test_client_put(cwist_test_client *client, const char *path, const char *body)
Perform a PUT request.
cwist_http_response * cwist_test_client_get(cwist_test_client *client, const char *path)
Perform a GET request.
cwist_http_response * cwist_test_client_delete(cwist_test_client *client, const char *path)
Perform a DELETE request.
cwist_http_response * cwist_test_client_patch(cwist_test_client *client, const char *path, const char *body)
Perform a PATCH request.
cwist_http_response * cwist_test_client_post(cwist_test_client *client, const char *path, const char *body)
Perform a POST request.

Each returns a cwist_http_response * owned by the caller; free with cwist_http_response_destroy().

For full control over headers, cookies, and query string use:

cwist_http_method_t method, const char *path,
cwist_http_method_t
Definition http.h:16
Optional parameters for advanced test requests.
Definition test_client.h:31
cwist_http_response * cwist_test_client_request_ex(cwist_test_client *client, cwist_http_method_t method, const char *path, const cwist_test_client_request_options *opts)
Perform a request with full control over headers, cookies and query.

Cookie jar

const char *name, const char *value, const char *path);
const char *cwist_test_client_get_cookie(cwist_test_client *client, const char *name);
void cwist_test_client_clear_cookies(cwist_test_client *client)
Clear all cookies in the jar.
void cwist_test_client_set_cookie(cwist_test_client *client, const char *name, const char *value, const char *path)
Set a persistent cookie in the client's cookie jar.
const char * cwist_test_client_get_cookie(cwist_test_client *client, const char *name)
Get a cookie value from the jar.

Test assertion macros

#define CWIST_ASSERT_BODY_CONTAINS(res, snippet)
#define CWIST_ASSERT_HEADER(res, header_name, expected_value)
#define CWIST_ASSERT_STATUS(res, expected_status)

Each macro prints a [ASSERT FAIL] message with file and line number and calls exit(1) on failure, matching the style of the framework's own test suite.