ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
server.h File Reference

Backend-neutral HTTP request/response contract. More...

Go to the source code of this file.

Data Structures

struct  http_header_t
struct  http_request_info
struct  http_server_config_t

Typedefs

typedef struct http_request http_request_t
typedef struct http_response http_response_t
typedef struct http_request_info http_request_info_t
typedef void(* http_request_fn) (http_request_t *request, http_response_t *response, void *user_data)
typedef void(* http_connection_fn) (const char *peer_address, bool connected, void *user_data)
typedef void(* http_error_fn) (asciichat_error_t error, const char *message, void *user_data)
typedef void(* http_wakeup_fn) (void *user_data)

Enumerations

enum  http_protocol_t { HTTP_PROTOCOL_10 = 0 , HTTP_PROTOCOL_11 , HTTP_PROTOCOL_2 , HTTP_PROTOCOL_3 }

Functions

asciichat_error_t http_server_init (http_server_t **server, const http_server_config_t *config)
asciichat_error_t http_server_start (http_server_t *server)
asciichat_error_t http_server_adopt_socket (http_server_t *server, intptr_t socket_handle)
asciichat_error_t http_server_wakeup (http_server_t *server)
void http_server_stop (http_server_t *server)
void http_server_destroy (http_server_t **server)
asciichat_error_t http_server_run (http_server_t *server)
const http_request_info_t * http_request_info (const http_request_t *request)
const void * http_request_body (const http_request_t *request, size_t *length)
bool http_request_is_cancelled (const http_request_t *request)
asciichat_error_t http_request_cancel (http_request_t *request)
bool http_response_is_cancelled (const http_response_t *response)
asciichat_error_t http_response_set_status (http_response_t *response, unsigned status)
asciichat_error_t http_response_retain (http_response_t *response, http_response_t **retained)
void http_response_release (http_response_t **response)
asciichat_error_t http_response_set_header (http_response_t *response, const char *name, const char *value)
asciichat_error_t http_response_write (http_response_t *response, const void *data, size_t length)
size_t http_response_body_length (const http_response_t *response)
asciichat_error_t http_response_finish (http_response_t *response)

Detailed Description

Backend-neutral HTTP request/response contract.

The public API deliberately contains no libuv, TLS, HTTP/2, HTTP/3, or libwebsockets types. Backends translate their protocol into this contract; handlers can therefore be shared by MCP, API, discovery, and WebTransport.

Definition in file include/ascii-chat/network/http/server/server.h.

Typedef Documentation

◆ http_connection_fn

typedef void(* http_connection_fn) (const char *peer_address, bool connected, void *user_data)

◆ http_error_fn

typedef void(* http_error_fn) (asciichat_error_t error, const char *message, void *user_data)

◆ http_request_fn

typedef void(* http_request_fn) (http_request_t *request, http_response_t *response, void *user_data)

◆ http_request_info_t

◆ http_request_t

◆ http_response_t

◆ http_wakeup_fn

typedef void(* http_wakeup_fn) (void *user_data)

Invoked on the HTTP event-loop thread after http_server_wakeup().

Definition at line 50 of file include/ascii-chat/network/http/server/server.h.

Enumeration Type Documentation

◆ http_protocol_t

Function Documentation

◆ http_request_body()

const void * http_request_body ( const http_request_t * request,
size_t * length )

Definition at line 879 of file lib/network/http/server/server.c.

879 {
880 if (n)
881 *n = r ? r->body_length : 0;
882 return r && r->body_length ? r->storage + r->body_offset : NULL;
883}

References http_request::body_length, http_request::body_offset, and http_request::storage.

◆ http_request_cancel()

asciichat_error_t http_request_cancel ( http_request_t * request)

Definition at line 894 of file lib/network/http/server/server.c.

894 {
895 if (!r)
896 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing HTTP request");
897 if (!r->cancelled)
899 r->cancelled = true;
900 return ASCIICHAT_OK;
901}
#define SET_ERRNO(code,...)
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_INVALID_PARAM
void stats_counter_add(stats_scope_t *scope, stats_counter_id_t id, uint64_t amount)
stats_scope_t * stats_runtime_scope(void)
Definition runtime.c:80

References ASCIICHAT_OK, http_request::cancelled, ERROR_INVALID_PARAM, SET_ERRNO, stats_counter_add(), STATS_COUNTER_HTTP_CANCELLED, and stats_runtime_scope().

◆ http_request_info()

const http_request_info_t * http_request_info ( const http_request_t * request)

Definition at line 876 of file lib/network/http/server/server.c.

876 {
877 return r ? &r->info : NULL;
878}

References http_request::info.

◆ http_request_is_cancelled()

bool http_request_is_cancelled ( const http_request_t * request)

Definition at line 888 of file lib/network/http/server/server.c.

888 {
889 return !r || r->cancelled;
890}

References http_request::cancelled.

◆ http_response_body_length()

size_t http_response_body_length ( const http_response_t * response)

Return the number of bytes buffered for the response body.

Definition at line 738 of file lib/network/http/server/server.c.

738 {
739 return r ? r->body_length : 0;
740}

References http_response::body_length.

◆ http_response_finish()

asciichat_error_t http_response_finish ( http_response_t * response)

Definition at line 741 of file lib/network/http/server/server.c.

741 {
742 if (!r || r->finished)
743 return SET_ERRNO(ERROR_INVALID_STATE, "HTTP response already finished");
744 r->finished = true;
745 if (r->status >= 400)
747 if (r->cancelled) {
748 if (r->inflight_accounted && !r->deferred) {
749 http_request_release(r->server);
750 r->inflight_accounted = false;
751 }
752 return SET_ERRNO(ERROR_INVALID_STATE, "HTTP response was cancelled");
753 }
754 asciichat_error_t result;
755 if (r->http3_submit)
756 result = r->http3_submit(r->http3_context, r->status, r->headers, r->header_count, r->body, r->body_length);
757 else if (r->client && r->client->http2_mode) {
758 result = http2_connection_submit_response(r->client->http2, r->http2_stream_id, r->status, r->headers,
759 r->header_count, r->body, r->body_length);
760 if (result == ASCIICHAT_OK)
761 result = http2_flush(r->client);
762 } else {
763 size_t cap = 256 + r->body_length;
764 for (size_t i = 0; i < r->header_count; i++)
765 cap += strlen(r->headers[i].name) + strlen(r->headers[i].value) + 4;
766 char *out = SAFE_MALLOC(cap, char *);
767 if (!out) {
768 if (r->inflight_accounted && !r->deferred) {
769 http_request_release(r->server);
770 r->inflight_accounted = false;
771 }
772 return SET_ERRNO(ERROR_MEMORY, "Cannot allocate HTTP response");
773 }
774 const char *version = r->protocol == HTTP_PROTOCOL_10 ? "HTTP/1.0" : "HTTP/1.1";
775 int n = safe_snprintf(out, cap, "%s %u %s\r\nContent-Length: %zu\r\nConnection: close\r\n", version, r->status,
776 reason(r->status), r->body_length);
777 for (size_t i = 0; i < r->header_count; i++)
778 n += safe_snprintf(out + n, cap - (size_t)n, "%s: %s\r\n", r->headers[i].name, r->headers[i].value);
779 n += safe_snprintf(out + n, cap - (size_t)n, "\r\n");
780 if (r->body_length)
781 memcpy(out + n, r->body, r->body_length);
782 n += (int)r->body_length;
783 result = client_write_plain(r->client, out, (size_t)n, true);
784 SAFE_FREE(out);
785 }
786 if (r->inflight_accounted && !r->deferred) {
787 http_request_release(r->server);
788 r->inflight_accounted = false;
789 }
790 return result;
791}
#define SAFE_FREE(ptr)
Definition common.h:377
#define SAFE_MALLOC(size, cast)
Definition common.h:265
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
@ ERROR_INVALID_STATE
@ ERROR_MEMORY
Definition error_codes.h:51
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Platform-safe snprintf wrapper.
asciichat_error_t http2_connection_submit_response(http2_connection_t *connection, int32_t stream_id, unsigned status, const http_header_t *headers, size_t header_count, const void *body, size_t body_length)
Definition http2.c:257
static bool size_t gotel_query_t * out
Definition queries.h:8

References ASCIICHAT_OK, http_response::body, http_response::body_length, http_response::cancelled, http_response::client, http_response::deferred, ERROR_INVALID_STATE, ERROR_MEMORY, http_response::finished, http_response::header_count, http_response::headers, http_server_client::http2, http2_connection_submit_response(), http_server_client::http2_mode, http_response::http2_stream_id, http_response::http3_context, http_response::http3_submit, HTTP_PROTOCOL_10, http_response::inflight_accounted, http_header_t::name, out, http_response::protocol, SAFE_FREE, SAFE_MALLOC, safe_snprintf(), http_response::server, SET_ERRNO, stats_counter_add(), STATS_COUNTER_HTTP_ERRORS, stats_runtime_scope(), http_response::status, and http_header_t::value.

Referenced by http_server_authorize(), and http_server_dispatch_http3().

◆ http_response_is_cancelled()

bool http_response_is_cancelled ( const http_response_t * response)

Definition at line 891 of file lib/network/http/server/server.c.

891 {
892 return !r || r->cancelled;
893}

References http_response::cancelled.

◆ http_response_release()

void http_response_release ( http_response_t ** response)

Release a response retained with http_response_retain().

Definition at line 687 of file lib/network/http/server/server.c.

687 {
688 if (!response || !*response)
689 return;
690 if ((*response)->retained) {
691 http_server_t *server = (*response)->server;
692 if ((*response)->inflight_accounted) {
693 http_request_release(server);
694 (*response)->inflight_accounted = false;
695 }
696 if (server) {
697 mutex_lock(&server->response_mutex);
698 http_response_t **cursor = &server->retained_responses;
699 while (*cursor && *cursor != *response)
700 cursor = &(*cursor)->next_retained;
701 if (*cursor == *response)
702 *cursor = (*response)->next_retained;
703 mutex_unlock(&server->response_mutex);
704 }
705 SAFE_FREE((*response)->body);
706 SAFE_FREE(*response);
707 }
708 *response = NULL;
709}
struct http_response http_response_t
http_response_t * retained_responses
struct http_server http_server_t
Definition tls.h:8

References http_response::next_retained, http_server::response_mutex, http_server::retained_responses, and SAFE_FREE.

◆ http_response_retain()

asciichat_error_t http_response_retain ( http_response_t * response,
http_response_t ** retained )

Retain a response for completion after the request callback returns.

Definition at line 649 of file lib/network/http/server/server.c.

649 {
650 if (!r || !retained || !r->server || r->finished || r->retained)
651 return SET_ERRNO(ERROR_INVALID_STATE, "HTTP response cannot be retained");
652 http_response_t *copy = SAFE_CALLOC(1, sizeof(*copy), http_response_t *);
653 if (!copy)
654 return SET_ERRNO(ERROR_MEMORY, "Cannot retain HTTP response");
655 copy->stream = r->stream;
656 copy->client = r->client;
657 copy->http2_stream_id = r->http2_stream_id;
658 copy->protocol = r->protocol;
659 copy->max_body_length = r->max_body_length;
660 copy->http3_submit = r->http3_submit;
661 copy->http3_context = r->http3_context;
662 copy->server = r->server;
663 copy->inflight_accounted = r->inflight_accounted;
664 copy->status = r->status;
665 copy->header_count = r->header_count;
666 memcpy(copy->headers, r->headers, r->header_count * sizeof(r->headers[0]));
667 if (r->body_length) {
668 copy->body = SAFE_MALLOC(r->body_length, char *);
669 if (!copy->body) {
670 SAFE_FREE(copy);
671 return SET_ERRNO(ERROR_MEMORY, "Cannot retain HTTP response body");
672 }
673 memcpy(copy->body, r->body, r->body_length);
674 copy->body_length = r->body_length;
675 }
676 copy->retained = true;
677 mutex_lock(&r->server->response_mutex);
679 r->server->retained_responses = copy;
680 mutex_unlock(&r->server->response_mutex);
681 r->deferred = true;
682 r->retained = true;
683 r->inflight_accounted = false;
684 *retained = copy;
685 return ASCIICHAT_OK;
686}
#define SAFE_CALLOC(count, size, cast)
Definition common.h:275
http_server_client_t * client
http3_submit_response_fn http3_submit

References ASCIICHAT_OK, http_response::body, http_response::body_length, http_response::client, http_response::deferred, ERROR_INVALID_STATE, ERROR_MEMORY, http_response::finished, http_response::header_count, http_response::headers, http_response::http2_stream_id, http_response::http3_context, http_response::http3_submit, http_response::inflight_accounted, http_response::max_body_length, http_response::next_retained, http_response::protocol, http_server::response_mutex, http_response::retained, http_server::retained_responses, SAFE_CALLOC, SAFE_FREE, SAFE_MALLOC, http_response::server, SET_ERRNO, http_response::status, and http_response::stream.

◆ http_response_set_header()

asciichat_error_t http_response_set_header ( http_response_t * response,
const char * name,
const char * value )

Definition at line 710 of file lib/network/http/server/server.c.

710 {
711 if (!r || !n || !v)
712 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid HTTP response header");
713 for (size_t i = 0; i < r->header_count; ++i) {
714 if (platform_strcasecmp(r->headers[i].name, n) == 0) {
715 r->headers[i] = (http_header_t){n, v};
716 return ASCIICHAT_OK;
717 }
718 }
719 if (r->header_count >= HTTP_HEADER_CAPACITY)
720 return SET_ERRNO(ERROR_INVALID_PARAM, "HTTP response header limit exceeded");
721 r->headers[r->header_count++] = (http_header_t){n, v};
722 return ASCIICHAT_OK;
723}
#define HTTP_HEADER_CAPACITY

References ASCIICHAT_OK, ERROR_INVALID_PARAM, http_response::header_count, http_response::headers, HTTP_HEADER_CAPACITY, http_header_t::name, and SET_ERRNO.

Referenced by http_server_authorize().

◆ http_response_set_status()

asciichat_error_t http_response_set_status ( http_response_t * response,
unsigned status )

Definition at line 643 of file lib/network/http/server/server.c.

643 {
644 if (!r || s < 100 || s > 599)
645 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid HTTP status");
646 r->status = s;
647 return ASCIICHAT_OK;
648}

References ASCIICHAT_OK, ERROR_INVALID_PARAM, SET_ERRNO, and http_response::status.

Referenced by http_server_authorize().

◆ http_response_write()

asciichat_error_t http_response_write ( http_response_t * response,
const void * data,
size_t length )

Definition at line 724 of file lib/network/http/server/server.c.

724 {
725 if (!r || (!d && n) || r->finished)
726 return SET_ERRNO(ERROR_INVALID_STATE, "HTTP response is not writable");
727 if (n > r->max_body_length || r->body_length > r->max_body_length - n)
728 return SET_ERRNO(ERROR_NETWORK_SIZE, "HTTP response body exceeds configured limit");
729 char *p = SAFE_REALLOC(r->body, r->body_length + n + 1, char *);
730 if (!p)
731 return SET_ERRNO(ERROR_MEMORY, "Cannot allocate HTTP response body");
732 r->body = p;
733 memcpy(p + r->body_length, d, n);
734 r->body_length += n;
735 p[r->body_length] = 0;
736 return ASCIICHAT_OK;
737}
#define SAFE_REALLOC(ptr, size, cast)
Definition common.h:285
@ ERROR_NETWORK_SIZE
Definition error_codes.h:77

References ASCIICHAT_OK, http_response::body, http_response::body_length, ERROR_INVALID_STATE, ERROR_MEMORY, ERROR_NETWORK_SIZE, http_response::finished, http_response::max_body_length, SAFE_REALLOC, and SET_ERRNO.

◆ http_server_adopt_socket()

asciichat_error_t http_server_adopt_socket ( http_server_t * server,
intptr_t socket_handle )

Adopt an already-listening native socket before starting the server.

Definition at line 1352 of file lib/network/http/server/server.c.

1352 {
1353 if (!s || s->running || s->adopted_socket || socket_handle < 0)
1354 return SET_ERRNO(ERROR_INVALID_STATE, "HTTP listener cannot adopt this socket");
1355 if (uv_tcp_open(&s->listener, (uv_os_sock_t)socket_handle) != 0)
1356 return SET_ERRNO(ERROR_NETWORK, "Cannot adopt HTTP listener socket");
1357 s->adopted_socket = true;
1358 return ASCIICHAT_OK;
1359}
@ ERROR_NETWORK
Definition error_codes.h:72

References http_server::adopted_socket, ASCIICHAT_OK, ERROR_INVALID_STATE, ERROR_NETWORK, http_server::listener, http_server::running, and SET_ERRNO.

◆ http_server_destroy()

void http_server_destroy ( http_server_t ** server)

Definition at line 1392 of file lib/network/http/server/server.c.

1392 {
1393 if (!p || !*p)
1394 return;
1395 http_server_t *s = *p;
1397 while (uv_run(&s->loop, UV_RUN_NOWAIT) != 0)
1398 ;
1399 uv_loop_close(&s->loop);
1400 http_server_detach_http3(s);
1402 mutex_destroy(&s->response_mutex);
1403 SSL_CTX_free(s->tls_context);
1404 SAFE_FREE(s);
1405 *p = NULL;
1406}
void http_server_stop(http_server_t *s)
void rate_limiter_destroy(rate_limiter_t *limiter)
Destroy rate limiter and free resources.
Definition rate_limit.c:126
rate_limiter_t * rate_limiter

References http_server_stop(), http_server::loop, http_server::rate_limiter, rate_limiter_destroy(), http_server::response_mutex, SAFE_FREE, and http_server::tls_context.

Referenced by api_server_main(), and mcp_http_run().

◆ http_server_init()

asciichat_error_t http_server_init ( http_server_t ** server,
const http_server_config_t * config )

Definition at line 1227 of file lib/network/http/server/server.c.

1227 {
1228 if (!out || !cfg || !cfg->on_request || (!cfg->enable_http1 && !cfg->enable_http2 && !cfg->enable_http3))
1229 return SET_ERRNO(ERROR_INVALID_PARAM, "At least one HTTP protocol and a request handler are required");
1230 if (cfg->max_connections == 0 || cfg->max_request_body_bytes == 0)
1231 return SET_ERRNO(ERROR_INVALID_PARAM, "HTTP limits must be non-zero");
1232 if (cfg->basic_auth.enabled && (!cfg->basic_auth.username || !cfg->basic_auth.password ||
1233 !cfg->basic_auth.username[0] || !cfg->basic_auth.password[0]))
1234 return SET_ERRNO(ERROR_INVALID_PARAM, "Basic authentication requires non-empty credentials");
1235 if ((cfg->enable_http3 && !cfg->http3_endpoint) || ((cfg->tls_cert_path == NULL) != (cfg->tls_key_path == NULL)))
1236 return SET_ERRNO(ERROR_INVALID_PARAM, "HTTP/3 requires a pre-opened endpoint and TLS requires certificate and key");
1237 http_server_t *s = SAFE_CALLOC(1, sizeof(*s), http_server_t *);
1238 if (mutex_init(&s->response_mutex, "http_responses") != 0) {
1239 SAFE_FREE(s);
1240 return SET_ERRNO(ERROR_NETWORK, "Cannot initialize HTTP response synchronization");
1241 }
1243 if (!s->rate_limiter) {
1244 mutex_destroy(&s->response_mutex);
1245 SAFE_FREE(s);
1246 return SET_ERRNO(ERROR_MEMORY, "Cannot initialize HTTP rate limiter");
1247 }
1248 s->config = *cfg;
1249 if (cfg->tls_cert_path) {
1250 s->tls_context = SSL_CTX_new(TLS_server_method());
1251 if (!s->tls_context) {
1253 mutex_destroy(&s->response_mutex);
1254 SAFE_FREE(s);
1255 return SET_ERRNO(ERROR_NETWORK, "Cannot initialize TLS context");
1256 }
1257 SSL_CTX_set_app_data(s->tls_context, s);
1258 SSL_CTX_set_alpn_select_cb(s->tls_context, http_select_alpn, s);
1259 if (cfg->tls_key_password) {
1260 SSL_CTX_set_default_passwd_cb_userdata(s->tls_context, (void *)cfg->tls_key_password);
1261 }
1262 if (cfg->tls_key_password)
1263 SSL_CTX_set_default_passwd_cb(s->tls_context, tls_password_cb);
1264 if (SSL_CTX_use_certificate_chain_file(s->tls_context, cfg->tls_cert_path) != 1 ||
1265 SSL_CTX_use_PrivateKey_file(s->tls_context, cfg->tls_key_path, SSL_FILETYPE_PEM) != 1 ||
1266 SSL_CTX_check_private_key(s->tls_context) != 1) {
1267 SSL_CTX_free(s->tls_context);
1268 s->tls_context = NULL;
1270 mutex_destroy(&s->response_mutex);
1271 SAFE_FREE(s);
1272 return SET_ERRNO(ERROR_NETWORK, "Cannot load HTTP TLS certificate or key");
1273 }
1274 }
1276 cfg->max_requests_per_peer
1277 ? (uint32_t)(cfg->max_requests_per_peer > UINT32_MAX ? UINT32_MAX : cfg->max_requests_per_peer)
1279 s->request_rate_limit.window_secs = cfg->request_rate_window_seconds
1280 ? cfg->request_rate_window_seconds
1282 if (uv_loop_init(&s->loop) != 0) {
1284 mutex_destroy(&s->response_mutex);
1285 SSL_CTX_free(s->tls_context);
1286 SAFE_FREE(s);
1287 return SET_ERRNO(ERROR_NETWORK, "Cannot initialize HTTP event loop");
1288 }
1289 if (uv_tcp_init(&s->loop, &s->listener) != 0) {
1290 uv_loop_close(&s->loop);
1292 mutex_destroy(&s->response_mutex);
1293 SSL_CTX_free(s->tls_context);
1294 SAFE_FREE(s);
1295 return SET_ERRNO(ERROR_NETWORK, "Cannot initialize HTTP listener");
1296 }
1297 s->listener_initialized = true;
1298 s->listener.data = s;
1299 if (uv_tcp_init(&s->loop, &s->listener6) != 0) {
1300 uv_close((uv_handle_t *)&s->listener, NULL);
1301 return SET_ERRNO(ERROR_NETWORK, "Cannot initialize IPv6 HTTP listener");
1302 }
1303 s->listener6_initialized = true;
1304 s->listener6.data = s;
1305 if (uv_async_init(&s->loop, &s->stop_async, stop_async_cb) != 0) {
1306 uv_close((uv_handle_t *)&s->listener, NULL);
1307 uv_run(&s->loop, UV_RUN_DEFAULT);
1308 uv_loop_close(&s->loop);
1310 mutex_destroy(&s->response_mutex);
1311 SSL_CTX_free(s->tls_context);
1312 SAFE_FREE(s);
1313 return SET_ERRNO(ERROR_NETWORK, "Cannot initialize HTTP stop handle");
1314 }
1315 s->stop_async_initialized = true;
1316 s->stop_async.data = s;
1317 if (uv_async_init(&s->loop, &s->wake_async, wake_async_cb) != 0) {
1318 uv_close((uv_handle_t *)&s->stop_async, NULL);
1319 uv_close((uv_handle_t *)&s->listener, NULL);
1320 uv_run(&s->loop, UV_RUN_DEFAULT);
1321 uv_loop_close(&s->loop);
1322 mutex_destroy(&s->response_mutex);
1324 SSL_CTX_free(s->tls_context);
1325 SAFE_FREE(s);
1326 return SET_ERRNO(ERROR_NETWORK, "Cannot initialize HTTP wakeup handle");
1327 }
1328 s->wake_async_initialized = true;
1329 s->wake_async.data = s;
1330 *out = s;
1331 return ASCIICHAT_OK;
1332}
unsigned int uint32_t
Definition common.h:62
rate_limiter_t * rate_limiter_create_memory(void)
Create in-memory rate limiter.
Definition rate_limit.c:83
const rate_limit_config_t DEFAULT_RATE_LIMITS[RATE_EVENT_MAX]
Default rate limits for each event type.
Definition rate_limit.c:33
@ RATE_EVENT_HTTP_REQUEST
HTTP requests from a client identity.
Definition rate_limit.h:61
http_server_config_t config
rate_limit_config_t request_rate_limit
uint32_t max_events
Maximum events allowed.
Definition rate_limit.h:74
uint32_t window_secs
Time window in seconds.
Definition rate_limit.h:75

References ASCIICHAT_OK, http_server_config_t::basic_auth, http_server::config, DEFAULT_RATE_LIMITS, http_server_config_t::enable_http1, http_server_config_t::enable_http2, http_server_config_t::enable_http3, http_basic_auth_config::enabled, ERROR_INVALID_PARAM, ERROR_MEMORY, ERROR_NETWORK, http_server_config_t::http3_endpoint, http_server::listener, http_server::listener6, http_server::listener6_initialized, http_server::listener_initialized, http_server::loop, http_server_config_t::max_connections, rate_limit_config_t::max_events, http_server_config_t::max_request_body_bytes, http_server_config_t::max_requests_per_peer, http_server_config_t::on_request, out, http_basic_auth_config::password, RATE_EVENT_HTTP_REQUEST, http_server::rate_limiter, rate_limiter_create_memory(), rate_limiter_destroy(), http_server::request_rate_limit, http_server_config_t::request_rate_window_seconds, http_server::response_mutex, SAFE_CALLOC, SAFE_FREE, SET_ERRNO, http_server::stop_async, http_server::stop_async_initialized, http_server_config_t::tls_cert_path, http_server::tls_context, http_server_config_t::tls_key_password, http_server_config_t::tls_key_path, http_basic_auth_config::username, http_server::wake_async, http_server::wake_async_initialized, and rate_limit_config_t::window_secs.

Referenced by api_server_main(), and mcp_http_run().

◆ http_server_run()

asciichat_error_t http_server_run ( http_server_t * server)

Run the server loop when embedding the server without a background thread.

Definition at line 1360 of file lib/network/http/server/server.c.

1360 {
1361 if (!s || s->running || s->thread_started)
1362 return SET_ERRNO(ERROR_INVALID_STATE, "HTTP server loop is already running in its worker thread");
1363 asciichat_error_t result = http_server_start_listener(s);
1364 if (result != ASCIICHAT_OK)
1365 return result;
1366 s->running = true;
1367 s->foreground_running = true;
1368 uv_run(&s->loop, UV_RUN_DEFAULT);
1369 s->foreground_running = false;
1370 s->running = false;
1371 http_server_detach_http3(s);
1372 return ASCIICHAT_OK;
1373}

References ASCIICHAT_OK, ERROR_INVALID_STATE, http_server::foreground_running, http_server::loop, http_server::running, SET_ERRNO, and http_server::thread_started.

◆ http_server_start()

asciichat_error_t http_server_start ( http_server_t * server)

Definition at line 1338 of file lib/network/http/server/server.c.

1338 {
1339 if (!s || s->running)
1340 return SET_ERRNO(ERROR_INVALID_STATE, "HTTP server is already running");
1341 asciichat_error_t result = http_server_start_listener(s);
1342 if (result != ASCIICHAT_OK)
1343 return result;
1344 s->running = true;
1345 if (platform_thread_create(&s->thread, "http_io", http_loop_thread, s) != 0) {
1346 http_server_rollback_start(s);
1347 return SET_ERRNO(ERROR_THREAD, "Cannot create HTTP event-loop thread");
1348 }
1349 s->thread_started = true;
1350 return ASCIICHAT_OK;
1351}
@ ERROR_THREAD

References ASCIICHAT_OK, ERROR_INVALID_STATE, ERROR_THREAD, http_server::running, SET_ERRNO, http_server::thread, and http_server::thread_started.

Referenced by api_server_main(), and mcp_http_run().

◆ http_server_stop()

void http_server_stop ( http_server_t * server)

Definition at line 1374 of file lib/network/http/server/server.c.

1374 {
1375 if (!s || !s->running)
1376 return;
1377 s->running = false;
1378 if (s->thread_started) {
1379 uv_async_send(&s->stop_async);
1380 thread_join(&s->thread, NULL);
1381 s->thread_started = false;
1382 http_server_detach_http3(s);
1383 } else if (s->foreground_running) {
1384 (void)uv_async_send(&s->stop_async);
1385 } else {
1386 stop_async_cb(&s->stop_async);
1387 while (uv_run(&s->loop, UV_RUN_NOWAIT) != 0)
1388 ;
1389 http_server_detach_http3(s);
1390 }
1391}

References http_server::foreground_running, http_server::loop, http_server::running, http_server::stop_async, http_server::thread, and http_server::thread_started.

Referenced by api_server_main(), http_server_destroy(), and mcp_http_run().

◆ http_server_wakeup()

asciichat_error_t http_server_wakeup ( http_server_t * server)

Wake the private event loop from a worker thread.

Definition at line 1333 of file lib/network/http/server/server.c.

1333 {
1334 if (!s || !s->running || uv_is_closing((uv_handle_t *)&s->wake_async))
1335 return SET_ERRNO(ERROR_INVALID_STATE, "HTTP server is not running");
1336 return uv_async_send(&s->wake_async) == 0 ? ASCIICHAT_OK : SET_ERRNO(ERROR_NETWORK, "Cannot wake HTTP event loop");
1337}

References ASCIICHAT_OK, ERROR_INVALID_STATE, ERROR_NETWORK, http_server::running, SET_ERRNO, and http_server::wake_async.

Referenced by mcp_http_wake().