|
cwist
Modern C web framework with libttak runtime
|
lsquic/BoringSSL-based HTTP/3 server for CWIST. More...
#include <cwist/net/http/http3.h>#include <cwist/net/http/http2.h>#include <cwist/core/log.h>#include <cwist/core/mem/alloc.h>#include <cwist/core/seq/seq.h>#include <cwist/sys/err/cwist_err.h>#include <cwist/sys/app/shutdown.h>#include <ttak/timing/timing.h>#include <ttak/async/sched.h>#include "tls_chain.h"#include "h3_hdr_out.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <errno.h>#include <fcntl.h>#include <arpa/inet.h>#include <netinet/in.h>#include <sys/socket.h>#include <sys/uio.h>#include <sys/stat.h>#include <poll.h>#include <pthread.h>#include <ctype.h>#include <strings.h>#include <inttypes.h>#include <openssl/ssl.h>#include <openssl/x509.h>#include <openssl/evp.h>#include <openssl/rsa.h>#include <openssl/bn.h>#include <openssl/rand.h>#include <openssl/hmac.h>#include <lsquic.h>#include <lsxpack_header.h>
Go to the source code of this file.
Macros | |
| #define | _POSIX_C_SOURCE 200809L |
| #define | MSG_DONTWAIT 0 |
| #define | H3_PSEUDO_METHOD 0x01u |
| #define | H3_PSEUDO_SCHEME 0x02u |
| #define | H3_PSEUDO_PATH 0x04u |
| #define | H3_PSEUDO_AUTHORITY 0x08u |
| #define | H3_PSEUDO_PROTOCOL 0x10u |
| #define | H3_MAX_HEADERS 256 |
| #define | H3_DECODE_BUF_SIZE 131072 |
| #define | H3_MAX_RESPONSE_HEADERS 256 |
| #define | H3_RESPONSE_HEADER_BUF_SIZE 32768 |
| #define | H3_FILE_CHUNKS_PER_TICK 4 |
Typedefs | |
| typedef struct h3_stream_ctx | h3_stream_ctx_t |
| typedef struct h3_dgram_node | h3_dgram_node_t |
| typedef struct h3_conn_ctx | h3_conn_ctx_t |
| typedef struct cwist_h3_hset | cwist_h3_hset_t |
| typedef struct cwist_h3_ticket_key | cwist_h3_ticket_key |
Functions | |
| int | cwist_http3_normalize_response_header_name (const char *name, char *out, size_t out_len) |
| Normalize a response header name to lowercase HTTP/3 form. | |
| int | cwist_http3_response_header_value_is_safe (const char *value) |
| Whether a response header value is safe to put on the wire. | |
| cwist_error_t | cwist_http3_init_context (cwist_http3_context **ctx, const char *cert_path, const char *key_path) |
| Create an HTTP/3 server context from a certificate/key pair. | |
| cwist_error_t | cwist_http3_init_context_ephemeral (cwist_http3_context **ctx) |
| Create an HTTP/3 server context with an ephemeral self-signed certificate ("localhost", RSA-2048, 1-year validity). | |
| void | cwist_http3_destroy_context (cwist_http3_context *ctx) |
| Destroy a context: graceful engine stop, engine destroy, hset sweep, SSL_CTX and ticket-key teardown, context free. | |
| cwist_error_t | cwist_http3_reload_context (cwist_http3_context *ctx, const char *cert_path, const char *key_path) |
| Swap in a new certificate chain and key without dropping QUIC connections. See the public contract in http3.h. | |
| cwist_error_t | cwist_http3_server_loop (int udp_fd, cwist_http3_context *ctx, cwist_http3_request_handler_func handler, void *user_ctx) |
| Run the blocking HTTP/3 server loop on a UDP socket. | |
| void | cwist_http3_set_push_enabled (cwist_http3_context *ctx, int enabled) |
| Enable or disable HTTP/3 server push for this context. Takes effect at cwist_http3_server_loop() time (lsquic engine setting). | |
| void | cwist_http3_set_early_data (cwist_http3_context *ctx, bool enabled) |
| Enable or disable TLS 1.3 early data (0-RTT) on the context. | |
| void | cwist_http3_set_early_data_guard (cwist_http3_context *ctx, int enabled) |
| Enable or disable the 0-RTT replay guard. | |
| int | cwist_http3_method_is_idempotent (const char *method_str) |
| String-based idempotency check (RFC 9110), used by tests and external checks. | |
| int | cwist_http3_push_resource (cwist_http_request *req, const char *path, const char *content_type) |
| Promise a pushed resource from inside a request handler. | |
| int | cwist_http3_set_stream_priority (cwist_http_request *req, unsigned priority) |
| Deprecated and always refused: returns -1. | |
| void | cwist_http3_set_webtransport_handler (cwist_http3_context *ctx, cwist_webtransport_handler_func handler) |
| Register the WebTransport session handler (extended CONNECT). | |
| void | cwist_webtransport_set_new_stream_handler (cwist_http3_context *ctx, void(*handler)(void *stream, void *user_ctx), void *user_ctx) |
| Register the callback invoked for every new WebTransport stream. | |
| ssize_t | cwist_webtransport_read (void *stream, void *buf, size_t len) |
| Stub used when the WebTransport server is not compiled in: always -1. | |
| ssize_t | cwist_webtransport_write (void *stream, const void *data, size_t len) |
| Stub used when the WebTransport server is not compiled in: always -1. | |
| int | cwist_webtransport_flush (void *stream) |
| Stub used when the WebTransport server is not compiled in: always -1. | |
| int | cwist_webtransport_close_stream (void *stream) |
| Stub used when the WebTransport server is not compiled in: always -1. | |
| int | cwist_webtransport_open_bidi_stream (void *session) |
| Stub used when the WebTransport server is not compiled in: always -1. | |
| int | cwist_webtransport_open_uni_stream (void *session) |
| Stub used when the WebTransport server is not compiled in: always -1. | |
| void | cwist_http3_set_idle_timeout (cwist_http3_context *ctx, int ms) |
| Set the connection idle timeout (milliseconds, <= 0 disables). Takes effect at cwist_http3_server_loop() time. | |
| void | cwist_http3_set_handshake_timeout (cwist_http3_context *ctx, int ms) |
| Set the handshake timeout (milliseconds, <= 0 disables). Takes effect at cwist_http3_server_loop() time. | |
| void | cwist_http3_set_ping_period (cwist_http3_context *ctx, int ms) |
| Set the keep-alive ping period (milliseconds, <= 0 disables). Takes effect at cwist_http3_server_loop() time. | |
| void | cwist_http3_set_noprogress_timeout (cwist_http3_context *ctx, int ms) |
| Set the no-progress timeout (milliseconds, <= 0 disables). Takes effect at cwist_http3_server_loop() time. | |
| void | cwist_http3_set_datagram_enabled (cwist_http3_context *ctx, int enabled) |
| Enable or disable H3 datagrams for this context. | |
| void | cwist_http3_set_datagram_callback (cwist_http3_context *ctx, void(*cb)(const void *data, size_t len, void *user_ctx), void *user_ctx) |
| Register the callback for incoming H3/WebTransport datagrams. | |
| int | cwist_http3_send_datagram (void *conn, const void *data, size_t len) |
| Queue an outgoing H3 datagram on a connection. | |
| ssize_t | cwist_webtransport_send_datagram (void *session, const void *data, size_t len) |
| Stub used when the WebTransport server is not compiled in: always -1. | |
| size_t | cwist_webtransport_max_datagram_size (void *session) |
| Stub used when the WebTransport server is not compiled in: always 0. | |
| int | cwist_webtransport_close_session (void *session, uint64_t code, const char *reason) |
| Stub used when the WebTransport server is not compiled in: always -1. | |
lsquic/BoringSSL-based HTTP/3 server for CWIST.
Implements a full HTTP/3 server using LiteSpeed's lsquic library linked statically against BoringSSL. Handles QUIC transport, QPACK, and HTTP/3 framing per RFC 9114.
Definition in file http3.c.
| #define H3_FILE_CHUNKS_PER_TICK 4 |
| typedef struct cwist_h3_hset cwist_h3_hset_t |
| typedef struct h3_conn_ctx h3_conn_ctx_t |
| typedef struct h3_dgram_node h3_dgram_node_t |
| typedef struct h3_stream_ctx h3_stream_ctx_t |
| void cwist_http3_destroy_context | ( | cwist_http3_context * | ctx | ) |
Destroy a context: graceful engine stop, engine destroy, hset sweep, SSL_CTX and ticket-key teardown, context free.
Destroy an HTTP/3 context.
| ctx | Context from cwist_http3_init_context*(); may be NULL (no-op). |
Releases the process-wide lsquic reference taken at init. Must not be called concurrently with cwist_http3_server_loop() on the same context.
Definition at line 2848 of file http3.c.
References cap, cwist_free(), cwist_http3_context::engine, cwist_http3_context::ssl_ctx, SSL_CTX_free, cwist_http3_context::ssl_ctx_handout, cwist_http3_context::ssl_ctx_lock, and cwist_http3_context::ticket_key.
Referenced by cwist_app_destroy().
| cwist_error_t cwist_http3_init_context | ( | cwist_http3_context ** | ctx, |
| const char * | cert_path, | ||
| const char * | key_path | ||
| ) |
Create an HTTP/3 server context from a certificate/key pair.
Callback function type for handling WebTransport sessions over HTTP/3.
| ctx | Receives the new context. |
| cert_path | PEM file with the certificate chain. |
| key_path | PEM file with the private key. |
Takes a process-wide lsquic reference (released by cwist_http3_destroy_context()).
Definition at line 2673 of file http3.c.
References cap, cwist_alloc(), CWIST_ERR_INT16, make_error(), and SSL_CTX_free.
| cwist_error_t cwist_http3_init_context_ephemeral | ( | cwist_http3_context ** | ctx | ) |
Create an HTTP/3 server context with an ephemeral self-signed certificate ("localhost", RSA-2048, 1-year validity).
Initialize an HTTP/3 context with an ephemeral self-signed certificate.
| ctx | Receives the new context. |
Intended for tests and local deployments where provisioning a real certificate is impractical. Takes a process-wide lsquic reference (released by cwist_http3_destroy_context()).
Definition at line 2721 of file http3.c.
References cap, cwist_alloc(), CWIST_ERR_INT16, EVP_sha256, make_error(), SSL_CTX_free, and SSL_CTX_new.
String-based idempotency check (RFC 9110), used by tests and external checks.
| 1 | The method is idempotent (GET/HEAD/PUT/DELETE/OPTIONS/TRACE). |
| 0 | NULL input or a non-idempotent/unknown method. |
Definition at line 3448 of file http3.c.
References cap, and cwist_http_string_to_method().
Normalize a response header name to lowercase HTTP/3 form.
| name | Source name. |
| out | Output buffer of at least out_len bytes. |
| out_len | Capacity of out (NUL included). |
| 0 | Name copied to out as lowercase NUL-terminated text. |
| -1 | NULL/empty input, insufficient capacity, pseudo-header prefix, or a character outside the RFC 9110 field-name grammar. |
Definition at line 1105 of file http3.c.
References cap.
| int cwist_http3_push_resource | ( | cwist_http_request * | req, |
| const char * | path, | ||
| const char * | content_type | ||
| ) |
Promise a pushed resource from inside a request handler.
Push a resource to the client.
| req | Request whose stream anchors the push (must carry the lsquic stream in private_data). |
| path | Request path for the pushed resource. |
| content_type | Ignored; a response field, not valid in a push request set. |
| 0 | Push stream created. |
| -1 | Bad arguments, no connection, or push not negotiated. |
Builds a request header set (:method GET, :scheme https, :path from path, :authority copied from the original request's Host or "localhost").
Definition at line 3469 of file http3.c.
References h3_hdr_out::arr, cap, cwist_http_header_get(), cwist_http_request::headers, and cwist_http_request::private_data.
| cwist_error_t cwist_http3_reload_context | ( | cwist_http3_context * | ctx, |
| const char * | cert_path, | ||
| const char * | key_path | ||
| ) |
Swap in a new certificate chain and key without dropping QUIC connections. See the public contract in http3.h.
Hot-reload the certificate chain and key of a live HTTP/3 context.
Definition at line 2879 of file http3.c.
References cap, CWIST_ERR_INT16, cwist_http3_context::early_data_enabled, make_error(), cwist_http3_context::ssl_ctx, SSL_CTX_free, cwist_http3_context::ssl_ctx_lock, and cwist_http3_context::ticket_key.
Referenced by cwist_app_reload_tls().
Whether a response header value is safe to put on the wire.
| 1 | Every byte satisfies the RFC 9113/9114 field-value grammar (no CTLs including CR/LF, no DEL). |
| 0 | value is NULL or contains a forbidden byte; clients would reject the response as malformed. |
Definition at line 1127 of file http3.c.
References cap.
Queue an outgoing H3 datagram on a connection.
Send an unreliable datagram over the given QUIC connection.
| conn | lsquic connection (as seen in cwist_http_request::private_data chains); used to find the per-connection queue. |
| data | Payload to copy. |
| len | Payload length. |
| 0 | Datagram queued; lsquic is signaled to drain it via the on_dg_write callback. |
| -1 | Bad arguments, no per-connection ctx, or OOM (nothing queued). |
Thread-safe: the payload is copied and appended to the connection's own mutex-guarded queue, so concurrent sends on different connections never share state and concurrent sends on one connection queue instead of clobbering each other.
Definition at line 3823 of file http3.c.
References cap.
| cwist_error_t cwist_http3_server_loop | ( | int | udp_fd, |
| cwist_http3_context * | ctx, | ||
| cwist_http3_request_handler_func | handler, | ||
| void * | user_ctx | ||
| ) |
Run the blocking HTTP/3 server loop on a UDP socket.
Run the HTTP/3 server event loop.
| udp_fd | Bound UDP socket; forced non-blocking here (idempotent). |
| ctx | Context with an initialized SSL_CTX. |
| handler | Request handler invoked per request (required). |
| user_ctx | Passed through to handler. |
Configures lsquic engine settings from the context's knobs (push, WebTransport, datagrams, flow-control windows, timeout set), then polls the socket (epoll on Linux, poll elsewhere; recvmmsg batching when available), feeds packets to the engine, and processes connections until shutdown. Linux receive batches and the packet buffer are heap-allocated so the loop does not require an oversized thread stack. On exit the engine is gracefully stopped and destroyed. CWIST_H3_DEBUG=1 routes lsquic's logger to stderr.
Definition at line 2932 of file http3.c.
References cwist_http3_context::allow_migration, cap, CWIST_ERR_INT16, cwist_http3_context::datagram_enabled, cwist_http3_context::engine, g_cwist_running, cwist_http3_context::handler, cwist_http3_context::handshake_timeout_ms, cwist_http3_context::idle_timeout_ms, make_error(), MSG_DONTWAIT, cwist_http3_context::noprogress_timeout_ms, cwist_http3_context::ping_period_ms, cwist_http3_context::push_enabled, cwist_http3_context::running, cwist_http3_context::udp_fd, cwist_http3_context::user_ctx, and cwist_http3_context::wt_handler.
| void cwist_http3_set_datagram_callback | ( | cwist_http3_context * | ctx, |
| void(*)(const void *data, size_t len, void *user_ctx) | cb, | ||
| void * | user_ctx | ||
| ) |
Register the callback for incoming H3/WebTransport datagrams.
Register a callback for incoming QUIC datagrams.
| user_ctx | Passed through as the last argument of cb. |
Definition at line 3799 of file http3.c.
References cwist_http3_context::datagram_cb, and cwist_http3_context::datagram_user_ctx.
| void cwist_http3_set_datagram_enabled | ( | cwist_http3_context * | ctx, |
| int | enabled | ||
| ) |
Enable or disable H3 datagrams for this context.
Enable or disable QUIC datagram extension on the given context.
Note: enabling WebTransport forces the datagram engine settings on regardless of this knob.
Definition at line 3791 of file http3.c.
References cwist_http3_context::datagram_enabled.
| void cwist_http3_set_early_data | ( | cwist_http3_context * | ctx, |
| bool | enabled | ||
| ) |
Enable or disable TLS 1.3 early data (0-RTT) on the context.
Enable or disable server-side 0-RTT early data on the given context.
Enabling also arms the replay guard (only idempotent methods are accepted as early data) unless the application overrides it with cwist_http3_set_early_data_guard().
Definition at line 3416 of file http3.c.
References cap, cwist_http3_context::early_data_enabled, cwist_http3_context::early_data_guard, cwist_http3_context::ssl_ctx, and cwist_http3_context::ssl_ctx_lock.
| void cwist_http3_set_early_data_guard | ( | cwist_http3_context * | ctx, |
| int | enabled | ||
| ) |
Enable or disable the 0-RTT replay guard.
Enable or disable the 0-RTT replay guard (default ON when early data is enabled).
While armed, requests received while the QUIC handshake is still in progress are refused with 425 unless their method is idempotent (RFC 8470).
Definition at line 3438 of file http3.c.
References cwist_http3_context::early_data_guard.
| void cwist_http3_set_handshake_timeout | ( | cwist_http3_context * | ctx, |
| int | ms | ||
| ) |
Set the handshake timeout (milliseconds, <= 0 disables). Takes effect at cwist_http3_server_loop() time.
Set the handshake timeout.
Definition at line 3761 of file http3.c.
References cap, and cwist_http3_context::handshake_timeout_ms.
| void cwist_http3_set_idle_timeout | ( | cwist_http3_context * | ctx, |
| int | ms | ||
| ) |
Set the connection idle timeout (milliseconds, <= 0 disables). Takes effect at cwist_http3_server_loop() time.
Set the idle timeout for QUIC connections.
Definition at line 3753 of file http3.c.
References cap, and cwist_http3_context::idle_timeout_ms.
| void cwist_http3_set_noprogress_timeout | ( | cwist_http3_context * | ctx, |
| int | ms | ||
| ) |
Set the no-progress timeout (milliseconds, <= 0 disables). Takes effect at cwist_http3_server_loop() time.
Set the no-progress timeout.
Definition at line 3777 of file http3.c.
References cap, and cwist_http3_context::noprogress_timeout_ms.
| void cwist_http3_set_ping_period | ( | cwist_http3_context * | ctx, |
| int | ms | ||
| ) |
Set the keep-alive ping period (milliseconds, <= 0 disables). Takes effect at cwist_http3_server_loop() time.
Set the keep-alive PING period.
Definition at line 3769 of file http3.c.
References cap, and cwist_http3_context::ping_period_ms.
| void cwist_http3_set_push_enabled | ( | cwist_http3_context * | ctx, |
| int | enabled | ||
| ) |
Enable or disable HTTP/3 server push for this context. Takes effect at cwist_http3_server_loop() time (lsquic engine setting).
Enable or disable HTTP/3 server push on the given context.
Definition at line 3405 of file http3.c.
References cwist_http3_context::push_enabled.
| int cwist_http3_set_stream_priority | ( | cwist_http_request * | req, |
| unsigned | priority | ||
| ) |
Deprecated and always refused: returns -1.
Set stream priority for the current response.
lsquic_stream_set_priority() on a request stream emits a PRIORITY_UPDATE frame on the control stream, which violates RFC 9218 (PRIORITY_UPDATE may only reference client-opened streams). Strict stacks (Firefox/neqo) then kill the connection with H3_FRAME_UNEXPECTED. Use the RFC 9218 Priority header instead. See the deprecation note in include/cwist/net/http/http3.h.
Definition at line 3508 of file http3.c.
References cap, and CWIST_LOG_WARN.
| void cwist_http3_set_webtransport_handler | ( | cwist_http3_context * | ctx, |
| cwist_webtransport_handler_func | handler | ||
| ) |
Register the WebTransport session handler (extended CONNECT).
Register a WebTransport session handler on the given HTTP/3 context.
When set, the server loop enables the lsquic WebTransport settings and extended-CONNECT requests with :protocol "webtransport" are handed to this handler via cwist_h3_wt_on_session_open().
Definition at line 3527 of file http3.c.
References cwist_http3_context::wt_handler.
Referenced by cwist_app_use_webtransport().
| void cwist_webtransport_set_new_stream_handler | ( | cwist_http3_context * | ctx, |
| void(*)(void *stream, void *user_ctx) | handler, | ||
| void * | user_ctx | ||
| ) |
Register the callback invoked for every new WebTransport stream.
Register a callback for newly created WebTransport data streams.
| user_ctx | Passed through as the second argument of handler. |
Definition at line 3536 of file http3.c.
References cwist_http3_context::wt_new_stream_ctx, and cwist_http3_context::wt_new_stream_handler.