ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
http3.c
Go to the documentation of this file.
1#include "http3.h"
2#include "server_internal.h"
3
4#include <ascii-chat/common.h>
5#include <string.h>
6
7#define H3_MAX_HEADER_BYTES 16384U
8#define H3_MAX_ORIGIN 512U
9#define H3_MAX_PATH 512U
10#define H3_SETTINGS_BUFFER 96U
11#define H3_MAX_HEADERS 64U
12#define H3_MAX_TEXT 2048U
13
15
45
62
63#define H3_FIELD(server, state, field) ((state) ? (state)->field : (server)->field)
64#define H3_PTR(server, state, field) ((state) ? &(state)->field : &(server)->field)
65
66static bool equal_bytes(nghttp3_vec bytes, const char *value) {
67 size_t length = strlen(value);
68 return bytes.len == length && memcmp(bytes.base, value, length) == 0;
69}
70
71static uint8_t *put_varint(uint8_t *p, uint64_t value) {
72 size_t length = value < (1ULL << 6) ? 1 : value < (1ULL << 14) ? 2 : value < (1ULL << 30) ? 4 : 8;
73 for (size_t i = 0; i < length; ++i)
74 p[length - i - 1] = (uint8_t)(value >> (8 * i));
75 p[0] |= length == 1 ? 0 : length == 2 ? 0x40 : length == 4 ? 0x80 : 0xc0;
76 return p + length;
77}
78
79static void make_settings(http_server_http3_t *server) {
81 uint8_t *p = body;
82 /* QPACK is static-only. Advertise HTTP datagrams, extended CONNECT, and
83 * browser WebTransport draft settings absent from nghttp3's settings API. */
84 static const uint64_t entries[][2] = {{1, 0}, {6, H3_MAX_HEADER_BYTES}, {7, 0}, {8, 1}, {0x33, 1},
85 {0xffd277, 1}, {0x2b603742, 1}, {0xc671706a, 1}};
86 for (size_t i = 0; i < sizeof(entries) / sizeof(entries[0]); ++i) {
87 p = put_varint(p, entries[i][0]);
88 p = put_varint(p, entries[i][1]);
89 }
90 uint8_t *out = server->settings;
91 out = put_varint(out, 0); /* HTTP/3 control stream */
92 out = put_varint(out, 4); /* SETTINGS frame */
93 out = put_varint(out, (uint64_t)(p - body));
94 memcpy(out, body, (size_t)(p - body));
95 server->settings_length = (size_t)(out - server->settings) + (size_t)(p - body);
96}
97
98static nghttp3_ssize keep_open(nghttp3_conn *conn, int64_t stream_id, nghttp3_vec *vec, size_t count, uint32_t *flags,
99 void *context, void *stream_context) {
100 (void)conn;
101 (void)stream_id;
102 (void)vec;
103 (void)count;
104 (void)flags;
105 (void)context;
106 (void)stream_context;
107 return NGHTTP3_ERR_WOULDBLOCK;
108}
109
110static nghttp3_ssize read_response_body(nghttp3_conn *conn, int64_t stream_id, nghttp3_vec *vec, size_t count,
111 uint32_t *flags, void *context, void *stream_context) {
112 (void)conn;
113 (void)stream_id;
114 http_server_http3_t *server = context;
115 http3_stream_state_t *state = stream_context;
116 size_t remaining = H3_FIELD(server, state, response_length) - H3_FIELD(server, state, response_offset);
117 if (!count || !remaining)
118 *flags |= NGHTTP3_DATA_FLAG_EOF;
119 if (!remaining)
120 return 0;
121 vec[0].base = H3_FIELD(server, state, response_body) + H3_FIELD(server, state, response_offset);
122 vec[0].len = remaining;
123 *H3_PTR(server, state, response_offset) = H3_FIELD(server, state, response_length);
124 *flags |= NGHTTP3_DATA_FLAG_EOF;
125 return 1;
126}
127
128static asciichat_error_t http3_submit_response(void *context, unsigned status, const http_header_t *headers,
129 size_t header_count, const void *body, size_t body_length) {
130 http_server_http3_t *server = ((http3_stream_state_t *)context)->owner;
131 http3_stream_state_t *state = context;
132 if (!server || (state ? state->stream_id < 0 : server->request < 0) || status < 100 || status > 599 ||
133 header_count > H3_MAX_HEADERS || body_length > http_server_max_response_body(server->http_server) ||
134 (!body && body_length))
135 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid HTTP/3 response");
136 char status_text[4];
137 safe_snprintf(status_text, sizeof(status_text), "%u", status);
138 nghttp3_nv fields[H3_MAX_HEADERS + 1] = {
139 {(uint8_t *)":status", (uint8_t *)status_text, sizeof(":status") - 1, strlen(status_text), NGHTTP3_NV_FLAG_NONE}};
140 for (size_t i = 0; i < header_count; ++i) {
141 if (!headers[i].name || !headers[i].value)
142 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid HTTP/3 response header");
143 fields[i + 1] = (nghttp3_nv){(uint8_t *)headers[i].name, (uint8_t *)headers[i].value, strlen(headers[i].name),
144 strlen(headers[i].value), NGHTTP3_NV_FLAG_NONE};
145 }
146 SAFE_FREE(*H3_PTR(server, state, response_body));
147 *H3_PTR(server, state, response_length) = body_length;
148 *H3_PTR(server, state, response_offset) = 0;
149 if (body_length) {
150 *H3_PTR(server, state, response_body) = SAFE_MALLOC(body_length, uint8_t *);
151 if (!H3_FIELD(server, state, response_body))
152 return SET_ERRNO(ERROR_MEMORY, "Cannot allocate HTTP/3 response body");
153 memcpy(H3_FIELD(server, state, response_body), body, body_length);
154 }
155 nghttp3_data_reader reader = {.read_data = read_response_body};
156 int64_t stream_id = state ? state->stream_id : server->request;
157 int result =
158 nghttp3_conn_submit_response(server->http, stream_id, fields, header_count + 1, body_length ? &reader : NULL);
159 if (result != 0) {
160 SAFE_FREE(*H3_PTR(server, state, response_body));
161 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Cannot submit HTTP/3 response: %s", nghttp3_strerror(result));
162 }
163 *H3_PTR(server, state, responded) = true;
164 return ASCIICHAT_OK;
165}
166
167static int maybe_respond(http_server_http3_t *server) {
168 if (!server->headers_done || !server->settings_received || server->responded)
169 return 0;
170 bool webtransport_connect = server->http_server && strcmp(server->method_text, "CONNECT") == 0 && server->protocol;
171 if (server->http_server && !webtransport_connect)
172 return 0;
173 bool accepted = !server->malformed;
174 accepted = accepted && server->method && server->scheme && server->authority;
175 accepted = accepted && server->protocol && server->request_path && server->request_origin;
176 static const uint8_t status_name[] = ":status", ok[] = "200", forbidden[] = "403";
177 static const uint8_t draft_name[] = "sec-webtransport-http3-draft", draft_value[] = "draft02";
178 nghttp3_nv fields[] = {
179 {status_name, accepted ? ok : forbidden, sizeof(status_name) - 1, 3, NGHTTP3_NV_FLAG_NONE},
180 {draft_name, draft_value, sizeof(draft_name) - 1, sizeof(draft_value) - 1, NGHTTP3_NV_FLAG_NONE}};
181 const nghttp3_data_reader reader = {.read_data = keep_open};
182 int result =
183 nghttp3_conn_submit_response(server->http, server->request, fields, accepted ? 2 : 1, accepted ? &reader : NULL);
184 if (result != 0)
185 return NGHTTP3_ERR_CALLBACK_FAILURE;
186 server->responded = true;
187 server->accepted = accepted;
188 return 0;
189}
190
191static int dispatch_generic_request(http_server_http3_t *server, http3_stream_state_t *state) {
192 if (!state || !server->http_server || !state->headers_done || !server->settings_received ||
193 !state->request_end_stream || state->responded)
194 return 0;
195 if (strcmp(state->method_text, "CONNECT") == 0 && state->protocol)
196 return 0;
198 server->http_server, state->method_text, state->request_target, state->headers, state->header_count,
199 state->request_body, state->request_body_length, server->peer_address, http3_submit_response, state);
200 return result == ASCIICHAT_OK ? 0 : NGHTTP3_ERR_CALLBACK_FAILURE;
201}
202
203static int receive_data(nghttp3_conn *conn, int64_t stream_id, const uint8_t *data, size_t length, void *context,
204 void *stream_context) {
205 (void)conn;
206 (void)stream_context;
207 http_server_http3_t *server = context;
208 http3_stream_state_t *state = stream_context;
209 if (!server->http_server)
210 return 0;
211 if (!state || stream_id != state->stream_id || (!data && length))
212 return NGHTTP3_ERR_CALLBACK_FAILURE;
213 size_t limit = http_server_max_request_body(server->http_server);
214 if (length > limit || state->request_body_length > limit - length)
215 return NGHTTP3_ERR_CALLBACK_FAILURE;
216 if (length) {
217 size_t required = state->request_body_length + length;
218 if (required > state->request_body_capacity) {
219 size_t capacity = state->request_body_capacity ? state->request_body_capacity : 4096;
220 while (capacity < required) {
221 if (capacity > SIZE_MAX / 2)
222 capacity = required;
223 else
224 capacity *= 2;
225 }
226 uint8_t *body = SAFE_REALLOC(state->request_body, capacity, uint8_t *);
227 if (!body)
228 return NGHTTP3_ERR_NOMEM;
229 state->request_body = body;
230 state->request_body_capacity = capacity;
231 }
232 memcpy(state->request_body + state->request_body_length, data, length);
233 state->request_body_length += length;
234 }
235 return 0;
236}
237
238static int end_stream(nghttp3_conn *conn, int64_t stream_id, void *context, void *stream_context) {
239 (void)conn;
240 (void)stream_context;
241 http_server_http3_t *server = context;
242 http3_stream_state_t *state = stream_context;
243 if (!server->http_server)
244 return 0;
245 if (!state || stream_id != state->stream_id || state->request_end_stream)
246 return NGHTTP3_ERR_CALLBACK_FAILURE;
247 state->request_end_stream = true;
248 return dispatch_generic_request(server, state);
249}
250
251static int begin_headers(nghttp3_conn *conn, int64_t stream_id, void *context, void *stream_context) {
252 (void)conn;
253 (void)stream_context;
254 http_server_http3_t *server = context;
255 if (stream_id < 0 || (stream_id & 3) != 0)
256 return NGHTTP3_ERR_CALLBACK_FAILURE;
257 if (!server->http_server)
258 if (server->request != -1)
259 return NGHTTP3_ERR_CALLBACK_FAILURE;
260 if (server->http_server) {
261 http3_stream_state_t *state = SAFE_CALLOC(1, sizeof(*state), http3_stream_state_t *);
262 if (!state)
263 return NGHTTP3_ERR_NOMEM;
264 state->owner = server;
265 state->stream_id = stream_id;
266 state->next = server->streams;
267 server->streams = state;
268 if (nghttp3_conn_set_stream_user_data(conn, stream_id, state) != 0) {
269 server->streams = state->next;
270 SAFE_FREE(state);
271 return NGHTTP3_ERR_CALLBACK_FAILURE;
272 }
273 } else
274 server->request = stream_id;
275 return 0;
276}
277
278static int receive_header(nghttp3_conn *conn, int64_t stream_id, int32_t token, nghttp3_rcbuf *name,
279 nghttp3_rcbuf *value, uint8_t flags, void *context, void *stream_context) {
280 (void)conn;
281 (void)token;
282 (void)flags;
283 (void)stream_context;
284 http_server_http3_t *server = context;
285 http3_stream_state_t *state = stream_context;
286 if (server->http_server && !state)
287 return NGHTTP3_ERR_CALLBACK_FAILURE;
288 nghttp3_vec key = nghttp3_rcbuf_get_buf(name), val = nghttp3_rcbuf_get_buf(value);
289 if (stream_id != (state ? state->stream_id : server->request) ||
290 key.len > H3_MAX_HEADER_BYTES - H3_FIELD(server, state, header_bytes) ||
291 val.len > H3_MAX_HEADER_BYTES - H3_FIELD(server, state, header_bytes) - key.len)
292 return NGHTTP3_ERR_CALLBACK_FAILURE;
293 *H3_PTR(server, state, header_bytes) += key.len + val.len;
294 if (key.len >= H3_MAX_TEXT || val.len >= H3_MAX_TEXT || H3_FIELD(server, state, header_count) >= H3_MAX_HEADERS)
295 return NGHTTP3_ERR_CALLBACK_FAILURE;
296 size_t index = H3_FIELD(server, state, header_count);
297 memcpy(H3_FIELD(server, state, header_names)[index], key.base, key.len);
298 H3_FIELD(server, state, header_names)[index][key.len] = 0;
299 memcpy(H3_FIELD(server, state, header_values)[index], val.base, val.len);
300 H3_FIELD(server, state, header_values)[index][val.len] = 0;
301 H3_FIELD(server, state, headers)
302 [index] =
303 (http_header_t){H3_FIELD(server, state, header_names)[index], H3_FIELD(server, state, header_values)[index]};
304 (*H3_PTR(server, state, header_count))++;
305 if (equal_bytes(key, ":method")) {
306 if (val.len >= sizeof(H3_FIELD(server, state, method_text)))
307 return NGHTTP3_ERR_CALLBACK_FAILURE;
308 memcpy(H3_FIELD(server, state, method_text), val.base, val.len);
309 H3_FIELD(server, state, method_text)[val.len] = 0;
310 } else if (equal_bytes(key, ":path")) {
311 if (val.len >= sizeof(H3_FIELD(server, state, request_target)))
312 return NGHTTP3_ERR_CALLBACK_FAILURE;
313 memcpy(H3_FIELD(server, state, request_target), val.base, val.len);
314 H3_FIELD(server, state, request_target)[val.len] = 0;
315 }
316 bool *field = NULL, valid = false;
317 if (equal_bytes(key, ":method")) {
318 field = &server->method;
319 valid = server->http_server ? val.len > 0 : equal_bytes(val, "CONNECT");
320 } else if (equal_bytes(key, ":scheme")) {
321 field = &server->scheme;
322 valid = equal_bytes(val, "https");
323 } else if (equal_bytes(key, ":authority")) {
324 field = &server->authority;
325 valid = val.len > 0;
326 } else if (equal_bytes(key, ":protocol")) {
327 field = &server->protocol;
328 valid = equal_bytes(val, "webtransport");
329 } else if (equal_bytes(key, ":path")) {
330 field = &server->request_path;
331 valid = server->http_server ? val.len > 0 : equal_bytes(val, server->path);
332 } else if (equal_bytes(key, "origin")) {
333 field = &server->request_origin;
334 valid = server->http_server ? true : equal_bytes(val, server->origin);
335 }
336 if (field && !state) {
337 if (*field || !valid)
338 server->malformed = true;
339 *field = true;
340 } else if (field) {
341 bool *stream_field = NULL;
342 if (equal_bytes(key, ":method"))
343 stream_field = &state->method;
344 else if (equal_bytes(key, ":scheme"))
345 stream_field = &state->scheme;
346 else if (equal_bytes(key, ":authority"))
347 stream_field = &state->authority;
348 else if (equal_bytes(key, ":protocol"))
349 stream_field = &state->protocol;
350 else if (equal_bytes(key, ":path"))
351 stream_field = &state->request_path;
352 else if (equal_bytes(key, "origin"))
353 stream_field = &state->request_origin;
354 if (*stream_field || !valid)
355 state->malformed = true;
356 *stream_field = true;
357 }
358 return 0;
359}
360
361static int end_headers(nghttp3_conn *conn, int64_t stream_id, int fin, void *context, void *stream_context) {
362 (void)conn;
363 (void)stream_context;
364 http_server_http3_t *server = context;
365 http3_stream_state_t *state = stream_context;
366 if (stream_id != (state ? state->stream_id : server->request) || H3_FIELD(server, state, headers_done))
367 return NGHTTP3_ERR_CALLBACK_FAILURE;
368 *H3_PTR(server, state, headers_done) = true;
369 if (server->http_server && state)
370 return 0;
371 server->malformed |= fin != 0;
372 return maybe_respond(server);
373}
374
375static int receive_settings(nghttp3_conn *conn, const nghttp3_proto_settings *settings, void *context) {
376 (void)conn;
377 http_server_http3_t *server = context;
378 if (!server->http_server && !settings->h3_datagram)
379 return NGHTTP3_ERR_CALLBACK_FAILURE;
380 server->settings_received = true;
381 if (server->http_server)
382 return 0;
383 return maybe_respond(server);
384}
385
386static int close_stream(nghttp3_conn *conn, int64_t stream_id, uint64_t app_error_code, void *context,
387 void *stream_context) {
388 (void)conn;
389 (void)app_error_code;
390 http_server_http3_t *server = context;
391 http3_stream_state_t *state = stream_context;
392 if (!server || !state || state->stream_id != stream_id)
393 return 0;
395 http3_stream_state_t **cursor = &server->streams;
396 while (*cursor && *cursor != state)
397 cursor = &(*cursor)->next;
398 if (*cursor == state)
399 *cursor = state->next;
400 SAFE_FREE(state->request_body);
401 SAFE_FREE(state->response_body);
402 SAFE_FREE(state);
403 return 0;
404}
405
406asciichat_error_t http_server_http3_create(const char *origin, const char *path, int64_t control, int64_t encoder,
407 int64_t decoder, http_server_t *http_server, const char *peer_address,
409 if (!out)
410 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing HTTP/3 server output");
411 *out = NULL;
412 if ((!http_server && (!origin || !path)) ||
413 (origin && strnlen(origin, sizeof(((http_server_http3_t *)0)->origin)) >= H3_MAX_ORIGIN) ||
414 (path && strnlen(path, sizeof(((http_server_http3_t *)0)->path)) >= H3_MAX_PATH) ||
415 (!http_server && (strncmp(origin, "https://", sizeof("https://") - 1) || path[0] != '/')) || control < 0 ||
416 encoder < 0 || decoder < 0 || control == encoder || control == decoder || encoder == decoder ||
417 (control & 3) != 3 || (encoder & 3) != 3 || (decoder & 3) != 3)
418 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid HTTP/3 WebTransport configuration");
419 http_server_http3_t *server = SAFE_CALLOC(1, sizeof(*server), http_server_http3_t *);
420 if (!server)
421 return SET_ERRNO(ERROR_MEMORY, "Cannot allocate HTTP/3 server");
422 if (origin)
423 memcpy(server->origin, origin, strlen(origin) + (size_t)1);
424 if (path)
425 memcpy(server->path, path, strlen(path) + (size_t)1);
426 server->control = control;
427 server->http_server = http_server;
428 safe_snprintf(server->peer_address, sizeof(server->peer_address), "%s", peer_address ? peer_address : "unknown");
429 server->request = -1;
430 make_settings(server);
431 nghttp3_callbacks callbacks = {.stream_close = close_stream,
432 .begin_headers = begin_headers,
433 .recv_header = receive_header,
434 .end_headers = end_headers,
435 .recv_data = receive_data,
436 .end_stream = end_stream,
437 .recv_settings2 = receive_settings};
438 nghttp3_settings settings;
439 nghttp3_settings_default(&settings);
440 settings.enable_connect_protocol = 1;
441 settings.h3_datagram = 1;
442 settings.qpack_max_dtable_capacity = 0;
443 settings.qpack_encoder_max_dtable_capacity = 0;
444 settings.qpack_blocked_streams = 0;
445 settings.max_field_section_size = H3_MAX_HEADER_BYTES;
446 int result = nghttp3_conn_server_new(&server->http, &callbacks, &settings, NULL, server);
447 if (!result)
448 result = nghttp3_conn_bind_control_stream(server->http, control);
449 if (!result)
450 result = nghttp3_conn_bind_qpack_streams(server->http, encoder, decoder);
451 if (result) {
453 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Cannot initialize HTTP/3: %s", nghttp3_strerror(result));
454 }
455 nghttp3_conn_set_max_client_streams_bidi(server->http, 128);
456 *out = server;
457 return ASCIICHAT_OK;
458}
459
461 size_t length, bool fin, uint64_t now_ns, size_t *consumed) {
462 if (!server || !consumed || (!data && length))
463 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid HTTP/3 input");
464 *consumed = 0;
465 nghttp3_ssize result = nghttp3_conn_read_stream2(server->http, stream_id, data, length, fin, now_ns);
466 if (result < 0)
467 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "HTTP/3 receive failed: %s", nghttp3_strerror((int)result));
468 *consumed = (size_t)result;
469 return ASCIICHAT_OK;
470}
471
472asciichat_error_t http_server_http3_write(http_server_http3_t *server, int64_t *stream_id, bool *fin,
473 nghttp3_vec *vectors, size_t capacity, size_t *count) {
474 if (!server || !stream_id || !fin || !vectors || !capacity || !count)
475 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid HTTP/3 output");
476 if (server->pending)
477 return SET_ERRNO(ERROR_INVALID_STATE, "HTTP/3 output has not been submitted");
478 *stream_id = -1;
479 *fin = false;
480 *count = 0;
481 if (server->settings_written < server->settings_length) {
482 *stream_id = server->control;
483 vectors[0].base = server->settings + server->settings_written;
484 vectors[0].len = server->settings_length - server->settings_written;
485 *count = 1;
486 server->pending = true;
487 server->pending_stream = *stream_id;
488 server->pending_bytes = vectors[0].len;
489 return ASCIICHAT_OK;
490 }
491 for (;;) {
492 int is_fin = 0;
493 nghttp3_ssize result = nghttp3_conn_writev_stream(server->http, stream_id, &is_fin, vectors, capacity);
494 if (result < 0)
495 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "HTTP/3 output failed: %s", nghttp3_strerror((int)result));
496 if (*stream_id != server->control) {
497 *fin = is_fin != 0;
498 *count = (size_t)result;
499 if (*stream_id >= 0) {
500 server->pending = true;
501 server->pending_stream = *stream_id;
502 server->pending_bytes = 0;
503 for (nghttp3_ssize i = 0; i < result; ++i) {
504 if (vectors[i].len > SIZE_MAX - server->pending_bytes)
505 return SET_ERRNO(ERROR_NETWORK_SIZE, "HTTP/3 output size overflow");
506 server->pending_bytes += vectors[i].len;
507 }
508 }
509 return ASCIICHAT_OK;
510 }
511 size_t skipped = 0;
512 for (nghttp3_ssize i = 0; i < result; ++i)
513 skipped += vectors[i].len;
514 if (is_fin || !skipped || nghttp3_conn_add_write_offset(server->http, *stream_id, skipped) ||
515 nghttp3_conn_add_ack_offset(server->http, *stream_id, skipped))
516 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Cannot replace HTTP/3 control settings");
517 }
518}
519
520asciichat_error_t http_server_http3_wrote(http_server_http3_t *server, int64_t stream_id, size_t length) {
521 if (!server || !server->pending || stream_id != server->pending_stream || length > server->pending_bytes)
522 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid HTTP/3 submitted output");
523 if (stream_id == server->control) {
524 server->settings_written += length;
525 server->pending = false;
526 return ASCIICHAT_OK;
527 }
528 int result = nghttp3_conn_add_write_offset(server->http, stream_id, length);
529 if (result)
530 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Cannot advance HTTP/3 output: %s", nghttp3_strerror(result));
531 server->pending = false;
532 return ASCIICHAT_OK;
533}
534
536 if (!server)
537 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid HTTP/3 server");
538 if (stream_id == server->control) {
539 if (length > server->settings_written - server->settings_acked)
540 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid HTTP/3 settings acknowledgement");
541 server->settings_acked += (size_t)length;
542 return ASCIICHAT_OK;
543 }
544 int result = nghttp3_conn_add_ack_offset(server->http, stream_id, length);
545 return result ? SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Cannot acknowledge HTTP/3 output: %s", nghttp3_strerror(result))
546 : ASCIICHAT_OK;
547}
548
550 if (!server || !server->accepted)
551 return false;
552 if (session_id)
553 *session_id = server->request;
554 return true;
555}
556
558 if (!server || !*server)
559 return;
560 http_server_invalidate_http3_context((*server)->http_server, *server);
561 nghttp3_conn_del((*server)->http);
562 while ((*server)->streams) {
563 http3_stream_state_t *state = (*server)->streams;
564 (*server)->streams = state->next;
565 SAFE_FREE(state->request_body);
566 SAFE_FREE(state->response_body);
567 SAFE_FREE(state);
568 }
569 SAFE_FREE((*server)->request_body);
570 SAFE_FREE((*server)->response_body);
571 SAFE_FREE(*server);
572}
#define SET_ERRNO(code,...)
⚙️ Common definitions, error codes, macros, and types shared throughout the application
bool valid
Definition fft.c:27
#define SAFE_REALLOC(ptr, size, cast)
Definition common.h:285
unsigned int uint32_t
Definition common.h:62
#define SAFE_FREE(ptr)
Definition common.h:377
#define SAFE_MALLOC(size, cast)
Definition common.h:265
#define SAFE_CALLOC(count, size, cast)
Definition common.h:275
unsigned long long uint64_t
Definition common.h:63
unsigned char uint8_t
Definition common.h:60
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
@ ERROR_INVALID_STATE
@ ERROR_NETWORK_PROTOCOL
Definition error_codes.h:76
@ ERROR_MEMORY
Definition error_codes.h:51
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_NETWORK_SIZE
Definition error_codes.h:77
@ ERROR_INVALID_PARAM
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Platform-safe snprintf wrapper.
bool http_server_http3_accepted(const http_server_http3_t *server, int64_t *session_id)
Definition http3.c:549
#define H3_PTR(server, state, field)
Definition http3.c:64
#define H3_FIELD(server, state, field)
Definition http3.c:63
asciichat_error_t http_server_http3_create(const char *origin, const char *path, int64_t control, int64_t encoder, int64_t decoder, http_server_t *http_server, const char *peer_address, http_server_http3_t **out)
Definition http3.c:406
asciichat_error_t http_server_http3_write(http_server_http3_t *server, int64_t *stream_id, bool *fin, nghttp3_vec *vectors, size_t capacity, size_t *count)
Definition http3.c:472
#define H3_MAX_HEADER_BYTES
Definition http3.c:7
void http_server_http3_destroy(http_server_http3_t **server)
Definition http3.c:557
asciichat_error_t http_server_http3_read(http_server_http3_t *server, int64_t stream_id, const uint8_t *data, size_t length, bool fin, uint64_t now_ns, size_t *consumed)
Definition http3.c:460
#define H3_MAX_PATH
Definition http3.c:9
asciichat_error_t http_server_http3_wrote(http_server_http3_t *server, int64_t stream_id, size_t length)
Definition http3.c:520
#define H3_SETTINGS_BUFFER
Definition http3.c:10
#define H3_MAX_ORIGIN
Definition http3.c:8
struct http3_stream_state http3_stream_state_t
Definition http3.c:14
#define H3_MAX_TEXT
Definition http3.c:12
asciichat_error_t http_server_http3_ack(http_server_http3_t *server, int64_t stream_id, uint64_t length)
Definition http3.c:535
#define H3_MAX_HEADERS
Definition http3.c:11
struct http_server_http3 http_server_http3_t
Definition http3.h:11
size_t http_server_max_request_body(const http_server_t *server)
size_t http_server_max_response_body(const http_server_t *server)
void http_server_invalidate_http3_context(http_server_t *server, void *context)
asciichat_error_t http_server_dispatch_http3(http_server_t *server, const char *method, const char *path, const http_header_t *headers, size_t header_count, const void *body, size_t body_length, const char *peer_address, http3_submit_response_fn submit, void *submit_context)
static bool size_t index
Definition queries.h:8
static bool size_t gotel_query_t * out
Definition queries.h:8
return true
Definition queries.h:13
uint8_t session_id[SESSION_ID_SIZE]
🔤 String Manipulation and Shell Escaping Utilities
bool headers_done
Definition http3.c:49
char method_text[32]
Definition http3.c:51
size_t header_bytes
Definition http3.c:54
size_t request_body_length
Definition http3.c:56
uint8_t * response_body
Definition http3.c:58
bool request_origin
Definition http3.c:50
char request_target[2048U]
Definition http3.c:51
http3_stream_state_t * next
Definition http3.c:60
size_t response_offset
Definition http3.c:59
char header_values[64U][2048U]
Definition http3.c:52
size_t response_length
Definition http3.c:59
bool request_path
Definition http3.c:50
size_t request_body_capacity
Definition http3.c:56
size_t header_count
Definition http3.c:54
uint8_t * request_body
Definition http3.c:55
bool request_end_stream
Definition http3.c:57
char header_names[64U][2048U]
Definition http3.c:52
http_server_http3_t * owner
Definition http3.c:47
http_header_t headers[64U]
Definition http3.c:53
int64_t stream_id
Definition http3.c:48
For acip http3 server, this is the live record that ties http, control, request, settings_length toge...
Definition http3.c:21
bool request_path
Definition http3.c:31
size_t request_body_capacity
Definition http3.c:39
size_t pending_bytes
Definition http3.c:28
char request_target[2048U]
Definition http3.c:34
size_t response_offset
Definition http3.c:42
uint8_t * response_body
Definition http3.c:41
int64_t control
Definition http3.c:23
nghttp3_conn * http
Definition http3.c:22
char origin[512U]
Definition http3.c:24
char peer_address[64]
Definition http3.c:33
char header_values[64U][2048U]
Definition http3.c:35
http_server_t * http_server
Definition http3.c:32
bool headers_done
Definition http3.c:30
http_header_t headers[64U]
Definition http3.c:36
uint8_t * request_body
Definition http3.c:38
char path[512U]
Definition http3.c:24
size_t settings_written
Definition http3.c:26
size_t settings_acked
Definition http3.c:26
bool request_end_stream
Definition http3.c:40
char method_text[32]
Definition http3.c:34
int64_t request
Definition http3.c:23
size_t response_length
Definition http3.c:42
size_t header_count
Definition http3.c:37
uint8_t settings[96U]
Definition http3.c:25
int64_t pending_stream
Definition http3.c:27
size_t header_bytes
Definition http3.c:26
bool request_origin
Definition http3.c:31
bool settings_received
Definition http3.c:30
char header_names[64U][2048U]
Definition http3.c:35
http3_stream_state_t * streams
Definition http3.c:43
size_t request_body_length
Definition http3.c:39
size_t settings_length
Definition http3.c:26
struct http_server http_server_t
Definition tls.h:8