HTTP/2 framing, HPACK and connection state, I/O-free
0

Configure Feed

Select the types of activity you want to include in your feed.

ocaml-h2 / lib / endpoint.mli
8.0 kB 171 lines
1(*--------------------------------------------------------------------------- 2 Copyright (c) 2019 Antonio Nuno Monteiro. Copyright (c) 2025 Anil Madhavapeddy 3 <anil@recoil.org>. 4 5 All rights reserved. 6 7 Redistribution and use in source and binary forms, with or without 8 modification, are permitted provided that the following conditions are met: 9 10 1. Redistributions of source code must retain the above copyright notice, this 11 list of conditions and the following disclaimer. 12 13 2. Redistributions in binary form must reproduce the above copyright notice, 14 this list of conditions and the following disclaimer in the documentation 15 and/or other materials provided with the distribution. 16 17 3. Neither the name of the copyright holder nor the names of its contributors 18 may be used to endorse or promote products derived from this software without 19 specific prior written permission. 20 21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 SPDX-License-Identifier: BSD-3-Clause 32 ---------------------------------------------------------------------------*) 33 34(** The frame-dispatch path shared by the I/O-free {!Server} and {!Client}. 35 36 Both endpoints handle inbound frames, the SETTINGS/PING/WINDOW_UPDATE 37 exchanges, CONTINUATION accumulation, receive-window bookkeeping and 38 HEADERS/DATA framing identically. {!Make} captures that shared path, 39 parametrised over the per-role differences: the event ADT each endpoint 40 surfaces, whether a client connection preface is consumed, and how an 41 inbound header block / DATA / RST_STREAM / GOAWAY maps to an event. *) 42 43module type ROLE = sig 44 type event 45 (** The endpoint's event ADT (a request on the server, a response on the 46 client). *) 47 48 val role : Connection.role 49 (** The endpoint's role on the connection. *) 50 51 val consume_preface : bool 52 (** Whether to expect and consume a client connection preface before any frame 53 (true for a server, false for a client). *) 54 55 val ensure_stream : 56 Connection.t -> int32 -> (Connection.t, Frame.error_code * string) result 57 (** Register a stream the peer is opening (the server), returning the updated 58 connection, or return it unchanged when the stream is one we opened (the 59 client). An id that is not a valid new peer stream -- even (server space) 60 or not strictly greater than the highest peer id seen -- is a connection 61 error (RFC 9113 sec 5.1.1 / 5.4.1): the [Error (code, msg)] then drives a 62 GOAWAY rather than admitting the offending frame. *) 63 64 val message_opened : Connection.t -> int32 -> bool 65 (** Whether [stream_id] has already received the header block that opens its 66 message: the request block on a server, the final (non-informational) 67 response block on a client -- interim 1xx blocks do not open it (RFC 9113 68 sec 8.1). Exactly one further header block may follow, the trailer 69 section, and it must bear END_STREAM; one that does not makes the message 70 malformed (sec 8.1 / 8.1.1). *) 71 72 val on_headers : 73 Connection.t -> 74 stream_id:int32 -> 75 end_stream:bool -> 76 Hpack.header list -> 77 Connection.t * event 78 (** The event for a completed inbound header block, with the (possibly 79 updated) connection -- the client records response/trailer headers on the 80 stream. *) 81 82 val malformed : end_stream:bool -> Hpack.header list -> bool 83 (** Whether a decoded header block makes its message malformed (RFC 9113 sec 84 8.1), which sec 8.1.1 turns into a stream error of type PROTOCOL_ERROR. 85 The client's rule is that an informational (1xx) response must not bear 86 END_STREAM: an interim response promises a final one, so a block that both 87 is interim and ends the stream promises a response that can never arrive. 88 *) 89 90 val on_data : stream_id:int32 -> data:string -> end_stream:bool -> event 91 (** The event for an inbound DATA frame. *) 92 93 val on_stream_reset : stream_id:int32 -> code:Frame.error_code -> event 94 (** The event for an inbound RST_STREAM. *) 95 96 val on_goaway : last_stream_id:int32 -> code:Frame.error_code -> event 97 (** The event for an inbound GOAWAY. *) 98 99 val data_requires_response : bool 100 (** Whether an inbound DATA frame on a live stream is malformed until the 101 peer's opening HEADERS block has arrived (RFC 9113 sec 8.1: a message is 102 HEADERS followed by DATA). True for the client, whose peer opens its 103 response on a stream the client created; the server's peer-created streams 104 only exist once their opening HEADERS arrived. *) 105end 106 107module Make (R : ROLE) : sig 108 type t 109 (** A connection endpoint: the {!Connection.t} plus inbound buffering and the 110 in-flight header-block state. *) 111 112 val v : Connection.t -> t 113 (** [v conn] wraps [conn] as a fresh endpoint. The caller emits the 114 connection's initial bytes (the client preface / SETTINGS). *) 115 116 val conn : t -> Connection.t 117 118 val with_conn : t -> Connection.t -> t 119 (** [with_conn t conn] is [t] with its underlying connection replaced by 120 [conn]. *) 121 122 val incoming : t -> Connection.hpack -> string -> t * R.event list * string 123 (** [incoming t hpack input] feeds inbound bytes and returns the advanced 124 endpoint, the events observed and the bytes to write back (acks, 125 flow-control WINDOW_UPDATE, or a GOAWAY on a connection error). Partial 126 trailing frames are buffered. [hpack] is the caller-owned codec resource 127 lent for decoding header blocks. *) 128 129 val send_headers : 130 t -> 131 Connection.hpack -> 132 stream_id:int32 -> 133 ?end_stream:bool -> 134 Hpack.header list -> 135 t * string 136 (** [send_headers t hpack ~stream_id headers] is the advanced endpoint and the 137 bytes for a HEADERS frame, driving the stream's send-side state. *) 138 139 val data : t -> stream_id:int32 -> ?end_stream:bool -> Rope.t -> t * Rope.t 140 (** [data t ~stream_id payload] queues [payload] for sending and returns the 141 advanced endpoint and the DATA frame(s) the send window admits right now, 142 split to the peer's maximum frame size (END_STREAM on the final frame when 143 [end_stream]). Any remainder stays queued and is returned by later 144 {!incoming} calls as inbound WINDOW_UPDATEs credit the window, so a sender 145 never emits more DATA than the peer has advertised room for (RFC 9113 sec 146 6.9). *) 147 148 val send_window : t -> stream_id:int32 -> int 149 (** [send_window t ~stream_id] is the bytes that may be sent on [stream_id] 150 now: the smaller of the connection and stream send windows (0 if the 151 stream is gone). *) 152 153 val pending_send : t -> stream_id:int32 -> int 154 (** [pending_send t ~stream_id] is the bytes queued on [stream_id] but not yet 155 emitted. *) 156 157 val trailers : 158 t -> Connection.hpack -> stream_id:int32 -> Hpack.header list -> t * string 159 (** [trailers t hpack ~stream_id headers] is the advanced endpoint and a 160 trailing HEADERS frame with END_STREAM. *) 161 162 val reset : t -> stream_id:int32 -> Frame.error_code -> t * string 163 (** [reset t ~stream_id code] is the advanced endpoint and the RST_STREAM 164 frame for [stream_id]. *) 165 166 val goaway : t -> Frame.error_code -> string -> t * string 167 (** [goaway t code debug] is the advanced endpoint and the GOAWAY frame; it 168 marks the connection closing. *) 169 170 val pp : Format.formatter -> t -> unit 171end