![]() |
Nilorea Library
C utilities for networking, threading, graphics
|
HTTP/2 (RFC 7540) server-side connection and stream state machine. More...
Go to the source code of this file.
Data Structures | |
| struct | N_H2_REQUEST |
| one complete request received on a stream; every pointer is owned by the server and valid only for the duration of the request callback More... | |
Macros | |
| #define | N_H2_SRV_MAX_BODY (16 * 1024 * 1024) |
| largest request body accumulated for one stream | |
| #define | N_H2_SRV_MAX_HEADERS 128 |
| largest number of header fields decoded from one request | |
| #define | N_H2_SRV_MAX_STREAMS 128 |
| largest number of streams tracked at once on one connection | |
| #define | N_H2_SRV_READ_CHUNK 16384 |
| bytes pulled from the read callback per call | |
HTTP/2 error codes (RFC 7540 7) | |
| #define | N_H2_ERR_CANCEL 0x8 |
| stream cancelled | |
| #define | N_H2_ERR_COMPRESSION_ERROR 0x9 |
| HPACK compression state not updated. | |
| #define | N_H2_ERR_CONNECT_ERROR 0xa |
| TCP connection error for CONNECT. | |
| #define | N_H2_ERR_ENHANCE_YOUR_CALM 0xb |
| processing capacity exceeded | |
| #define | N_H2_ERR_FLOW_CONTROL_ERROR 0x3 |
| flow-control limits exceeded | |
| #define | N_H2_ERR_FRAME_SIZE_ERROR 0x6 |
| frame size incorrect | |
| #define | N_H2_ERR_HTTP_1_1_REQUIRED 0xd |
| use HTTP/1.1 for the request | |
| #define | N_H2_ERR_INADEQUATE_SECURITY 0xc |
| negotiated TLS parameters not acceptable | |
| #define | N_H2_ERR_INTERNAL_ERROR 0x2 |
| implementation fault | |
| #define | N_H2_ERR_NO_ERROR 0x0 |
| graceful shutdown | |
| #define | N_H2_ERR_PROTOCOL_ERROR 0x1 |
| unspecific protocol error | |
| #define | N_H2_ERR_REFUSED_STREAM 0x7 |
| stream not processed | |
| #define | N_H2_ERR_SETTINGS_TIMEOUT 0x4 |
| settings not acknowledged | |
| #define | N_H2_ERR_STREAM_CLOSED 0x5 |
| frame received for a closed stream | |
Typedefs | |
| typedef ssize_t(* | n_h2_srv_read_fn) (void *io, void *buf, size_t len) |
| read up to len bytes into buf: returns the bytes read (>0), 0 on a clean end of stream, or -1 on error (a timeout included) | |
| typedef int(* | n_h2_srv_request_cb) (void *user_data, N_H2_SERVER *srv, const N_H2_REQUEST *req) |
| called with each complete request; answer it with n_http2_server_respond() (or n_http2_server_rst_stream()). | |
| typedef ssize_t(* | n_h2_srv_write_fn) (void *io, const void *buf, size_t len) |
| write exactly len bytes from buf: returns len on success, -1 on error | |
Functions | |
| const char * | n_http2_server_error (const N_H2_SERVER *srv) |
| the reason the connection failed, or NULL when none was recorded | |
| void | n_http2_server_free (N_H2_SERVER **srv) |
| free a server connection and NULL the caller's pointer | |
| int | n_http2_server_goaway (N_H2_SERVER *srv, uint32_t error_code) |
| send GOAWAY, naming the last stream we processed | |
| int | n_http2_server_handshake (N_H2_SERVER *srv) |
| read and validate the client connection preface, then send ours | |
| N_H2_SERVER * | n_http2_server_new (void *io, n_h2_srv_read_fn rd, n_h2_srv_write_fn wr) |
| create a server connection over the given I/O callbacks | |
| size_t | n_http2_server_request_count (const N_H2_SERVER *srv) |
| the number of requests delivered to the callback so far | |
| int | n_http2_server_respond (N_H2_SERVER *srv, uint32_t stream_id, const N_H2_HEADER *headers, size_t nheaders, const unsigned char *body, size_t body_len) |
| write a complete response on a stream (HEADERS then DATA, END_STREAM) | |
| int | n_http2_server_rst_stream (N_H2_SERVER *srv, uint32_t stream_id, uint32_t error_code) |
| abort one stream with RST_STREAM | |
| int | n_http2_server_run (N_H2_SERVER *srv, n_h2_srv_request_cb cb, void *user_data) |
| serve the connection until it ends | |
HTTP/2 (RFC 7540) server-side connection and stream state machine.
The server half of HTTP/2, built on the framing and HPACK codec of n_http2.h: it validates the client connection preface, exchanges SETTINGS, reassembles HEADERS plus CONTINUATION per stream, accumulates DATA until END_STREAM, hands each complete request to a callback, and writes responses back as HEADERS plus DATA. It answers PING, honours RST_STREAM, and closes with GOAWAY.
Both directions are flow controlled at the connection AND the stream level: the receive windows are replenished as request bodies are consumed, and a response body is never written past the peer's advertised window (when a window is exhausted the server pumps incoming frames until a WINDOW_UPDATE reopens it). A server that skips this works against small responses and deadlocks against large ones.
Byte I/O goes through injected read/write callbacks rather than a socket, so the same core runs over a plain connection (h2c prior knowledge, and the tests against a scripted peer) or a TLS connection that negotiated ALPN "h2"; the callbacks own the timeouts and the TLS.
Requests are delivered one at a time: the callback for a stream returns before the next stream's request is delivered, so a handler may block. Streams are still multiplexed on the wire (the client may open many at once, and their frames keep being read and buffered), they are simply served in the order they complete.
Definition in file n_http2_server.h.
| struct N_H2_REQUEST |
one complete request received on a stream; every pointer is owned by the server and valid only for the duration of the request callback
Definition at line 104 of file n_http2_server.h.
| Data Fields | ||
|---|---|---|
| const char * | authority | the :authority pseudo-header, or NULL when absent |
| const unsigned char * | body | the request body, or NULL when there is none |
| size_t | body_len | the body length in bytes |
| N_H2_HEADER * | headers | the decoded header fields, pseudo-headers included |
| const char * | method | the :method pseudo-header, or NULL when absent |
| size_t | nheaders | number of header fields |
| const char * | path | the :path pseudo-header, or NULL when absent |
| const char * | scheme | the :scheme pseudo-header, or NULL when absent |
| uint32_t | stream_id | the stream the request arrived on |
| #define N_H2_ERR_CANCEL 0x8 |
stream cancelled
Definition at line 84 of file n_http2_server.h.
Referenced by test_rst_stream().
| #define N_H2_ERR_COMPRESSION_ERROR 0x9 |
HPACK compression state not updated.
Definition at line 85 of file n_http2_server.h.
| #define N_H2_ERR_CONNECT_ERROR 0xa |
TCP connection error for CONNECT.
Definition at line 86 of file n_http2_server.h.
| #define N_H2_ERR_ENHANCE_YOUR_CALM 0xb |
processing capacity exceeded
Definition at line 87 of file n_http2_server.h.
Referenced by srv_apply_data().
| #define N_H2_ERR_FLOW_CONTROL_ERROR 0x3 |
flow-control limits exceeded
Definition at line 79 of file n_http2_server.h.
| #define N_H2_ERR_FRAME_SIZE_ERROR 0x6 |
frame size incorrect
Definition at line 82 of file n_http2_server.h.
| #define N_H2_ERR_HTTP_1_1_REQUIRED 0xd |
use HTTP/1.1 for the request
Definition at line 89 of file n_http2_server.h.
| #define N_H2_ERR_INADEQUATE_SECURITY 0xc |
negotiated TLS parameters not acceptable
Definition at line 88 of file n_http2_server.h.
| #define N_H2_ERR_INTERNAL_ERROR 0x2 |
implementation fault
Definition at line 78 of file n_http2_server.h.
| #define N_H2_ERR_NO_ERROR 0x0 |
graceful shutdown
Definition at line 76 of file n_http2_server.h.
Referenced by n_http2_server_run().
| #define N_H2_ERR_PROTOCOL_ERROR 0x1 |
unspecific protocol error
Definition at line 77 of file n_http2_server.h.
| #define N_H2_ERR_REFUSED_STREAM 0x7 |
stream not processed
Definition at line 83 of file n_http2_server.h.
Referenced by srv_apply_headers().
| #define N_H2_ERR_SETTINGS_TIMEOUT 0x4 |
settings not acknowledged
Definition at line 80 of file n_http2_server.h.
| #define N_H2_ERR_STREAM_CLOSED 0x5 |
frame received for a closed stream
Definition at line 81 of file n_http2_server.h.
| #define N_H2_SRV_MAX_BODY (16 * 1024 * 1024) |
largest request body accumulated for one stream
Definition at line 68 of file n_http2_server.h.
Referenced by srv_apply_data().
| #define N_H2_SRV_MAX_HEADERS 128 |
largest number of header fields decoded from one request
Definition at line 66 of file n_http2_server.h.
Referenced by srv_finish_headers().
| #define N_H2_SRV_MAX_STREAMS 128 |
largest number of streams tracked at once on one connection
Definition at line 70 of file n_http2_server.h.
Referenced by n_http2_server_free(), n_http2_server_handshake(), n_http2_server_run(), srv_apply_settings(), srv_next_ready(), srv_stream_find(), and srv_stream_open().
| #define N_H2_SRV_READ_CHUNK 16384 |
bytes pulled from the read callback per call
Definition at line 72 of file n_http2_server.h.
Referenced by srv_fill().
| typedef ssize_t(* n_h2_srv_read_fn) (void *io, void *buf, size_t len) |
read up to len bytes into buf: returns the bytes read (>0), 0 on a clean end of stream, or -1 on error (a timeout included)
Definition at line 94 of file n_http2_server.h.
| typedef int(* n_h2_srv_request_cb) (void *user_data, N_H2_SERVER *srv, const N_H2_REQUEST *req) |
called with each complete request; answer it with n_http2_server_respond() (or n_http2_server_rst_stream()).
Return 0 to keep serving the connection, -1 to stop n_http2_server_run().
Definition at line 119 of file n_http2_server.h.
| typedef ssize_t(* n_h2_srv_write_fn) (void *io, const void *buf, size_t len) |
write exactly len bytes from buf: returns len on success, -1 on error
Definition at line 97 of file n_http2_server.h.
| const char * n_http2_server_error | ( | const N_H2_SERVER * | srv | ) |
the reason the connection failed, or NULL when none was recorded
Definition at line 833 of file n_http2_server.c.
References N_H2_SERVER::err.
Referenced by server_fn(), test_continuation(), test_guards(), test_handshake_errors(), and test_send_window_stall().
| void n_http2_server_free | ( | N_H2_SERVER ** | srv | ) |
free a server connection and NULL the caller's pointer
Definition at line 602 of file n_http2_server.c.
References N_H2_SERVER::dec, h2buf_free(), N_H2_SERVER::hblock, N_H2_SRV_MAX_STREAMS, n_http2_hpack_free(), N_H2_SERVER::rb, srv_stream_close(), and N_H2_SERVER::streams.
Referenced by server_fn(), test_callback_stop(), test_continuation(), test_dribbled_reads(), test_get(), test_guards(), test_handshake(), test_handshake_errors(), test_multiplex(), test_ping_goaway(), test_post_body(), test_rst_stream(), test_send_flow_control(), and test_send_window_stall().
| int n_http2_server_goaway | ( | N_H2_SERVER * | srv, |
| uint32_t | error_code ) |
send GOAWAY, naming the last stream we processed
| srv | the server connection, not NULL |
| error_code | an N_H2_ERR_* code |
< GOAWAY
Definition at line 817 of file n_http2_server.c.
References __n_assert, N_H2_SERVER::io_failed, N_H2_SERVER::last_stream_id, N_H2_GOAWAY, and srv_send().
Referenced by n_http2_server_run().
| int n_http2_server_handshake | ( | N_H2_SERVER * | srv | ) |
read and validate the client connection preface, then send ours
Reads the 24-byte preface, requires the client's first frame to be SETTINGS (RFC 7540 3.5), acknowledges it, and sends our own SETTINGS plus the connection-level WINDOW_UPDATE that opens our receive window.
| srv | the server connection, not NULL |
< SETTINGS
< SETTINGS
< SETTINGS/PING: acknowledgement
Definition at line 617 of file n_http2_server.c.
References __n_assert, H2BUF::data, N_H2_SERVER::err, N_H2_FRAME::flags, H2_DEFAULT_WINDOW, H2_SRV_RECV_WINDOW, h2buf_shift(), N_H2_FLAG_ACK, N_H2_PREFACE, N_H2_SETTINGS, N_H2_SETTINGS_ENABLE_PUSH, N_H2_SETTINGS_INITIAL_WINDOW_SIZE, N_H2_SETTINGS_MAX_CONCURRENT_STREAMS, N_H2_SRV_MAX_STREAMS, N_H2_SERVER::rb, srv_handle_frame(), srv_need(), srv_next_frame(), srv_put_setting(), srv_send(), srv_window_update(), N_H2_FRAME::stream_id, and N_H2_FRAME::type.
Referenced by server_fn(), test_callback_stop(), test_continuation(), test_dribbled_reads(), test_get(), test_guards(), test_handshake(), test_handshake_errors(), test_multiplex(), test_ping_goaway(), test_post_body(), test_rst_stream(), test_send_flow_control(), and test_send_window_stall().
| N_H2_SERVER * n_http2_server_new | ( | void * | io, |
| n_h2_srv_read_fn | rd, | ||
| n_h2_srv_write_fn | wr ) |
create a server connection over the given I/O callbacks
| io | opaque handle handed to the callbacks |
| rd | read callback, not NULL |
| wr | write callback, not NULL |
Definition at line 579 of file n_http2_server.c.
References __n_assert, N_H2_SERVER::dec, H2_DEFAULT_MAX_FRAME, H2_DEFAULT_WINDOW, N_H2_SERVER::io, LOG_ERR, n_http2_hpack_new(), n_log, N_H2_SERVER::peer_initial_win, N_H2_SERVER::peer_max_frame, N_H2_SERVER::rd, N_H2_SERVER::send_win_conn, and N_H2_SERVER::wr.
Referenced by server_fn(), test_callback_stop(), test_continuation(), test_dribbled_reads(), test_get(), test_guards(), test_handshake(), test_handshake_errors(), test_multiplex(), test_ping_goaway(), test_post_body(), test_rst_stream(), test_send_flow_control(), and test_send_window_stall().
| size_t n_http2_server_request_count | ( | const N_H2_SERVER * | srv | ) |
the number of requests delivered to the callback so far
Definition at line 837 of file n_http2_server.c.
References N_H2_SERVER::nrequests.
Referenced by test_get(), and test_guards().
| int n_http2_server_respond | ( | N_H2_SERVER * | srv, |
| uint32_t | stream_id, | ||
| const N_H2_HEADER * | headers, | ||
| size_t | nheaders, | ||
| const unsigned char * | body, | ||
| size_t | body_len ) |
write a complete response on a stream (HEADERS then DATA, END_STREAM)
headers must start with the :status pseudo-header and hold no connection-specific field (RFC 7540 8.1.2.2 forbids them). The body is split into DATA frames at the peer's SETTINGS_MAX_FRAME_SIZE and paced by the stream and connection send windows, pumping incoming frames whenever a window is exhausted.
| srv | the server connection, not NULL |
| stream_id | the stream to answer |
| headers | the response header fields, :status first, not NULL |
| nheaders | number of header fields |
| body | the response body, or NULL for none |
| body_len | the body length |
< HEADERS/PUSH_PROMISE/CONTINUATION: header block complete
< DATA/HEADERS: last frame of the stream
< HEADERS
< CONTINUATION
< DATA
< DATA/HEADERS: last frame of the stream
Definition at line 725 of file n_http2_server.c.
References __n_assert, N_H2_SERVER::err, N_H2_CONTINUATION, N_H2_DATA, N_H2_FLAG_END_HEADERS, N_H2_FLAG_END_STREAM, N_H2_HEADERS, n_http2_hpack_encode(), N_H2_SERVER::peer_max_frame, H2_STREAM::reset, H2_STREAM::send_win, N_H2_SERVER::send_win_conn, srv_pump_one(), srv_send(), srv_stream_find(), and N_H2_HEADER::value.
Referenced by h2_on_request(), and on_request().
| int n_http2_server_rst_stream | ( | N_H2_SERVER * | srv, |
| uint32_t | stream_id, | ||
| uint32_t | error_code ) |
abort one stream with RST_STREAM
| srv | the server connection, not NULL |
| stream_id | the stream to reset |
| error_code | an N_H2_ERR_* code |
< RST_STREAM
Definition at line 807 of file n_http2_server.c.
References __n_assert, N_H2_RST_STREAM, and srv_send().
Referenced by srv_apply_data(), and srv_apply_headers().
| int n_http2_server_run | ( | N_H2_SERVER * | srv, |
| n_h2_srv_request_cb | cb, | ||
| void * | user_data ) |
serve the connection until it ends
Reads frames, reassembles requests, and calls cb once per complete request. Returns when the peer closes or sends GOAWAY, when the callback returns -1, or on an error.
| srv | the handshaked server connection, not NULL |
| cb | the request callback, not NULL |
| user_data | opaque pointer handed to the callback |
< graceful shutdown
< graceful shutdown
Definition at line 661 of file n_http2_server.c.
References __n_assert, N_H2_REQUEST::authority, H2_STREAM::body, N_H2_REQUEST::body, N_H2_REQUEST::body_len, H2BUF::data, H2_STREAM::delivered, N_H2_SERVER::eof, N_H2_SERVER::goaway_recv, H2_STREAM::hdrs, N_H2_REQUEST::headers, H2_STREAM::id, H2_STREAM::in_use, N_H2_SERVER::io_failed, H2BUF::len, N_H2_REQUEST::method, N_H2_ERR_NO_ERROR, N_H2_SRV_MAX_STREAMS, n_http2_server_goaway(), N_H2_HEADER::name, H2_STREAM::nhdrs, N_H2_REQUEST::nheaders, N_H2_SERVER::nrequests, N_H2_REQUEST::path, H2_STREAM::reset, N_H2_REQUEST::scheme, srv_next_ready(), srv_pump_one(), srv_stream_close(), srv_stream_find(), stop(), N_H2_REQUEST::stream_id, N_H2_SERVER::streams, and N_H2_HEADER::value.
Referenced by server_fn(), test_callback_stop(), test_continuation(), test_dribbled_reads(), test_get(), test_guards(), test_multiplex(), test_ping_goaway(), test_post_body(), test_rst_stream(), test_send_flow_control(), and test_send_window_stall().