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

Request/response context implementation. More...

#include <ctype.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <uv.h>
#include "context_internal.h"
#include "csilk/core/internal.h"
#include "csilk/csilk.h"
#include "server_internal.h"
Include dependency graph for context.c:

Functions

static uint32_t hash_key (const char *key)
 Hash a header key string into a bucket index using djb2.
 
static const char * map_get (csilk_header_map_t *map, const char *key)
 Look up a header value by key in the hash map (case-insensitive).
 
static void map_set (csilk_ctx_t *c, csilk_header_map_t *map, const char *key, const char *value)
 Set a header value in the hash map, overwriting any existing entry.
 
static void map_add (csilk_ctx_t *c, csilk_header_map_t *map, const char *key, const char *value)
 Add a header value to the hash map, allowing duplicate keys.
 
void csilk_next (csilk_ctx_t *c)
 Advance to the next handler in the chain and invoke it.
 
void csilk_abort (csilk_ctx_t *c)
 Abort the handler chain immediately.
 
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 the response body as plain text with a status code.
 
const char * csilk_get_param (csilk_ctx_t *c, const char *key)
 Get a URL path parameter value by name.
 
int csilk_get_params_count (csilk_ctx_t *c)
 Get the count of path parameters.
 
const char * csilk_get_param_key (csilk_ctx_t *c, int index)
 Get the name of a parameter by index.
 
const char * csilk_get_param_value (csilk_ctx_t *c, int index)
 Get the value of a parameter by index.
 
const char * csilk_get_header (csilk_ctx_t *c, const char *key)
 Get a request header value by key (case-insensitive).
 
const char * csilk_get_response_header (csilk_ctx_t *c, const char *key)
 Get a response header value by key (case-insensitive).
 
const char * csilk_get_query (csilk_ctx_t *c, const char *key)
 Get a query parameter value by key.
 
void csilk_set_request_header (csilk_ctx_t *c, const char *key, const char *value)
 Set a request header, overwriting any existing value for the same key.
 
void csilk_set_header (csilk_ctx_t *c, const char *key, const char *value)
 Set a response header, overwriting any existing value for the same key.
 
void csilk_ctx_cleanup (csilk_ctx_t *c)
 Clean up request context resources between requests.
 
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 URL path of the current request.
 
const char * csilk_get_body (csilk_ctx_t *c, size_t *out_len)
 Get the request body data and optionally its length.
 
size_t csilk_get_body_len (csilk_ctx_t *c)
 Get the length of the request body.
 
int csilk_is_websocket (csilk_ctx_t *c)
 Check if the current request is a WebSocket upgrade.
 
void csilk_set_websocket (csilk_ctx_t *c, int is_websocket)
 Enable/disable WebSocket mode.
 
int csilk_is_sse (csilk_ctx_t *c)
 Check if the current connection is a Server-Sent Events stream.
 
void csilk_set_sse (csilk_ctx_t *c, int is_sse)
 Enable/disable SSE mode.
 
void * _csilk_get_internal_client (csilk_ctx_t *c)
 Get the internal client connection handle.
 
void _csilk_set_internal_client (csilk_ctx_t *c, void *client)
 Set the internal client connection handle.
 
const char * csilk_get_request_id (csilk_ctx_t *c)
 Get the unique request ID string.
 
csilk_arena_tcsilk_get_arena (csilk_ctx_t *c)
 Get the arena allocator associated with the context.
 
int csilk_get_status (csilk_ctx_t *c)
 Get the currently set response status code.
 
void csilk_set_async (csilk_ctx_t *c, int is_async)
 Mark the response as asynchronous (sent later, not automatically).
 
csilk_server_t * csilk_ctx_get_server (csilk_ctx_t *c)
 Get the server instance owning this context.
 
csilk_mq_t * csilk_ctx_get_mq (csilk_ctx_t *c)
 Get the internal MQ instance from the context.
 
int csilk_is_async (csilk_ctx_t *c)
 Check if the response is in async mode.
 
int csilk_get_handler_index (csilk_ctx_t *c)
 Get the handler chain index.
 
void csilk_set_request_id (csilk_ctx_t *c, const char *id)
 Set the request UUID.
 
uv_work_t * csilk_get_work_req (csilk_ctx_t *c)
 Get the internal libuv work request.
 
void csilk_set_file_response (csilk_ctx_t *c, int fd, size_t offset, size_t size)
 Configure zero-copy file transmission.
 
int csilk_get_file_fd (csilk_ctx_t *c)
 Get the zero-copy file descriptor.
 
const char * csilk_ctx_get_handler_path (csilk_ctx_t *c)
 Get the route pattern for the current request.
 
const char * csilk_ctx_get_handler_perm_required (csilk_ctx_t *c)
 Get the permission required by the current handler.
 
const char * csilk_ctx_get_handler_perm_resource (csilk_ctx_t *c)
 Get the resource pattern for the current handler's permission check.
 
const char * csilk_get_response_body (csilk_ctx_t *c, size_t *out_len)
 Get the response body data and optionally its length.
 
void csilk_set_response_body (csilk_ctx_t *c, const char *body, size_t len, int managed)
 Set the response body directly with explicit ownership semantics.
 
int csilk_is_aborted (csilk_ctx_t *c)
 Check if the client has disconnected (connection 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).
 
void _csilk_ctx_init (csilk_ctx_t *c, struct csilk_server_s *s, void *client)
 Initialize a request context.
 
void csilk_ctx_set_storage_driver (csilk_ctx_t *c, csilk_storage_driver_t *driver)
 Set the storage driver.
 
void csilk_ctx_set_crypto_driver (csilk_ctx_t *c, csilk_crypto_driver_t *driver)
 Set the crypto driver.
 
void csilk_ctx_set_cipher_driver (csilk_ctx_t *c, csilk_cipher_driver_t *driver)
 Set the cipher driver.
 
void csilk_redirect (csilk_ctx_t *c, int status, const char *location)
 Redirect the client to a different URL with a specific status code.
 
void csilk_redirect_simple (csilk_ctx_t *c, const char *url)
 Redirect to another URL using the default status code 302 (Found).
 
void csilk_set (csilk_ctx_t *c, const char *key, void *value)
 Store a value in the context's key-value storage.
 
void * csilk_get (csilk_ctx_t *c, const char *key)
 Retrieve a value from the context's key-value storage.
 
cJSON * csilk_bind_json (csilk_ctx_t *c)
 Parse the request body as JSON using cJSON.
 
cJSON * csilk_bind_json_err (csilk_ctx_t *c, const char **error)
 Parse the request body as JSON with detailed error feedback.
 
const char * csilk_get_cookie (csilk_ctx_t *c, const char *name)
 Get a cookie value by its name from the Cookie header.
 
void csilk_add_header (csilk_ctx_t *c, const char *key, const char *value)
 Add a response header, allowing multiple values for the same key.
 
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 response via Set-Cookie header.
 
void csilk_json (csilk_ctx_t *c, int status, cJSON *json)
 Send a JSON response. The cJSON object is freed by this call.
 
void csilk_json_error (csilk_ctx_t *c, int status, const char *message)
 Send a JSON error response containing an "error" field.
 
int csilk_bind_reflect (csilk_ctx_t *c, const char *type_name, void *ptr)
 Bind the request body JSON to a registered struct via reflection.
 
void csilk_json_reflect (csilk_ctx_t *c, int status, const char *type_name, const void *ptr)
 Send a JSON response from a registered struct via reflection.
 
void csilk_parse_query (csilk_ctx_t *c, const char *query_string)
 Parse a raw query string into the context's query_params hash map.
 
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.
 
static void on_stream_write (uv_write_t *req, int status)
 libuv write completion callback for streaming (non-terminal) writes.
 
static int client_wants_close (csilk_ctx_t *c)
 Check if the client requested "Connection: close" in the request.
 
static void on_stream_end_write (uv_write_t *req, int status)
 libuv write completion callback for a terminal chunk — closes the connection.
 
static int send_chunked_headers (csilk_ctx_t *c)
 Send HTTP response headers with Transfer-Encoding: chunked.
 
static void write_chunk_frame (csilk_ctx_t *c, const uint8_t *data, size_t len)
 Write a single chunked transfer frame: [hex-size]\r\n[data]\r\n.
 
void csilk_response_write (csilk_ctx_t *c, const uint8_t *data, size_t len)
 Write data to a streaming response using chunked transfer encoding.
 
void csilk_response_end (csilk_ctx_t *c)
 Finalize a streaming response by sending the terminal chunk.
 

Variables

void(*)(csilk_ctx_t *c, const uint8_t *payload, size_t len, int opcode) csilk_get_on_ws_message (csilk_ctx_t *c)
 Get the registered WebSocket callback.
 

Detailed Description

Request/response context implementation.

Provides the per-request csilk_ctx_t lifecycle: header hash-map operations (djb2-based, case-insensitive), request/body management, response status and body setup, query parameter parsing, async/chunked response support, and context cleanup.

Key design points:

  • Headers are stored in a fixed-size hash map (CSILK_HEADER_BUCKETS) with linked-list chaining. Allocations come from the request arena for zero-fragmentation cleanup.
  • The context carries an arena (bump allocator) for all request-scoped allocations — path strings, query params, handler chains, header entries. The entire arena is freed in one shot at request end.
  • Query parameters are parsed from the URL query string on demand and split into key=value pairs.
  • Async mode is signalled via ctx->is_async: when true, the response is NOT sent in on_message_complete; the handler must call csilk_send() or csilk_stream() explicitly.
  • The context also holds driver pointers (storage, crypto, cipher) inherited from the server at connection time.

Function Documentation

◆ _csilk_ctx_init()

void _csilk_ctx_init ( csilk_ctx_t *  c,
struct csilk_server_s s,
void *  client 
)

Initialize a request context.

Internal context initialiser.

Sets up default values for all fields. Should be called for both static (embedded in client) and dynamic (H2 stream) contexts.

Parameters
cThe context to initialize.
sThe owning server instance.
clientThe underlying connection object (csilk_client_t*).

◆ _csilk_get_internal_client()

void * _csilk_get_internal_client ( csilk_ctx_t *  c)

Get the internal client connection handle.

Get the internal client connection object.

Parameters
cThe request context.
Returns
Opaque pointer to csilk_client_t.

◆ _csilk_set_internal_client()

void _csilk_set_internal_client ( csilk_ctx_t *  c,
void *  client 
)

Set the internal client connection handle.

Set the internal client connection object.

Parameters
cThe request context.
clientOpaque pointer to csilk_client_t.

◆ client_wants_close()

static int client_wants_close ( csilk_ctx_t *  c)
static

Check if the client requested "Connection: close" in the request.

Examines the "Connection" request header for a value of "close" (case-insensitive).

Parameters
cThe request context.
Returns
1 if the client requested close, 0 otherwise.
Note
Used by send_chunked_headers() to determine the response's Connection header value.

◆ csilk_abort()

void csilk_abort ( csilk_ctx_t *  c)

Abort the handler chain immediately.

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 
)

Add a response header, allowing multiple values for the same key.

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_bind_json()

cJSON * csilk_bind_json ( csilk_ctx_t *  c)

Parse the request body as JSON using cJSON.

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 
)

Parse the request body as JSON with detailed error feedback.

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 
)

Bind the request body JSON to a registered struct via reflection.

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_ctx_cleanup()

void csilk_ctx_cleanup ( csilk_ctx_t *  c)

Clean up request context resources between requests.

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_handler_path()

const char * csilk_ctx_get_handler_path ( csilk_ctx_t *  c)

Get the route pattern for the current request.

Get the route pattern for the matched handler (e.g., "/users/:id").

Parameters
cThe request context.
Returns
The route path string (e.g., "/users/:id") or NULL.

◆ csilk_ctx_get_handler_perm_required()

const char * csilk_ctx_get_handler_perm_required ( csilk_ctx_t *  c)

Get the permission required by the current handler.

Get the permission string required by the matched handler.

Parameters
cThe request context.
Returns
Permission string or NULL.

◆ csilk_ctx_get_handler_perm_resource()

const char * csilk_ctx_get_handler_perm_resource ( csilk_ctx_t *  c)

Get the resource pattern for the current handler's permission check.

Get the resource pattern for the matched handler's permission check.

Parameters
cThe request context.
Returns
Resource string or NULL.

◆ 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 owning this context.

Get the server instance associated with the current context.

Parameters
cThe request context.
Returns
Pointer to csilk_server_t.

◆ csilk_ctx_set_cipher_driver()

void csilk_ctx_set_cipher_driver ( csilk_ctx_t *  c,
csilk_cipher_driver_t driver 
)

Set the cipher driver.

Set the cipher driver for the context.

Parameters
cThe request context.
driverPointer to driver vtable.

◆ csilk_ctx_set_crypto_driver()

void csilk_ctx_set_crypto_driver ( csilk_ctx_t *  c,
csilk_crypto_driver_t driver 
)

Set the crypto driver.

Set the crypto driver for the context.

Parameters
cThe request context.
driverPointer to driver vtable.

◆ csilk_ctx_set_storage_driver()

void csilk_ctx_set_storage_driver ( csilk_ctx_t *  c,
csilk_storage_driver_t driver 
)

Set the storage driver.

Set the storage driver for the context.

Parameters
cThe request context.
driverPointer to driver vtable.

◆ csilk_get()

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

Retrieve a value from the context's key-value storage.

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 context.

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 request body data and optionally its length.

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 request body.

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_cookie()

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

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

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_file_fd()

int csilk_get_file_fd ( csilk_ctx_t *  c)

Get the zero-copy file descriptor.

Get the current zero-copy file descriptor.

Parameters
cThe request context.
Returns
File descriptor or -1.

◆ 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.

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_handler_index()

int csilk_get_handler_index ( csilk_ctx_t *  c)

Get the handler chain index.

Get the index of the currently executing handler in the chain.

Parameters
cThe request context.
Returns
Current handler index.

◆ csilk_get_header()

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

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

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.

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 value by name.

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_param_key()

const char * csilk_get_param_key ( csilk_ctx_t *  c,
int  index 
)

Get the name of a parameter by index.

Get the name of a path parameter by its index.

Parameters
cThe request context.
indexParameter index.
Returns
Parameter name or NULL.

◆ csilk_get_param_value()

const char * csilk_get_param_value ( csilk_ctx_t *  c,
int  index 
)

Get the value of a parameter by index.

Get the value of a path parameter by its index.

Parameters
cThe request context.
indexParameter index.
Returns
Parameter value or NULL.

◆ csilk_get_params_count()

int csilk_get_params_count ( csilk_ctx_t *  c)

Get the count of path parameters.

Get the number of path parameters extracted from the URL.

Parameters
cThe request context.
Returns
Number of parameters.

◆ csilk_get_path()

const char * csilk_get_path ( csilk_ctx_t *  c)

Get the URL path of the current request.

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 parameter value by key.

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 request ID string.

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 response body data and optionally its length.

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 key (case-insensitive).

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 currently set response status code.

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_get_work_req()

uv_work_t * csilk_get_work_req ( csilk_ctx_t *  c)

Get the internal libuv work request.

Get the libuv work request associated with the context.

Parameters
cThe request context.
Returns
Pointer to uv_work_t.

◆ csilk_is_aborted()

int csilk_is_aborted ( csilk_ctx_t *  c)

Check if the client has disconnected (connection aborted).

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 if the response is in async mode.

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 if the current connection is a Server-Sent Events stream.

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 if the current request is a WebSocket upgrade.

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. The cJSON object is freed by this call.

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 error response containing an "error" field.

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 
)

Send a JSON response from a registered struct via reflection.

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_next()

void csilk_next ( csilk_ctx_t *  c)

Advance to the next handler in the chain and invoke it.

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_parse_form_urlencoded()

void csilk_parse_form_urlencoded ( csilk_ctx_t *  c)

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

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 into the context's query_params hash map.

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_redirect()

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

Redirect the client to a different URL with a specific status code.

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 
)

Redirect to another URL using the default status code 302 (Found).

Send a simple 302 Found redirect.

Convenience wrapper around csilk_redirect().

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

◆ csilk_response_end()

void csilk_response_end ( csilk_ctx_t *  c)

Finalize a streaming response by sending the terminal chunk.

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 data to a streaming response using chunked transfer encoding.

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_set()

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

Store a value in the context's key-value storage.

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 
)

Mark the response as asynchronous (sent later, not automatically).

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 response via Set-Cookie header.

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_file_response()

void csilk_set_file_response ( csilk_ctx_t *  c,
int  fd,
size_t  offset,
size_t  size 
)

Configure zero-copy file transmission.

Set the zero-copy file response parameters.

Parameters
cThe request context.
fdOpen file descriptor.
offsetByte offset to start sending.
sizeNumber of bytes to send.

◆ csilk_set_header()

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

Set a response header, overwriting any existing value for the same key.

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.

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 a request header, overwriting any existing value for the same key.

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_request_id()

void csilk_set_request_id ( csilk_ctx_t *  c,
const char *  id 
)

Set the request UUID.

Set the request unique identifier.

Parameters
cThe request context.
idThe new UUID string (will be truncated to 36 chars).

◆ csilk_set_response_body()

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

Set the response body directly with explicit ownership semantics.

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_set_sse()

void csilk_set_sse ( csilk_ctx_t *  c,
int  is_sse 
)

Enable/disable SSE mode.

Enable or disable Server-Sent Events (SSE) mode.

Parameters
cThe request context.
is_sse1 to enable, 0 to disable.

◆ csilk_set_websocket()

void csilk_set_websocket ( csilk_ctx_t *  c,
int  is_websocket 
)

Enable/disable WebSocket mode.

Enable or disable WebSocket mode.

Parameters
cThe request context.
is_websocket1 to enable, 0 to disable.

◆ csilk_status()

void csilk_status ( csilk_ctx_t *  c,
int  status 
)

Set the HTTP response status code.

Parameters
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 the response body as plain text with a status code.

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.

◆ hash_key()

static uint32_t hash_key ( const char *  key)
static

Hash a header key string into a bucket index using djb2.

Applies the djb2 hash algorithm with case-insensitive character folding (via tolower()) so that "Content-Type" and "content-type" map to the same bucket. This ensures consistent lookups regardless of header casing.

Parameters
keyHeader key string (null-terminated).
Returns
Bucket index in the range [0, CSILK_HEADER_BUCKETS - 1].
Note
The caller must ensure key is non-NULL.

◆ map_add()

static void map_add ( csilk_ctx_t *  c,
csilk_header_map_t map,
const char *  key,
const char *  value 
)
static

Add a header value to the hash map, allowing duplicate keys.

Unlike map_set(), this function does NOT search for an existing entry with the same key. It always prepends a new header node, so multiple calls with the same key produce multiple entries (e.g., multiple Set-Cookie headers).

Parameters
cRequest context for arena-based memory allocation.
mapHeader hash map.
keyHeader key.
valueHeader value.
Note
Both key and value are duplicated into arena memory. Silently does nothing if the arena is NULL.

◆ map_get()

static const char * map_get ( csilk_header_map_t map,
const char *  key 
)
static

Look up a header value by key in the hash map (case-insensitive).

Iterates the linked list at the hashed bucket and compares keys using strcasecmp. Returns the first matching value.

Parameters
mapHeader hash map (must not be NULL).
keyHeader key to find (case-insensitive).
Returns
Pointer to the value string, or NULL if the key is not found.
Note
The returned string shares the lifetime of the map's arena.

◆ map_set()

static void map_set ( csilk_ctx_t *  c,
csilk_header_map_t map,
const char *  key,
const char *  value 
)
static

Set a header value in the hash map, overwriting any existing entry.

Hashes the key, searches the bucket for an existing entry, and replaces its value. If no entry is found, a new header node is allocated via the context's arena allocator and prepended to the bucket's linked list.

Parameters
cRequest context used for arena-based memory allocation.
mapHeader hash map (request or response headers).
keyHeader key (case-insensitive via strcasecmp on lookup).
valueHeader value string.
Note
The key and value are duplicated into arena memory. If the arena is NULL this function silently does nothing.

◆ on_stream_end_write()

static void on_stream_end_write ( uv_write_t *  req,
int  status 
)
static

libuv write completion callback for a terminal chunk — closes the connection.

Frees the write buffer and request structure, then closes the underlying handle. This is used for the final chunk of a streaming response.

Parameters
reqThe completed write request (freed by this callback).
statusUV status code (negative indicates error).

◆ on_stream_write()

static void on_stream_write ( uv_write_t *  req,
int  status 
)
static

libuv write completion callback for streaming (non-terminal) writes.

Frees the write buffer and request structure. On error, logs to stderr. Does NOT close the connection — terminal writes use on_stream_end_write().

Parameters
reqThe completed write request (freed by this callback).
statusUV status code (negative indicates error).

◆ send_chunked_headers()

static int send_chunked_headers ( csilk_ctx_t *  c)
static

Send HTTP response headers with Transfer-Encoding: chunked.

Constructs and sends the HTTP status line, chunked transfer-encoding header, connection header (keep-alive or close), and all custom response headers. This is automatically called on the first call to csilk_response_write() if the response has not started yet.

Parameters
cRequest context.
Returns
0 on success, -1 on allocation failure or NULL input.
Note
Sets c->response_started = 1 on success.

◆ write_chunk_frame()

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

Write a single chunked transfer frame: [hex-size]\r\n[data]\r\n.

Formats the data length as a hex string, prepends it, appends the trailing CRLF, and sends the complete frame via _csilk_send_data(). The frame buffer is heap-allocated and freed after sending.

Parameters
cRequest context.
dataPayload data for this chunk.
lenLength of payload in bytes.
Note
The terminal chunk (zero-length) should be sent via csilk_response_end().

Variable Documentation

◆ csilk_get_on_ws_message

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

Get the registered WebSocket callback.

Parameters
cThe request context.
Returns
Function pointer or NULL.