Csilk 0.2.1
A lightweight, high-performance C HTTP web framework
Loading...
Searching...
No Matches
csilk.h File Reference

High-performance C web framework — main public API header. More...

#include <setjmp.h>
#include <stddef.h>
#include <stdint.h>
#include <uv.h>
#include "cJSON.h"
#include "csilk/drivers/ai.h"
#include "csilk/drivers/cipher.h"
#include "csilk/drivers/db.h"
#include "csilk/drivers/perm.h"
#include "csilk/reflection/reflect.h"
Include dependency graph for csilk.h:

Go to the source code of this file.

Data Structures

struct  csilk_storage_driver_t
 Pluggable storage driver for context key-value pairs. More...
 
struct  csilk_header_t
 A single HTTP header stored as a node in a chained hash table. More...
 
struct  csilk_header_map_t
 A fixed-size chained hash table for HTTP headers. More...
 
struct  csilk_request_t
 Parsed HTTP request. More...
 
struct  csilk_response_t
 Mutable HTTP response. More...
 
struct  csilk_param_t
 A single URL path parameter extracted from a route pattern. More...
 
struct  csilk_log_config_t
 Logger initialisation configuration. More...
 
struct  csilk_cors_config_t
 CORS middleware configuration. More...
 
struct  csilk_server_config_t
 Low-level server configuration options. More...
 
struct  csilk_config_t
 Top-level application configuration. More...
 
struct  csilk_valid_rule_t
 A single validation rule for request parameter checking. More...
 
struct  csilk_router_t
 The main HTTP router. More...
 
struct  csilk_multipart_part_t
 A single part parsed from a multipart/form-data request body. More...
 
struct  csilk_crypto_driver_t
 Pluggable cryptographic primitive driver. More...
 
struct  csilk_config_t.cors
 
struct  csilk_config_t.rate_limit
 
struct  csilk_config_t.static_files
 
struct  csilk_config_t.middleware
 
struct  csilk_config_t.ai
 
struct  csilk_config_t.cipher
 

Macros

#define CSILK_VERSION   "0.2.3"
 Csilk framework version string (MAJOR.MINOR.PATCH). Used for identification in logs, headers, and the OpenAPI spec.
 
#define CSILK_MAX_PARAMS   20
 Maximum number of URL path parameters that can be extracted from a single request. Parameters beyond this limit are silently ignored. Tune if your routes contain more than 20 dynamic segments.
 
#define CSILK_HEADER_BUCKETS   64
 Number of buckets in the header chained hash table.
 
#define csilk_bind(c, type, ptr)   csilk_bind_reflect(c, #type, ptr)
 Convenience macro for binding JSON body to a reflected struct. Wraps csilk_bind_reflect, automatically stringifying the type name.
 
#define csilk_json_t(c, status, type, ptr)   csilk_json_reflect(c, status, #type, ptr)
 Convenience macro for sending a reflected struct as JSON response. Wraps csilk_json_reflect, automatically stringifying the type name.
 
#define CSILK_ROUTE( r, method, path, handlers, handler_count, input_type, output_type, summary, desc)
 Convenience macro to register a route with metadata.
 
HTTP Status Codes

Standardized macros for common HTTP response status codes. Use these instead of raw integer literals for readability.

#define CSILK_STATUS_CONTINUE   100
 
#define CSILK_STATUS_SWITCHING_PROTOCOLS   101
 
#define CSILK_STATUS_OK   200
 
#define CSILK_STATUS_CREATED   201
 
#define CSILK_STATUS_NO_CONTENT   204
 
#define CSILK_STATUS_PARTIAL_CONTENT   206
 
#define CSILK_STATUS_MOVED_PERMANENTLY   301
 
#define CSILK_STATUS_FOUND   302
 
#define CSILK_STATUS_NOT_MODIFIED   304
 
#define CSILK_STATUS_TEMPORARY_REDIRECT   307
 
#define CSILK_STATUS_BAD_REQUEST   400
 
#define CSILK_STATUS_UNAUTHORIZED   401
 
#define CSILK_STATUS_PAYMENT_REQUIRED   402
 
#define CSILK_STATUS_FORBIDDEN   403
 
#define CSILK_STATUS_NOT_FOUND   404
 
#define CSILK_STATUS_METHOD_NOT_ALLOWED   405
 
#define CSILK_STATUS_REQUEST_TIMEOUT   408
 
#define CSILK_STATUS_CONFLICT   409
 
#define CSILK_STATUS_GONE   410
 
#define CSILK_STATUS_PAYLOAD_TOO_LARGE   413
 
#define CSILK_STATUS_RANGE_NOT_SATISFIABLE   416
 
#define CSILK_STATUS_URI_TOO_LONG   414
 
#define CSILK_STATUS_UNSUPPORTED_MEDIA_TYPE   415
 
#define CSILK_STATUS_TOO_MANY_REQUESTS   429
 
#define CSILK_STATUS_INTERNAL_SERVER_ERROR   500
 
#define CSILK_STATUS_NOT_IMPLEMENTED   501
 
#define CSILK_STATUS_BAD_GATEWAY   502
 
#define CSILK_STATUS_SERVICE_UNAVAILABLE   503
 
#define CSILK_STATUS_GATEWAY_TIMEOUT   504
 
Logging Macros

Convenience macros that capture source location.

#define CSILK_LOG_T(...)    _csilk_log_internal(CSILK_LOG_TRACE, __FILE__, __LINE__, __func__, __VA_ARGS__)
 Log a TRACE-level message.
 
#define CSILK_LOG_D(...)    _csilk_log_internal(CSILK_LOG_DEBUG, __FILE__, __LINE__, __func__, __VA_ARGS__)
 Log a DEBUG-level message.
 
#define CSILK_LOG_I(...)    _csilk_log_internal(CSILK_LOG_INFO, __FILE__, __LINE__, __func__, __VA_ARGS__)
 Log an INFO-level message.
 
#define CSILK_LOG_W(...)    _csilk_log_internal(CSILK_LOG_WARN, __FILE__, __LINE__, __func__, __VA_ARGS__)
 Log a WARN-level message.
 
#define CSILK_LOG_E(...)    _csilk_log_internal(CSILK_LOG_ERROR, __FILE__, __LINE__, __func__, __VA_ARGS__)
 Log an ERROR-level message.
 
#define CSILK_LOG_F(...)    _csilk_log_internal(CSILK_LOG_FATAL, __FILE__, __LINE__, __func__, __VA_ARGS__)
 Log a FATAL-level message.
 
#define CSILK_LOG_STRUCT(level, extra, ...)    _csilk_log_structured(level, __FILE__, __LINE__, __func__, extra, __VA_ARGS__)
 Log a structured JSON message (only meaningful when json_format is on).
 
Validation flags

Bit flags for use in csilk_valid_rule_t.flags. Combine with |.

#define CSILK_VALID_REQUIRED   (1 << 0)
 
#define CSILK_VALID_INT   (1 << 1)
 
#define CSILK_VALID_STRING    (1 << 2)
 
#define CSILK_VALID_EMAIL    (1 << 3)
 
Group Route Macros

Convenience macros for adding routes to groups.

#define csilk_GET(group, path, handler)   csilk_group_add_route(group, "GET", path, handler)
 Register a GET route on the group.
 
#define csilk_POST(group, path, handler)   csilk_group_add_route(group, "POST", path, handler)
 Register a POST route on the group.
 
#define csilk_PUT(group, path, handler)   csilk_group_add_route(group, "PUT", path, handler)
 Register a PUT route on the group.
 
#define csilk_DELETE(group, path, handler)   csilk_group_add_route(group, "DELETE", path, handler)
 Register a DELETE route on the group.
 
#define csilk_PATCH(group, path, handler)   csilk_group_add_route(group, "PATCH", path, handler)
 Register a PATCH route on the group.
 
#define csilk_OPTIONS(group, path, handler)   csilk_group_add_route(group, "OPTIONS", path, handler)
 Register an OPTIONS route on the group.
 
#define csilk_HEAD(group, path, handler)   csilk_group_add_route(group, "HEAD", path, handler)
 Register a HEAD route on the group.
 

Typedefs

typedef void(* csilk_handler_t) (csilk_ctx_t *c)
 Function pointer for route handlers and middleware.
 
typedef struct csilk_arena_s csilk_arena_t
 Opaque arena allocator type.
 
typedef int(* csilk_auth_validator_t) (const char *token)
 Authentication validator callback.
 
typedef void(* csilk_multipart_handler_t) (csilk_multipart_part_t *part)
 Callback invoked for each part during multipart parsing.
 
typedef void(* csilk_server_hook_handler_t) (csilk_server_t *s)
 Callback signature for server-level hooks.
 
typedef void(* csilk_ctx_hook_handler_t) (csilk_ctx_t *c)
 Callback signature for request/connection-level hooks.
 
typedef void(* csilk_mq_handler_t) (csilk_mq_ctx_t *ctx)
 MQ handler signature for middleware and subscribers.
 
typedef void(* csilk_mq_worker_t) (const char *topic, const void *payload, size_t len)
 Signature for a background MQ worker function.
 

Enumerations

enum  csilk_log_level_t {
  CSILK_LOG_TRACE , CSILK_LOG_DEBUG , CSILK_LOG_INFO , CSILK_LOG_WARN ,
  CSILK_LOG_ERROR , CSILK_LOG_FATAL
}
 Log severity levels. More...
 
enum  csilk_hook_type_t {
  CSILK_HOOK_SERVER_START , CSILK_HOOK_SERVER_STOP , CSILK_HOOK_CONN_OPEN , CSILK_HOOK_CONN_CLOSE ,
  CSILK_HOOK_REQUEST_BEGIN , CSILK_HOOK_REQUEST_END , CSILK_HOOK_COUNT
}
 Lifecycle hook types for the server and individual requests. More...
 

Functions

const char * csilk_get_method (csilk_ctx_t *c)
 Get the HTTP method of the current request.
 
const char * csilk_get_path (csilk_ctx_t *c)
 Get the decoded URL path of the current request.
 
const char * csilk_get_body (csilk_ctx_t *c, size_t *out_len)
 Get the raw request body and its length.
 
size_t csilk_get_body_len (csilk_ctx_t *c)
 Get the length of the raw request body.
 
int csilk_is_websocket (csilk_ctx_t *c)
 Check whether the connection has been upgraded to WebSocket.
 
int csilk_is_sse (csilk_ctx_t *c)
 Check whether the connection is in Server-Sent Events mode.
 
int csilk_is_aborted (csilk_ctx_t *c)
 Check whether the handler chain has been aborted.
 
void csilk_set_on_ws_message (csilk_ctx_t *c, void(*callback)(csilk_ctx_t *c, const uint8_t *payload, size_t len, int opcode))
 Register a callback for incoming WebSocket messages.
 
void csilk_set_on_ws_send (csilk_ctx_t *c, void(*callback)(csilk_ctx_t *c, const uint8_t *payload, size_t len, int opcode))
 Set a callback for outgoing WebSocket frames (for testing).
 
const char * csilk_get_request_id (csilk_ctx_t *c)
 Get the unique identifier for the current request.
 
csilk_arena_tcsilk_get_arena (csilk_ctx_t *c)
 Get the arena allocator associated with the request context.
 
int csilk_get_status (csilk_ctx_t *c)
 Get the current response status code.
 
void csilk_set_async (csilk_ctx_t *c, int is_async)
 Enable or disable asynchronous response mode.
 
int csilk_is_async (csilk_ctx_t *c)
 Check whether asynchronous response mode is enabled.
 
void csilk_set_response_body (csilk_ctx_t *c, const char *body, size_t len, int managed)
 Overwrite the response body from middleware.
 
const char * csilk_get_response_body (csilk_ctx_t *c, size_t *out_len)
 Get the current response body and its length.
 
void csilk_redirect (csilk_ctx_t *c, int status, const char *location)
 Send an HTTP redirect response with a custom status code.
 
void csilk_redirect_simple (csilk_ctx_t *c, const char *url)
 Send a simple 302 Found redirect.
 
void csilk_set (csilk_ctx_t *c, const char *key, void *value)
 Store an opaque value in the request context.
 
void * csilk_get (csilk_ctx_t *c, const char *key)
 Retrieve an opaque value from the request context.
 
void csilk_next (csilk_ctx_t *c)
 Pass control to the next handler in the middleware/handler chain.
 
void csilk_abort (csilk_ctx_t *c)
 Immediately abort the handler chain.
 
void csilk_status (csilk_ctx_t *c, int status)
 Set the HTTP response status code.
 
void csilk_string (csilk_ctx_t *c, int status, const char *msg)
 Set a plain-text response body and status code.
 
const char * csilk_get_param (csilk_ctx_t *c, const char *key)
 Get a URL path parameter by key.
 
const char * csilk_get_header (csilk_ctx_t *c, const char *key)
 Get a request header value by name (case-insensitive).
 
const char * csilk_get_response_header (csilk_ctx_t *c, const char *key)
 Get a response header value by name (case-insensitive).
 
const char * csilk_get_query (csilk_ctx_t *c, const char *key)
 Get a query-string parameter by key.
 
void csilk_parse_form_urlencoded (csilk_ctx_t *c)
 Parse the request body as application/x-www-form-urlencoded.
 
const char * csilk_get_form_field (csilk_ctx_t *c, const char *key)
 Get a form-urlencoded field value by key.
 
void csilk_set_request_header (csilk_ctx_t *c, const char *key, const char *value)
 Set (or overwrite) a request header.
 
void csilk_set_header (csilk_ctx_t *c, const char *key, const char *value)
 Set (or overwrite) a response header.
 
void csilk_add_header (csilk_ctx_t *c, const char *key, const char *value)
 Append a response header, preserving any existing value(s).
 
void csilk_ctx_cleanup (csilk_ctx_t *c)
 Release all memory and resources associated with a request context.
 
csilk_arena_tcsilk_arena_new (size_t default_chunk_size)
 Create a new arena allocator.
 
void * csilk_arena_alloc (csilk_arena_t *arena, size_t size)
 Allocate zero-initialised memory from an arena.
 
char * csilk_arena_strdup (csilk_arena_t *arena, const char *s)
 Duplicate a NUL-terminated string using the arena allocator.
 
char * csilk_arena_strndup (csilk_arena_t *arena, const char *s, size_t n)
 Duplicate n bytes of a string using the arena allocator.
 
void csilk_arena_free (csilk_arena_t *arena)
 Free all memory chunks owned by the arena.
 
void csilk_arena_reset (csilk_arena_t *arena)
 Reset the arena without freeing its chunks.
 
void csilk_recovery_handler (csilk_ctx_t *c)
 Panic-recovery middleware.
 
void csilk_panic (csilk_ctx_t *c)
 Trigger a panic (caught by recovery middleware).
 
int csilk_log_init (csilk_log_config_t config)
 Initialize the global logger with config.
 
void _csilk_log_internal (csilk_log_level_t lv, const char *file, int line, const char *func, const char *fmt,...)
 Internal log function (use macros instead).
 
void csilk_log_close ()
 Close the global logger.
 
void _csilk_log_structured (csilk_log_level_t lv, const char *file, int line, const char *func, cJSON *extra, const char *fmt,...)
 Log a structured JSON message with extra key-value fields.
 
int csilk_log_is_json (void)
 Check whether the logger is in JSON format mode.
 
void csilk_log_set_request_id (const char *request_id)
 Set the Request ID for the current thread (for log correlation).
 
cJSON * csilk_log_make_kv (const char *key,...)
 Create a simple key-value cJSON object for structured logging.
 
void csilk_logger_handler (csilk_ctx_t *c)
 Logging middleware handler. Logs request method, path, and processing time.
 
void csilk_request_id_middleware (csilk_ctx_t *c)
 Request ID middleware. Generates a unique ID for each request and sets X-Request-Id header.
 
void csilk_health_check_handler (csilk_ctx_t *c)
 Built-in Health Check handler. Returns a simple JSON response {"status": "up"}.
 
void csilk_cors_middleware (csilk_ctx_t *c, const csilk_cors_config_t *config)
 CORS middleware — handles preflight and adds CORS headers.
 
void csilk_rate_limit_middleware (csilk_ctx_t *c, int limit)
 Simple per-IP rate-limiting middleware.
 
void csilk_csrf_middleware (csilk_ctx_t *c)
 Stateless CSRF protection middleware.
 
int csilk_csrf_generate_token (char *buf, size_t buf_size)
 Generate a cryptographically random CSRF token.
 
int csilk_load_config (const char *yaml_path, csilk_config_t *config)
 Load and parse a YAML configuration file.
 
int csilk_config_validate (const csilk_config_t *config, const char **error_msg)
 Validate configuration values for semantic correctness.
 
void csilk_config_free (csilk_config_t *config)
 Free all heap-allocated strings inside a configuration.
 
void csilk_auth_middleware (csilk_ctx_t *c, csilk_auth_validator_t validator)
 Simple token-based authentication middleware.
 
void csilk_static (csilk_ctx_t *c, const char *root_dir)
 Serve static files from a local directory.
 
void csilk_file (csilk_ctx_t *c, const char *file_path)
 Serve a specific file from the local filesystem.
 
cJSON * csilk_bind_json (csilk_ctx_t *c)
 Bind the request body (JSON) to a cJSON object.
 
cJSON * csilk_bind_json_err (csilk_ctx_t *c, const char **error)
 Bind request body to cJSON with a descriptive error message.
 
const char * csilk_get_cookie (csilk_ctx_t *c, const char *name)
 Get a cookie value by name from the Cookie request header.
 
void csilk_set_cookie (csilk_ctx_t *c, const char *name, const char *value, int max_age, const char *path, const char *domain, int secure, int http_only)
 Set a cookie in the Set-Cookie response header.
 
void csilk_session_init (void)
 Initialise the session subsystem (call once at startup).
 
void csilk_session_start (csilk_ctx_t *c)
 Start or resume a session for the current request.
 
void csilk_session_set (csilk_ctx_t *c, const char *key, void *value)
 Store a value in the session.
 
void * csilk_session_get (csilk_ctx_t *c, const char *key)
 Retrieve a value from the session.
 
void csilk_session_destroy (csilk_ctx_t *c)
 Destroy the session and clear the session cookie.
 
const char * csilk_validate (csilk_ctx_t *c, const csilk_valid_rule_t *rules)
 Validate request parameters against a set of rules.
 
void csilk_json (csilk_ctx_t *c, int status, cJSON *json)
 Send a JSON response (takes ownership of the cJSON object).
 
void csilk_json_error (csilk_ctx_t *c, int status, const char *message)
 Send a JSON-formatted error response.
 
int csilk_bind_reflect (csilk_ctx_t *c, const char *type_name, void *ptr)
 Parse the JSON request body into a struct registered via reflection.
 
void csilk_json_reflect (csilk_ctx_t *c, int status, const char *type_name, const void *ptr)
 Serialise a reflected struct as a JSON response.
 
const char * csilk_get_client_ip (csilk_ctx_t *c)
 Get the client's IP address.
 
void csilk_split_url (const char *url, char **path, char **query)
 Split a URL into path and query-string components.
 
void csilk_parse_query (csilk_ctx_t *c, const char *query_string)
 Parse a raw query string and populate the query_params map.
 
csilk_router_tcsilk_router_new (void)
 Create a new empty router.
 
void csilk_router_add (csilk_router_t *r, const char *method, const char *path, csilk_handler_t *handlers, size_t handler_count)
 Register a route with one or more handlers.
 
csilk_handler_tcsilk_router_match (csilk_router_t *r, const char *method, const char *path)
 Match a raw method+path to handlers (standalone, no context).
 
int csilk_router_match_ctx (csilk_router_t *r, csilk_ctx_t *c)
 Match the current request against the router and update the context.
 
void csilk_router_free (csilk_router_t *r)
 Destroy the router and release all its resources.
 
cJSON * csilk_router_collect_routes (csilk_router_t *r)
 Collect all registered routes from the router tree as a cJSON array.
 
cJSON * csilk_generate_openapi_json (csilk_router_t *router, const char *title, const char *version, const char *description)
 Generate an OpenAPI 3.0 specification JSON from the router.
 
void csilk_router_add_extended (csilk_router_t *r, const char *method, const char *path, csilk_handler_t *handlers, size_t handler_count, const char *path_pattern, const char *input_type, const char *output_type, const char *summary, const char *description)
 Register a route with full OpenAPI/reflection metadata.
 
void csilk_router_add_perm (csilk_router_t *r, const char *method, const char *path, csilk_handler_t *handlers, size_t handler_count, const char *perm_required, const char *perm_resource)
 Register a route with permission metadata.
 
void csilk_router_add_extended_perm (csilk_router_t *r, const char *method, const char *path, csilk_handler_t *handlers, size_t handler_count, const char *path_pattern, const char *input_type, const char *output_type, const char *summary, const char *description, const char *perm_required, const char *perm_resource)
 Register a route with full metadata including permissions.
 
void csilk_serve_openapi (csilk_ctx_t *c, csilk_router_t *r, const char *title, const char *version, const char *description)
 Serve the OpenAPI JSON specification as the response.
 
void csilk_serve_swagger_ui (csilk_ctx_t *c)
 Serve the embedded Swagger UI page.
 
csilk_group_t * csilk_group_new (csilk_router_t *router, const char *prefix)
 Create a new route group with a URL prefix.
 
csilk_group_t * csilk_group_group (csilk_group_t *parent, const char *prefix)
 Create a nested sub-group within an existing group.
 
void csilk_group_use (csilk_group_t *group, csilk_handler_t handler)
 Add middleware to a group.
 
void csilk_group_add_route (csilk_group_t *group, const char *method, const char *path, csilk_handler_t handler)
 Add a route to the group.
 
void csilk_group_add_route_extended (csilk_group_t *group, const char *method, const char *path, csilk_handler_t handler, const char *input_type, const char *output_type, const char *summary, const char *description)
 Add a route with OpenAPI/reflection metadata to a group.
 
void csilk_group_add_route_extended_perm (csilk_group_t *group, const char *method, const char *path, csilk_handler_t handler, const char *input_type, const char *output_type, const char *summary, const char *description, const char *perm_required, const char *perm_resource)
 Add a route with full OpenAPI metadata and permission requirements to a group.
 
void csilk_group_add_handlers (csilk_group_t *group, const char *method, const char *path, csilk_handler_t *handlers, size_t count)
 Add a route with an explicit array of handlers.
 
void csilk_group_free (csilk_group_t *group)
 Destroy a route group and release its resources.
 
void csilk_ws_handshake (csilk_ctx_t *c)
 Perform the WebSocket upgrade handshake (HTTP Upgrade request).
 
void csilk_ws_send (csilk_ctx_t *c, const uint8_t *payload, size_t len, int opcode)
 Send a WebSocket data frame.
 
void csilk_ws_close (csilk_ctx_t *c, uint16_t status_code, const char *reason)
 Send a WebSocket close frame.
 
void csilk_response_write (csilk_ctx_t *c, const uint8_t *data, size_t len)
 Write a chunk to the response stream (chunked transfer encoding).
 
void csilk_response_end (csilk_ctx_t *c)
 Finalise a chunked streaming response.
 
void csilk_sse_init (csilk_ctx_t *c)
 Initialise a Server-Sent Events connection.
 
void csilk_sse_send (csilk_ctx_t *c, const char *event, const char *data)
 Send an SSE event (or comment) to the client.
 
void csilk_sse_close (csilk_ctx_t *c)
 Close the SSE connection.
 
char * csilk_jwt_generate (csilk_ctx_t *c, cJSON *payload, const char *secret)
 Generate a signed JWT token (HS256).
 
cJSON * csilk_jwt_verify (csilk_ctx_t *c, const char *token, const char *secret)
 Verify a JWT token and extract its payload.
 
void csilk_jwt_middleware (csilk_ctx_t *c, const char *secret)
 JWT authentication middleware.
 
void csilk_gzip_middleware (csilk_ctx_t *c)
 Gzip response compression middleware.
 
void csilk_multipart_parse (csilk_ctx_t *c, csilk_multipart_handler_t handler)
 Parse a multipart/form-data request body.
 
csilk_server_t * csilk_ctx_get_server (csilk_ctx_t *c)
 Get the server instance associated with the current context.
 
void csilk_server_add_hook (csilk_server_t *s, csilk_hook_type_t type, void *handler)
 Register a lifecycle hook callback.
 
void csilk_server_set_crypto_driver (csilk_server_t *server, csilk_crypto_driver_t *driver)
 Set the global crypto driver for the server.
 
void csilk_server_set_cipher_driver (csilk_server_t *server, csilk_cipher_driver_t *driver)
 Set the global cipher algorithm driver for the server.
 
csilk_server_t * csilk_server_new (csilk_router_t *router)
 Create a new server instance.
 
int csilk_server_use (csilk_server_t *server, csilk_handler_t handler)
 Register global middleware.
 
void csilk_server_set_not_found_handler (csilk_server_t *server, csilk_handler_t handler)
 Set a custom handler for 404 (route-not-found) responses.
 
void csilk_server_set_spa_fallback (csilk_server_t *server, const char *doc_root)
 Enable single-page application (SPA) fallback mode.
 
void csilk_server_free (csilk_server_t *server)
 Destroy the server and release all resources.
 
void csilk_server_stop (csilk_server_t *server)
 Request a graceful server shutdown.
 
void csilk_server_set_config (csilk_server_t *server, const csilk_server_config_t *config)
 Apply server configuration options.
 
int csilk_server_set_max_connections (csilk_server_t *server, int max)
 Set the maximum number of concurrent connections and return the previous limit.
 
void csilk_server_set_storage_driver (csilk_server_t *server, csilk_storage_driver_t *driver)
 Replace the context key-value storage driver.
 
int csilk_server_run (csilk_server_t *server, int port)
 Start the server and enter the libuv event loop.
 
void csilk_db_init (void)
 Initialise the database subsystem.
 
csilk_db_pool_tcsilk_db_pool_new (const char *driver_name, const char *dsn)
 Create a new database connection pool.
 
void csilk_db_pool_free (csilk_db_pool_t *pool)
 Free a database pool and disconnect.
 
cJSON * csilk_db_query_json (csilk_db_pool_t *pool, const char *sql)
 Execute a SELECT query and return the result as a JSON array.
 
int csilk_db_exec (csilk_db_pool_t *pool, const char *sql)
 Execute a statement that returns no result rows.
 
cJSON * csilk_db_query_param_json (csilk_db_pool_t *pool, const char *sql, const char **params)
 Execute a parameterised SELECT query with ? placeholders.
 
void csilk_metrics_middleware (csilk_ctx_t *c, const char *arg)
 Prometheus metrics middleware.
 
void csilk_metrics_handler (csilk_ctx_t *c)
 Prometheus /metrics endpoint handler.
 
csilk_mq_t * csilk_ctx_get_mq (csilk_ctx_t *c)
 Get the internal MQ instance from the context.
 
csilk_mq_t * csilk_server_get_mq (csilk_server_t *server)
 Get the Message Queue instance attached to a server.
 
csilk_router_tcsilk_server_get_router (csilk_server_t *server)
 Get the router instance attached to a server.
 
void csilk_mq_next (csilk_mq_ctx_t *ctx)
 Pass control to the next middleware or subscriber in the MQ chain.
 
void csilk_mq_abort (csilk_mq_ctx_t *ctx)
 Abort the MQ middleware/subscriber chain.
 
void csilk_mq_offload (csilk_mq_ctx_t *ctx, csilk_mq_worker_t worker)
 Offload message processing to a background thread.
 
const char * csilk_mq_get_topic (csilk_mq_ctx_t *ctx)
 Get the topic of the current message.
 
const void * csilk_mq_get_payload (csilk_mq_ctx_t *ctx, size_t *len)
 Get the payload of the current message.
 
void csilk_mq_use (csilk_mq_t *mq, const char *topic, csilk_mq_handler_t middleware)
 Register MQ middleware for a topic.
 
void csilk_mq_subscribe (csilk_mq_t *mq, const char *topic, csilk_mq_handler_t subscriber)
 Register a subscriber for a topic.
 
int csilk_mq_publish (csilk_mq_t *mq, const char *topic, const void *payload, size_t len)
 Publish a message to a topic.
 
int csilk_mq_set_persistence (csilk_mq_t *mq, const char *wal_path)
 Enable Write-Ahead Log (WAL) persistence for the MQ.
 
WebSocket Room Management (MQ-based)

High-concurrency room broadcasting system leveraging the Message Queue.

void csilk_ws_join_room (csilk_ctx_t *c, const char *room_name)
 Join a WebSocket client to a room.
 
void csilk_ws_leave_room (csilk_ctx_t *c, const char *room_name)
 Remove a WebSocket client from a room.
 
void csilk_ws_broadcast_room (csilk_ctx_t *c, const char *room_name, const char *message)
 Broadcast a message to all WebSockets in a room via MQ.
 

Detailed Description

High-performance C web framework — main public API header.

Defines all public types, enums, macros, and function declarations for the csilk HTTP web framework, including the request context, router, server, middleware, WebSocket, SSE, and utility APIs. Inspired by Gin (Golang).

Version
0.2.1

Data Structure Documentation

◆ csilk_header_t

struct csilk_header_t

A single HTTP header stored as a node in a chained hash table.

Key and value are NUL-terminated strings allocated from the request arena. The next pointer forms a singly-linked list for hash-collision chains.

Note
Strings are NOT individually freeable — they live until the arena is destroyed in csilk_ctx_cleanup.
Data Fields
char * key

NUL-terminated header field name (lowercased for case-insensitive lookup).

size_t key_len

Cached strlen(key) for rapid comparison.

struct csilk_header_s * next

Pointer to the next header in the same hash bucket (collision chain).

char * value

NUL-terminated header field value (raw, as received or set).

size_t value_len

Cached strlen(value).

◆ csilk_header_map_t

struct csilk_header_map_t

A fixed-size chained hash table for HTTP headers.

Uses CSILK_HEADER_BUCKETS buckets; each bucket holds a singly-linked list of csilk_header_t nodes. Used for both request and response headers, query parameters, and form fields.

Note
Not thread-safe — all mutations occur on the event-loop thread.
Collaboration diagram for csilk_header_map_t:
Data Fields
csilk_header_t * buckets[CSILK_HEADER_BUCKETS]

Bucket array; each entry points to the head of a collision chain (or NULL).

◆ csilk_request_t

struct csilk_request_t

Parsed HTTP request.

Populated by the HTTP parser before handlers are invoked. All string fields point into arena-allocated memory that stays valid until csilk_ctx_cleanup.

Collaboration diagram for csilk_request_t:
Data Fields
char * body

Raw request body bytes, or NULL for requests without a body.

size_t body_len

Number of bytes in body.

csilk_header_map_t form_params

Hash map of parsed application/x-www-form-urlencoded fields (populated by csilk_parse_form_urlencoded).

csilk_header_map_t headers

Hash map of request headers (keys lowercased for case-insensitive lookup).

char * method

HTTP method verb (e.g., "GET", "POST", "DELETE").

char * path

Decoded URL path (percent-encoding removed, query string stripped).

csilk_header_map_t query_params

Hash map of parsed query-string parameters.

◆ csilk_response_t

struct csilk_response_t

Mutable HTTP response.

Handlers write their response into this struct. The framework serialises it after the handler chain completes (or when csilk_response_end is called for streaming responses).

Collaboration diagram for csilk_response_t:
Data Fields
const char * body

Response body content. If body_is_managed is 1 the framework calls free() when done.

int body_is_managed

Non-zero if body was allocated with malloc() and must be free()'d by the framework.

size_t body_len

Byte length of body.

csilk_header_map_t headers

Hash map of response headers to send.

int status

HTTP status code (e.g., 200, 404, 500). Defaults to 200.

◆ csilk_param_t

struct csilk_param_t

A single URL path parameter extracted from a route pattern.

For a route like /users/:id/posts/:post_id, two csilk_param_t entries are generated: {"id", actual_id} and {"post_id", actual_post_id}.

Note
The key and value strings live in the request arena and are valid until csilk_ctx_cleanup.
Data Fields
char * key

Parameter name as defined in the route pattern (e.g., "id").

char * value

Actual decoded value from the request URL.

◆ csilk_log_config_t

struct csilk_log_config_t

Logger initialisation configuration.

Controls log output destination, formatting, level filtering, and rotation. Passed by value (not pointer) to csilk_log_init.

Data Fields
const char * file_path

Path to the log file, or NULL to log to stderr.

int json_format

When non-zero, emit newline-delimited JSON records instead of human-readable lines.

csilk_log_level_t level

Minimum level to emit (messages below this are filtered out).

size_t max_file_size

Maximum file size in bytes before rotation (0 = rotation disabled). Requires file_path to be set.

int use_colors

Enable ANSI colour escape codes: 1 = on, 0 = off, -1 = auto-detect (default).

◆ csilk_cors_config_t

struct csilk_cors_config_t

CORS middleware configuration.

Maps directly to the Access-Control-* response headers. Strings are used as-is — the caller must ensure they remain valid for the lifetime of the middleware.

Data Fields
int allow_credentials

Non-zero to include Access-Control-Allow-Credentials: true.

const char * allow_headers

Value of the Access-Control-Allow-Headers header (e.g., "Content-Type, Authorization").

const char * allow_methods

Value of the Access-Control-Allow-Methods header (e.g., "GET, POST, PUT, DELETE").

const char * allow_origin

Value of the Access-Control-Allow-Origin header (e.g., "*" or "https://example.com").

int max_age

Value of Access-Control-Max-Age in seconds (e.g., 86400 for 24 h).

◆ csilk_server_config_t

struct csilk_server_config_t

Low-level server configuration options.

Controls timeouts, resource limits, TCP tuning, and TLS settings. A zero-initialised struct provides safe defaults for most fields. Apply via csilk_server_set_config before calling csilk_server_run.

Examples
/home/runner/work/csilk/csilk/include/csilk/app/app.h.
Data Fields
int enable_tls

Non-zero enables HTTPS via TLS. Requires tls_cert_file and tls_key_file.

unsigned int idle_timeout_ms

HTTP keep-alive idle timeout in milliseconds. Connection closed when no new request arrives within this window. 0 = use default (typically 30 s).

int listen_backlog

TCP listen(2) backlog hint passed to the kernel.

size_t max_body_size

Maximum allowed request body size in bytes. Requests exceeding this get 413 Payload Too Large.

int max_connections

Maximum concurrent client connections (0 = unlimited).

size_t max_header_size

Maximum total size of all request headers in bytes.

size_t max_headers_count

Maximum number of individual header fields (0 = unlimited).

size_t max_url_size

Maximum URL length in bytes (0 = disabled).

unsigned int read_timeout_ms

Maximum time in milliseconds to wait for the full request headers+body (0 = disabled).

unsigned int request_timeout_ms

Maximum time in milliseconds for a complete request/response cycle (0 = disabled). Overrides read/write timeouts if set.

int tcp_keepalive

TCP keep-alive probe interval in seconds (0 = disabled).

int tcp_nodelay

Non-zero enables TCP_NODELAY (disable Nagle's algorithm).

char * tls_ca_file

Path to the CA certificate bundle for client-certificate verification (optional).

char * tls_cert_file

Path to the SSL/TLS certificate file (PEM format). Must be set if enable_tls is 1.

char * tls_key_file

Path to the SSL/TLS private key file (PEM format). Must be set if enable_tls is 1.

int tls_verify_peer

Non-zero to require and verify a client certificate. Requires tls_ca_file.

int worker_threads

Number of worker threads for SO_REUSEPORT listener sockets. 0 = number of CPUs.

unsigned int write_timeout_ms

Maximum time in milliseconds to send the response (0 = disabled).

◆ csilk_config_t

struct csilk_config_t

Top-level application configuration.

Unifies server, logger, middleware, and feature-flag settings. Typically populated from a YAML file via csilk_load_config.

Examples
/home/runner/work/csilk/csilk/include/csilk/app/app.h.
Collaboration diagram for csilk_config_t:
Data Fields
struct csilk_config_t ai

AI integration settings.

struct csilk_config_t.ai ai

AI integration settings.

struct csilk_config_t cipher

Cipher/cryptography settings.

struct csilk_config_t.cipher cipher

Cipher/cryptography settings.

struct csilk_config_t cors

Cross-Origin Resource Sharing settings.

struct csilk_config_t.cors cors

Cross-Origin Resource Sharing settings.

csilk_log_config_t logger

Logger initialisation settings.

struct csilk_config_t middleware

Built-in middleware toggles.

struct csilk_config_t.middleware middleware

Built-in middleware toggles.

int port

TCP port the server listens on.

struct csilk_config_t rate_limit

Per-IP rate limiting settings.

struct csilk_config_t.rate_limit rate_limit

Per-IP rate limiting settings.

csilk_server_config_t server

Low-level server/connection settings.

struct csilk_config_t static_files

Static file server settings.

struct csilk_config_t.static_files static_files

Static file server settings.

◆ csilk_valid_rule_t

struct csilk_valid_rule_t

A single validation rule for request parameter checking.

Rules are collected into a NULL-terminated array and passed to csilk_validate. Each rule specifies constraints for one field.

Data Fields
const char * field

Name of the field to validate.

int flags

Bitwise OR of CSILK_VALID_* flags. Set to 0 for no constraints (only min/max apply).

int max

Maximum allowed length (string fields) or numeric value (int fields).

int min

Minimum allowed length (string fields) or numeric value (int fields).

const char * source

Location to look for the field: "query", "form", "header", "cookie", or NULL to auto-detect.

◆ csilk_router_t

struct csilk_router_t

The main HTTP router.

Wraps a radix-tree root node and provides methods to register routes, match incoming requests, and generate OpenAPI specs. Routing is based on a compressed radix tree (Patricia trie) for O(k) path matching where k is the URL path length. Dynamic segments (:param) and wildcards (*param) are supported.

Lifecycle

Note
Not thread-safe for mutation after the server starts. All routes must be registered before csilk_server_run.

Wraps a radix-tree root node and provides methods to register routes, match incoming requests, and generate OpenAPI specs.

Note
Not thread-safe for mutation after the server starts. All routes must be registered before csilk_server_run.
Examples
/home/runner/work/csilk/csilk/include/csilk/app/app.h.
Data Fields
csilk_router_node_t * root

Root node of the radix (Patricia) trie.

◆ csilk_multipart_part_t

struct csilk_multipart_part_t

A single part parsed from a multipart/form-data request body.

Contains the field name, optional filename (for file uploads), content type, and the binary data. Strings are NUL-terminated fixed-size buffers; data longer than the buffer is truncated.

Data Fields
char content_type[64]

Content-Type of the part (e.g., "image/png"). Truncated to 63 chars.

csilk_ctx_t * ctx

Owning request context (for memory allocation).

uint8_t * data

Pointer to the part's binary data. Valid until csilk_ctx_cleanup.

size_t data_len

Byte length of data.

char filename[256]

Original filename for file uploads (empty string if not a file). Truncated to 255 chars.

char name[128]

Form field name (NUL-terminated). Truncated to 127 chars.

◆ csilk_config_t.cors

struct csilk_config_t.cors
Data Fields
csilk_cors_config_t config

CORS header values when enabled.

csilk_cors_config_t config

CORS header values when enabled.

int enable

Non-zero to install the CORS middleware.

int enable

Non-zero to install the CORS middleware.

◆ csilk_config_t.rate_limit

struct csilk_config_t.rate_limit
Data Fields
int enable

Non-zero to install the rate-limiter middleware.

int enable

Non-zero to install the rate-limiter middleware.

int requests_per_minute

Maximum requests/minute/IP when enabled.

int requests_per_minute

Maximum requests/minute/IP when enabled.

◆ csilk_config_t.static_files

struct csilk_config_t.static_files
Data Fields
int enable

Non-zero to enable static file serving.

int enable

Non-zero to enable static file serving.

char * prefix

URL prefix for static files (e.g., "/static").

char * prefix

URL prefix for static files (e.g., "/static").

char * root_dir

Absolute or relative path to the local directory to serve.

char * root_dir

Absolute or relative path to the local directory to serve.

◆ csilk_config_t.middleware

struct csilk_config_t.middleware
Data Fields
char * auth_token

Expected bearer token when enable_auth is 1 (NULL = disabled even if enabled).

char * auth_token

Expected bearer token when enable_auth is 1 (NULL = disabled even if enabled).

int enable_auth

Non-zero to install the token-auth middleware.

int enable_auth

Non-zero to install the token-auth middleware.

int enable_csrf

Non-zero to install the CSRF-protection middleware.

int enable_csrf

Non-zero to install the CSRF-protection middleware.

int enable_logger

Non-zero to install the request-logging middleware.

int enable_logger

Non-zero to install the request-logging middleware.

int enable_recovery

Non-zero to install the panic-recovery middleware.

int enable_recovery

Non-zero to install the panic-recovery middleware.

◆ csilk_config_t.ai

struct csilk_config_t.ai
Data Fields
char * api_key

API key for the AI service.

char * api_key

API key for the AI service.

char * base_url

Optional base URL for API requests.

char * base_url

Optional base URL for API requests.

char * driver

AI driver name (e.g., "openai", "claude").

char * driver

AI driver name (e.g., "openai", "claude").

int enable

Non-zero to install the rate-limiter middleware.

char * model

AI model identifier (e.g., "gpt-4", "claude-3").

char * model

AI model identifier (e.g., "gpt-4", "claude-3").

int requests_per_minute

Maximum requests/minute/IP when enabled.

◆ csilk_config_t.cipher

struct csilk_config_t.cipher
Data Fields
char * driver

Cipher driver name (e.g., "openssl").

char * driver

Cipher driver name (e.g., "openssl").

int enable

Non-zero to install the rate-limiter middleware.

int enable

Non-zero to enable cipher functionality.

int enable

Non-zero to enable cipher functionality.

int requests_per_minute

Maximum requests/minute/IP when enabled.

Macro Definition Documentation

◆ csilk_bind

#define csilk_bind (   c,
  type,
  ptr 
)    csilk_bind_reflect(c, #type, ptr)

Convenience macro for binding JSON body to a reflected struct. Wraps csilk_bind_reflect, automatically stringifying the type name.

Parameters
cThe request context.
typeThe struct type (used with #type to get the name).
ptrPointer to the struct instance.

◆ csilk_DELETE

#define csilk_DELETE (   group,
  path,
  handler 
)    csilk_group_add_route(group, "DELETE", path, handler)

Register a DELETE route on the group.

◆ csilk_GET

#define csilk_GET (   group,
  path,
  handler 
)    csilk_group_add_route(group, "GET", path, handler)

Register a GET route on the group.

◆ csilk_HEAD

#define csilk_HEAD (   group,
  path,
  handler 
)    csilk_group_add_route(group, "HEAD", path, handler)

Register a HEAD route on the group.

◆ CSILK_HEADER_BUCKETS

#define CSILK_HEADER_BUCKETS   64

Number of buckets in the header chained hash table.

Larger values reduce collision chains at the cost of a small amount of per-map memory. Override at compile-time with -DCSILK_HEADER_BUCKETS=N.

Note
Must be a power of two for efficient bucket indexing.

◆ csilk_json_t

#define csilk_json_t (   c,
  status,
  type,
  ptr 
)    csilk_json_reflect(c, status, #type, ptr)

Convenience macro for sending a reflected struct as JSON response. Wraps csilk_json_reflect, automatically stringifying the type name.

Parameters
cThe request context.
statusHTTP status code.
typeThe struct type (used with #type to get the name).
ptrPointer to the struct instance.

◆ CSILK_LOG_D

#define CSILK_LOG_D (   ...)     _csilk_log_internal(CSILK_LOG_DEBUG, __FILE__, __LINE__, __func__, __VA_ARGS__)

Log a DEBUG-level message.

◆ CSILK_LOG_E

#define CSILK_LOG_E (   ...)     _csilk_log_internal(CSILK_LOG_ERROR, __FILE__, __LINE__, __func__, __VA_ARGS__)

Log an ERROR-level message.

◆ CSILK_LOG_F

#define CSILK_LOG_F (   ...)     _csilk_log_internal(CSILK_LOG_FATAL, __FILE__, __LINE__, __func__, __VA_ARGS__)

Log a FATAL-level message.

◆ CSILK_LOG_I

#define CSILK_LOG_I (   ...)     _csilk_log_internal(CSILK_LOG_INFO, __FILE__, __LINE__, __func__, __VA_ARGS__)

Log an INFO-level message.

◆ CSILK_LOG_STRUCT

#define CSILK_LOG_STRUCT (   level,
  extra,
  ... 
)     _csilk_log_structured(level, __FILE__, __LINE__, __func__, extra, __VA_ARGS__)

Log a structured JSON message (only meaningful when json_format is on).

Parameters
levelLog level.
extracJSON* with extra fields (can be NULL).
...printf-style format and args for the message string.

◆ CSILK_LOG_T

#define CSILK_LOG_T (   ...)     _csilk_log_internal(CSILK_LOG_TRACE, __FILE__, __LINE__, __func__, __VA_ARGS__)

Log a TRACE-level message.

◆ CSILK_LOG_W

#define CSILK_LOG_W (   ...)     _csilk_log_internal(CSILK_LOG_WARN, __FILE__, __LINE__, __func__, __VA_ARGS__)

Log a WARN-level message.

◆ CSILK_MAX_PARAMS

#define CSILK_MAX_PARAMS   20

Maximum number of URL path parameters that can be extracted from a single request. Parameters beyond this limit are silently ignored. Tune if your routes contain more than 20 dynamic segments.

◆ csilk_OPTIONS

#define csilk_OPTIONS (   group,
  path,
  handler 
)    csilk_group_add_route(group, "OPTIONS", path, handler)

Register an OPTIONS route on the group.

◆ csilk_PATCH

#define csilk_PATCH (   group,
  path,
  handler 
)    csilk_group_add_route(group, "PATCH", path, handler)

Register a PATCH route on the group.

◆ csilk_POST

#define csilk_POST (   group,
  path,
  handler 
)    csilk_group_add_route(group, "POST", path, handler)

Register a POST route on the group.

◆ csilk_PUT

#define csilk_PUT (   group,
  path,
  handler 
)    csilk_group_add_route(group, "PUT", path, handler)

Register a PUT route on the group.

◆ CSILK_ROUTE

#define CSILK_ROUTE (   r,
  method,
  path,
  handlers,
  handler_count,
  input_type,
  output_type,
  summary,
  desc 
)
Value:
method, \
path, \
handlers, \
handler_count, \
path, \
input_type, \
output_type, \
summary, \
desc)
void csilk_router_add_extended(csilk_router_t *r, const char *method, const char *path, csilk_handler_t *handlers, size_t handler_count, const char *path_pattern, const char *input_type, const char *output_type, const char *summary, const char *description)
Register a route with full OpenAPI/reflection metadata.
Definition router.c:452

Convenience macro to register a route with metadata.

Automatically passes path as both the URL pattern and the documentation path pattern. Wraps csilk_router_add_extended.

◆ CSILK_STATUS_BAD_GATEWAY

#define CSILK_STATUS_BAD_GATEWAY   502

◆ CSILK_STATUS_BAD_REQUEST

#define CSILK_STATUS_BAD_REQUEST   400

◆ CSILK_STATUS_CONFLICT

#define CSILK_STATUS_CONFLICT   409

◆ CSILK_STATUS_CONTINUE

#define CSILK_STATUS_CONTINUE   100

◆ CSILK_STATUS_CREATED

#define CSILK_STATUS_CREATED   201

◆ CSILK_STATUS_FORBIDDEN

#define CSILK_STATUS_FORBIDDEN   403

◆ CSILK_STATUS_FOUND

#define CSILK_STATUS_FOUND   302

◆ CSILK_STATUS_GATEWAY_TIMEOUT

#define CSILK_STATUS_GATEWAY_TIMEOUT   504

◆ CSILK_STATUS_GONE

#define CSILK_STATUS_GONE   410

◆ CSILK_STATUS_INTERNAL_SERVER_ERROR

#define CSILK_STATUS_INTERNAL_SERVER_ERROR   500

◆ CSILK_STATUS_METHOD_NOT_ALLOWED

#define CSILK_STATUS_METHOD_NOT_ALLOWED   405

◆ CSILK_STATUS_MOVED_PERMANENTLY

#define CSILK_STATUS_MOVED_PERMANENTLY   301

◆ CSILK_STATUS_NO_CONTENT

#define CSILK_STATUS_NO_CONTENT   204

◆ CSILK_STATUS_NOT_FOUND

#define CSILK_STATUS_NOT_FOUND   404

◆ CSILK_STATUS_NOT_IMPLEMENTED

#define CSILK_STATUS_NOT_IMPLEMENTED   501

◆ CSILK_STATUS_NOT_MODIFIED

#define CSILK_STATUS_NOT_MODIFIED   304

◆ CSILK_STATUS_OK

#define CSILK_STATUS_OK   200

◆ CSILK_STATUS_PARTIAL_CONTENT

#define CSILK_STATUS_PARTIAL_CONTENT   206

◆ CSILK_STATUS_PAYLOAD_TOO_LARGE

#define CSILK_STATUS_PAYLOAD_TOO_LARGE   413

◆ CSILK_STATUS_PAYMENT_REQUIRED

#define CSILK_STATUS_PAYMENT_REQUIRED   402

◆ CSILK_STATUS_RANGE_NOT_SATISFIABLE

#define CSILK_STATUS_RANGE_NOT_SATISFIABLE   416

◆ CSILK_STATUS_REQUEST_TIMEOUT

#define CSILK_STATUS_REQUEST_TIMEOUT   408

◆ CSILK_STATUS_SERVICE_UNAVAILABLE

#define CSILK_STATUS_SERVICE_UNAVAILABLE   503

◆ CSILK_STATUS_SWITCHING_PROTOCOLS

#define CSILK_STATUS_SWITCHING_PROTOCOLS   101

◆ CSILK_STATUS_TEMPORARY_REDIRECT

#define CSILK_STATUS_TEMPORARY_REDIRECT   307

◆ CSILK_STATUS_TOO_MANY_REQUESTS

#define CSILK_STATUS_TOO_MANY_REQUESTS   429

◆ CSILK_STATUS_UNAUTHORIZED

#define CSILK_STATUS_UNAUTHORIZED   401

◆ CSILK_STATUS_UNSUPPORTED_MEDIA_TYPE

#define CSILK_STATUS_UNSUPPORTED_MEDIA_TYPE   415

◆ CSILK_STATUS_URI_TOO_LONG

#define CSILK_STATUS_URI_TOO_LONG   414

◆ CSILK_VALID_EMAIL

#define CSILK_VALID_EMAIL    (1 << 3)

Value must match a basic email format (contains '@' and a \ dot).

◆ CSILK_VALID_INT

#define CSILK_VALID_INT   (1 << 1)

Value must parse as a valid integer.

◆ CSILK_VALID_REQUIRED

#define CSILK_VALID_REQUIRED   (1 << 0)

Field must be present (non-NULL, non-empty).

◆ CSILK_VALID_STRING

#define CSILK_VALID_STRING    (1 << 2)

Value must be a string (always true for form/query values; \ included for symmetry).

◆ CSILK_VERSION

#define CSILK_VERSION   "0.2.3"

Csilk framework version string (MAJOR.MINOR.PATCH). Used for identification in logs, headers, and the OpenAPI spec.

Typedef Documentation

◆ csilk_arena_t

typedef struct csilk_arena_s csilk_arena_t

Opaque arena allocator type.

Provides bump-allocation semantics: memory is allocated in large chunks and individual allocations are never freed — the entire arena is reset or freed at once. Ideal for request-scoped allocations because it is faster than malloc/free and produces zero fragmentation.

Note
Not thread-safe — each request should have its own arena.

◆ csilk_auth_validator_t

typedef int(* csilk_auth_validator_t) (const char *token)

Authentication validator callback.

Receives the token extracted from the Authorization header and returns non-zero if the token is valid.

Parameters
tokenThe bearer token string extracted from the request.
Returns
Non-zero if the token is valid, 0 to reject.

◆ csilk_ctx_hook_handler_t

typedef void(* csilk_ctx_hook_handler_t) (csilk_ctx_t *c)

Callback signature for request/connection-level hooks.

Parameters
cThe request context.

◆ csilk_handler_t

typedef void(* csilk_handler_t) (csilk_ctx_t *c)

Function pointer for route handlers and middleware.

Every handler receives the per-request context and operates on it (reading request data, setting response data, calling csilk_next to pass control to the next handler in the chain, etc.).

Parameters
cThe per-request context.
Examples
/home/runner/work/csilk/csilk/include/csilk/app/app.h.

◆ csilk_mq_handler_t

typedef void(* csilk_mq_handler_t) (csilk_mq_ctx_t *ctx)

MQ handler signature for middleware and subscribers.

Parameters
ctxMQ context providing topic, payload, and chain control.

◆ csilk_mq_worker_t

typedef void(* csilk_mq_worker_t) (const char *topic, const void *payload, size_t len)

Signature for a background MQ worker function.

Parameters
topicThe topic string (valid only during the call).
payloadOpaque data pointer.
lenByte length of payload.

◆ csilk_multipart_handler_t

typedef void(* csilk_multipart_handler_t) (csilk_multipart_part_t *part)

Callback invoked for each part during multipart parsing.

Parameters
partThe parsed part. The data pointer is valid only during the callback invocation — do not store the pointer for later use (copy the data if needed).

◆ csilk_server_hook_handler_t

typedef void(* csilk_server_hook_handler_t) (csilk_server_t *s)

Callback signature for server-level hooks.

Parameters
sThe server instance.

Enumeration Type Documentation

◆ csilk_hook_type_t

Lifecycle hook types for the server and individual requests.

Hooks allow users to inject custom logic at well-defined points in the server and request lifecycle without modifying the framework code.

Enumerator
CSILK_HOOK_SERVER_START 

Invoked just before the event loop starts (server-level).

CSILK_HOOK_SERVER_STOP 

Invoked when the server is shutting down (server-level).

CSILK_HOOK_CONN_OPEN 

Invoked when a new TCP connection is accepted (context-level).

CSILK_HOOK_CONN_CLOSE 

Invoked when a TCP connection is closed (context-level).

CSILK_HOOK_REQUEST_BEGIN 

Invoked when the full HTTP request has been parsed (context-level).

CSILK_HOOK_REQUEST_END 

Invoked after the response has been sent (context-level).

CSILK_HOOK_COUNT 

Sentinel — total number of hook types. Not a valid hook type.

◆ csilk_log_level_t

Log severity levels.

Levels are ordered: messages at or above the configured minimum level are emitted. CSILK_LOG_FATAL terminates the process after logging.

Enumerator
CSILK_LOG_TRACE 

Finest-grained diagnostic messages (development only).

CSILK_LOG_DEBUG 

Debugging information useful during development.

CSILK_LOG_INFO 

Normal operational messages (e.g., request completed).

CSILK_LOG_WARN 

Warning conditions that are not errors (e.g., slow request).

CSILK_LOG_ERROR 

Error conditions that still allow the server to continue.

CSILK_LOG_FATAL 

Fatal errors; the server will exit after logging.

Function Documentation

◆ _csilk_log_internal()

void _csilk_log_internal ( csilk_log_level_t  lv,
const char *  file,
int  line,
const char *  func,
const char *  fmt,
  ... 
)

Internal log function (use macros instead).

Parameters
lvLog severity level.
fileSource file name (FILE).
lineSource line number (LINE).
funcFunction name (func).
fmtPrintf-style format string.
...Format arguments.

Internal log function (use macros instead).

Formats the variadic message via vsnprintf, acquires the logger mutex, checks file rotation (if file logging and max_file_size exceeded), and writes the entry as either JSON or plain text depending on configuration.

Parameters
lvLog severity level (filtered against g_logger.config.level).
fileSource file name (provided by CSILK_LOG_* macro).
lineSource line number (provided by CSILK_LOG_* macro).
funcFunction name (provided by CSILK_LOG_* macro).
fmtprintf-style format string.
...Variadic arguments for the format string.
Note
Use the CSILK_LOG_* macros (CSILK_LOG_I, CSILK_LOG_E, etc.) instead of calling this function directly. The macros automatically supply FILE, LINE, and func.

◆ _csilk_log_structured()

void _csilk_log_structured ( csilk_log_level_t  lv,
const char *  file,
int  line,
const char *  func,
cJSON *  extra,
const char *  fmt,
  ... 
)

Log a structured JSON message with extra key-value fields.

Produces a JSON log line with the standard fields (time/level/file/line/func/msg) plus any fields in extra. If json_format is off this behaves like a normal log line (extra fields are ignored).

Parameters
lvLog severity level.
fileSource file name (FILE).
lineSource line number (LINE).
funcFunction name (func).
extracJSON object with extra structured fields (can be NULL). Ownership is taken — do not use after the call.
fmtPrintf-style format string for the log message.
...Format arguments.

Log a structured JSON message with extra key-value fields.

Like _csilk_log_internal() but accepts an additional cJSON object of extra fields. In JSON mode, the extra fields are merged into the output. In text mode, the extra fields are discarded (cJSON_Delete is called).

Parameters
lvLog severity level.
fileSource file name.
lineSource line number.
funcFunction name.
extracJSON object of extra fields to include (ownership taken).
fmtprintf-style format string.
...Variadic arguments.
Note
Use the CSILK_LOG_KV macro instead of calling this directly.

◆ csilk_abort()

void csilk_abort ( csilk_ctx_t *  c)

Immediately abort the handler chain.

No further handlers or middleware run (except code after csilk_next in the current handler that checks csilk_is_aborted). The response accumulated so far is sent to the client.

Parameters
cThe request context.

Immediately abort the handler chain.

Sets the aborted flag on the context. Subsequent calls to csilk_next() are ignored. The response is still sent once the current handler returns.

Parameters
cThe request context.
Note
This does NOT close the connection — it only prevents further handlers from executing.

◆ csilk_add_header()

void csilk_add_header ( csilk_ctx_t *  c,
const char *  key,
const char *  value 
)

Append a response header, preserving any existing value(s).

Unlike csilk_set_header, this adds another entry rather than replacing the existing one. Useful for headers like Set-Cookie that may appear multiple times.

Parameters
cThe request context.
keyThe header field name.
valueThe header field value to append.

Append a response header, preserving any existing value(s).

Unlike csilk_set_header(), this function prepends a new header node without removing any existing values for the same key. This is useful for headers like Set-Cookie where multiple values are allowed.

Parameters
cThe request context.
keyHeader key.
valueHeader value.
Note
Both key and value are duplicated into arena memory.

◆ csilk_arena_alloc()

void * csilk_arena_alloc ( csilk_arena_t arena,
size_t  size 
)

Allocate zero-initialised memory from an arena.

The returned memory is valid until csilk_arena_free, csilk_arena_reset, or csilk_ctx_cleanup. No individual free() is required.

Parameters
arenaThe arena allocator.
sizeNumber of bytes to allocate.
Returns
Pointer to the allocated block (always suitably aligned), or NULL if the allocation failed (the arena's malloc failed).

Allocate zero-initialised memory from an arena.

Returns memory from the current chunk if there is room; otherwise allocates a new chunk large enough to satisfy the request. The returned memory is zero-initialized only by virtue of being freshly allocated from the OS.

Parameters
arenaThe arena allocator (must not be NULL).
sizeNumber of bytes to allocate. The actual allocation is rounded up to the nearest multiple of 8 for alignment.
Returns
Pointer to the allocated block, or NULL on allocation failure.
Note
The returned pointer must NOT be freed individually; all arena memory is reclaimed via csilk_arena_free() or csilk_arena_reset().

◆ csilk_arena_free()

void csilk_arena_free ( csilk_arena_t arena)

Free all memory chunks owned by the arena.

After this call the arena pointer is invalid and must not be used again.

Parameters
arenaThe arena allocator to destroy.

Free all memory chunks owned by the arena.

Walks the linked list of chunks, frees each one, then frees the arena header. After this call the arena pointer is invalid and must not be used.

Parameters
arenaThe arena to destroy (may be NULL).
Note
Safe to call with NULL — it is a no-op.

◆ csilk_arena_new()

csilk_arena_t * csilk_arena_new ( size_t  default_chunk_size)

Create a new arena allocator.

The arena allocates memory in fixed-size chunks and hands out bump-allocated blocks. When the current chunk is exhausted a new one is allocated.

Parameters
default_chunk_sizeInitial chunk size in bytes. Pass 0 for a sensible default (typically 4–8 KB).
Returns
Pointer to the new arena, or NULL if malloc fails.

Allocates and initializes an arena memory manager. The arena allocates memory in chunks of at least default_chunk_size bytes. Individual allocations within the arena are never freed separately; instead, all memory is reclaimed at once by calling csilk_arena_free() or csilk_arena_reset().

Parameters
default_chunk_sizeMinimum size in bytes for each new chunk. Pass 0 to let the implementation choose a default.
Returns
Pointer to the new arena, or NULL on allocation failure.
Note
The returned arena must be freed with csilk_arena_free().
This function is not thread-safe; each thread should use its own arena.

◆ csilk_arena_reset()

void csilk_arena_reset ( csilk_arena_t arena)

Reset the arena without freeing its chunks.

The arena can be reused after a reset — subsequent allocations reuse the existing chunk memory. Useful for pooling arenas across requests to reduce malloc pressure.

Parameters
arenaThe arena allocator to reset.

Reset the arena without freeing its chunks.

Sets the used counter to zero on every chunk in the chain, making all arena memory available for new allocations. No system calls (malloc/free) are performed, making this much cheaper than csilk_arena_free() + _new().

Parameters
arenaThe arena to reset (may be NULL).
Note
Useful for request-scoped arenas that are recycled between requests.
Safe to call with NULL — it is a no-op.

◆ csilk_arena_strdup()

char * csilk_arena_strdup ( csilk_arena_t arena,
const char *  s 
)

Duplicate a NUL-terminated string using the arena allocator.

Parameters
arenaThe arena allocator.
sSource string to duplicate. Must be NUL-terminated.
Returns
A copy of s allocated from arena, or NULL on allocation failure. If s is NULL the behaviour is undefined.

Duplicate a NUL-terminated string using the arena allocator.

Allocates enough arena memory for a copy of s, including the null terminator, and copies the string contents.

Parameters
arenaThe arena allocator.
sSource string to duplicate.
Returns
Pointer to the new string in arena memory, or NULL if s is NULL or on allocation failure.
Note
The result is subject to the same lifetime rules as other arena allocations — it lives until the arena is freed or reset.

◆ csilk_arena_strndup()

char * csilk_arena_strndup ( csilk_arena_t arena,
const char *  s,
size_t  n 
)

Duplicate n bytes of a string using the arena allocator.

Parameters
arenaThe arena allocator.
sSource string to duplicate.
nNumber of bytes to copy.
Returns
A copy of n bytes of s allocated from arena, or NULL on allocation failure. If s is NULL the behaviour is undefined.

Allocates n + 1 bytes of arena memory, copies n bytes from s, and adds a null terminator.

Parameters
arenaThe arena allocator.
sSource string to duplicate.
nNumber of bytes to copy.
Returns
Pointer to the new string in arena memory, or NULL if s is NULL or on allocation failure.

◆ csilk_auth_middleware()

void csilk_auth_middleware ( csilk_ctx_t *  c,
csilk_auth_validator_t  validator 
)

Simple token-based authentication middleware.

Extracts the Bearer token from the Authorization header, passes it to validator, and aborts the chain with 401 if validation fails.

Parameters
cThe request context.
validatorCallback that inspects the token and returns 1 for valid, 0 for invalid. Called synchronously on the event-loop thread.

Simple token-based authentication middleware.

Extracts the Bearer token from the Authorization header and validates it using the caller-provided validator callback. If validation fails, a 401 Unauthorized response is sent with a WWW-Authenticate header, and the request pipeline is aborted.

Parameters
cThe request context.
validatorCallback that receives the token string and returns non-zero if the token is valid, zero otherwise.
Note
This middleware does NOT handle token parsing beyond stripping the "Bearer " prefix — use the JWT middleware for structured token verification. Should be registered early in the pipeline (after request_id and session, before route handlers).
Warning
The validator must be stateless or thread-safe, as it may be invoked from multiple worker threads concurrently.

◆ csilk_bind_json()

cJSON * csilk_bind_json ( csilk_ctx_t *  c)

Bind the request body (JSON) to a cJSON object.

Parses the raw request body as JSON. The returned cJSON object is heap-allocated and must be freed by the caller with cJSON_Delete.

Parameters
cThe request context.
Returns
A cJSON object parsed from the body, or NULL if the body is empty or is not valid JSON.

Bind the request body (JSON) to a cJSON object.

Parameters
cThe request context.
Returns
A cJSON object parsed from the request body, or NULL if the body is NULL or the JSON is invalid.
Note
The caller owns the returned cJSON object and must free it with cJSON_Delete(). For error details use csilk_bind_json_err().

◆ csilk_bind_json_err()

cJSON * csilk_bind_json_err ( csilk_ctx_t *  c,
const char **  error 
)

Bind request body to cJSON with a descriptive error message.

Like csilk_bind_json, but sets error to a static string describing why parsing failed.

Parameters
cThe request context.
[out]errorPointer to receive a static error string (do NOT free). Unchanged on success.
Returns
A cJSON object, or NULL on parse failure (error is set).

Bind request body to cJSON with a descriptive error message.

Like csilk_bind_json() but sets error to a descriptive string on failure (e.g., "Null context", "No request body", or the cJSON parse error position).

Parameters
cThe request context.
error[out] Optional pointer to receive a static error string.
Returns
A cJSON object parsed from the request body, or NULL on failure.
Note
The caller owns the returned cJSON object and must free it. The error string is a static pointer (do not free).

◆ csilk_bind_reflect()

int csilk_bind_reflect ( csilk_ctx_t *  c,
const char *  type_name,
void *  ptr 
)

Parse the JSON request body into a struct registered via reflection.

Combines csilk_bind_json_err and csilk_json_unmarshal into one call. The struct at ptr must have been registered with CSILK_REGISTER_REFLECT or csilk_reflect_register.

Parameters
cThe request context.
type_nameRegistered type name string (must match the name used in csilk_reflect_register).
[out]ptrPointer to the struct instance to populate.
Returns
1 on success, 0 on failure (with the response set to a JSON error).

Parse the JSON request body into a struct registered via reflection.

Deserializes the JSON request body into the provided struct pointer using the csilk reflection engine. If type_name is NULL, the type is inferred from the current handler's input_type metadata (if available).

Parameters
cThe request context.
type_nameRegistered type name (e.g., "my_request_t"), or NULL to infer from the route handler's metadata.
ptrPointer to the target struct to populate.
Returns
1 on success, 0 on failure (NULL context, no body, type not found, or JSON parse error).
Note
Uses csilk_json_unmarshal() internally. The struct should have been registered via CSILK_REGISTER_REFLECT().

◆ csilk_config_free()

void csilk_config_free ( csilk_config_t config)

Free all heap-allocated strings inside a configuration.

Does NOT free the csilk_config_t struct itself (only its members). Safe to call on a zero-initialised struct.

Parameters
configPointer to the configuration struct whose fields should be freed.

Free all heap-allocated strings inside a configuration.

Releases memory for logger.file_path, cors allow_origin/methods/headers, static_files root_dir/prefix, and middleware.auth_token. Each pointer is set to NULL after being freed, making repeated calls safe.

Parameters
configConfiguration structure whose strings will be freed.
Note
Does NOT free the config struct itself — only its internal heap allocations. Safe to call with NULL.

◆ csilk_config_validate()

int csilk_config_validate ( const csilk_config_t config,
const char **  error_msg 
)

Validate configuration values for semantic correctness.

Checks for out-of-range ports, conflicting settings, missing required paths, etc.

Parameters
configPointer to the configuration to validate.
[out]error_msgOptional pointer to receive a static error string (do NOT free). Unchanged on success.
Returns
0 if the configuration is valid, -1 if invalid (error_msg is set).

Checks that port is in range [1, 65535], timeouts are non-negative, max_body_size and max_header_size are positive, listen_backlog and worker_threads are >= 1, and that optional features (rate_limit, static_files, auth middleware) have their required sub-fields set when enabled. Returns the first validation error found.

Parameters
configConfiguration to validate.
error_msg[out] Optional pointer to receive a human-readable error string. The error string is a static literal; do not free it.
Returns
0 if valid, -1 if validation fails (error_msg is set on failure).

◆ csilk_cors_middleware()

void csilk_cors_middleware ( csilk_ctx_t *  c,
const csilk_cors_config_t config 
)

CORS middleware — handles preflight and adds CORS headers.

Must be called as a route or group middleware. For preflight OPTIONS requests the middleware sends the appropriate headers and aborts the chain (status 204). For other requests the CORS headers are added and the chain continues.

Parameters
cThe request context.
configCORS settings. Must remain valid for the call duration.

CORS middleware — handles preflight and adds CORS headers.

Applies the configured Access-Control-* headers to every response. When the Vary: Origin header is set for non-wildcard origins. If the incoming request is an OPTIONS preflight (indicated by Access-Control-Request-Method), the middleware short-circuits with a 204 No Content response instead of forwarding to downstream handlers.

Parameters
cThe request context.
configPointer to a CORS configuration struct specifying allowed origins, methods, headers, credentials, and max-age. Must remain valid for the duration of the call.
Note
This middleware always calls csilk_next() for non-preflight requests after setting response headers.
Warning
The config pointer is not deep-copied; the caller must ensure it lives long enough for the current request.

◆ csilk_csrf_generate_token()

int csilk_csrf_generate_token ( char *  buf,
size_t  buf_size 
)

Generate a cryptographically random CSRF token.

Produces a hex-encoded 32-byte (256-bit) random token.

Parameters
[out]bufOutput buffer. Must be at least 33 bytes for the 64-character hex string plus NUL terminator.
buf_sizeSize of buf in bytes.
Returns
0 on success, -1 if buf_size is too small or the RNG fails.

Reads 16 bytes from /dev/urandom and formats them as a 32-character hex string (plus null terminator). If /dev/urandom cannot be opened, falls back to a weak PRNG seeded with time XOR pid.

Parameters
bufOutput buffer to receive the null-terminated hex token.
buf_sizeSize of the output buffer. Must be at least 33 bytes.
Returns
0 on success, -1 if buf is NULL, buf_size < 33, or fread fails.
Warning
The fallback path uses rand_r() which is NOT cryptographically secure. Production deployments should always ensure /dev/urandom is available.

◆ csilk_csrf_middleware()

void csilk_csrf_middleware ( csilk_ctx_t *  c)

Stateless CSRF protection middleware.

Checks for a valid CSRF token in the request (via header or form field) on state-changing methods (POST, PUT, DELETE, PATCH). If the token is missing or invalid the chain is aborted with 403 Forbidden.

Parameters
cThe request context.

Stateless CSRF protection middleware.

On safe HTTP methods (GET, HEAD, OPTIONS), the middleware ensures a CSRF cookie called "csrf_token" is present (generating one if missing) and proceeds to the next handler.

On state-changing methods (POST, PUT, DELETE, etc.), it validates the X-CSRF-Token request header against the csrf_token cookie. If the tokens do not match or the header is absent, a 403 Forbidden response is returned and the pipeline is aborted.

Parameters
cThe request context.
Note
Must be registered before any handler that mutates server state.
Warning
The token is generated from /dev/urandom when available, with a weak fallback (time + pid). In high-security deployments, ensure /dev/urandom is accessible.

◆ csilk_ctx_cleanup()

void csilk_ctx_cleanup ( csilk_ctx_t *  c)

Release all memory and resources associated with a request context.

Frees the arena allocator, destroys header hash tables, and resets the context struct. Called automatically by the framework after the response is sent. Not intended for direct use in user code.

Parameters
cThe request context to clean up.

Release all memory and resources associated with a request context.

Resets the arena allocator for reuse, frees URL path parameters, request body, and path strings. Clears all header maps (request, response, query, form). Cleans up storage items and resets all state flags for the next request. Called after each HTTP request is fully processed.

Parameters
cThe request context.

◆ csilk_ctx_get_mq()

csilk_mq_t * csilk_ctx_get_mq ( csilk_ctx_t *  c)

Get the internal MQ instance from the context.

Parameters
cThe request context.
Returns
Pointer to csilk_mq_t, or NULL if not available.

◆ csilk_ctx_get_server()

csilk_server_t * csilk_ctx_get_server ( csilk_ctx_t *  c)

Get the server instance associated with the current context.

Parameters
cThe request context.
Returns
Server handle, or NULL on error.

Get the server instance associated with the current context.

Parameters
cThe request context.
Returns
Pointer to csilk_server_t.

◆ csilk_db_exec()

int csilk_db_exec ( csilk_db_pool_t pool,
const char *  sql 
)

Execute a statement that returns no result rows.

Suitable for INSERT, UPDATE, DELETE, CREATE TABLE, etc.

Parameters
poolConnection pool.
sqlSQL statement.
Returns
0 on success, -1 on failure.

Execute a statement that returns no result rows.

◆ csilk_db_init()

void csilk_db_init ( void  )

Initialise the database subsystem.

Registers built-in drivers (SQLite3, etc.). Must be called once before any csilk_db_pool_new call. Safe to call multiple times.

Registers all built-in drivers (SQLite3, MySQL, PostgreSQL, etc.). Must be called once before any csilk_db_pool_new call. Safe to call multiple times.

◆ csilk_db_pool_free()

void csilk_db_pool_free ( csilk_db_pool_t pool)

Free a database pool and disconnect.

Closes the underlying connection and frees the pool struct.

Parameters
poolThe pool to free. Must not be NULL.

Free a database pool and disconnect.

Teardown

  1. Call driver->disconnect() — closes the database connection.
  2. Destroy the pool mutex.
  3. Free the pool struct.

The driver's free_result is not called here — any outstanding results must have been freed by the caller.

◆ csilk_db_pool_new()

csilk_db_pool_t * csilk_db_pool_new ( const char *  driver_name,
const char *  dsn 
)

Create a new database connection pool.

The pool maintains a single connection (or opens a new one on demand). All database operations go through the pool, which provides mutex-based thread safety.

Parameters
driver_nameDriver identifier (e.g., "sqlite"). Must have been registered via csilk_db_register_driver or the built-in init.
dsnData source name (driver-specific, e.g., "file:test.db").
Returns
A new pool instance, or NULL if the driver is unknown or connection fails.

Create a new database connection pool.

Pool creation

  1. Look up the driver by name in the global registry.
  2. calloc the pool struct, init the pool mutex.
  3. Call driver->connect() with the DSN — this may block for network round-trips.
  4. On success: return the pool. On failure: destroy mutex, free pool.

The pool holds exactly ONE connection (mutex-serialized access). This is intentional — the caller is expected to manage a pool of pools if concurrency is needed.

Parameters
driver_nameRegistered driver name (e.g., "sqlite3").
dsnData source name (e.g., "/tmp/test.db" or "host=...").

◆ csilk_db_query_json()

cJSON * csilk_db_query_json ( csilk_db_pool_t pool,
const char *  sql 
)

Execute a SELECT query and return the result as a JSON array.

Each row becomes a JSON object keyed by column name.

Parameters
poolConnection pool.
sqlSQL SELECT statement.
Returns
A cJSON array of row objects (caller must free with cJSON_Delete), or NULL on failure.

Execute a SELECT query and return the result as a JSON array.

◆ csilk_db_query_param_json()

cJSON * csilk_db_query_param_json ( csilk_db_pool_t pool,
const char *  sql,
const char **  params 
)

Execute a parameterised SELECT query with ? placeholders.

Each ? in sql is replaced with the corresponding value from params (The driver handles escaping internally). The result is returned as a JSON array.

Parameters
poolConnection pool.
sqlSQL with ? placeholders.
paramsNULL-terminated array of string values for the placeholders. The array must end with a NULL sentinel.
Returns
A cJSON array (caller must free), or NULL on failure.

Execute a parameterised SELECT query with ? placeholders.

String substitution algorithm

  1. Pre-compute the final SQL length: original SQL + sum of all param lengths + 2 bytes per param for surrounding single quotes.
  2. Allocate a buffer of that size.
  3. Walk the original SQL character by character:
    • '?' → replace with 'value' (single-quote wrapped)
    • any other char → copy verbatim.
  4. Execute the constructed SQL via csilk_db_query_json_locked().

Security caveat

This is naive string substitution — NOT prepared-statement binding. Parameter values are NOT escaped for SQL special characters. A parameter containing "' OR '1'='1" will inject into the SQL verbatim.

Parameters
poolDatabase pool.
sqlSQL pattern with ? placeholders.
paramsNULL-terminated array of string values.

◆ csilk_file()

void csilk_file ( csilk_ctx_t *  c,
const char *  file_path 
)

Serve a specific file from the local filesystem.

Like csilk_static, this function offloads file I/O to a worker thread and uses zero-copy transmission (sendfile).

Parameters
cThe request context.
file_pathAbsolute or relative path to the file.

Serve a specific file from the local filesystem.

Offloads file open/stat operations to the libuv thread pool. The response is sent via the normal _csilk_send_response() path using zero-copy.

Parameters
cThe request context.
file_pathPath to the file to serve.

◆ csilk_generate_openapi_json()

cJSON * csilk_generate_openapi_json ( csilk_router_t router,
const char *  title,
const char *  version,
const char *  description 
)

Generate an OpenAPI 3.0 specification JSON from the router.

Traverses all registered routes and uses the reflection system to build JSON schemas for request bodies and responses. Produces a complete OpenAPI document suitable for use with Swagger UI, Redoc, etc.

Parameters
routerThe router instance.
titleAPI title for the OpenAPI info block.
versionAPI version for the OpenAPI info block.
descriptionAPI description (optional — pass NULL to omit).
Returns
A cJSON object representing the full OpenAPI spec. Caller must free with cJSON_Delete.

Generate an OpenAPI 3.0 specification JSON from the router.

Builds the full OpenAPI JSON structure including:

  • openapi version field ("3.0.3")
  • info section (title, version, description)
  • paths section (one entry per route, with parameters, requestBody, and responses)
  • components/schemas section (auto-generated from all registered reflection types)

Path parameters are extracted from the route patterns and converted to OpenAPI format. Request/response schemas are generated from input_type and output_type metadata using the reflection engine.

Parameters
routerThe router instance containing registered routes.
titleAPI title for the info section (pass NULL for default).
versionAPI version string (pass NULL for default "1.0.0").
descriptionAPI description (may be NULL).
Returns
A cJSON object representing the full OpenAPI document. Caller must free with cJSON_Delete(). Returns NULL if router is NULL or allocation fails.

◆ csilk_get()

void * csilk_get ( csilk_ctx_t *  c,
const char *  key 
)

Retrieve an opaque value from the request context.

Parameters
cThe request context.
keyNUL-terminated key name.
Returns
The value pointer previously stored with csilk_set, or NULL if key was never set (or was explicitly set to NULL — see the note on csilk_set).

Retrieve an opaque value from the request context.

If a storage driver is set on the context, delegates to it. Otherwise, searches the internal linked list for the given key.

Parameters
cThe request context.
keyStorage key to look up.
Returns
The value pointer previously stored with csilk_set(), or NULL if the key is not found or the context is NULL.

◆ csilk_get_arena()

csilk_arena_t * csilk_get_arena ( csilk_ctx_t *  c)

Get the arena allocator associated with the request context.

Use this for all short-lived per-request allocations. Memory is automatically reclaimed in csilk_ctx_cleanup and does not need individual free() calls.

Parameters
cThe request context.
Returns
Pointer to the arena allocator.

Get the arena allocator associated with the request context.

The arena is request-scoped and created automatically on each new connection. Use it for short-lived allocations that should live for the duration of the request.

Parameters
cThe request context.
Returns
Pointer to the arena, or NULL if context is NULL.
Note
All arena memory is reclaimed when the request completes (via csilk_arena_reset() in csilk_ctx_cleanup()).

◆ csilk_get_body()

const char * csilk_get_body ( csilk_ctx_t *  c,
size_t *  out_len 
)

Get the raw request body and its length.

Only valid after the full body has been parsed. Returns NULL for methods that have no body (GET, HEAD, etc.) or when the body is empty.

Parameters
cThe request context.
[out]out_lenOptional pointer to receive the body length in bytes. May be NULL if the caller does not need the length.
Returns
Pointer to the raw body data (not NUL-terminated), or NULL if no body is present.

Get the raw request body and its length.

Parameters
cThe request context.
out_len[out] If non-NULL, receives the body length in bytes.
Returns
Pointer to the raw request body, or NULL if no body or NULL context.
Note
The returned pointer is heap-allocated and freed in csilk_ctx_cleanup().

◆ csilk_get_body_len()

size_t csilk_get_body_len ( csilk_ctx_t *  c)

Get the length of the raw request body.

Convenience shortcut for csilk_get_body(c, &len) when only the length is needed.

Parameters
cThe request context.
Returns
Body length in bytes, or 0 if no body is present.

Get the length of the raw request body.

Parameters
cThe request context.
Returns
Body length in bytes, or 0 if the context is NULL or body is empty.

◆ csilk_get_client_ip()

const char * csilk_get_client_ip ( csilk_ctx_t *  c)

Get the client's IP address.

Checks the X-Forwarded-For / X-Real-IP headers first (if present), then falls back to the socket peer address.

Parameters
cThe request context.
Returns
A NUL-terminated IP string, or NULL if the address cannot be determined. Valid until csilk_ctx_cleanup.

Get the client's IP address.

Resolves the client's IP address (IPv4 or IPv6) from the underlying TCP socket using libuv's getpeername. The result is allocated in arena memory so it is valid for the duration of the request.

Parameters
cThe request context.
Returns
A string with the client IP (e.g., "127.0.0.1" or "::1"), or NULL if the context is NULL or the address cannot be resolved.

◆ csilk_get_cookie()

const char * csilk_get_cookie ( csilk_ctx_t *  c,
const char *  name 
)

Get a cookie value by name from the Cookie request header.

Parses the Cookie header on first call and caches the result.

Parameters
cThe request context.
nameThe cookie name.
Returns
The cookie value, or NULL if no cookie with that name exists. Valid until csilk_ctx_cleanup.

Get a cookie value by name from the Cookie request header.

Parses the "Cookie" request header by splitting on "; " and then on "=". Returns the value for the first cookie matching name.

Parameters
cThe request context.
nameCookie name to look up.
Returns
The cookie value string (arena-allocated), or NULL if the cookie is not found, the header is absent, or the context/arena is NULL.
Note
The returned value is URL-decoded only as much as the raw header contains. Cookie attributes (path, domain, etc.) are not supported.

◆ csilk_get_form_field()

const char * csilk_get_form_field ( csilk_ctx_t *  c,
const char *  key 
)

Get a form-urlencoded field value by key.

Only returns meaningful data after csilk_parse_form_urlencoded has been called.

Parameters
cThe request context.
keyThe form field name.
Returns
The field value, or NULL if not found. Valid until csilk_ctx_cleanup.

Get a form-urlencoded field value by key.

Looks up the given key in the request's form_params hash map, populated by a prior call to csilk_parse_form_urlencoded().

Parameters
cThe request context.
keyField name to look up.
Returns
The URL-decoded field value, or NULL if not found.
Note
The returned pointer lives in arena memory.

◆ csilk_get_header()

const char * csilk_get_header ( csilk_ctx_t *  c,
const char *  key 
)

Get a request header value by name (case-insensitive).

Parameters
cThe request context.
keyThe header field name (e.g., "Content-Type").
Returns
The header value string, or NULL if the header is not present. Valid until csilk_ctx_cleanup.

Get a request header value by name (case-insensitive).

Searches the request header hash map. Key comparison uses strcasecmp so "Content-Type" and "content-type" are treated as equivalent.

Parameters
cThe request context.
keyHeader key to look up.
Returns
Header value string, or NULL if the header is not present.
Note
The returned pointer lives in arena memory (valid until arena reset).

◆ csilk_get_method()

const char * csilk_get_method ( csilk_ctx_t *  c)

Get the HTTP method of the current request.

Parameters
cThe request context.
Returns
A NUL-terminated string such as "GET", "POST", etc. The pointer is valid until csilk_ctx_cleanup.

Returns the method string as parsed by the HTTP parser (e.g., "GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS").

Parameters
cThe request context.
Returns
The method string, or NULL if the context is NULL.
Note
The returned pointer is valid until csilk_ctx_cleanup().

◆ csilk_get_param()

const char * csilk_get_param ( csilk_ctx_t *  c,
const char *  key 
)

Get a URL path parameter by key.

Parameters are extracted from the route pattern by the router. For a route /users/:id, csilk_get_param(c, "id") returns the actual value.

Parameters
cThe request context.
keyThe parameter name as defined in the route pattern (e.g., "id").
Returns
The decoded parameter value, or NULL if key is not a known parameter. Valid until csilk_ctx_cleanup.

Get a URL path parameter by key.

Path parameters are extracted from the URL during routing when the route pattern contains :param segments (e.g., "/users/:id").

Parameters
cThe request context.
keyParameter name (as declared in the route pattern without the ':').
Returns
The URL-unescaped parameter value string, or NULL if not found.
Note
The returned pointer is heap-allocated and valid until csilk_ctx_cleanup() is called.

◆ csilk_get_path()

const char * csilk_get_path ( csilk_ctx_t *  c)

Get the decoded URL path of the current request.

The path has percent-encoding removed and the query string stripped.

Parameters
cThe request context.
Returns
The path string (e.g., "/users/42"). Valid until csilk_ctx_cleanup.

Get the decoded URL path of the current request.

Returns the decoded URL path (without the query string). For example, a request to "/foo/bar?id=1" yields path "/foo/bar".

Parameters
cThe request context.
Returns
The URL path string, or NULL if the context is NULL.
Note
The returned pointer is heap-allocated and freed in csilk_ctx_cleanup().

◆ csilk_get_query()

const char * csilk_get_query ( csilk_ctx_t *  c,
const char *  key 
)

Get a query-string parameter by key.

Only works after the request has been fully parsed (always true in handlers). The first value is returned when a key appears multiple times.

Parameters
cThe request context.
keyThe query parameter name.
Returns
The parameter value, or NULL if not present. Valid until csilk_ctx_cleanup.

Get a query-string parameter by key.

Query parameters are populated by csilk_parse_query() which is called automatically during request finalization. The value is URL-decoded.

Parameters
cThe request context.
keyQuery parameter name.
Returns
The URL-decoded value string, or an empty string if the parameter was present without a value, or NULL if the parameter is absent.
Note
The returned pointer lives in arena memory (valid until arena reset).

◆ csilk_get_request_id()

const char * csilk_get_request_id ( csilk_ctx_t *  c)

Get the unique identifier for the current request.

The ID is auto-generated (UUID v4) by the csilk_request_id_middleware or by the server if no middleware is installed.

Parameters
cThe request context.
Returns
A NUL-terminated UUID string (e.g., "f81d4fae-7dec-11d0-a765-00a0c91e6bf6"). Valid until csilk_ctx_cleanup.

Get the unique identifier for the current request.

Returns the UUID v4 request identifier that was generated when the request was first parsed. The ID is formatted as 8-4-4-4-12 hex digits (37 bytes including null terminator).

Parameters
cThe request context.
Returns
Pointer to the request ID string, or NULL if context is NULL.
Note
The ID is generated via csilk_generate_uuid() and stored inline in the context. It is valid for the lifetime of the context.

◆ csilk_get_response_body()

const char * csilk_get_response_body ( csilk_ctx_t *  c,
size_t *  out_len 
)

Get the current response body and its length.

Returns the response body as set by csilk_string, csilk_json, or csilk_set_response_body. Useful in after-response middleware (e.g., logging or post-processing the body).

Parameters
cThe request context.
[out]out_lenOptional pointer to receive the body length in bytes.
Returns
Pointer to the response body, or NULL if no body has been set. The pointer is valid until the response is sent.

Get the current response body and its length.

Parameters
cThe request context.
out_len[out] If non-NULL, receives the response body length.
Returns
Pointer to the response body, or NULL if no body or NULL context.
Note
The body may be managed (arena or heap) depending on how it was set. The caller must not free the returned pointer.

◆ csilk_get_response_header()

const char * csilk_get_response_header ( csilk_ctx_t *  c,
const char *  key 
)

Get a response header value by name (case-insensitive).

Parameters
cThe request context.
keyThe header field name.
Returns
The header value string, or NULL if the header has not been set. Valid until csilk_ctx_cleanup.

Get a response header value by name (case-insensitive).

Searches the response header hash map. Header values retrieved here are those that have been set via csilk_set_header() / csilk_add_header().

Parameters
cThe request context.
keyHeader key to look up.
Returns
Header value string, or NULL if not found.
Note
The returned pointer lives in arena memory (valid until arena reset).

◆ csilk_get_status()

int csilk_get_status ( csilk_ctx_t *  c)

Get the current response status code.

Parameters
cThe request context.
Returns
The HTTP status code (e.g., 200, 404). Default is 200 if not set.

Get the current response status code.

Parameters
cThe request context.
Returns
The HTTP response status code, or 0 if the context is NULL or no status has been explicitly set.

◆ csilk_group_add_handlers()

void csilk_group_add_handlers ( csilk_group_t *  group,
const char *  method,
const char *  path,
csilk_handler_t handlers,
size_t  count 
)

Add a route with an explicit array of handlers.

Useful when you need to attach multiple middleware + the final handler without calling group_use first.

Parameters
groupThe route group.
methodHTTP method.
pathPath relative to the group prefix.
handlersArray of handler function pointers (middleware first, route handler last). Stored by pointer — must outlive the router.
countNumber of elements in handlers.

Add a route with an explicit array of handlers.

Assembly pipeline

  1. join_path(group->prefix, path) → full_path (e.g., "/api/v1/users").
  2. gather_handlers(group, ...) → flat array of all inherited middleware (parent first, then child), grown via realloc.
  3. realloc to append caller's handlers[] to the end.
  4. csilk_router_add(group->router, method, full_path, combined, count).

The final handler chain stored in the router looks like: [parent_mw..., group_mw..., handler_1, ..., handler_n]

Parameters
groupThe route group.
methodHTTP method.
pathPath relative to the group prefix.
handlersArray of handler functions (the chain).
countNumber of handlers in the array.
Note
The handlers array is combined with group middleware — group middleware always runs first, followed by the provided handlers.

◆ csilk_group_add_route()

void csilk_group_add_route ( csilk_group_t *  group,
const char *  method,
const char *  path,
csilk_handler_t  handler 
)

Add a route to the group.

The full URL pattern is the group prefix concatenated with path. The group's middleware is prepended to the handler.

Parameters
groupThe route group.
methodHTTP method.
pathPath relative to the group prefix (e.g., "/:id").
handlerThe route handler function.

Add a route to the group.

The route's path is automatically prefixed with the group's prefix. The handler is wrapped in a 1-element array and passed to csilk_group_add_handlers() which combines group middleware.

Parameters
groupThe route group.
methodHTTP method (e.g., "GET", "POST").
pathPath relative to the group prefix (e.g., "/users").
handlerThe route handler function.

◆ csilk_group_add_route_extended()

void csilk_group_add_route_extended ( csilk_group_t *  group,
const char *  method,
const char *  path,
csilk_handler_t  handler,
const char *  input_type,
const char *  output_type,
const char *  summary,
const char *  description 
)

Add a route with OpenAPI/reflection metadata to a group.

Extended version that also records input/output types and documentation for automatic OpenAPI spec generation.

Parameters
groupThe route group.
methodHTTP method.
pathPath relative to the group prefix.
handlerThe route handler function.
input_typeRegistered type name for request-body binding (NULL if none).
output_typeRegistered type name for response serialisation (NULL if none).
summaryShort operation summary for OpenAPI (NULL to omit).
descriptionDetailed operation description for OpenAPI (NULL to omit).

Add a route with OpenAPI/reflection metadata to a group.

Like csilk_group_add_route() but enriches the route with metadata used by the OpenAPI spec generator. The metadata is stored in the method handler for later retrieval by csilk_generate_openapi_json().

Parameters
groupThe route group.
methodHTTP method.
pathPath relative to the group prefix.
handlerThe route handler function.
input_typeRegistered reflection type name for the request body (e.g., "CreateUserRequest"), or NULL.
output_typeRegistered reflection type name for the response body, or NULL.
summaryShort description for OpenAPI operation summary.
descriptionDetailed description for OpenAPI operation.

◆ csilk_group_add_route_extended_perm()

void csilk_group_add_route_extended_perm ( csilk_group_t *  group,
const char *  method,
const char *  path,
csilk_handler_t  handler,
const char *  input_type,
const char *  output_type,
const char *  summary,
const char *  description,
const char *  perm_required,
const char *  perm_resource 
)

Add a route with full OpenAPI metadata and permission requirements to a group.

Parameters
groupThe route group.
methodHTTP method string.
pathPath relative to the group prefix.
handlerThe route handler function.
input_typeRegistered type name for request-body binding (NULL if none).
output_typeRegistered type name for response serialisation (NULL if none).
summaryShort operation summary for OpenAPI (NULL to omit).
descriptionDetailed operation description for OpenAPI (NULL to omit).
perm_requiredPermission identifier (e.g., "read"), or NULL.
perm_resourceResource pattern (e.g., "users:*"), or NULL.

Add a route with full OpenAPI metadata and permission requirements to a group.

Extended version that also records input/output types and documentation for automatic OpenAPI spec generation.

Parameters
groupThe route group.
methodHTTP method.
pathPath relative to the group prefix.
handlerThe route handler function.
input_typeRegistered type name for request-body binding (NULL if none).
output_typeRegistered type name for response serialisation (NULL if none).
summaryShort operation summary for OpenAPI (NULL to omit).
descriptionDetailed operation description for OpenAPI (NULL to omit).

Add a route with OpenAPI/reflection metadata to a group.

Like csilk_group_add_route() but enriches the route with metadata used by the OpenAPI spec generator. The metadata is stored in the method handler for later retrieval by csilk_generate_openapi_json().

Parameters
groupThe route group.
methodHTTP method.
pathPath relative to the group prefix.
handlerThe route handler function.
input_typeRegistered reflection type name for the request body (e.g., "CreateUserRequest"), or NULL.
output_typeRegistered reflection type name for the response body, or NULL.
summaryShort description for OpenAPI operation summary.
descriptionDetailed description for OpenAPI operation.
perm_requiredPermission required for this route, or NULL.
perm_resourceResource pattern for permission check, or NULL.

Permission metadata is forwarded to the router which stores it alongside the route for authorization middleware to inspect at request time.

◆ csilk_group_free()

void csilk_group_free ( csilk_group_t *  group)

Destroy a route group and release its resources.

Frees the group struct and its prefix string. Does NOT free the associated router or any handler functions.

Parameters
groupThe group to free. Must not be NULL.

Destroy a route group and release its resources.

Releases the group's prefix string, middleware handlers array, and the group struct itself. Does NOT free child groups or the router.

Parameters
groupThe group to free (may be NULL).
Note
Child groups created with csilk_group_group() must be freed separately. The router is not owned by the group.

◆ csilk_group_group()

csilk_group_t * csilk_group_group ( csilk_group_t *  parent,
const char *  prefix 
)

Create a nested sub-group within an existing group.

The sub-group inherits the parent's middleware and its prefix is concatenated.

Parameters
parentThe parent group.
prefixSub-prefix appended to the parent's prefix (e.g., "admin").
Returns
A new sub-group instance, or NULL on allocation failure.

Create a nested sub-group within an existing group.

The child inherits the parent's router and its prefix is joined with the parent's prefix (e.g., parent="/api", child="/v1" -> combined prefix "/api/v1").

Parameters
parentThe parent group (cannot be NULL).
prefixURL prefix for this subgroup (e.g., "/v1").
Returns
A new csilk_group_t, or NULL on failure.
Note
The child must be freed separately with csilk_group_free() — freeing the parent does NOT free its children.

◆ csilk_group_new()

csilk_group_t * csilk_group_new ( csilk_router_t router,
const char *  prefix 
)

Create a new route group with a URL prefix.

Groups allow sharing a common prefix and middleware set across multiple routes (e.g., "/api/v1").

Parameters
routerThe router to attach the group to.
prefixURL prefix for all routes in this group (e.g., "/api/v1").
Returns
A new csilk_group_t instance, or NULL on allocation failure.

Create a new route group with a URL prefix.

Root groups are attached directly to a router. All routes added to this group will be prefixed with prefix.

Parameters
routerThe router instance this group belongs to.
prefixURL prefix for all routes in this group (e.g., "/api/v1"). Pass NULL or "/" for no prefix.
Returns
A new csilk_group_t, or NULL on allocation failure.
Note
The group must be freed with csilk_group_free().

◆ csilk_group_use()

void csilk_group_use ( csilk_group_t *  group,
csilk_handler_t  handler 
)

Add middleware to a group.

Middleware is stored in the order it is added and is executed for every route in the group (and any nested sub-groups).

Parameters
groupThe route group.
handlerMiddleware function to prepend to all group routes.

Add middleware to a group.

Middleware handlers are executed before route handlers in the order they are registered. The internal middleware array grows dynamically (doubling capacity) as needed.

Parameters
groupThe route group.
handlerMiddleware handler function. Receives the request context and should call csilk_next() to pass control forward.
Note
Middleware from parent groups is automatically inherited by child groups and prepended before child middleware.

◆ csilk_gzip_middleware()

void csilk_gzip_middleware ( csilk_ctx_t *  c)

Gzip response compression middleware.

If the client advertises gzip/deflate support (Accept-Encoding header), this middleware compresses the response body transparently. Must be registered as a group-level or server-level middleware that wraps the handler chain.

Parameters
cThe request context.

Gzip response compression middleware.

Calls csilk_next() first, then inspects the response. Compression is skipped if:

  • The response body is empty,
  • Content-Encoding is already set,
  • The Content-Type is binary / incompressible (image, video, audio, pdf, zip, gzip),
  • The client does not advertise gzip in Accept-Encoding,
  • The response body is smaller than CSILK_GZIP_MIN_LENGTH (1 KB).

When eligible, the response body is made managed (copied if necessary) and compression is offloaded to the libuv thread pool via a work request.

Parameters
cThe request context.
Note
This middleware must be registered AFTER handlers that produce the response body (since it calls csilk_next() first).
Warning
The response body is replaced in-place; subsequent middleware or cleanup code must not free the original pointer after compression.

◆ csilk_health_check_handler()

void csilk_health_check_handler ( csilk_ctx_t *  c)

Built-in Health Check handler. Returns a simple JSON response {"status": "up"}.

Parameters
cThe request context.

Built-in Health Check handler. Returns a simple JSON response {"status": "up"}.

Provides a simple "shallow" check to verify that the server's event loop is alive and responsive. Returns a JSON response with status 200 OK.

Parameters
cThe request context. If NULL the function returns immediately.
Note
Used by load balancers and orchestrators for Liveness probes.

◆ csilk_is_aborted()

int csilk_is_aborted ( csilk_ctx_t *  c)

Check whether the handler chain has been aborted.

Handlers can check this after calling csilk_next to see if a downstream handler or middleware called csilk_abort.

Parameters
cThe request context.
Returns
1 if csilk_abort was called, 0 otherwise.

Check whether the handler chain has been aborted.

Parameters
cThe request context.
Returns
1 if the connection was aborted/closed, 0 otherwise.
Note
Handlers should check this flag before performing expensive work for a disconnected client.

◆ csilk_is_async()

int csilk_is_async ( csilk_ctx_t *  c)

Check whether asynchronous response mode is enabled.

Parameters
cThe request context.
Returns
1 if async mode is active, 0 if the framework owns response flushing.

Check whether asynchronous response mode is enabled.

Parameters
cThe request context.
Returns
1 if async mode is enabled, 0 otherwise.
Note
In async mode the framework does not automatically flush the response — the handler must do it explicitly.

◆ csilk_is_sse()

int csilk_is_sse ( csilk_ctx_t *  c)

Check whether the connection is in Server-Sent Events mode.

Returns 1 only after csilk_sse_init has been called successfully.

Parameters
cThe request context.
Returns
1 if SSE mode is active, 0 otherwise.

Check whether the connection is in Server-Sent Events mode.

Parameters
cThe request context.
Returns
1 if SSE mode is active, 0 otherwise.
Note
Set externally by the handler that initiates SSE streaming.

◆ csilk_is_websocket()

int csilk_is_websocket ( csilk_ctx_t *  c)

Check whether the connection has been upgraded to WebSocket.

Returns 1 only after a successful csilk_ws_handshake call.

Parameters
cThe request context.
Returns
1 if WebSocket mode is active, 0 otherwise.

Check whether the connection has been upgraded to WebSocket.

Parameters
cThe request context.
Returns
1 if the connection has been upgraded to WebSocket, 0 otherwise.
Note
Set to 1 by csilk_ws_handshake() after a successful upgrade.

◆ csilk_json()

void csilk_json ( csilk_ctx_t *  c,
int  status,
cJSON *  json 
)

Send a JSON response (takes ownership of the cJSON object).

Serializes json to a string, sets the Content-Type header to application/json, and sends the response. The cJSON object is freed by this function — the caller must not use it afterward.

Parameters
cThe request context.
statusHTTP status code.
jsoncJSON object to serialise and send. Ownership is transferred to the framework (cJSON_Delete is called internally).

Send a JSON response (takes ownership of the cJSON object).

Sets the Content-Type header to "application/json", serializes the cJSON object to an unformatted JSON string, and sets it as the response body. The cJSON object is deleted (freed) after serialization — the caller must NOT free it.

Parameters
cThe request context.
statusHTTP status code for the response.
jsoncJSON object to serialize. Ownership is taken by this call.
Note
If there is a previous body marked as managed, it is freed first. The serialized JSON string is heap-allocated and managed by the framework.

◆ csilk_json_error()

void csilk_json_error ( csilk_ctx_t *  c,
int  status,
const char *  message 
)

Send a JSON-formatted error response.

Produces {"error": "<message>"} with the given status code. The message is copied into the request arena.

Parameters
cThe request context.
statusHTTP status code (e.g., 400, 500).
messageHuman-readable error description.

Send a JSON-formatted error response.

Creates a JSON object with a single "error" key containing message and sends it as the response via csilk_json().

Parameters
cThe request context.
statusHTTP status code.
messageError message string (if NULL, "Unknown error" is used).

◆ csilk_json_reflect()

void csilk_json_reflect ( csilk_ctx_t *  c,
int  status,
const char *  type_name,
const void *  ptr 
)

Serialise a reflected struct as a JSON response.

Marshals the struct via csilk_json_marshal and sends the result as a JSON response. The struct must have been registered with the reflection system.

Parameters
cThe request context.
statusHTTP status code.
type_nameRegistered type name string.
ptrPointer to the struct instance to serialise.

Serialise a reflected struct as a JSON response.

Serializes the provided struct to JSON using the csilk reflection engine and sends it as the HTTP response. If type_name is NULL, the type is inferred from the current handler's output_type metadata.

Parameters
cThe request context.
statusHTTP status code.
type_nameRegistered type name, or NULL to infer from route metadata.
ptrPointer to the struct to serialize.
Note
The serialized JSON string is heap-allocated and managed by the framework (freed during cleanup). Uses csilk_json_marshal() internally.

◆ csilk_jwt_generate()

char * csilk_jwt_generate ( csilk_ctx_t *  c,
cJSON *  payload,
const char *  secret 
)

Generate a signed JWT token (HS256).

Creates a three-part JWT (header.payload.signature) using HMAC-SHA256. The payload is used as-is for the claims.

Parameters
cRequest context (for crypto-driver access).
payloadcJSON object containing JWT claims (e.g., {"sub":"123"}). Not modified; ownership stays with caller.
secretSecret key string for HMAC signing.
Returns
A heap-allocated JWT string (caller must free), or NULL on failure.

Generate a signed JWT token (HS256).

Constructs a JWT with the fixed header {"alg":"HS256","typ":"JWT"} and the caller-supplied cJSON payload. The token is signed using HMAC-SHA256 with the provided secret. Every component (header, payload, signature) is base64url-encoded per RFC 4648 §5.

Parameters
cThe request context (used for HMAC operations).
payloadA cJSON object containing the claims. Must not be NULL.
secretThe HMAC-SHA256 signing secret. Must not be NULL.
Returns
A newly allocated, null-terminated JWT string in the format header.payload.signature, or NULL on allocation failure or invalid arguments.
Note
The caller is responsible for freeing the returned string with free().
Warning
The payload is NOT deep-copied during generation. The caller retains ownership and should free it after this function returns.

◆ csilk_jwt_middleware()

void csilk_jwt_middleware ( csilk_ctx_t *  c,
const char *  secret 
)

JWT authentication middleware.

Extracts the Bearer token from the Authorization header, verifies it, and stores the decoded payload in the context under the key "jwt_payload". If the token is missing or invalid, responds with 401 Unauthorized and aborts the chain.

Parameters
cThe request context.
secretSecret key for token verification.

Extracts the Bearer token from the Authorization header, verifies it via csilk_jwt_verify(), and checks the "exp" claim if present. On success the decoded payload is stored in the context under the key "jwt_payload" and the next handler is called. On failure (missing header, invalid token, or expired), a 401 Unauthorized response is sent.

Parameters
cThe request context.
secretThe HMAC-SHA256 verification secret.
Note
The jwt_payload is stored with csilk_set() and is NOT automatically freed by the context cleanup. Downstream handlers should retrieve it with csilk_get() and call cJSON_Delete() when done, or register a cleanup callback.
Warning
This middleware must be registered before any handler that accesses the jwt_payload via csilk_get(c, "jwt_payload").

◆ csilk_jwt_verify()

cJSON * csilk_jwt_verify ( csilk_ctx_t *  c,
const char *  token,
const char *  secret 
)

Verify a JWT token and extract its payload.

Validates the signature (HMAC-SHA256), checks the "exp" claim if present, and returns the parsed payload.

Parameters
cRequest context (for crypto-driver access).
tokenThe JWT string to verify.
secretSecret key for HMAC verification.
Returns
A heap-allocated cJSON object with the payload claims, or NULL if the token is invalid or expired. Caller must free with cJSON_Delete.

Verify a JWT token and extract its payload.

Splits the token into its three dot-separated components (header, payload, signature), recomputes the HMAC-SHA256 signature over the signing input, and compares it against the provided signature (constant-time not guaranteed — uses strcmp). On success, the payload is base64url-decoded and parsed into a cJSON object.

Parameters
cThe request context (used for HMAC operations).
tokenThe JWT string in the format header.payload.signature.
secretThe HMAC-SHA256 verification secret.
Returns
A newly allocated cJSON object representing the payload claims, or NULL if the token is malformed, the signature is invalid, or memory allocation fails.
Note
The caller owns the returned cJSON object and must free it with cJSON_Delete() when no longer needed.
Warning
Signature comparison uses strcmp, which is NOT constant-time. This may be vulnerable to timing attacks in high-security environments.

◆ csilk_load_config()

int csilk_load_config ( const char *  yaml_path,
csilk_config_t config 
)

Load and parse a YAML configuration file.

Reads a YAML file at yaml_path and populates config. All string fields in config are heap-allocated and must be freed with csilk_config_free.

Parameters
yaml_pathPath to a YAML configuration file.
[out]configPointer to a caller-allocated csilk_config_t to populate.
Returns
0 on success, -1 on failure (parse error or file not found).

Load and parse a YAML configuration file.

Opens the specified YAML file, parses its contents, and populates the provided csilk_config_t structure. The parser recognizes top-level keys ("port") and section keys ("server", "logger", "cors", "rate_limit", "static_files", "middleware"). All fields not present in the YAML retain their default values (initialized at the start of this function).

Parameters
yaml_pathAbsolute or relative path to the YAML configuration file.
config[out] Pre-allocated config structure to populate.
Returns
0 on success, -1 on I/O error, parse error, or NULL input.
Note
Dynamically allocated strings (file_path, allow_origin, etc.) are strdup'd and must be freed later with csilk_config_free().
The config structure is memset to zero first, then defaults are set. Callers that have already populated fields will lose them.

◆ csilk_log_close()

void csilk_log_close ( void  )

Close the global logger.

Close the global logger.

Closes file handles and destroys mutexes. Safe to call multiple times.

◆ csilk_log_init()

int csilk_log_init ( csilk_log_config_t  config)

Initialize the global logger with config.

Parameters
configLogger configuration.
Returns
0 on success, -1 on failure.

Initialize the global logger with config.

Configures the output destination (stdout if no file_path, or a file if set), the minimum log level, coloring (auto-detected for terminals when use_colors is -1), and whether to use structured JSON format. If the logger was previously initialized, csilk_log_close() is called first. A mutex is initialized for thread-safe operation.

Parameters
configLogger configuration struct with desired settings.
Returns
0 on success, -1 if the file could not be opened or mutex init fails.
Note
If file_path is NULL, output goes to stdout and max_file_size is effectively ignored (set to 0 internally).

◆ csilk_log_is_json()

int csilk_log_is_json ( void  )

Check whether the logger is in JSON format mode.

Returns
1 if json_format is enabled, 0 otherwise.

Check whether the logger is in JSON format mode.

Returns
1 if the logger is initialized and json_format is enabled, 0 otherwise.
Note
Useful for handlers that want to produce consistent log output format matching the global setting.

◆ csilk_log_make_kv()

cJSON * csilk_log_make_kv ( const char *  key,
  ... 
)

Create a simple key-value cJSON object for structured logging.

Convenience helper that builds a cJSON object from alternating key/value string pairs terminated by a NULL key.

cJSON* fields = csilk_log_make_kv("method", method, "path", path, NULL);
_csilk_log_structured(CSILK_LOG_INFO, __FILE__, __LINE__, __func__, fields,
"request completed");
void _csilk_log_structured(csilk_log_level_t lv, const char *file, int line, const char *func, cJSON *extra, const char *fmt,...)
Log a structured JSON message with extra key-value fields.
Definition logger.c:411
@ CSILK_LOG_INFO
Definition csilk.h:743
cJSON * csilk_log_make_kv(const char *key,...)
Create a simple key-value cJSON object for structured logging.
Definition logger.c:491
Parameters
keyFirst key.
...Value, then key, value, ... terminated by NULL.
Returns
New cJSON object (caller owns).

Create a simple key-value cJSON object for structured logging.

Helper to create a flat JSON object from a NULL-terminated list of strings. Used primarily with CSILK_LOG_KV.

◆ csilk_log_set_request_id()

void csilk_log_set_request_id ( const char *  request_id)

Set the Request ID for the current thread (for log correlation).

Parameters
request_idThe Request ID string, or NULL to clear.

Set the Request ID for the current thread (for log correlation).

Stores the request ID in thread-local storage, allowing subsequent log calls on the same thread to automatically include it without passing the context explicitly.

◆ csilk_logger_handler()

void csilk_logger_handler ( csilk_ctx_t *  c)

Logging middleware handler. Logs request method, path, and processing time.

Parameters
cThe request context.

Logging middleware handler. Logs request method, path, and processing time.

Records the start time of the request using a high-resolution monotonic clock (CLOCK_MONOTONIC), proceeds to the next handler via csilk_next(), and then calculates the total elapsed time. It automatically selects between plain-text logging and structured JSON logging based on the global logger configuration.

In JSON mode, the request details are marshalled into a csilk_req_log_t struct and logged via the reflection-based JSON logger. In text mode, a simple "[HTTP] METHOD PATH STATUS DURATION" line is emitted.

If a request ID is set on the context, it is propagated to the logger's thread-local state for correlating log entries.

Parameters
cThe request context.
Note
This middleware should be one of the first in the pipeline so that the timing covers the entire request lifecycle.
Warning
csilk_next() is called BEFORE the log output; the response status must therefore be set by downstream handlers before returning.

◆ csilk_metrics_handler()

void csilk_metrics_handler ( csilk_ctx_t *  c)

Prometheus /metrics endpoint handler.

Exposes collected metrics in the standard Prometheus text exposition format (content-type: text/plain; version=0.0.4).

Parameters
cThe request context.

Prometheus /metrics endpoint handler.

Renders full system telemetry in standard Prometheus text-based format.

◆ csilk_metrics_middleware()

void csilk_metrics_middleware ( csilk_ctx_t *  c,
const char *  arg 
)

Prometheus metrics middleware.

Tracks request-level metrics: QPS, latency distribution histogram, and HTTP status code counters. Should be added early in the middleware chain.

Parameters
cThe request context.
argOptional config string (currently unused, pass NULL).

Prometheus metrics middleware.

Wraps the request execution to measure latency and update atomic counters.

◆ csilk_mq_abort()

void csilk_mq_abort ( csilk_mq_ctx_t *  ctx)

Abort the MQ middleware/subscriber chain.

No further handlers execute for the current message.

Parameters
ctxThe MQ context.

Abort the MQ middleware/subscriber chain.

Sets the aborted flag on the context. Subsequent calls to csilk_mq_next() will be ignored.

Parameters
ctxMessage queue context (may be NULL).

◆ csilk_mq_get_payload()

const void * csilk_mq_get_payload ( csilk_mq_ctx_t *  ctx,
size_t *  len 
)

Get the payload of the current message.

Parameters
ctxThe MQ context.
[out]lenOptional pointer to receive the payload byte length (may be NULL).
Returns
Pointer to the message payload. Valid only for the duration of the handler call. The pointer must NOT be freed.

Get the payload of the current message.

Parameters
ctxMessage queue context.
len[out] If non-NULL, receives the payload length in bytes.
Returns
Pointer to the raw payload data, or NULL if the context or message is NULL.
Note
The returned pointer is valid only for the duration of the handler callback. If the data is needed later, the handler must copy it.

◆ csilk_mq_get_topic()

const char * csilk_mq_get_topic ( csilk_mq_ctx_t *  ctx)

Get the topic of the current message.

Parameters
ctxThe MQ context.
Returns
The topic string. Valid only for the duration of the handler call.

Get the topic of the current message.

Parameters
ctxMessage queue context.
Returns
The topic string (e.g., "user.created"), or NULL if the context or message is NULL.

◆ csilk_mq_next()

void csilk_mq_next ( csilk_mq_ctx_t *  ctx)

Pass control to the next middleware or subscriber in the MQ chain.

Must be called exactly once (or zero times if csilk_mq_abort is used) for the chain to advance.

Parameters
ctxThe MQ context.

Pass control to the next middleware or subscriber in the MQ chain.

Execution model

Handlers form a linear chain: [global_mw..., topic_mw..., subscriber...]. Each handler calls csilk_mq_next() to yield control to the next one. This is a non-recursive, non-reentrant manual trampoline — the chain is driven by the handlers themselves, not by a central loop.

If ctx->aborted is set (by a previous csilk_mq_abort() call), this is a no-op. Out-of-bounds handler_index is also silently ignored (end of chain).

Parameters
ctxMessage queue context.
Note
Typically called by middleware to pass control to the next handler or subscriber.

◆ csilk_mq_offload()

void csilk_mq_offload ( csilk_mq_ctx_t *  ctx,
csilk_mq_worker_t  worker 
)

Offload message processing to a background thread.

Hands off the current message to libuv's thread pool for processing. csilk_mq_next is called internally so the chain continues immediately. The worker runs on a separate thread — it must be thread-safe and must NOT call back into the MQ or context APIs.

Parameters
ctxThe MQ context.
workerBackground worker function that receives the topic and a copy of the payload.

Offload message processing to a background thread.

Mechanism

  1. Deep-copy topic (strdup) and payload (malloc+memcpy) into a work ctx.
  2. Queue the work via uv_queue_work() — runs worker_cb on a libuv thread pool thread.
  3. worker_after_cb fires on the main loop thread: frees the work ctx.
  4. Call csilk_mq_next() immediately on the main thread to continue the handler chain, without waiting for the background worker.

The deep copy avoids shared mutable state between the background thread and the event loop. The caller's handler chain continues in parallel with the offloaded work — there is no result channel.

Parameters
ctxMessage queue context.
workerWorker function that will receive topic, payload, and length on a background thread.
Note
The payload is deep-copied so the background thread can safely process it without worrying about mutex locking.

◆ csilk_mq_publish()

int csilk_mq_publish ( csilk_mq_t *  mq,
const char *  topic,
const void *  payload,
size_t  len 
)

Publish a message to a topic.

The payload is copied internally so the caller can reuse the buffer immediately. The message is enqueued and processed asynchronously on the main event loop via a libuv async handle, making this function thread-safe.

Parameters
mqThe MQ instance.
topicTarget topic name.
payloadPointer to the data to publish (copied internally).
lenByte length of payload.
Returns
0 on success, non-zero errno-compatible code on failure (typically ENOMEM).

Publish a message to a topic.

Write-ahead: WAL then memory

The two operations are NOT atomic (WAL can succeed, memory enqueue can fail). This is a deliberate trade-off:

  • If WAL succeeds but enqueue fails: message is safe on disk but lost in memory — it will be recovered on next restart.
  • If WAL fails: the message is dropped entirely (return -1).

Processing is asynchronous — the caller receives no delivery confirmation. The message is deep-copied at both stages.

Parameters
mqThe MQ instance.
topicTarget topic name (cannot be NULL).
payloadMessage payload data (may be NULL).
lenPayload length in bytes.
Returns
0 on success, -1 if the topic is NULL or WAL append fails.
Note
Thread-safe. The caller may free or reuse payload immediately after this call returns — the data is copied internally.

◆ csilk_mq_set_persistence()

int csilk_mq_set_persistence ( csilk_mq_t *  mq,
const char *  wal_path 
)

Enable Write-Ahead Log (WAL) persistence for the MQ.

When enabled, every published message is appended to wal_path before being processed. The WAL can be replayed on restart to recover messages.

Parameters
mqThe MQ instance.
wal_pathFile path for the WAL (e.g., "mq.wal"). The string is copied internally.
Returns
0 on success, non-zero on file-open failure.

Enable Write-Ahead Log (WAL) persistence for the MQ.

WAL handshake

  1. Lock wal_mutex (held for the entire setup + recovery).
  2. Close any previously-opened WAL file + free old wal_path.
  3. Open (or create) the WAL file at wal_path with O_CREAT | O_RDWR | O_APPEND.
  4. Store fd and path in the MQ struct.
  5. Call _mq_recovery() to replay any existing messages from the WAL file into the in-memory queue. This ensures messages survive process restarts.

After this call, every csilk_mq_publish() appends to the WAL before enqueuing in memory.

Parameters
mqThe MQ instance.
wal_pathFile path for the WAL. The file is created if it does not exist.
Returns
0 on success, -1 if parameters are NULL or the file cannot be opened.
Note
The WAL uses a simple binary format: [topic_len][topic][payload_len] [payload][checksum] entries. Checksum is a simple XOR for integrity.

◆ csilk_mq_subscribe()

void csilk_mq_subscribe ( csilk_mq_t *  mq,
const char *  topic,
csilk_mq_handler_t  subscriber 
)

Register a subscriber for a topic.

Subscribers run after all applicable middleware (global + topic-specific) has completed.

Parameters
mqThe MQ instance.
topicTopic name to subscribe to.
subscriberHandler function. Must not be NULL.

Register a subscriber for a topic.

Subscribers are treated as handlers appended to the end of the chain (after global and topic middlewares). This is a convenience wrapper around csilk_mq_use().

Parameters
mqThe MQ instance.
topicTopic name to subscribe to.
subscriberHandler function invoked when a message matches.

◆ csilk_mq_use()

void csilk_mq_use ( csilk_mq_t *  mq,
const char *  topic,
csilk_mq_handler_t  middleware 
)

Register MQ middleware for a topic.

Middleware runs before subscribers. Pass NULL as topic to register global middleware that intercepts all messages.

Parameters
mqThe MQ instance.
topicTopic name to intercept, or NULL for global middleware.
middlewareHandler function. Must not be NULL.

Register MQ middleware for a topic.

Global vs topic-specific

  • topic == NULL: handler is appended to mq->global_middlewares[]. These run for EVERY message, regardless of topic, and execute first.
  • topic != NULL: handler is appended to that topic's handlers[] array. The topic is created lazily via get_or_create_topic(). These run only when fnmatch(topic_name, msg_topic) matches.

Both arrays grow by doubling (initial cap = 4) when full.

Parameters
mqThe MQ instance.
topicTopic name (e.g., "user.created"), or NULL for global.
middlewareHandler function to invoke during message processing.
Note
The handler arrays grow dynamically (doubling capacity) as needed. Topic matching supports glob patterns via fnmatch().

◆ csilk_multipart_parse()

void csilk_multipart_parse ( csilk_ctx_t *  c,
csilk_multipart_handler_t  handler 
)

Parse a multipart/form-data request body.

Iterates over all parts in the request body (using the Content-Type boundary) and calls handler for each. Files and form fields are treated uniformly — check the filename field to distinguish them.

Parameters
cThe request context.
handlerCallback invoked once per part.

Parse a multipart/form-data request body.

Extracts the boundary string from the Content-Type header, then iterates through the request body looking for boundary-delimited parts. For each part, the function parses the Content-Disposition header (extracting name and optional filename), the optional Content-Type header, and the part body. A csilk_multipart_part_t struct is populated and passed to the caller-supplied handler callback.

Parameters
cThe request context containing the parsed body.
handlerCallback invoked once per parsed part. Receives a pointer to a csilk_multipart_part_t describing the part. Must not be NULL.
Note
The part data pointers reference memory within the request body buffer directly — they are NOT copies. The handler must not modify or store the pointers beyond its invocation.
Warning
Part body data is NOT null-terminated. Use part.data_len to determine the bounds.
Maximum part name length is 127 bytes, maximum filename length is 255 bytes, and maximum part headers per section is 32. Parts exceeding these limits will be silently truncated.

◆ csilk_next()

void csilk_next ( csilk_ctx_t *  c)

Pass control to the next handler in the middleware/handler chain.

Implements the "onion" model: handlers before csilk_next run on the way in, handlers after csilk_next run on the way out (after downstream handlers). Call csilk_is_aborted after returning to check whether a downstream handler called csilk_abort.

Parameters
cThe request context.

Pass control to the next handler in the middleware/handler chain.

Increments the internal handler index and calls the next handler function. If the request has been aborted (via csilk_abort()), this is a no-op. The handler chain is a NULL-terminated array; if the next entry is NULL, execution falls through (the response is sent automatically if not async).

Parameters
cThe request context.
Note
Typically called at the end of a middleware or route handler to pass control to the next handler in the pipeline.

◆ csilk_panic()

void csilk_panic ( csilk_ctx_t *  c)

Trigger a panic (caught by recovery middleware).

Calls longjmp back to the setjmp point established by csilk_recovery_handler. If no recovery middleware is registered the behaviour is undefined (likely a crash).

Parameters
cThe request context.

Trigger a panic (caught by recovery middleware).

If a recovery handler has been installed (c->has_jump_buffer is set), this function performs a longjmp back to the recovery point set by csilk_recovery_handler().

If no recovery handler is registered, it prints a fatal error message to stderr and calls exit(1) to terminate the process.

Parameters
cThe request context. May be NULL (will trigger abort path).
Warning
This function does NOT return when executed without a recovery handler.

◆ csilk_parse_form_urlencoded()

void csilk_parse_form_urlencoded ( csilk_ctx_t *  c)

Parse the request body as application/x-www-form-urlencoded.

Populates the form_params hash map in the request. After calling this, form fields can be retrieved with csilk_get_form_field. Safe to call multiple times — subsequent calls are no-ops.

Parameters
cThe request context.

Checks the Content-Type header for "application/x-www-form-urlencoded" and, if matched, parses the request body into the form_params hash map. Key-value parsing and URL-decoding follow the same logic as csilk_parse_query().

Parameters
cThe request context.
Note
This function must be called explicitly by the handler; it is NOT invoked automatically. Typically called at the start of a handler that expects form data.

◆ csilk_parse_query()

void csilk_parse_query ( csilk_ctx_t *  c,
const char *  query_string 
)

Parse a raw query string and populate the query_params map.

Internal helper. Parses key=value pairs separated by '&' and URL-decodes both keys and values.

Parameters
cThe request context.
query_stringRaw query string (the part after '?', may be NULL or empty).

Parse a raw query string and populate the query_params map.

Splits the query string on '&' and each key-value pair on '=', URL-decodes both keys and values, and adds them to the request's query_params map. Parameters without a '=' get an empty-string value.

Parameters
cThe request context.
query_stringThe raw query string (e.g., "foo=1&bar=baz"). The leading '?' should NOT be included.
Note
The query string is duplicated into arena memory before parsing, so the original string can be freed immediately after this call. This is called automatically during request finalization.

◆ csilk_rate_limit_middleware()

void csilk_rate_limit_middleware ( csilk_ctx_t *  c,
int  limit 
)

Simple per-IP rate-limiting middleware.

Uses a fixed-window counter per client IP. If the limit is exceeded a 429 Too Many Requests response is sent and the handler chain is aborted.

Parameters
cThe request context.
limitMaximum number of requests allowed per minute for a single IP.

Simple per-IP rate-limiting middleware.

Tracks request counts per client IP address within a configurable window. If the number of requests from a given IP exceeds the limit, a 429 Too Many Requests response is sent (with a Retry-After header) and the pipeline is aborted.

The IP table is protected by a libuv mutex for thread safety. Stale entries are periodically evicted to prevent unbounded memory growth.

Parameters
cThe request context.
limitMaximum number of requests allowed per IP within the WINDOW_SIZE (60-second) sliding window.
Note
The mutex is initialized once via uv_once on the first call.
Warning
Rate limiting is per-worker-process. In multi-process deployments, each process maintains its own independent table unless an external store (Redis, etc.) is used instead.
If csilk_get_client_ip() returns NULL (e.g. in tests or certain proxy setups), the request is passed through without rate limiting.

◆ csilk_recovery_handler()

void csilk_recovery_handler ( csilk_ctx_t *  c)

Panic-recovery middleware.

Wraps the handler chain in a setjmp/longjmp boundary. If a handler calls csilk_panic (or a segfault occurs within the protected scope), this middleware sends a 500 response and logs the error instead of crashing the server.

Should be registered as the outermost middleware.

Parameters
cThe request context.

Panic-recovery middleware.

Installs a setjmp recovery point before calling csilk_next(). If any downstream handler triggers csilk_panic(), execution resumes at the setjmp point and an "Internal Server Error" response (500) is sent instead of crashing the process.

After the normal (non-panic) path completes, the jump buffer flag is cleared.

Parameters
cThe request context (must have a valid jump_buffer).
Note
This middleware MUST be registered before any handler that may call csilk_panic().
Warning
setjmp/longjmp do NOT unwind the C stack or call destructors. Resources allocated by panicked handlers (malloc, open files, etc.) WILL leak. Use this as a last-resort safety net, not as a primary error-handling mechanism.

◆ csilk_redirect()

void csilk_redirect ( csilk_ctx_t *  c,
int  status,
const char *  location 
)

Send an HTTP redirect response with a custom status code.

Sets the Location header and the response body to a minimal HTML redirect page. The handler chain is aborted after this call.

Parameters
cThe request context.
statusHTTP redirect status (e.g., 301 Moved Permanently, 302 Found, 307 Temporary Redirect).
locationThe destination URL. Must not be NULL.

Send an HTTP redirect response with a custom status code.

Sets the Location header, updates the response status, and aborts the handler chain. If the provided status is outside the 3xx range, it is coerced to 302 (Found).

Parameters
cThe request context.
statusHTTP redirect status (typically 301, 302, 303, 307, 308).
locationThe target URL for the Location header.
Note
After calling this function the handler chain is aborted and no further handlers execute.

◆ csilk_redirect_simple()

void csilk_redirect_simple ( csilk_ctx_t *  c,
const char *  url 
)

Send a simple 302 Found redirect.

Convenience wrapper around csilk_redirect with status 302.

Parameters
cThe request context.
urlThe destination URL.

Send a simple 302 Found redirect.

Convenience wrapper around csilk_redirect().

Parameters
cThe request context.
urlThe target URL for the redirect.

◆ csilk_request_id_middleware()

void csilk_request_id_middleware ( csilk_ctx_t *  c)

Request ID middleware. Generates a unique ID for each request and sets X-Request-Id header.

Parameters
cThe request context.

Request ID middleware. Generates a unique ID for each request and sets X-Request-Id header.

Ensures every request has a unique UUID v4 identifier. If the request context does not already have an ID (c->request_id is empty), a new UUID is generated via _csilk_generate_uuid(). The identifier is then set as the "X-Request-Id" response header and propagated to the thread-local logger state for distributed tracing correlation.

Parameters
cThe request context. If NULL the function returns immediately.
Note
Should be registered as the very first middleware in the pipeline so all downstream handlers and log entries share the same request identifier.
Warning
The UUID generation uses whatever _csilk_generate_uuid() implements — ensure it provides sufficient entropy for your deployment.

◆ csilk_response_end()

void csilk_response_end ( csilk_ctx_t *  c)

Finalise a chunked streaming response.

Sends the terminal (zero-length) chunk and any trailers. The connection is then kept alive or closed according to the HTTP keep-alive header.

Parameters
cThe request context.

Finalise a chunked streaming response.

If the response has not yet started, sends chunked headers first. Then sends the zero-length terminal chunk ("0\\r\\n\\r\\n") which signals to the client that the stream is complete.

Parameters
cRequest context.
Note
Must be called after all csilk_response_write() calls are done. Safe to call even if response_started is false.

◆ csilk_response_write()

void csilk_response_write ( csilk_ctx_t *  c,
const uint8_t *  data,
size_t  len 
)

Write a chunk to the response stream (chunked transfer encoding).

The first call sends the HTTP response headers with Transfer-Encoding: chunked. Subsequent calls append chunked frames. The handler MUST set async mode (csilk_set_async(c, 1)) before calling this and MUST NOT use csilk_string, csilk_json, etc.

Parameters
cThe request context.
dataRaw data for the chunk.
lenByte length of data.

Write a chunk to the response stream (chunked transfer encoding).

On the first call, automatically sends chunked headers (status line + Transfer-Encoding: chunked). Subsequent calls append data chunks. Sets the response to async mode so the framework does not auto-send the response after the handler returns.

Parameters
cRequest context.
dataPayload data to write.
lenLength of data in bytes.
Note
After all data has been written, call csilk_response_end() to send the terminal chunk and finalize the response.
Calling with len=0 is a no-op.

◆ csilk_router_add()

void csilk_router_add ( csilk_router_t r,
const char *  method,
const char *  path,
csilk_handler_t handlers,
size_t  handler_count 
)

Register a route with one or more handlers.

The route is inserted into the radix tree. Dynamic segments (:param) and wildcard segments (*wildcard) are supported in path. The handlers are stored by pointer — the caller must ensure they remain valid for the lifetime of the router.

Parameters
rRouter instance.
methodHTTP method (e.g., "GET", "POST", "DELETE", "*" for any).
pathURL pattern (e.g., "/users/:id/posts").
handlersArray of handler function pointers.
handler_countNumber of elements in handlers.

Register a route with one or more handlers.

Convenience wrapper around csilk_router_add_extended() that passes NULL for all optional metadata fields.

Parameters
rThe router instance.
methodHTTP method.
pathURL path pattern.
handlersArray of handler functions.
handler_countNumber of handlers.

◆ csilk_router_add_extended()

void csilk_router_add_extended ( csilk_router_t r,
const char *  method,
const char *  path,
csilk_handler_t handlers,
size_t  handler_count,
const char *  path_pattern,
const char *  input_type,
const char *  output_type,
const char *  summary,
const char *  description 
)

Register a route with full OpenAPI/reflection metadata.

Extended version of csilk_router_add that also stores metadata for automatic OpenAPI spec generation and request/response binding.

Parameters
rRouter instance.
methodHTTP method string.
pathURL pattern (e.g., "/users/:id").
handlersArray of handler functions.
handler_countNumber of handlers in handlers.
path_patternCanonical path pattern string for documentation (may differ from the radix-tree path).
input_typeRegistered type name for request-body binding (NULL if there is no request body).
output_typeRegistered type name for response serialisation (NULL if raw response is used).
summaryShort summary of the operation (NULL to omit from spec).
descriptionDetailed description of the operation (NULL to omit).

◆ csilk_router_add_extended_perm()

void csilk_router_add_extended_perm ( csilk_router_t r,
const char *  method,
const char *  path,
csilk_handler_t handlers,
size_t  handler_count,
const char *  path_pattern,
const char *  input_type,
const char *  output_type,
const char *  summary,
const char *  description,
const char *  perm_required,
const char *  perm_resource 
)

Register a route with full metadata including permissions.

Parameters
rRouter instance.
methodHTTP method string.
pathURL pattern.
handlersHandler function array.
handler_countNumber of handlers.
path_patternCanonical path pattern for docs.
input_typeRegistered type name for request-body (NULL if none).
output_typeRegistered type name for response (NULL if none).
summaryShort operation summary (NULL to omit).
descriptionDetailed description (NULL to omit).
perm_requiredPermission identifier (e.g., "read"), or NULL.
perm_resourceResource pattern (e.g., "users:*"), or NULL.

Combines csilk_router_add_extended with permission metadata in a single call. The permission fields are used by csilk_perm_auto_middleware.

Parameters
rThe router instance.
methodHTTP method.
pathURL path pattern.
handlersArray of handler functions.
handler_countNumber of handlers.
path_patternOriginal path pattern for OpenAPI metadata.
input_typeRegistered type name for request body, or NULL.
output_typeRegistered type name for response body, or NULL.
summaryOpenAPI operation summary, or NULL.
descriptionOpenAPI operation description, or NULL.
perm_requiredPermission identifier (e.g., "read"), or NULL.
perm_resourceResource pattern (e.g., "users:*"), or NULL.

◆ csilk_router_add_perm()

void csilk_router_add_perm ( csilk_router_t r,
const char *  method,
const char *  path,
csilk_handler_t handlers,
size_t  handler_count,
const char *  perm_required,
const char *  perm_resource 
)

Register a route with permission metadata.

Parameters
rRouter instance.
methodHTTP method string.
pathURL pattern.
handlersHandler function array.
handler_countNumber of handlers.
perm_requiredPermission identifier (e.g., "read"), or NULL.
perm_resourceResource pattern (e.g., "users:*"), or NULL.

Same as csilk_router_add but also stores permission requirement for interface-level access control. The auto-check middleware (csilk_perm_auto_middleware) reads these fields at request time.

Parameters
rThe router instance.
methodHTTP method.
pathURL path pattern.
handlersArray of handler functions.
handler_countNumber of handlers.
perm_requiredPermission identifier (e.g., "read", "write"), or NULL.
perm_resourceResource pattern (e.g., "users:*"), or NULL.

◆ csilk_router_collect_routes()

cJSON * csilk_router_collect_routes ( csilk_router_t r)

Collect all registered routes from the router tree as a cJSON array.

Collect metadata for all registered routes.

Parameters
rThe router instance.
Returns
A cJSON array of route objects. Caller must free with cJSON_Delete().

Traverses the radix tree and returns a cJSON array where each element contains "method", "path", "input_type", "output_type", "summary", and "description" fields.

Parameters
rRouter instance.
Returns
A cJSON array (caller must free with cJSON_Delete), or NULL on allocation failure.

Traverses the entire trie and returns a JSON array where each element is an object with method, path, input_type, output_type, summary, and description fields.

Parameters
rThe router instance.
Returns
A cJSON array of route objects. Caller must free with cJSON_Delete(). Returns NULL if the router is NULL or allocation fails.

◆ csilk_router_free()

void csilk_router_free ( csilk_router_t r)

Destroy the router and release all its resources.

Frees the radix tree nodes and any associated copy of route metadata (OpenAPI annotations).

Parameters
rRouter instance to free. Must not be NULL.

Destroy the router and release all its resources.

Recursively frees the entire trie starting from the root node, then frees the router struct itself.

Parameters
rThe router to free (may be NULL).

◆ csilk_router_match()

csilk_handler_t * csilk_router_match ( csilk_router_t r,
const char *  method,
const char *  path 
)

Match a raw method+path to handlers (standalone, no context).

Useful for testing or when no csilk_ctx_t is available. The returned array is owned by the router and must NOT be freed.

Parameters
rRouter instance.
methodHTTP method string.
pathDecoded URL path.
Returns
Pointer to the handler array for the matched route, or NULL if no route matches.

Match a raw method+path to handlers (standalone, no context).

Direct matching without populating path parameters. Useful for checking whether a route exists without processing a full request.

Parameters
rThe router instance.
methodHTTP method.
pathURL path.
Returns
Pointer to the handler array if matched, NULL otherwise.
Note
No parameter capture is performed since no context is provided.

◆ csilk_router_match_ctx()

int csilk_router_match_ctx ( csilk_router_t r,
csilk_ctx_t *  c 
)

Match the current request against the router and update the context.

On success the matched handlers are stored in the context and path parameters (csilk_get_param) become available.

Parameters
rRouter instance.
cRequest context containing the parsed request.
Returns
1 if a matching route was found, 0 if no route matches.

Match the current request against the router and update the context.

Sets the context's handlers array, handler index (reset to -1), and current_handler metadata on a successful match. Path parameters are captured into the context's params array.

Parameters
rThe router instance.
cThe request context (must have method and path set).
Returns
1 if a matching route was found, 0 otherwise.
Note
On success, the context is ready for csilk_next() to begin handler execution. On failure, the caller should send a 404 response.

◆ csilk_router_new()

csilk_router_t * csilk_router_new ( )

Create a new empty router.

Allocates and initialises the router structure with a single root node.

Returns
A pointer to the new router (heap-allocated), or NULL on allocation failure.

Create a new empty router.

Returns
A new csilk_router_t, or NULL on allocation failure.
Note
The router must be freed with csilk_router_free(). The root node is a static node with an empty segment, representing the root "/".

◆ csilk_serve_openapi()

void csilk_serve_openapi ( csilk_ctx_t *  c,
csilk_router_t r,
const char *  title,
const char *  version,
const char *  description 
)

Serve the OpenAPI JSON specification as the response.

Intended to be called from within a handler to expose the API spec.

void openapi_handler(csilk_ctx_t* c) {
csilk_serve_openapi(c, router, "My API", "1.0.0", "API Description");
}
static void openapi_handler(csilk_ctx_t *c)
Built-in handler for the /openapi.json endpoint.
Definition app.c:123
void csilk_serve_openapi(csilk_ctx_t *c, csilk_router_t *r, const char *title, const char *version, const char *description)
Serve the OpenAPI JSON specification as the response.
Definition swagger.c:625
Parameters
cThe request context.
rThe router instance whose routes will be documented.
titleAPI title.
versionAPI version.
descriptionAPI description (optional, pass NULL to omit).

Serve the OpenAPI JSON specification as the response.

Intended to be called from within a route handler. Generates the OpenAPI document via csilk_generate_openapi_json() and sends it as a JSON response.

Parameters
cThe request context.
rThe router instance.
titleAPI title.
versionAPI version.
descriptionAPI description.
Note
The response is sent synchronously via csilk_json(). On failure, a 500 error response is sent.

◆ csilk_serve_swagger_ui()

void csilk_serve_swagger_ui ( csilk_ctx_t *  c)

Serve the embedded Swagger UI page.

The UI loads the OpenAPI spec from /openapi.json (the client fetches it separately). Register a handler for GET /openapi.json that calls csilk_serve_openapi.

void docs_handler(csilk_ctx_t* c) {
}
static void docs_handler(csilk_ctx_t *c)
Built-in handler for the /docs endpoint — serves the Swagger UI HTML page.
Definition app.c:146
void csilk_serve_swagger_ui(csilk_ctx_t *c)
Serve the embedded Swagger UI page.
Definition swagger.c:709
Parameters
cThe request context.

Serve the embedded Swagger UI page.

◆ csilk_server_add_hook()

void csilk_server_add_hook ( csilk_server_t *  s,
csilk_hook_type_t  type,
void *  handler 
)

Register a lifecycle hook callback.

The handler is cast to the appropriate type internally based on type. Multiple handlers may be registered for the same hook type.

Parameters
sThe server instance.
typeThe hook type (see csilk_hook_type_t).
handlerPointer to the callback function. Must match the expected signature for type (csilk_server_hook_handler_t for SERVER_*, csilk_ctx_hook_handler_t for others).

Register a lifecycle hook callback.

Hooks are invoked at specific points in the request lifecycle (conn_open, conn_close, request_begin, request_end, server_start, server_stop). Multiple handlers can be registered for the same hook type; they are called in reverse order of registration (LIFO).

Parameters
sThe server instance.
typeHook type (CSILK_HOOK_CONN_OPEN, CSILK_HOOK_REQUEST_BEGIN, CSILK_HOOK_CONN_CLOSE, CSILK_HOOK_REQUEST_END, CSILK_HOOK_SERVER_START, CSILK_HOOK_SERVER_STOP).
handlerFunction pointer. For server hooks (start/stop), the signature is void(*)(csilk_server_t*). For context hooks, the signature is void(*)(csilk_ctx_t*).

◆ csilk_server_free()

void csilk_server_free ( csilk_server_t *  server)

Destroy the server and release all resources.

Stops the server if running, closes all connections, and frees the router, hooks, and internal structures.

Parameters
serverServer instance to free.

Destroy the server and release all resources.

Should only be called after the event loop has stopped. Joins any worker threads, frees the SPA doc root, drains the client pool, cleans up TLS, frees the message queue, frees all registered hooks, destroys the clients mutex, and frees the server struct.

Parameters
serverThe server to free (may be NULL).
Note
Safe to call with NULL. After this call the server pointer is invalid.

◆ csilk_server_get_mq()

csilk_mq_t * csilk_server_get_mq ( csilk_server_t *  server)

Get the Message Queue instance attached to a server.

The MQ is created lazily on first access.

Parameters
serverPointer to the server instance.
Returns
Pointer to the server's MQ, or NULL if the server is not yet initialised.

Get the Message Queue instance attached to a server.

The MQ is created automatically during csilk_server_new(). It can be used to register topics, subscribers, and publish messages.

Parameters
serverThe server instance.
Returns
Pointer to the MQ instance, or NULL if server is NULL.

◆ csilk_server_get_router()

csilk_router_t * csilk_server_get_router ( csilk_server_t *  server)

Get the router instance attached to a server.

Parameters
serverThe server instance.
Returns
Pointer to csilk_router_t.

◆ csilk_server_new()

csilk_server_t * csilk_server_new ( csilk_router_t router)

Create a new server instance.

Allocates and initialises a server bound to the given router. The server takes ownership of the router and frees it in csilk_server_free.

Parameters
routerThe router to use for request dispatch. Must not be NULL.
Returns
A new server instance, or NULL on allocation failure.

Create a new server instance.

Initializes the reflection system, allocates the server struct, sets up the libuv default loop, configures the llhttp parser callbacks, applies default server configuration (timeouts, buffer limits, backlog), creates a clients mutex, and creates the internal message queue (MQ) instance.

Parameters
routerThe router instance to use for request matching.
Returns
A new csilk_server_t instance, or NULL on allocation failure.
Note
The server must be configured (via csilk_server_set_config()) and started via csilk_server_run(). Free with csilk_server_free().

◆ csilk_server_run()

int csilk_server_run ( csilk_server_t *  server,
int  port 
)

Start the server and enter the libuv event loop.

This call blocks until the server is stopped (csilk_server_stop) or a fatal error occurs.

Parameters
serverServer instance.
portTCP port to listen on.
Returns
0 on normal shutdown, -1 on initialisation failure.

Start the server and enter the libuv event loop.

This is the final step in server startup. The full bootstrap sequence:

  1. TLS init: load SSL_CTX with cert + key (if enable_tls is set). If TLS init fails, the server returns -1 (fail-fast).
  2. Async handle: uv_async_init for cross-thread stop signals. csilk_server_stop() calls uv_async_send() which wakes the event loop and runs on_stop_async().
  3. Bind + listen: bind_and_listen() with SO_REUSEPORT if worker_threads > 1, otherwise standard single-socket bind.
  4. TCP keepalive: if configured, enable TCP keepalive probes to detect dead peers.
  5. Worker threads: if worker_threads > 1, spawn N-1 worker threads each running their own libuv loop + accept loop (SO_REUSEPORT). The main thread also runs its own event loop, so total accept loops = worker_threads.
  6. SIGINT handler: register a libuv signal watcher that calls csilk_server_stop() on SIGINT (Ctrl+C).
  7. Fire CSILK_HOOK_SERVER_START.
  8. uv_run(): enter the event loop. Blocks until the loop stops (via csilk_server_stop() or SIGINT).
Parameters
serverThe server instance.
portTCP port to bind to.
Returns
The uv_run() return value on exit, or -1 on initialization failure.
Note
When worker_threads > 1, the main thread runs the event loop and additional worker threads each run their own independent loop.

◆ csilk_server_set_cipher_driver()

void csilk_server_set_cipher_driver ( csilk_server_t *  server,
csilk_cipher_driver_t driver 
)

Set the global cipher algorithm driver for the server.

Replaces the built-in AES/RSA routines with a user-provided implementation.

Parameters
serverThe server instance.
driverPointer to a csilk_cipher_driver_t.

◆ csilk_server_set_config()

void csilk_server_set_config ( csilk_server_t *  server,
const csilk_server_config_t config 
)

Apply server configuration options.

Copies values from config into the server's internal state. Should be called before csilk_server_run. The config struct may be stack-allocated.

Parameters
serverServer instance.
configPointer to the configuration to apply.

Apply server configuration options.

Copies the provided configuration into the server instance. This should be called before csilk_server_run().

Parameters
serverThe server instance.
configPointer to the configuration to apply (copied by value).

◆ csilk_server_set_crypto_driver()

void csilk_server_set_crypto_driver ( csilk_server_t *  server,
csilk_crypto_driver_t driver 
)

Set the global crypto driver for the server.

Replaces the default software crypto routines with a user-provided implementation. Pass NULL to restore the built-in defaults.

Parameters
serverThe server instance.
driverPointer to a csilk_crypto_driver_t, or NULL for defaults. The driver struct must remain valid for the server's lifetime.

Set the global crypto driver for the server.

When set, HMAC and UUID operations on request contexts will delegate to the driver instead of using the built-in software implementations.

Parameters
serverThe server instance.
driverPointer to the crypto driver vtable (may be NULL to reset).

◆ csilk_server_set_max_connections()

int csilk_server_set_max_connections ( csilk_server_t *  server,
int  max 
)

Set the maximum number of concurrent connections and return the previous limit.

Parameters
serverServer instance.
maxNew limit (0 = unlimited).
Returns
The previous maximum connections value.

Set the maximum number of concurrent connections and return the previous limit.

When this limit is reached, new connections are accepted and immediately closed to drain the listen backlog. A value of 0 means unlimited.

Parameters
serverThe server instance.
maxMaximum concurrent connections (0 for unlimited).
Returns
The previous maximum connections value, or -1 if server is NULL.

◆ csilk_server_set_not_found_handler()

void csilk_server_set_not_found_handler ( csilk_server_t *  server,
csilk_handler_t  handler 
)

Set a custom handler for 404 (route-not-found) responses.

Replaces the default 404 behaviour. The handler is invoked with the request context (status 404 is NOT pre-set — the handler may set its own). Pass NULL to restore the default 404 handler.

Parameters
serverServer instance.
handlerHandler function, or NULL for default.

Set a custom handler for 404 (route-not-found) responses.

Replaces the default "Not Found" plain-text response with a custom handler. Overridden by csilk_server_set_spa_fallback().

Parameters
serverThe server instance.
handlerHandler function invoked for unmatched routes.

◆ csilk_server_set_spa_fallback()

void csilk_server_set_spa_fallback ( csilk_server_t *  server,
const char *  doc_root 
)

Enable single-page application (SPA) fallback mode.

Unmatched GET requests serve index.html from doc_root instead of returning 404. Overrides any custom 404 handler. Useful for serving React/Vue/Angular SPAs where the router handles URLs client-side.

Parameters
serverServer instance.
doc_rootDirectory containing index.html. The path is copied internally.

Enable single-page application (SPA) fallback mode.

Sets the SPA document root and replaces the 404 handler with the built-in spa_fallback_handler. Overrides any custom 404 handler set via csilk_server_set_not_found_handler().

Parameters
serverThe server instance.
doc_rootAbsolute or relative filesystem path to the directory containing index.html.
Note
The doc_root string is strdup'd internally. Pass NULL to disable.

◆ csilk_server_set_storage_driver()

void csilk_server_set_storage_driver ( csilk_server_t *  server,
csilk_storage_driver_t driver 
)

Replace the context key-value storage driver.

Parameters
serverServer instance.
driverPointer to the new driver, or NULL to restore the default in-memory arena-backed driver. The driver struct must remain valid for the server's lifetime.

Replace the context key-value storage driver.

When set, calls to csilk_set()/csilk_get() on request contexts belonging to this server will delegate to the driver instead of using the default arena-backed linked list.

Parameters
serverThe server instance.
driverPointer to the storage driver vtable (may be NULL to reset).

◆ csilk_server_stop()

void csilk_server_stop ( csilk_server_t *  server)

Request a graceful server shutdown.

Signals the event loop to stop after all active requests complete. New connections are refused.

Parameters
serverServer instance.

Request a graceful server shutdown.

Sends an async signal to the event loop which triggers on_stop_async() on the main loop thread. The function returns immediately; the server shuts down asynchronously.

Parameters
serverThe server instance.
Note
This is safe to call from any thread, including signal handlers.

◆ csilk_server_use()

int csilk_server_use ( csilk_server_t *  server,
csilk_handler_t  handler 
)

Register global middleware.

Middleware is executed for every request in the order it was added. The handler array has a fixed maximum size (typically 64).

Parameters
serverServer instance.
handlerMiddleware function.
Returns
0 on success, -1 if the internal handler array is full.

Register global middleware.

Global middlewares are prepended to the matched route's handler chain. They run before route-specific middleware and the final handler. There is a hard limit of 32 global middlewares.

Parameters
serverThe server instance.
handlerMiddleware handler function.
Returns
0 on success, -1 if the limit is reached or parameters are NULL.

◆ csilk_session_destroy()

void csilk_session_destroy ( csilk_ctx_t *  c)

Destroy the session and clear the session cookie.

Removes all stored session data and sets a Set-Cookie header with an expired session ID to instruct the client to delete it.

Parameters
cThe request context.

Destroy the session and clear the session cookie.

Removes the session from the global store, frees all its key-value data items and the session struct itself, clears the "_session" context entry, and sets an empty session cookie with a negative max-age to instruct the client to delete it.

Parameters
cThe request context.

◆ csilk_session_get()

void * csilk_session_get ( csilk_ctx_t *  c,
const char *  key 
)

Retrieve a value from the session.

Parameters
cThe request context.
keyKey name.
Returns
The value previously stored with csilk_session_set, or NULL if not found.

Searches the current session's data list for the given key and returns its associated value.

Parameters
cThe request context (used to look up the session).
keyNull-terminated key string. Must not be NULL.
Returns
The value pointer previously stored with csilk_session_set(), or NULL if the key is not found or no session is active.

◆ csilk_session_init()

void csilk_session_init ( void  )

Initialise the session subsystem (call once at startup).

Must be called before any request handling. Sets up the session ID generator and storage backend.

Initialise the session subsystem (call once at startup).

Performs an immediate cleanup of any expired sessions from the store. This should be called once during server startup.

◆ csilk_session_set()

void csilk_session_set ( csilk_ctx_t *  c,
const char *  key,
void *  value 
)

Store a value in the session.

Parameters
cThe request context.
keyKey name (copied internally).
valueOpaque value pointer (ownership remains with caller).

If the key already exists in the current session, its value is replaced. Otherwise, a new key-value pair is prepended to the session's data list.

Parameters
cThe request context (used to look up the session via csilk_get(c, "_session")).
keyNull-terminated key string. Must not be NULL.
valueOpaque pointer to the value to store. May be NULL.
Note
The key is duplicated via strdup(). The value pointer is stored as-is — the caller is responsible for managing its lifetime.
Warning
This function does NOT acquire the session mutex. It operates on the session pointer stored in the per-request context, which is already exclusively owned by the current request handler.

◆ csilk_session_start()

void csilk_session_start ( csilk_ctx_t *  c)

Start or resume a session for the current request.

If the client sent a session cookie, the existing session is loaded. Otherwise a new session is created and a Set-Cookie header is added.

Parameters
cThe request context.

Looks for an existing session cookie named "csilk_session". If a valid session is found, its expiry is extended by SESSION_TTL seconds. If not, a new session is created with a fresh UUID, stored in the global list, and a session cookie is set on the response. The session pointer is stored in the context under the key "_session".

Parameters
cThe request context.
Note
Must be called after csilk_request_id_middleware (or equivalent) so that _csilk_generate_uuid is available.
Warning
The session's data items are NOT automatically serialized to persistent storage. All sessions are in-memory and are lost on process restart.

◆ csilk_set()

void csilk_set ( csilk_ctx_t *  c,
const char *  key,
void *  value 
)

Store an opaque value in the request context.

The key string is duplicated into the request arena. The value pointer is stored as-is — the context does NOT take ownership. The caller must ensure the pointed-to data remains valid at least until csilk_ctx_cleanup.

Parameters
cThe request context.
keyNUL-terminated key name (a copy is made internally).
valueOpaque pointer to store. May be NULL (which will be returned by csilk_get, so storing NULL is indistinguishable from "not set" — avoid it).

Store an opaque value in the request context.

If a storage driver is set on the context, delegates to it. Otherwise, uses a simple linked list allocated from the arena. If the key already exists, its value is replaced. There is a hard limit of 64 storage items per request to prevent excessive arena consumption.

Parameters
cThe request context.
keyStorage key (null-terminated string).
valueOpaque pointer to store (may be NULL to clear a previous value).
Note
The key is duplicated into arena memory. The value is stored as a raw pointer — no deep copy or freeing is performed.

◆ csilk_set_async()

void csilk_set_async ( csilk_ctx_t *  c,
int  is_async 
)

Enable or disable asynchronous response mode.

When async mode is enabled the framework will NOT automatically flush the response after the handler chain returns. The handler is responsible for calling csilk_response_write / csilk_response_end at a later time (e.g., after an async I/O operation completes).

Parameters
cThe request context.
is_async1 to enable async mode, 0 to disable (default).

Enable or disable asynchronous response mode.

When a response is asynchronous, the framework will NOT automatically send the response after the handler chain completes. The handler is responsible for calling _csilk_send_response() or _csilk_send_data() explicitly after the async operation finishes.

Parameters
cThe request context.
is_async1 to enable async mode, 0 to disable.
Note
Async mode is automatically set by csilk_response_write() for streaming responses.

◆ csilk_set_cookie()

void csilk_set_cookie ( csilk_ctx_t *  c,
const char *  name,
const char *  value,
int  max_age,
const char *  path,
const char *  domain,
int  secure,
int  http_only 
)

Set a cookie in the Set-Cookie response header.

Appends a Set-Cookie header (using csilk_add_header so multiple cookies are preserved).

Parameters
cThe request context.
nameCookie name (not URL-encoded — the caller must encode if needed).
valueCookie value (not URL-encoded).
max_ageLifetime in seconds: >0 = max age, 0 = session cookie, -1 = immediate expiry (delete).
pathCookie path scope, or NULL for "/".
domainCookie domain scope, or NULL for current host.
secureNon-zero adds the Secure flag (HTTPS only).
http_onlyNon-zero adds the HttpOnly flag (not accessible to JS).

Set a cookie in the Set-Cookie response header.

Constructs a properly formatted Set-Cookie header with the given name, value, and attributes. The cookie is added using csilk_add_header() so multiple cookies can be set on the same response.

Parameters
cThe request context.
nameCookie name (cannot be NULL).
valueCookie value (cannot be NULL).
max_ageCookie Max-Age in seconds. Pass 0 to omit, negative for immediate expiry (Max-Age=0), positive for a future expiry.
pathCookie path (pass NULL for default "/").
domainCookie domain (pass NULL to omit).
secureIf non-zero, adds the Secure flag.
http_onlyIf non-zero, adds the HttpOnly flag.
Note
The cookie is arena-allocated. The name+value and attribute strings should not contain characters that break cookie formatting.

◆ csilk_set_header()

void csilk_set_header ( csilk_ctx_t *  c,
const char *  key,
const char *  value 
)

Set (or overwrite) a response header.

If the header already exists its value is replaced. Key and value are copied into the request arena.

Parameters
cThe request context.
keyThe header field name.
valueThe header field value.

Set (or overwrite) a response header.

Parameters
cThe request context.
keyHeader key.
valueHeader value.
Note
Both key and value are duplicated into arena memory.
To allow duplicate values (e.g., multiple Set-Cookie), use csilk_add_header() instead.

◆ csilk_set_on_ws_message()

void csilk_set_on_ws_message ( csilk_ctx_t *  c,
void(*)(csilk_ctx_t *c, const uint8_t *payload, size_t len, int opcode)  callback 
)

Register a callback for incoming WebSocket messages.

Must be called after csilk_ws_handshake and before the event loop delivers data. The callback receives the context, payload bytes, payload length, and the WebSocket opcode.

Parameters
cThe request context.
cbCallback function invoked for each received message. The callback must not block; it runs on the event-loop thread.

The callback is invoked for each data frame received on the WebSocket connection. It receives the context, payload pointer, payload length, and the WebSocket opcode (0x01 for text, 0x02 for binary).

Parameters
cThe request context.
cbCallback function. It receives the context, a pointer to the unmasked payload data, the payload length, and the frame opcode.
Note
The payload pointer is valid only within the callback invocation. If the handler needs the data after the callback returns, it must copy it.

◆ csilk_set_on_ws_send()

void csilk_set_on_ws_send ( csilk_ctx_t *  c,
void(*)(csilk_ctx_t *c, const uint8_t *payload, size_t len, int opcode)  callback 
)

Set a callback for outgoing WebSocket frames (for testing).

◆ csilk_set_request_header()

void csilk_set_request_header ( csilk_ctx_t *  c,
const char *  key,
const char *  value 
)

Set (or overwrite) a request header.

The key and value are copied into the request arena.

Parameters
cThe request context.
keyThe header field name.
valueThe header field value.

Set (or overwrite) a request header.

Parameters
cThe request context.
keyHeader key (case-insensitive for matching on subsequent lookups).
valueHeader value.
Note
Both key and value are duplicated into arena memory.

◆ csilk_set_response_body()

void csilk_set_response_body ( csilk_ctx_t *  c,
const char *  body,
size_t  len,
int  managed 
)

Overwrite the response body from middleware.

Useful for middleware that transforms the response (e.g., gzip compression, response transformation). If managed is 1 the framework takes ownership and calls free() when the response is sent.

Parameters
cThe request context.
bodyPointer to the new body data.
lenByte length of body.
managedOwnership flag: 1 = framework calls free(body) when done, 0 = caller retains ownership and body must stay valid until the response is sent.

Overwrite the response body from middleware.

Replaces any existing response body. If the old body was marked as managed it is freed before replacement. The caller specifies whether the new body should be freed automatically during cleanup.

Parameters
cThe request context.
bodyPointer to the body data (may be NULL).
lenBody length in bytes.
managedIf non-zero, the framework will free body during cleanup.
Note
Setting managed=1 transfers ownership to the framework. With managed=0 the caller retains ownership and must keep the pointer valid until the response is sent.

◆ csilk_split_url()

void csilk_split_url ( const char *  url,
char **  path,
char **  query 
)

Split a URL into path and query-string components.

Internal helper. The returned path and query point into the original url string (the '?' separator is overwritten with NUL).

Parameters
urlFull URL string (will be modified in-place).
[out]pathReceives a pointer to the path portion inside url.
[out]queryReceives a pointer to the query portion inside url, or NULL if no query was present.

Split a URL into path and query-string components.

Finds the first '?' separator. The path portion is URL-decoded and returned in path. The query portion (everything after '?') is returned raw in query (NOT URL-decoded — use csilk_parse_query() for that). If there is no '?', the entire URL is treated as the path and query is set to NULL.

Parameters
urlFull URL string (e.g., "/foo/bar?key=val").
path[out] Receives a malloc'd, URL-decoded path string.
query[out] Receives a malloc'd raw query string, or NULL if no query was present.
Note
Both output strings must be freed by the caller with free(). On allocation failure, both outputs may be NULL.

◆ csilk_sse_close()

void csilk_sse_close ( csilk_ctx_t *  c)

Close the SSE connection.

Sends any remaining buffered data and closes the TCP connection.

Parameters
cThe request context.

Closes the underlying libuv stream handle for the SSE client connection. Performs a graceful close via uv_close(). Any pending write requests will complete before the handle is fully closed.

Parameters
cThe request context (must be in SSE mode with an active client).

◆ csilk_sse_init()

void csilk_sse_init ( csilk_ctx_t *  c)

Initialise a Server-Sent Events connection.

Sends the HTTP 200 response with Content-Type: text/event-stream and disables request buffering. Must be called at the start of an SSE handler before any csilk_sse_send calls.

Parameters
cThe request context.

Initialise a Server-Sent Events connection.

Sets the Content-Type, Cache-Control, Connection, and X-Accel-Buffering headers, marks the context as an SSE connection (is_sse = 1), and writes the raw HTTP 200 OK response headers directly to the client socket.

Parameters
cThe request context.
Note
After calling csilk_sse_init(), the connection is established and the caller should not call csilk_next() — SSE hijacks the socket.
Warning
The headers are written as a raw string bypassing the normal response pipeline. The connection remains open for the lifetime of the SSE stream.

◆ csilk_sse_send()

void csilk_sse_send ( csilk_ctx_t *  c,
const char *  event,
const char *  data 
)

Send an SSE event (or comment) to the client.

Formats and flushes one SSE message. If event is NULL and data is non-NULL, a default "message" event is sent. If data is NULL, a comment line (starting with ":") is written.

Parameters
cThe request context.
eventOptional event type string (e.g., "update"), or NULL.
dataEvent data string, or NULL to send a comment line.

Send an SSE event (or comment) to the client.

Formats and writes a Server-Sent Event message to the client. If an event type is provided, an "event:" line is emitted. The data is written as a "data:" line. Both are terminated by an empty line ("\n") as required by the SSE specification (RFC 8895 §2).

Parameters
cThe request context (must be in SSE mode).
eventOptional event type string (e.g. "message", "update"). May be NULL, in which case no "event:" line is emitted.
dataThe event payload string. May be NULL (produces a "data:" line with no content). Must not contain embedded "\n\n" sequences unless multi-line data is intended per SSE spec.
Note
Each send allocates a new buffer and write request. For high- frequency event streams, consider batching or a pooled allocator.
Warning
This function does NOT check for backpressure. If the client reads slower than the server writes, the kernel buffer may fill and writes will fail with EAGAIN (reported via on_sse_write).

◆ csilk_static()

void csilk_static ( csilk_ctx_t *  c,
const char *  root_dir 
)

Serve static files from a local directory.

Maps the current request path to a file under root_dir. If the file exists and is readable its contents are sent with the appropriate Content-Type. If not found the handler chain continues (so a 404 handler can pick it up).

Note
The URL prefix must be stripped from c->request.path before calling this function (the low-level API uses the raw path). Use csilk_app_static() for automatic prefix handling.
Parameters
cThe request context.
root_dirAbsolute or relative path to the directory to serve.

Serve static files from a local directory.

Offloads file resolution, path traversal checks, and file open/stat operations to the libuv thread pool. The response is sent via the normal _csilk_send_response() path, which sends the file using platform-specific zero-copy mechanisms (e.g. sendfile on Linux).

The URL prefix is automatically stripped from the request path before resolving against root_dir — the "static_prefix" must be set via csilk_set(c, "static_prefix", prefix_string) before calling this function.

Parameters
cThe request context.
root_dirAbsolute or relative path to the static file root directory. Must not be NULL.
Note
The prefix is configured separately via csilk_set(c, "static_prefix", ...) NOT via this function's parameters.
Warning
Path traversal attacks are mitigated via realpath() comparison. Ensure root_dir does not contain symlinks that could be exploited.

◆ csilk_status()

void csilk_status ( csilk_ctx_t *  c,
int  status 
)

Set the HTTP response status code.

Parameters
cThe request context.
statusThe HTTP status code (e.g., 200, 404, 500).
cThe request context.
statusHTTP status code (e.g., 200, 404, 500).
Note
Also accessible via CSILK_STATUS_OK, CSILK_STATUS_NOT_FOUND, etc.

◆ csilk_string()

void csilk_string ( csilk_ctx_t *  c,
int  status,
const char *  msg 
)

Set a plain-text response body and status code.

The msg string is copied into the request arena so the caller's buffer can be reused immediately. Equivalent to calling csilk_status then setting the response body.

Parameters
cThe request context.
statusThe HTTP status code.
msgThe plain-text body string (NUL-terminated).

Set a plain-text response body and status code.

If the context has an arena allocator, the body string is duplicated into arena memory. Otherwise, it falls back to strdup() and marks the body as managed (so it will be freed during cleanup). The Content-Type header is NOT set automatically — callers should set it explicitly if needed.

Parameters
cThe request context.
statusHTTP status code for the response.
msgPlain text body (may be NULL).
Note
Ownership: when arena is unavailable, the strdup'd copy is freed automatically during csilk_ctx_cleanup(). Safe to pass NULL for msg.

◆ csilk_validate()

const char * csilk_validate ( csilk_ctx_t *  c,
const csilk_valid_rule_t rules 
)

Validate request parameters against a set of rules.

Iterates through the rule array and checks each field for presence, type, and range constraints. Returns the name of the first field that fails validation.

Parameters
cThe request context.
rulesNULL-terminated array of csilk_valid_rule_t. The array must end with an entry whose field field is NULL.
Returns
NULL if all rules pass, or a pointer to the failing field name (the returned pointer points into the rule array, not into the context).

Validate request parameters against a set of rules.

Iterates through an array of validation rules, stopping at the first rule that fails. Each rule specifies the source of the value (query, form, header, cookie, or automatic fallback) and the validation flags to apply (CSILK_VALID_REQUIRED, CSILK_VALID_INT, CSILK_VALID_STRING, CSILK_VALID_EMAIL).

For integer validation, an optional [min, max] range can be specified. For string validation, an optional [min, max] length range can be specified. Ranges are ignored when min >= max.

Parameters
cThe request context to extract values from.
rulesA null-terminated array of csilk_valid_rule_t rules (the last entry must have field == NULL). Must not be NULL.
Returns
NULL if all rules pass, or a pointer to the field name (string from the rule definition) of the first field that fails.
Note
When no explicit source is specified, the function first tries the query string, then falls back to the form body.
Warning
The returned error pointer points into the rules array; it must not be freed or dereferenced after the rules array goes out of scope.

◆ csilk_ws_broadcast_room()

void csilk_ws_broadcast_room ( csilk_ctx_t *  c,
const char *  room_name,
const char *  message 
)

Broadcast a message to all WebSockets in a room via MQ.

Parameters
cRequest context (used to access the server's MQ).
room_nameRoom to broadcast to.
messageNUL-terminated message string.

◆ csilk_ws_close()

void csilk_ws_close ( csilk_ctx_t *  c,
uint16_t  status_code,
const char *  reason 
)

Send a WebSocket close frame.

Initiates the close handshake per RFC 6455 §5.5.1. After sending, the server waits for the client's close frame before fully closing the TCP connection.

Parameters
cThe request context.
status_codeClose status code (e.g., 1000 for normal closure, 0 to omit the status code from the frame).
reasonOptional human-readable reason string (may be NULL).

Send a WebSocket close frame.

Constructs and sends a close frame with an optional status code and reason string. The payload is limited to 125 bytes (close frame + reason). After sending, the connection is NOT immediately closed — the peer is expected to respond with its own close frame.

Parameters
cThe request context.
status_codeWebSocket close status code (e.g., 1000 for normal, 1001 for "going away"). Pass 0 to omit the status code.
reasonHuman-readable reason string (may be NULL).
Note
The frame is sent asynchronously. The connection should be closed by the caller after receiving the peer's close frame or on timeout.

◆ csilk_ws_handshake()

void csilk_ws_handshake ( csilk_ctx_t *  c)

Perform the WebSocket upgrade handshake (HTTP Upgrade request).

Validates the Upgrade, Connection, Sec-WebSocket-Key, and version headers, computes the Sec-WebSocket-Accept response, and sends a 101 Switching Protocols response. After success, csilk_is_websocket returns 1 and the connection can send/receive frames.

Parameters
cThe request context.

Perform the WebSocket upgrade handshake (HTTP Upgrade request).

Validates the presence of the Sec-WebSocket-Key header, computes the expected Sec-WebSocket-Accept response by concatenating the key with the WebSocket GUID ("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"), SHA-1 hashing the result, and Base64-encoding the digest. Sets the Upgrade, Connection, and Sec-WebSocket-Accept response headers, sets status to 101 Switching Protocols, and marks the context as a WebSocket connection.

Parameters
cThe request context.
Note
After a successful handshake, the context's is_websocket flag is set and the connection is ready for frame I/O via csilk_ws_send() and csilk_ws_parse_frame(). On failure (missing Sec-WebSocket-Key), a 400 Bad Request JSON error is sent.

◆ csilk_ws_join_room()

void csilk_ws_join_room ( csilk_ctx_t *  c,
const char *  room_name 
)

Join a WebSocket client to a room.

Parameters
cRequest context (must be a WebSocket).
room_nameName of the room to join.

◆ csilk_ws_leave_room()

void csilk_ws_leave_room ( csilk_ctx_t *  c,
const char *  room_name 
)

Remove a WebSocket client from a room.

Parameters
cRequest context.
room_nameName of the room to leave.

◆ csilk_ws_send()

void csilk_ws_send ( csilk_ctx_t *  c,
const uint8_t *  payload,
size_t  len,
int  opcode 
)

Send a WebSocket data frame.

Encodes and sends a single WebSocket frame per RFC 6455. Masks the payload if required (client-to-server masking).

Parameters
cThe request context.
payloadRaw data to send.
lenByte length of payload.
opcodeWebSocket opcode: 0x1 for text, 0x2 for binary, 0x9 for ping.

Send a WebSocket data frame.

Constructs a WebSocket frame with the FIN bit set (final fragment), the specified opcode (0x01 for text, 0x02 for binary), and no masking (server-to-client frames are unmasked per RFC 6455). Supports payload lengths up to 2^64-1 using 7-bit, 16-bit, or 64-bit extended length fields as appropriate.

Parameters
cThe request context (must have _internal_client set).
payloadFrame payload data.
lenPayload length in bytes.
opcodeWebSocket opcode (0x01 for text, 0x02 for binary).
Note
The payload is copied into a heap-allocated frame buffer which is freed by the write completion callback. This function returns immediately; the write happens asynchronously.