|
cwist
Modern C web framework with libttak runtime
|
OpenSSL-backed HTTPS accept, receive, send, and server-loop helpers. More...
#include <cwist/net/http/https.h>#include <cwist/net/http/writer_fast.h>#include <cwist/core/sstring/sstring.h>#include <cwist/sys/err/cwist_err.h>#include <cwist/core/mem/alloc.h>#include <cwist/core/mem/gc.h>#include <cwist/sys/app/shutdown.h>#include "tls_chain.h"#include "async_internal.h"#include <openssl/ssl.h>#include <openssl/err.h>#include <openssl/evp.h>#include <openssl/hmac.h>#include <openssl/rand.h>#include <openssl/crypto.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <errno.h>#include <poll.h>#include <fcntl.h>#include <sys/socket.h>#include <arpa/inet.h>#include <netinet/tcp.h>#include <stdint.h>#include <pthread.h>#include <stdbool.h>#include <stdatomic.h>#include <time.h>
Go to the source code of this file.
Macros | |
| #define | _POSIX_C_SOURCE 200809L |
| #define | CWIST_TLS_COALESCE_MAX (16 * 1024) |
| #define | HTTPS_TASK_QUEUE_INITIAL 1024 |
| #define | HTTPS_TASK_QUEUE_MAX 2097152 |
| #define | CWIST_ALPN_HTTP11 ((const unsigned char *)"\x08http/1.1") |
| #define | CWIST_ALPN_H2_HTTP11 ((const unsigned char *)"\x02h2\x08http/1.1") |
| #define | CWIST_ALPN_H3_H2_HTTP11 ((const unsigned char *)"\x02h3\x02h2\x08http/1.1") |
| #define | CWIST_ALPN_HTTP11_LEN 9 |
| #define | CWIST_ALPN_H2_HTTP11_LEN 12 |
| #define | CWIST_ALPN_H3_H2_HTTP11_LEN 15 |
Typedefs | |
| typedef struct cwist_tls_ticket_key | cwist_tls_ticket_key |
Functions | |
| bool | cwist_tls_apply_pqc_layer (cwist_app *app, SSL_CTX *ctx) |
| Apply PQC hybrid key exchange settings to an SSL context. | |
| void | https_pool_submit_ready (int client_fd, SSL *pres_ssl, cwist_https_context *ctx, void(*handler)(cwist_https_connection *, void *), void *user_ctx) |
| Submit a connection whose TLS handshake already completed (pres_ssl). Blocks while the queue is full; on pool shutdown closes and frees the socket instead of queueing. | |
| int | https_hs_shepherd_start (void) |
| void | https_hs_shepherd_stop (void) |
| int | https_pool_init (void) |
| Create the worker threads, mutex, and condition variables of the global HTTPS thread pool. No-op if already initialized. | |
| void | https_pool_submit (int client_fd, cwist_https_context *ctx, void(*handler)(cwist_https_connection *, void *), void *user_ctx) |
| Queue a freshly accepted client socket whose TLS handshake still needs to run in a pool worker. | |
| void | https_pool_submit_conn (cwist_https_connection *conn, cwist_https_context *ctx, void(*handler)(cwist_https_connection *, void *), void *user_ctx) |
| Submit an established connection back to the worker pool (e.g. keep-alive re-arm after async defer). Blocks while the queue is full; on pool shutdown closes the connection instead of queueing. | |
| void | https_pool_destroy (void) |
| Shut down the global HTTPS thread pool: signal workers to exit, join them, close any connections still queued, and destroy the pool's mutex and condition variables. No-op if never initialized. | |
| bool | cwist_https_park (cwist_https_connection *conn, uint64_t idle_ms, cwist_https_park_class cls) |
| Hand an idle connection back to the HTTPS pool's park set. | |
| bool | cwist_https_conn_idle (cwist_https_connection *conn) |
True when conn has no buffered TLS bytes and nothing readable. | |
| uint64_t | cwist_https_idle_timeout_ms (void) |
| Idle keep-alive budget for parked HTTP/1.1 TLS connections, in ms. CWIST_HTTPS_IDLE_TIMEOUT_MS overrides the default (CWIST_HTTP_TIMEOUT_MS, the same 30 s the blocking header read waited). | |
| long | cwist_https_pending_handshakes (void) |
| Number of TLS handshakes currently parked in the shepherd. | |
| void | cwist_https_dispatch (int client_fd, cwist_https_context *ctx, void(*handler)(cwist_https_connection *, void *), void *user_ctx) |
| Accept a TLS connection without parking a worker on the handshake. Completes the handshake inline when the ClientHello is already pending, otherwise parks the connection with the handshake shepherd thread and returns immediately. Established sessions are submitted to the HTTPS worker pool. Safe to call from reactor callbacks. | |
| cwist_error_t | cwist_https_init_context (cwist_https_context **ctx, const char *cert_path, const char *key_path) |
| cwist_error_t | cwist_https_init_context_with_options (cwist_https_context **ctx, const char *cert_path, const char *key_path, const cwist_https_options *options, cwist_app *app) |
| cwist_error_t | cwist_https_reload_context (cwist_https_context *ctx, const char *cert_path, const char *key_path, cwist_app *app) |
| Swap in a new certificate chain and key without dropping connections. | |
| void | cwist_https_destroy_context (cwist_https_context *ctx) |
| Free an HTTPS context and release its OpenSSL resources. | |
| long | cwist_https_tls_handshakes_total (void) |
| Total TLS handshakes that completed (full + resumed). | |
| long | cwist_https_tls_handshakes_resumed_total (void) |
| TLS handshakes completed via session resumption/ticket. | |
| long | cwist_https_tls_handshakes_tls12_total (void) |
| Handshakes that negotiated TLS 1.2. | |
| long | cwist_https_tls_handshakes_tls13_total (void) |
| Handshakes that negotiated TLS 1.3. | |
| long | cwist_https_tls_ciphers_aes128_gcm_total (void) |
| Handshakes negotiated with TLS_AES_128_GCM_SHA256. | |
| long | cwist_https_tls_ciphers_aes256_gcm_total (void) |
| Handshakes negotiated with TLS_AES_256_GCM_SHA384. | |
| long | cwist_https_tls_ciphers_chacha20_total (void) |
| Handshakes negotiated with TLS_CHACHA20_POLY1305_SHA256. | |
| long | cwist_https_tls_ciphers_other_total (void) |
| Handshakes negotiated with any other cipher. | |
| long | cwist_https_tls_connections_active (void) |
| Currently established TLS connections (wrap minus teardown). | |
| cwist_error_t | cwist_https_accept (cwist_https_context *ctx, int client_fd, cwist_https_connection **conn) |
| bool | cwist_https_connection_uses_http2 (const cwist_https_connection *conn) |
| Gracefully close an HTTPS connection and free its buffers. | |
| cwist_https_protocol | cwist_https_connection_protocol (const cwist_https_connection *conn) |
| void | cwist_https_close_connection (cwist_https_connection *conn) |
| cwist_http_request * | cwist_https_receive_request (cwist_https_connection *conn) |
| Read from the TLS stream until a full HTTP request has been assembled. | |
| cwist_error_t | cwist_https_send_response (cwist_https_connection *conn, cwist_http_response *res) |
| Serialize an HTTP response and send it over an active TLS connection. | |
| cwist_error_t | cwist_https_send_response_head (cwist_https_connection *conn, cwist_http_response *res) |
| cwist_error_t | cwist_https_server_loop (int server_fd, cwist_https_context *ctx, void(*handler)(cwist_https_connection *, void *), void *user_ctx) |
| Accept HTTPS clients in a loop and dispatch each one to the supplied handler. | |
OpenSSL-backed HTTPS accept, receive, send, and server-loop helpers.
Definition in file https.c.
| cwist_error_t cwist_https_accept | ( | cwist_https_context * | ctx, |
| int | client_fd, | ||
| cwist_https_connection ** | conn | ||
| ) |
Perform SSL handshake on an accepted socket. Returns a new cwist_https_connection wrapper.
Definition at line 1756 of file https.c.
References cap, CWIST_ERR_INT16, CWIST_HTTP_TIMEOUT_MS, CWIST_HTTPS_HANDSHAKE_TIMEOUT_MS, make_error(), SSL_accept, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE, SSL_free, SSL_get_error, and SSL_set_fd.
| void cwist_https_close_connection | ( | cwist_https_connection * | conn | ) |
Close and free the HTTPS connection.
Definition at line 1875 of file https.c.
References cwist_conn_registry_untrack(), and cwist_full_gc_enabled().
Referenced by https_pool_destroy(), and https_pool_submit_conn().
| bool cwist_https_conn_idle | ( | cwist_https_connection * | conn | ) |
True when conn has no buffered TLS bytes and nothing readable.
Definition at line 683 of file https.c.
References cwist_https_connection::buf_len, cap, cwist_https_connection::fd, cwist_https_connection::ssl, and SSL_pending.
Referenced by cwist_http2_serve_connection_ex().
| cwist_https_protocol cwist_https_connection_protocol | ( | const cwist_https_connection * | conn | ) |
Returns the protocol selected by ALPN, or HTTP/1.1 when no higher protocol matched.
Definition at line 1821 of file https.c.
References CWIST_HTTPS_PROTOCOL_NONE, and cwist_https_connection::negotiated_protocol.
| bool cwist_https_connection_uses_http2 | ( | const cwist_https_connection * | conn | ) |
Gracefully close an HTTPS connection and free its buffers.
| conn | HTTPS connection wrapper to close. |
Definition at line 1817 of file https.c.
References CWIST_HTTPS_PROTOCOL_HTTP2, and cwist_https_connection::negotiated_protocol.
| void cwist_https_destroy_context | ( | cwist_https_context * | ctx | ) |
Free an HTTPS context and release its OpenSSL resources.
| ctx | Context to destroy. |
Definition at line 1558 of file https.c.
References cap, cwist_https_context::ctx, cwist_https_context::ctx_lock, cwist_free(), OPENSSL_cleanse, SSL_CTX_free, and cwist_https_context::ticket_key.
Referenced by cwist_app_destroy().
| void cwist_https_dispatch | ( | int | client_fd, |
| cwist_https_context * | ctx, | ||
| void(*)(cwist_https_connection *, void *) | handler, | ||
| void * | user_ctx | ||
| ) |
Accept a TLS connection without parking a worker on the handshake. Completes the handshake inline when the ClientHello is already pending, otherwise parks the connection with the handshake shepherd thread and returns immediately. Established sessions are submitted to the HTTPS worker pool. Safe to call from reactor callbacks.
Definition at line 1141 of file https.c.
References cap, and https_pool_submit().
Referenced by cwist_https_server_loop().
Idle keep-alive budget for parked HTTP/1.1 TLS connections, in ms. CWIST_HTTPS_IDLE_TIMEOUT_MS overrides the default (CWIST_HTTP_TIMEOUT_MS, the same 30 s the blocking header read waited).
Definition at line 710 of file https.c.
References cap, and CWIST_HTTP_TIMEOUT_MS.
| cwist_error_t cwist_https_init_context | ( | cwist_https_context ** | ctx, |
| const char * | cert_path, | ||
| const char * | key_path | ||
| ) |
Initialize the OpenSSL library and create an SSL context. Loads certificate and private key.
Definition at line 1369 of file https.c.
References cap, and cwist_https_init_context_with_options().
| cwist_error_t cwist_https_init_context_with_options | ( | cwist_https_context ** | ctx, |
| const char * | cert_path, | ||
| const char * | key_path, | ||
| const cwist_https_options * | options, | ||
| cwist_app * | app | ||
| ) |
Initialize an HTTPS context with explicit transport options. The HTTP/2 option only applies the standard TLS/ALPN profile today. Application request handling remains HTTP/1.1 unless a frame engine is added.
Definition at line 1451 of file https.c.
References cap, cwist_alloc(), CWIST_ERR_INT16, cwist_https_options::enable_http2, cwist_https_options::enable_http3, make_error(), SSL_CTX_free, and SSL_CTX_set_alpn_select_cb.
Referenced by cwist_https_init_context().
| bool cwist_https_park | ( | cwist_https_connection * | conn, |
| uint64_t | idle_ms, | ||
| cwist_https_park_class | cls | ||
| ) |
Hand an idle connection back to the HTTPS pool's park set.
— API Functions —
A pool thread that has nothing to read on conn calls this instead of blocking in poll(): the connection is watched by one epoll thread and resubmitted to the pool when bytes arrive, so an idle keep-alive connection costs memory but no thread. Returns true when the connection was parked; the caller must then return without touching conn again (another pool thread may already be serving it). Returns false when parking is unavailable (full GC, CWIST_HTTPS_PARK=0, shutdown); the caller keeps serving the connection the blocking way.
| idle_ms | Idle budget before the class-specific expiry action. |
Definition at line 672 of file https.c.
References cap.
Referenced by cwist_http2_serve_connection_ex().
| cwist_http_request * cwist_https_receive_request | ( | cwist_https_connection * | conn | ) |
Read from the TLS stream until a full HTTP request has been assembled.
| conn | Active HTTPS connection wrapper. |
Definition at line 1887 of file https.c.
References cwist_http_request::body, cwist_https_connection::buf_len, cap, cwist_http_request::client_fd, cwist_http_request::content_length, cwist_alloc(), cwist_free(), cwist_full_gc_enabled(), cwist_gc_scope_disown(), CWIST_HTTP_BODY_IDLE_TIMEOUT_MS, CWIST_HTTP_HEADERS_TIMEOUT_MS, CWIST_HTTP_MAX_BODY_SIZE, cwist_http_parse_request(), CWIST_HTTP_READ_BUFFER_SIZE, cwist_http_request_destroy(), CWIST_HTTP_TIMEOUT_MS, cwist_sstring_adopt_len(), cwist_https_connection::fd, cwist_http_request::https_conn, cwist_https_connection::read_buf, cwist_https_connection::ssl, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE, SSL_get_error, SSL_pending, and SSL_read.
| cwist_error_t cwist_https_reload_context | ( | cwist_https_context * | ctx, |
| const char * | cert_path, | ||
| const char * | key_path, | ||
| cwist_app * | app | ||
| ) |
Swap in a new certificate chain and key without dropping connections.
Hot-reload the certificate chain and key of a live HTTPS context.
| ctx | Live HTTPS context whose SSL_CTX is replaced. |
| cert_path | Path to the new PEM certificate chain. |
| key_path | Path to the new PEM private key. |
| app | Application context for the PQC layer (may be NULL). |
The new SSL_CTX is fully built and validated before the swap. Connections established (or handshaking) on the old SSL_CTX keep it alive through BoringSSL's reference counting and finish on the old certificate; new handshakes use the new one. The shared session-ticket key is carried over unchanged, so tickets issued before the reload still resume afterwards (see docs/decisions/0002-tls-hot-reload.md).
Definition at line 1508 of file https.c.
References cap, cwist_https_context::ctx, cwist_https_context::ctx_lock, CWIST_ERR_INT16, cwist_https_options::enable_http2, cwist_https_context::http2_enabled, cwist_https_context::http3_enabled, make_error(), SSL_CTX_free, SSL_CTX_set_alpn_select_cb, SSL_CTX_set_ex_data, SSL_CTX_set_tlsext_ticket_key_cb, and cwist_https_context::ticket_key.
Referenced by cwist_app_reload_tls().
| cwist_error_t cwist_https_send_response | ( | cwist_https_connection * | conn, |
| cwist_http_response * | res | ||
| ) |
Serialize an HTTP response and send it over an active TLS connection.
Zero-copy counterpart of the plaintext send path: the header block is serialized into a stack buffer and written first, then the body is streamed straight from its origin (pointer body, sstring, or file stream) instead of materializing one contiguous heap blob.
| conn | Active HTTPS connection wrapper. |
| res | Response object to serialize. |
Definition at line 2102 of file https.c.
References cwist_http_response::body, cap, cwist_alloc(), CWIST_ERR_INT16, cwist_free(), cwist_http_header_add(), cwist_http_header_get(), CWIST_HTTP_MAX_HEADER_SIZE, cwist_http_serialize_headers(), CWIST_TLS_COALESCE_MAX, cwist_sstring::data, cwist_https_connection::fd, cwist_http_response::file_stream_fd, cwist_http_response::file_stream_len, cwist_http_response::file_stream_offset, cwist_http_response::headers, cwist_https_connection::http3_enabled, cwist_http_response::is_ptr_body, make_error(), cwist_http_response::ptr_body, cwist_http_response::ptr_body_len, cwist_sstring::size, cwist_https_connection::ssl, and cwist_http_response::use_file_stream.
| cwist_error_t cwist_https_send_response_head | ( | cwist_https_connection * | conn, |
| cwist_http_response * | res | ||
| ) |
Definition at line 2197 of file https.c.
References cap, CWIST_ERR_INT16, cwist_http_header_add(), cwist_http_header_get(), CWIST_HTTP_MAX_HEADER_SIZE, cwist_http_serialize_headers(), cwist_https_connection::fd, cwist_http_response::headers, cwist_https_connection::http3_enabled, make_error(), and cwist_https_connection::ssl.
| cwist_error_t cwist_https_server_loop | ( | int | server_fd, |
| cwist_https_context * | ctx, | ||
| void(*)(cwist_https_connection *, void *) | handler, | ||
| void * | user_ctx | ||
| ) |
Accept HTTPS clients in a loop and dispatch each one to the supplied handler.
| server_fd | Bound listening socket descriptor. |
| ctx | HTTPS context shared by all accepted connections. |
| handler | Callback invoked for each successful TLS client wrapper. |
| user_ctx | Opaque pointer forwarded to the handler. |
Definition at line 2295 of file https.c.
References cap, CWIST_ERR_INT16, cwist_https_dispatch(), g_cwist_running, https_pool_destroy(), https_pool_init(), and make_error().
Apply PQC hybrid key exchange settings to an SSL context.
| app | Application context containing PQC configuration. |
| ctx | OpenSSL/BoringSSL SSL_CTX to mutate. |
Definition at line 19 of file pqc_layer.c.
References cap, CWIST_LOG_ERROR, CWIST_LOG_INFO, CWIST_LOG_WARN, cwist_app::pqc_layer_enabled, SSL_CTX_set1_groups_list, SSL_CTX_set_min_proto_version, SSL_CTX_set_options, SSL_OP_NO_TLSv1, SSL_OP_NO_TLSv1_1, SSL_OP_NO_TLSv1_2, TLS1_3_VERSION, and cwist_app::tls_groups.
Definition at line 1134 of file https.c.
Referenced by https_pool_destroy().
Shut down the global HTTPS thread pool: signal workers to exit, join them, close any connections still queued, and destroy the pool's mutex and condition variables. No-op if never initialized.
Definition at line 370 of file https.c.
References cap, cwist_free(), cwist_https_close_connection(), get_optimal_thread_count(), https_hs_shepherd_stop(), and SSL_free.
Referenced by cwist_async_server_loop(), and cwist_https_server_loop().
Create the worker threads, mutex, and condition variables of the global HTTPS thread pool. No-op if already initialized.
Definition at line 268 of file https.c.
References cap, and get_optimal_thread_count().
Referenced by cwist_async_server_loop(), and cwist_https_server_loop().
| void https_pool_submit | ( | int | client_fd, |
| cwist_https_context * | ctx, | ||
| void(*)(cwist_https_connection *, void *) | handler, | ||
| void * | user_ctx | ||
| ) |
Queue a freshly accepted client socket whose TLS handshake still needs to run in a pool worker.
| client_fd | Accepted TCP socket descriptor. |
| ctx | HTTPS context for the handshake. |
| handler | Callback invoked once the connection is established. |
| user_ctx | Opaque pointer forwarded to the handler. |
Definition at line 292 of file https.c.
References cap, and https_pool_submit_ready().
Referenced by cwist_https_dispatch().
| void https_pool_submit_conn | ( | cwist_https_connection * | conn, |
| cwist_https_context * | ctx, | ||
| void(*)(cwist_https_connection *, void *) | handler, | ||
| void * | user_ctx | ||
| ) |
Submit an established connection back to the worker pool (e.g. keep-alive re-arm after async defer). Blocks while the queue is full; on pool shutdown closes the connection instead of queueing.
| conn | Established connection wrapper (ownership transfers to the pool). |
| ctx | HTTPS context. |
| handler | Callback invoked for the connection. |
| user_ctx | Opaque pointer forwarded to the handler. |
Definition at line 341 of file https.c.
References cap, cwist_https_close_connection(), and cwist_https_connection::fd.
| void https_pool_submit_ready | ( | int | client_fd, |
| SSL * | pres_ssl, | ||
| cwist_https_context * | ctx, | ||
| void(*)(cwist_https_connection *, void *) | handler, | ||
| void * | user_ctx | ||
| ) |
Submit a connection whose TLS handshake already completed (pres_ssl). Blocks while the queue is full; on pool shutdown closes and frees the socket instead of queueing.
| client_fd | Accepted TCP socket descriptor. |
| pres_ssl | Established SSL session, or NULL if the worker must run the handshake itself. |
| ctx | HTTPS context. |
| handler | Callback invoked for the connection. |
| user_ctx | Opaque pointer forwarded to the handler. |
Definition at line 308 of file https.c.
Referenced by https_pool_submit().