4#define _POSIX_C_SOURCE 200809L
15#include <sys/socket.h>
17#define REDIS_RATE_SLOTS 8
18#define REDIS_RATE_PREFIX_MAX 128
29static size_t rate_cfg_count;
36static const char rate_script[] =
"local n=redis.call('INCR',KEYS[1]);"
37 "if n==1 or redis.call('PTTL',KEYS[1])<0 then "
38 "redis.call('PEXPIRE',KEYS[1],60000);end;return n";
65 "[CWIST] Redis rate limiter backend error %d (%s); "
66 "check pool process ownership and Redis connectivity/permissions.\n",
67 code, cfg->fail_closed ?
"fail-closed" :
"fail-open");
69 if (!cfg->fail_closed) {
79 const redis_rate_cfg *cfg = &rate_cfgs[
slot];
82 backend_failure(cfg, req, res, next, -
ENOTCONN);
86 snprintf(key,
sizeof(key),
"%s%s", cfg->prefix, ip);
87 const void *
args[] = {
"EVAL", rate_script,
"1", key};
88 size_t lengths[] = {4,
sizeof(rate_script) - 1, 1,
strlen(key)};
91 cfg->timeout_ms, &
reply);
96 backend_failure(cfg, req, res, next,
code);
110#define REDIS_RATE_WRAPPER(N) \
111 static void redis_rate_wrap_##N(cwist_http_request *req, cwist_http_response *res, \
112 cwist_handler_func next) { \
113 redis_rate_handler(N, req, res, next); \
135 for (
size_t i = 0;
i < rate_cfg_count; ++
i) {
136 const redis_rate_cfg *
old = &rate_cfgs[
i];
148 size_t slot = rate_cfg_count++;
149 rate_cfgs[
slot] = (redis_rate_cfg){.pool = cfg->
pool,
155 return wrappers[
slot];
Memory allocation wrappers backed by libttak.
cwist_error_t cwist_sstring_assign(cwist_sstring *str, const char *data)
Assign a C string.
struct cwist_redis_pool cwist_redis_pool_t
Redis connection pool handle.
cwist_error_t cwist_redis_pool_command_argv_reply_timeout(cwist_redis_pool_t *pool, size_t argc, const void *const *argv, const size_t *argv_lens, unsigned timeout_ms, cwist_redis_reply_t **reply)
Run one binary-safe pooled command under a single deadline.
void cwist_redis_reply_free(cwist_redis_reply_t *reply)
cwist_error_t cwist_http_header_add(cwist_http_header_node **head, const char *key, const char *value)
Add a header to the list.
cwist_middleware_func cwist_mw_rate_limit_ip_redis(const cwist_rate_limit_redis_cfg_t *cfg)
Shared per-IP 60-second window using one atomic Redis Lua command.
#define REDIS_RATE_WRAPPER(N)
#define REDIS_RATE_PREFIX_MAX
Integrated error structure used throughout the system.
HTTP Response Object. Supports standard string body or Zero-Copy pointer body.
cwist_http_status_t status_code
cwist_http_header_node * headers
Redis-backed rate limiter configuration. Strings are copied.
cwist_redis_pool_t * pool
void(* cwist_handler_func)(cwist_http_request *req, cwist_http_response *res)
Function pointer type for HTTP route handlers.
void(* cwist_middleware_func)(cwist_http_request *req, cwist_http_response *res, cwist_handler_func next)
Middleware type that receives req/res pair and the next stage in the chain.
Built-in middleware factories.
void cwist_error_dispose(cwist_error_t *err)
Release resources owned by an error value. Currently only CWIST_ERR_JSON owns memory (the cJSON paylo...