KEEL 1.0.0
Minimal C11 HTTP client/server library built on epoll/kqueue/io_uring/poll
Loading...
Searching...
No Matches
Data Structures | Typedefs | Functions
router.h File Reference
#include <keel/allocator.h>
#include <keel/request.h>
#include <keel/response.h>
#include <keel/body_reader.h>
#include <stddef.h>
Include dependency graph for router.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  KlRoute
 
struct  KlMiddlewareEntry
 
struct  KlRouter
 

Typedefs

typedef void(* KlHandler) (KlRequest *req, KlResponse *res, void *user_data)
 Route handler function.
 
typedef int(* KlMiddleware) (KlRequest *req, KlResponse *res, void *user_data)
 Middleware function signature.
 
typedef struct KlWsServerConfig KlWsServerConfig
 
typedef struct KlRouter KlRouter
 

Functions

int kl_router_init (KlRouter *r, KlAllocator *alloc)
 Initialize a router with an empty route table.
 
int kl_router_add (KlRouter *r, const char *method, const char *pattern, KlHandler handler, void *user_data, KlBodyReaderFactory body_reader)
 Register a route. Pattern supports :param segments (e.g. "/users/:id").
 
int kl_router_add_streaming (KlRouter *r, const char *method, const char *pattern, KlHandler handler, void *user_data, KlBodyReaderFactory body_reader)
 Register a streaming-handler route. Identical to kl_router_add except the handler runs after the body reader is set up but BEFORE the body is fully received. The handler is expected to consume the body incrementally (e.g. via the streaming multipart pull iterator) and may yield mid-stream. The body reader's on_data callback is responsible for resuming the yielded handler when more bytes arrive.
 
int kl_router_add_streaming_async (KlRouter *r, const char *method, const char *pattern, KlHandler handler, void *user_data, KlBodyReaderFactory body_reader)
 Register an async-streaming-handler route (v2.2.0+).
 
int kl_router_match (KlRouter *r, const char *method, size_t method_len, const char *path, size_t path_len, KlRoute **matched, KlParam *params, int *num_params)
 Match a request against registered routes. HEAD requests automatically fall back to GET routes.
 
int kl_router_use (KlRouter *r, const char *method, const char *pattern, KlMiddleware fn, void *user_data)
 Register pre-body middleware that runs before body reading.
 
int kl_router_use_post (KlRouter *r, const char *method, const char *pattern, KlMiddleware fn, void *user_data)
 Register post-body middleware that runs after body reading.
 
int kl_router_run_middleware (KlRouter *r, KlRequest *req, KlResponse *res)
 Run all matching pre-body middleware in registration order.
 
int kl_router_run_post_middleware (KlRouter *r, KlRequest *req, KlResponse *res)
 Run all matching post-body middleware in registration order.
 
int kl_router_dispatch_synthetic (KlRouter *r, KlRequest *req, KlResponse *res, int run_middleware)
 Run a fully-formed synthetic request through the router pipeline: match → pre-body middleware → post-body middleware → handler.
 
void kl_router_free (KlRouter *r)
 Free router resources.
 

Typedef Documentation

◆ KlHandler

typedef void(* KlHandler) (KlRequest *req, KlResponse *res, void *user_data)

Route handler function.

◆ KlMiddleware

typedef int(* KlMiddleware) (KlRequest *req, KlResponse *res, void *user_data)

Middleware function signature.

Returns
0 to continue to next middleware/handler, non-zero to short-circuit (response must already be written by the middleware).

◆ KlWsServerConfig

◆ KlRouter

typedef struct KlRouter KlRouter

Function Documentation

◆ kl_router_init()

int kl_router_init ( KlRouter r,
KlAllocator alloc 
)

Initialize a router with an empty route table.

Parameters
rRouter to initialize.
allocAllocator for route table growth.
Returns
0 on success, -1 on allocation failure.

◆ kl_router_add()

int kl_router_add ( KlRouter r,
const char *  method,
const char *  pattern,
KlHandler  handler,
void *  user_data,
KlBodyReaderFactory  body_reader 
)

Register a route. Pattern supports :param segments (e.g. "/users/:id").

Parameters
rRouter instance.
methodHTTP method ("GET", "POST", "*" for any).
patternURL pattern to match.
handlerHandler function invoked on match.
user_dataPassed to handler and body reader factory.
body_readerFactory for body reader, or NULL to discard body.
Returns
0 on success, -1 on allocation failure.

◆ kl_router_add_streaming()

int kl_router_add_streaming ( KlRouter r,
const char *  method,
const char *  pattern,
KlHandler  handler,
void *  user_data,
KlBodyReaderFactory  body_reader 
)

Register a streaming-handler route. Identical to kl_router_add except the handler runs after the body reader is set up but BEFORE the body is fully received. The handler is expected to consume the body incrementally (e.g. via the streaming multipart pull iterator) and may yield mid-stream. The body reader's on_data callback is responsible for resuming the yielded handler when more bytes arrive.

Post-body middleware is NOT run for streaming routes (the handler has already executed by the time the body completes).

A non-NULL body_reader factory is required.

Returns
0 on success, -1 on allocation failure or NULL body_reader.

◆ kl_router_add_streaming_async()

int kl_router_add_streaming_async ( KlRouter r,
const char *  method,
const char *  pattern,
KlHandler  handler,
void *  user_data,
KlBodyReaderFactory  body_reader 
)

Register an async-streaming-handler route (v2.2.0+).

   Identical to kl_router_add_streaming, plus: the handler is
   invoked BEFORE any leftover body bytes are fed via on_data.
   It MUST yield on NEED_DATA — the body reader's on_data
   callback will resume it when bytes arrive (both the leftover
   from the headers-read and subsequent socket reads).

   Enables the full error-path mid-stream early-exit: if the
   body reader rejects bytes (on_data returns -1) at any point,
   the parked handler is resumed via on_error and can catch the
   parser error to write a structured response. Routes that opt
   out (use the legacy kl_router_add_streaming) still get the
   partial early-exit covering caps that fire after dispatch
   but lose the structured response for caps that fire during
   leftover processing.

   Synchronous C handlers that consume the body without yielding
   (i.e. they call into the body reader expecting events to be
   immediately available) must use the legacy kl_router_add_
   streaming — they'll see NEED_DATA on the first call here
   and have no way to recover.
Parameters
rRouter instance.
methodHTTP method.
patternURL pattern.
handlerYield-on-NEED_DATA handler.
user_dataOpaque pointer.
body_readerBody reader factory (NULL rejected).
Returns
0 on success, -1 on allocation failure or NULL body_reader.

◆ kl_router_match()

int kl_router_match ( KlRouter r,
const char *  method,
size_t  method_len,
const char *  path,
size_t  path_len,
KlRoute **  matched,
KlParam params,
int *  num_params 
)

Match a request against registered routes. HEAD requests automatically fall back to GET routes.

Parameters
rRouter instance.
methodRequest method string.
method_lenLength of method string.
pathRequest path string.
path_lenLength of path string.
matchedReceives the matched route, or NULL.
paramsReceives extracted :param values.
num_paramsReceives the number of extracted params.
Returns
200 on match, 404 if no path matches, 405 if path matches but method doesn't.

◆ kl_router_use()

int kl_router_use ( KlRouter r,
const char *  method,
const char *  pattern,
KlMiddleware  fn,
void *  user_data 
)

Register pre-body middleware that runs before body reading.

Parameters
rRouter instance.
methodHTTP method filter ("GET", "POST", "*" for any).
patternURL pattern — exact match or prefix with trailing slash-star.
fnMiddleware function. Return 0 to continue, non-zero to short-circuit.
user_dataPassed to fn on each invocation.
Returns
0 on success, -1 on allocation failure.

◆ kl_router_use_post()

int kl_router_use_post ( KlRouter r,
const char *  method,
const char *  pattern,
KlMiddleware  fn,
void *  user_data 
)

Register post-body middleware that runs after body reading.

Post-body middleware can access req->body_reader data. Short-circuiting preserves keep_alive since the body has already been consumed.

Parameters
rRouter instance.
methodHTTP method filter ("GET", "POST", "*" for any).
patternURL pattern — exact match or prefix with trailing slash-star.
fnMiddleware function. Return 0 to continue, non-zero to short-circuit.
user_dataPassed to fn on each invocation.
Returns
0 on success, -1 on allocation failure.

◆ kl_router_run_middleware()

int kl_router_run_middleware ( KlRouter r,
KlRequest req,
KlResponse res 
)

Run all matching pre-body middleware in registration order.

Returns
0 if all passed, non-zero if a middleware short-circuited.

◆ kl_router_run_post_middleware()

int kl_router_run_post_middleware ( KlRouter r,
KlRequest req,
KlResponse res 
)

Run all matching post-body middleware in registration order.

Returns
0 if all passed, non-zero if a middleware short-circuited.

◆ kl_router_dispatch_synthetic()

int kl_router_dispatch_synthetic ( KlRouter r,
KlRequest req,
KlResponse res,
int  run_middleware 
)

Run a fully-formed synthetic request through the router pipeline: match → pre-body middleware → post-body middleware → handler.

The caller is responsible for initialising req (method, path, headers, optional body_reader) and res (via kl_response_init). On return, res holds the response state the handler (or a short-circuiting middleware) produced; the caller is responsible for kl_response_free and for inspecting res->status, res->body, res->hdr_buf, etc.

req->num_params / req->params are filled in from the match before the pipeline runs; callers do not need to pre-populate them.

If run_middleware is 0, pre- and post-body middleware are skipped (only the matched handler runs). When the match fails (404/405) and middleware is disabled, no handler is invoked and the caller should read the return value to know what happened.

This is the in-process counterpart to the network-driven dispatch in connection.c / h2.c. Hull's test harness uses it; user code can use it for synthetic requests (e.g. agent-API self-calls).

Parameters
rRouter instance.
reqPre-built request (must outlive the call).
resPre-initialised response (the call writes into it).
run_middlewareNon-zero to run pre- and post-body middleware.
Returns
200 if the handler ran (or middleware short-circuited with a success-shaped response); 404 if no path matched; 405 if a path matched but the method didn't; non-zero short-circuit code if middleware short-circuited; -1 on invalid arguments.

◆ kl_router_free()

void kl_router_free ( KlRouter r)

Free router resources.