|
cwist
Modern C web framework with libttak runtime
|
Implementation of HTTP/2 protocol handler for CWIST. More...
#include <unistd.h>#include <stdbool.h>#include <stdio.h>#include <stdint.h>#include <stdlib.h>#include <string.h>#include <strings.h>#include <poll.h>#include <fcntl.h>#include <pthread.h>#include <ctype.h>#include <stdatomic.h>#include <sys/socket.h>#include <arpa/inet.h>#include <errno.h>#include <time.h>#include <cwist/net/http/http2.h>#include <cwist/net/http/http2_flow_control.h>#include <cwist/net/http/async.h>#include "async_internal.h"#include "h2_wire.h"#include <cwist/core/mem/alloc.h>#include <cwist/core/mem/gc.h>#include <cwist/core/log.h>#include <cwist/sys/metrics/metrics.h>#include <cwist/core/seq/seq.h>#include <cwist/sys/err/cwist_err.h>#include <cwist/sys/app/shutdown.h>#include <openssl/ssl.h>#include <openssl/err.h>
Go to the source code of this file.
Typedefs | |
| typedef struct h2_conn | h2_conn |
| typedef struct cwist_h2_stream | h2_stream |
| typedef struct h2_hpack_entry | h2_hpack_entry |
| typedef struct h2_deferred_frame | h2_deferred_frame |
| typedef struct h2_async_node | h2_async_node |
| typedef struct h2_huffman_node | h2_huffman_node |
| typedef struct h2_header_state | h2_header_state |
| typedef struct h2_session | h2_session |
Functions | |
| cwist_h2_async_queue * | cwist_h2_async_queue_acquire (cwist_h2_async_queue *q) |
| Take an additional reference on the queue (for an in-flight cwist_async handle). | |
| void | cwist_h2_async_queue_release (cwist_h2_async_queue *q) |
| Drop a reference on the queue. On the last reference: closes the wake descriptors, destroys the mutex, and frees the queue. Callers must not enqueue after close(). | |
| int | cwist_h2_async_queue_enqueue (cwist_h2_async_queue *q, uint32_t stream_id, cwist_http_request *req, cwist_http_response *send, cwist_http_response *res, bool send_owned) |
| int | h2_decode_integer (const unsigned char *buf, size_t len, size_t *pos, uint8_t prefix_bits, uint32_t *value) |
| Decode an HPACK integer. | |
| char * | h2_huffman_decode (const unsigned char *src, size_t src_len, size_t *out_len) |
| Decode an HPACK Huffman-coded string (RFC 7541 Appendix B). Lazily initializes the decode tree on first call. | |
| char * | h2_decode_string (const unsigned char *buf, size_t len, size_t *pos) |
Decode one HPACK string literal (with optional Huffman coding). Reads the length prefix (7-bit prefix integer with the Huffman flag) and advances pos past the encoded bytes. | |
| const cwist_http2_static_header * | h2_static_header (uint32_t index) |
| Resolve an RFC 7541 static table entry by 1-based index. | |
| size_t | h2_encode_integer (unsigned char *dst, size_t dst_cap, uint32_t value, uint8_t prefix_bits) |
| Encode an integer with an N-bit prefix (RFC 7541 section 5.1). Preserves the high bits of dst[0] outside the prefix mask. | |
| size_t | h2_encode_string (unsigned char *dst, size_t dst_cap, const char *str) |
| Encode a literal string without Huffman coding (RFC 7541 section 5.2). | |
| int | cwist_http2_stream_send_headers (cwist_h2_stream *stream, int status, const cwist_http2_header *headers, size_t header_count, int end_stream) |
| int | cwist_http2_stream_send_data (cwist_h2_stream *stream, const unsigned char *data, size_t len) |
Send DATA on a hook-taken stream, honoring flow-control credit. Splits data into peer_max_frame_size chunks. When the send window is exhausted the batch buffer is flushed and the calling handler thread parks on the connection's fc_cond until the dispatcher applies WINDOW_UPDATE credit or the stream goes away; credit is re-checked under out_mu before each frame is written. | |
| int | cwist_http2_stream_send_trailers (cwist_h2_stream *stream, const cwist_http2_header *trailers, size_t trailer_count) |
| cwist_error_t | cwist_http2_serve_connection (cwist_https_connection *conn, void *user_ctx, cwist_http2_request_handler_func handler) |
| Serve one HTTP/2 connection until it closes (no stream hooks). Convenience wrapper over cwist_http2_serve_connection_ex with NULL hooks. | |
| cwist_error_t | cwist_http2_serve_connection_ex (cwist_https_connection *conn, void *user_ctx, cwist_http2_request_handler_func handler, const cwist_http2_stream_hooks *hooks) |
| Serve one HTTP/2 connection until it closes. Verifies the preface, sends our SETTINGS, then runs the frame dispatcher: HEADERS/CONTINUATION, DATA, SETTINGS, PING, WINDOW_UPDATE, RST_STREAM, and GOAWAY, with per-connection DoS budgets and flow control. A session may be parked off its thread (cwist_https_park) and resumed via conn->proto_state; on exit the session is torn down and proto_state cleared. | |
| int | cwist_http2_push_resource (cwist_http_request *req, const char *path, const char *content_type, const unsigned char *data, size_t data_len) |
| Push a resource to the client (HTTP/2 server push). Sends a PUSH_PROMISE on the request's stream for a fresh server-initiated stream, then responds on that promised stream with a 200 and the supplied body. The :authority pseudo-header is copied from the request's Host header. | |
| #define CWIST_HTTP2_CONNECTION_PREFACE "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" |
| #define CWIST_HTTP2_GOAWAY_GRACE_MS_DEFAULT 2000 |
Grace window between sending GOAWAY on idle timeout and closing the connection. A client that raced a request onto the connection just as it went idle needs time to see the GOAWAY and retry; closing the socket the instant GOAWAY leaves makes strict clients (Firefox) surface a protocol error where lenient ones silently retry. Overridable via CWIST_HTTP2_GOAWAY_GRACE_MS.
| #define CWIST_HTTP2_SEQ_CHUNK_PAYLOAD | ( | max_frame | ) | ((uint16_t)((max_frame) > CWIST_SEQ_HEADER_SIZE ? (max_frame) - CWIST_SEQ_HEADER_SIZE : 0)) |
| cwist_h2_async_queue * cwist_h2_async_queue_acquire | ( | cwist_h2_async_queue * | q | ) |
Take an additional reference on the queue (for an in-flight cwist_async handle).
| q | Queue to retain; NULL is tolerated. |
q. Definition at line 316 of file http2.c.
References cap.
Referenced by cwist_async_defer().
| int cwist_h2_async_queue_enqueue | ( | cwist_h2_async_queue * | q, |
| uint32_t | stream_id, | ||
| cwist_http_request * | req, | ||
| cwist_http_response * | send, | ||
| cwist_http_response * | res, | ||
| bool | send_owned | ||
| ) |
Definition at line 339 of file http2.c.
References cap, cwist_alloc(), cwist_full_gc_enabled(), cwist_gc_scope_disown(), cwist_http_request_destroy(), and cwist_http_response_destroy().
| void cwist_h2_async_queue_release | ( | cwist_h2_async_queue * | q | ) |
Drop a reference on the queue. On the last reference: closes the wake descriptors, destroys the mutex, and frees the queue. Callers must not enqueue after close().
| q | Queue to release; NULL is tolerated. |
Definition at line 327 of file http2.c.
References cap, and cwist_free().
| int cwist_http2_push_resource | ( | cwist_http_request * | req, |
| const char * | path, | ||
| const char * | content_type, | ||
| const unsigned char * | data, | ||
| size_t | data_len | ||
| ) |
Push a resource to the client (HTTP/2 server push). Sends a PUSH_PROMISE on the request's stream for a fresh server-initiated stream, then responds on that promised stream with a 200 and the supplied body. The :authority pseudo-header is copied from the request's Host header.
Push a resource to the client over HTTP/2 Server Push.
| req | Request of the stream that triggered the push; its private_data must be the cwist_https_connection. |
| path | :path for the promised request. |
| content_type | Optional content-type header value. |
| data | Body bytes (may be NULL when data_len is 0). |
| data_len | Body length. |
| 0 | Response queued/written successfully. |
| -1 | Invalid arguments, missing Host header, or send failure. |
Definition at line 4210 of file http2.c.
References cwist_http_request::arena, cwist_http_response::body, cap, CWIST_HTTP2_FLAG_END_HEADERS, CWIST_HTTP2_MAX_FRAME_SIZE, cwist_http_header_add(), CWIST_HTTP_OK, cwist_http_response_create_in_arena(), cwist_http_response_destroy(), cwist_sstring_assign_len(), cwist_sstring::data, h2_encode_integer(), h2_encode_string(), cwist_http_request::headers, cwist_http_response::headers, cwist_http_header_node::key, cwist_http_header_node::next, cwist_http_request::private_data, cwist_http_response::status_code, cwist_http_request::stream_id, and cwist_http_header_node::value.
| cwist_error_t cwist_http2_serve_connection | ( | cwist_https_connection * | conn, |
| void * | user_ctx, | ||
| cwist_http2_request_handler_func | handler | ||
| ) |
Serve one HTTP/2 connection until it closes (no stream hooks). Convenience wrapper over cwist_http2_serve_connection_ex with NULL hooks.
Starts serving an HTTP/2 connection over an established HTTPS session.
| conn | HTTPS connection with a completed TLS (or h2c) handshake. |
| user_ctx | Opaque context passed to handler. |
| handler | Request handler invoked per stream. |
Definition at line 3493 of file http2.c.
References cap, and cwist_http2_serve_connection_ex().
| cwist_error_t cwist_http2_serve_connection_ex | ( | cwist_https_connection * | conn, |
| void * | user_ctx, | ||
| cwist_http2_request_handler_func | handler, | ||
| const cwist_http2_stream_hooks * | hooks | ||
| ) |
Serve one HTTP/2 connection until it closes. Verifies the preface, sends our SETTINGS, then runs the frame dispatcher: HEADERS/CONTINUATION, DATA, SETTINGS, PING, WINDOW_UPDATE, RST_STREAM, and GOAWAY, with per-connection DoS budgets and flow control. A session may be parked off its thread (cwist_https_park) and resumed via conn->proto_state; on exit the session is torn down and proto_state cleared.
| conn | HTTPS connection with a completed TLS (or h2c) handshake. |
| user_ctx | Opaque context passed to handler and the hooks. |
| handler | Request handler invoked per stream. |
| hooks | Optional stream-lifetime hooks (may be NULL). |
Definition at line 3573 of file http2.c.
References cap, cwist_alloc(), cwist_async_dispatch_ack(), cwist_async_dispatch_take(), CWIST_DEFER_FREE, CWIST_ERR_INT16, cwist_free(), CWIST_HTTP2_FLAG_ACK, CWIST_HTTP2_FLAG_END_HEADERS, CWIST_HTTP2_FLAG_END_STREAM, CWIST_HTTP2_FLAG_PADDED, CWIST_HTTP2_FLAG_PRIORITY, cwist_http2_flow_control_consume(), cwist_http2_flow_control_receive(), cwist_http2_flow_control_update_rtt(), CWIST_HTTP2_FRAME_CONTINUATION, CWIST_HTTP2_FRAME_DATA, CWIST_HTTP2_FRAME_GOAWAY, CWIST_HTTP2_FRAME_HEADERS, CWIST_HTTP2_FRAME_PING, CWIST_HTTP2_FRAME_PUSH_PROMISE, CWIST_HTTP2_FRAME_RST_STREAM, CWIST_HTTP2_FRAME_SETTINGS, CWIST_HTTP2_FRAME_WINDOW_UPDATE, CWIST_HTTP2_MAX_FRAME_SIZE, CWIST_HTTP2_MAX_WINDOW, cwist_http2_stream_flow_control_consume(), cwist_http2_stream_flow_control_receive(), CWIST_HTTP_MAX_BODY_SIZE, cwist_http_response_create_in_arena(), cwist_http_response_destroy(), cwist_https_conn_idle(), cwist_https_park(), CWIST_HTTPS_PARK_HTTP2, CWIST_LOG_WARN, cwist_seq_assembler_create_limited(), cwist_seq_assembler_feed(), cwist_seq_assembler_get_data(), cwist_seq_chunk_parse(), CWIST_SEQ_HEADER_SIZE, cwist_sstring_append_len(), __prim_cwist_error_t::err_i16, cwist_error_t::error, g_cwist_running, H2_ERR_ENHANCE_YOUR_CALM, H2_ERR_FLOW_CONTROL_ERROR, H2_ERR_FRAME_SIZE_ERROR, H2_ERR_NO_ERROR, H2_ERR_PROTOCOL_ERROR, H2_ERR_REFUSED_STREAM, make_error(), cwist_http2_stream_hooks::next_deadline_ms, cwist_http2_stream_hooks::on_cancel, cwist_http2_stream_hooks::on_conn_open, cwist_http2_stream_hooks::on_data, cwist_http2_stream_hooks::on_poll, cwist_https_connection::park_expired, cwist_https_connection::proto_state, and cwist_https_connection::proto_state_free.
Referenced by cwist_app_http_handler(), cwist_app_http_handler_async(), and cwist_http2_serve_connection().
| int cwist_http2_stream_send_data | ( | cwist_h2_stream * | stream, |
| const unsigned char * | data, | ||
| size_t | len | ||
| ) |
Send DATA on a hook-taken stream, honoring flow-control credit. Splits data into peer_max_frame_size chunks. When the send window is exhausted the batch buffer is flushed and the calling handler thread parks on the connection's fc_cond until the dispatcher applies WINDOW_UPDATE credit or the stream goes away; credit is re-checked under out_mu before each frame is written.
| stream | Stream to send on; must belong to a live connection. |
| data | Payload bytes. |
| len | Payload length. |
Definition at line 2642 of file http2.c.
References cap, CWIST_HTTP2_FRAME_DATA, and CWIST_HTTP2_MAX_FRAME_SIZE.
| int cwist_http2_stream_send_headers | ( | cwist_h2_stream * | stream, |
| int | status, | ||
| const cwist_http2_header * | headers, | ||
| size_t | header_count, | ||
| int | end_stream | ||
| ) |
Immediate outbound writes for hook-taken streams. Safe to call from the stream handler's own thread; frames bypass the batching delay and are flushed to the socket before returning.
cwist_http2_stream_send_headers emits a response HEADERS frame (status is taken from status, the pairs carry the remaining fields). cwist_http2_stream_send_data emits DATA frames (chunked to the peer's frame/window limits). cwist_http2_stream_send_trailers emits a trailer HEADERS frame with END_STREAM. All return 0 on success, -1 on failure.
Definition at line 2608 of file http2.c.
References cap, cwist_free(), CWIST_HTTP2_FLAG_END_HEADERS, CWIST_HTTP2_FLAG_END_STREAM, and CWIST_HTTP2_FRAME_HEADERS.
| int cwist_http2_stream_send_trailers | ( | cwist_h2_stream * | stream, |
| const cwist_http2_header * | trailers, | ||
| size_t | trailer_count | ||
| ) |
Definition at line 2688 of file http2.c.
References cap, cwist_free(), CWIST_HTTP2_FLAG_END_HEADERS, CWIST_HTTP2_FLAG_END_STREAM, CWIST_HTTP2_FRAME_HEADERS, and cwist_realloc().
| int h2_decode_integer | ( | const unsigned char * | buf, |
| size_t | len, | ||
| size_t * | pos, | ||
| uint8_t | prefix_bits, | ||
| uint32_t * | value | ||
| ) |
Decode an HPACK integer.
Definition at line 1267 of file http2.c.
References cap.
Referenced by h2_decode_string().
Decode one HPACK string literal (with optional Huffman coding). Reads the length prefix (7-bit prefix integer with the Huffman flag) and advances pos past the encoded bytes.
Decode an HPACK string (literal or huffman).
| buf | Buffer holding the encoded header block. |
| len | Total length of buf. |
| pos | In/out: offset of the string; advanced past it on success. |
Definition at line 1543 of file http2.c.
References cap, cwist_alloc(), h2_decode_integer(), and h2_huffman_decode().
| size_t h2_encode_integer | ( | unsigned char * | dst, |
| size_t | dst_cap, | ||
| uint32_t | value, | ||
| uint8_t | prefix_bits | ||
| ) |
Encode an integer with an N-bit prefix (RFC 7541 section 5.1). Preserves the high bits of dst[0] outside the prefix mask.
Encode an HPACK integer; returns bytes written, 0 when dst is too small.
| dst | Destination buffer; dst[0] must already hold any flag bits. |
| dst_cap | Capacity of dst in bytes. |
| value | Integer to encode. |
| prefix_bits | Number of prefix bits (1..8). |
dst_cap is too small. Definition at line 1875 of file http2.c.
References cap.
Referenced by cwist_http2_push_resource(), and h2_encode_string().
Encode a literal string without Huffman coding (RFC 7541 section 5.2).
Encode an HPACK string (literal, non-huffman); 0 when dst is too small.
| dst | Destination buffer. |
| dst_cap | Capacity of dst in bytes. |
| str | NUL-terminated string to encode. |
dst_cap is too small. Definition at line 1903 of file http2.c.
References cap, and h2_encode_integer().
Referenced by cwist_http2_push_resource().
Decode an HPACK Huffman-coded string (RFC 7541 Appendix B). Lazily initializes the decode tree on first call.
Decode an HPACK huffman-encoded string.
| src | Encoded bytes. |
| src_len | Number of encoded bytes. |
| out_len | Out: decoded length in bytes. |
Definition at line 1442 of file http2.c.
References cap, cwist_alloc(), cwist_free(), and cwist_realloc().
Referenced by h2_decode_string().
| const cwist_http2_static_header * h2_static_header | ( | uint32_t | index | ) |