Skip to main content

simoom_h2/
conn.rs

1//! The sans-io connection: preface, settings, stream states, flow control, PING, GOAWAY,
2//! RST_STREAM, header blocks and the DoS budgets.
3
4use std::collections::HashMap;
5use std::hash::{BuildHasherDefault, Hasher};
6
7use simoom_hpack::{Decoder, Encoder, Error as HpackError};
8
9use crate::budget::{Kind as Budget, Meter};
10use crate::frame::{self, be32, flag, kind, setting, ErrorCode, FrameHeader, DEFAULT_WINDOW, HEADER_LEN, MAX_WINDOW, PREFACE};
11use crate::headers::{connection_specific, valid_name, valid_value, Headers, Kind as HeadKind};
12use crate::upgrade::{base64url_decode, base64url_encode};
13use crate::{Config, Error, Event};
14
15/// Which end of the connection this is.
16#[derive(Clone, Copy, Debug, PartialEq, Eq)]
17pub enum Role {
18    Client,
19    Server,
20}
21
22/// Hasher for stream ids: one multiply, rotated so the bucket bits are well mixed.
23#[derive(Default)]
24struct IdHasher(u64);
25
26impl Hasher for IdHasher {
27    fn finish(&self) -> u64 {
28        self.0
29    }
30    fn write(&mut self, b: &[u8]) {
31        for &x in b {
32            self.0 = (self.0.rotate_left(8) ^ x as u64).wrapping_mul(0x9e37_79b9_7f4a_7c15);
33        }
34    }
35    fn write_u32(&mut self, n: u32) {
36        self.0 = (n as u64).wrapping_mul(0x9e37_79b9_7f4a_7c15).rotate_left(32);
37    }
38}
39
40type StreamMap = HashMap<u32, Stream, BuildHasherDefault<IdHasher>>;
41
42#[derive(Debug, Default)]
43struct Stream {
44    send_window: i64,
45    recv_window: i64,
46    /// DATA bytes delivered to the application and not yet released.
47    unreleased: u32,
48    /// Released bytes not yet announced with a stream WINDOW_UPDATE.
49    unacked: u32,
50    /// DATA payload received, for the content-length check.
51    received: u64,
52    content_length: Option<u64>,
53    remote_end: bool,
54    local_end: bool,
55    reset: bool,
56    /// The reset came from the peer: later frames are STREAM_CLOSED errors, not ignored.
57    peer_reset: bool,
58    /// Counted in `open_count`.
59    open: bool,
60    /// Counted in `handlers`: the application's work for it has not finished.
61    handler: bool,
62    final_sent: bool,
63    final_recv: bool,
64    blocked: bool,
65    /// The request was HEAD: the response's content-length describes no body.
66    head: bool,
67}
68
69impl Stream {
70    fn closed(&self) -> bool {
71        self.reset || (self.local_end && self.remote_end)
72    }
73}
74
75#[derive(Clone, Copy, Debug, PartialEq, Eq)]
76enum Phase {
77    /// Server: waiting for the client magic.
78    Preface,
79    /// Waiting for the peer's first SETTINGS frame.
80    Settings,
81    Open,
82    Closed,
83}
84
85/// A header block being reassembled from HEADERS + CONTINUATION.
86#[derive(Clone, Copy, Debug)]
87struct Block {
88    stream: u32,
89    end_stream: bool,
90    self_dep: bool,
91    frames: u32,
92}
93
94type R = Result<(), (ErrorCode, &'static str)>;
95
96fn perr(msg: &'static str) -> R {
97    Err((ErrorCode::PROTOCOL_ERROR, msg))
98}
99
100fn calm(msg: &'static str) -> R {
101    Err((ErrorCode::ENHANCE_YOUR_CALM, msg))
102}
103
104const BDP_PING: [u8; 8] = *b"simoomBD";
105/// Streams remembered as closed by the peer or normally (for the STREAM_CLOSED errors).
106const CLOSED_WINDOW: usize = 32;
107/// Peer stream ids tracked as used or skipped below the highest one (256 bytes).
108const SEEN_WINDOW: usize = 2048;
109const SHUTDOWN_PING: [u8; 8] = *b"simoomGA";
110const KEEPALIVE_PING: [u8; 8] = *b"simoomKA";
111/// At most one window-tuning PING per this many milliseconds.
112const BDP_INTERVAL_MS: u64 = 500;
113
114/// Our SETTINGS values for `role` (also the h2c `HTTP2-Settings` payload).
115fn local_settings(role: Role, c: &Config) -> Vec<(u16, u32)> {
116    let mut s = Vec::with_capacity(6);
117    if c.header_table_size != 4096 {
118        s.push((setting::HEADER_TABLE_SIZE, c.header_table_size));
119    }
120    if role == Role::Client {
121        s.push((setting::ENABLE_PUSH, 0));
122    } else {
123        s.push((setting::MAX_CONCURRENT_STREAMS, c.max_concurrent_streams));
124        if cfg!(feature = "connect-protocol") && c.enable_connect_protocol {
125            s.push((setting::ENABLE_CONNECT_PROTOCOL, 1));
126        }
127    }
128    if c.initial_window_size != DEFAULT_WINDOW {
129        s.push((setting::INITIAL_WINDOW_SIZE, c.initial_window_size));
130    }
131    if c.max_frame_size != frame::MIN_FRAME_SIZE {
132        s.push((setting::MAX_FRAME_SIZE, c.max_frame_size));
133    }
134    s.push((setting::MAX_HEADER_LIST_SIZE, c.max_header_list_size));
135    s
136}
137
138/// The `HTTP2-Settings` header value a client sends with an h2c upgrade request.
139pub fn http2_settings_header(config: &Config) -> String {
140    let mut p = Vec::new();
141    for (id, v) in local_settings(Role::Client, &sanitize(config.clone())) {
142        p.extend_from_slice(&id.to_be_bytes());
143        p.extend_from_slice(&v.to_be_bytes());
144    }
145    base64url_encode(&p)
146}
147
148fn sanitize(mut c: Config) -> Config {
149    c.max_frame_size = c.max_frame_size.clamp(frame::MIN_FRAME_SIZE, frame::MAX_FRAME_SIZE);
150    c.initial_window_size = c.initial_window_size.min(MAX_WINDOW);
151    c.connection_window_size = c.connection_window_size.clamp(DEFAULT_WINDOW, MAX_WINDOW);
152    c.max_stream_window = c.max_stream_window.clamp(c.initial_window_size, MAX_WINDOW);
153    c.max_connection_window = c.max_connection_window.clamp(c.connection_window_size, MAX_WINDOW);
154    c.max_send_buffer = c.max_send_buffer.max(1024);
155    c
156}
157
158/// One HTTP/2 connection, either end.
159pub struct Connection {
160    role: Role,
161    cfg: Config,
162    phase: Phase,
163    now: u64,
164    out: Vec<u8>,
165    out_pos: usize,
166    enc: Encoder,
167    dec: Decoder,
168    streams: StreamMap,
169    rx: Headers,
170    hb: Option<Block>,
171    hb_buf: Vec<u8>,
172    scratch: Vec<u8>,
173    // peer settings
174    peer_initial_window: u32,
175    peer_max_frame: usize,
176    peer_max_concurrent: u32,
177    /// The peer's SETTINGS_MAX_HEADER_LIST_SIZE (unlimited until it sends one).
178    peer_max_header_list: u32,
179    /// The peer (a server) sent SETTINGS_ENABLE_CONNECT_PROTOCOL = 1.
180    peer_connect_protocol: bool,
181    /// PING keepalive: when the peer last sent anything, and the deadline of an unanswered
182    /// keepalive PING.
183    last_recv: Option<u64>,
184    keepalive_deadline: Option<u64>,
185    // flow control
186    send_window: i64,
187    recv_window: i64,
188    conn_target: u32,
189    conn_unacked: u32,
190    stream_target: u32,
191    /// Window a new stream gets: `stream_target`, or 65535 when that is larger and our first
192    /// SETTINGS is not yet acknowledged.
193    stream_effective: u32,
194    first_settings_acked: bool,
195    settings_unacked: u32,
196    settings_deadline: Option<u64>,
197    // streams
198    next_stream_id: u32,
199    last_peer_stream: u32,
200    open_count: u32,
201    handlers: u32,
202    // shutdown
203    goaway_sent: Option<u32>,
204    graceful_deadline: Option<u64>,
205    goaway_recv: Option<u32>,
206    close_code: Option<ErrorCode>,
207    // window auto-tuning
208    bdp_sent: bool,
209    bdp_bytes: u64,
210    bdp_last: Option<u64>,
211    meter: Meter,
212    /// The last streams that closed normally or were reset by the peer: a frame on one of them
213    /// is the peer's error (STREAM_CLOSED). Every other forgotten stream id at or below the
214    /// highest seen counts as closed by our RST_STREAM, so late frames on it are ignored (RFC
215    /// 9113 §5.4.2), however long ago that was; this window only decides which error to send.
216    recent_closed: [u32; CLOSED_WINDOW],
217    closed_pos: usize,
218    /// Which of the peer's last `SEEN_WINDOW` stream ids (odd for a client) were used, so a
219    /// frame on an id that never was a stream stays a PROTOCOL_ERROR.
220    seen: [u64; SEEN_WINDOW / 64],
221    blocked: Vec<u32>,
222}
223
224impl std::fmt::Debug for Connection {
225    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
226        f.debug_struct("Connection")
227            .field("role", &self.role)
228            .field("phase", &self.phase)
229            .field("streams", &self.streams.len())
230            .field("handlers", &self.handlers)
231            .finish()
232    }
233}
234
235impl Connection {
236    fn new(role: Role, cfg: Config) -> Connection {
237        let cfg = sanitize(cfg);
238        let mut c = Connection {
239            role,
240            phase: Phase::Settings,
241            now: 0,
242            out: Vec::with_capacity(1024),
243            out_pos: 0,
244            enc: Encoder::new(cfg.encoder_table_size as usize),
245            dec: Decoder::new((cfg.header_table_size as usize).max(4096), cfg.max_header_list_size as usize),
246            streams: StreamMap::default(),
247            rx: Headers::default(),
248            hb: None,
249            hb_buf: Vec::new(),
250            scratch: Vec::new(),
251            peer_initial_window: DEFAULT_WINDOW,
252            peer_max_frame: frame::MIN_FRAME_SIZE as usize,
253            peer_max_concurrent: u32::MAX,
254            peer_max_header_list: u32::MAX,
255            peer_connect_protocol: false,
256            last_recv: None,
257            keepalive_deadline: None,
258            send_window: DEFAULT_WINDOW as i64,
259            recv_window: cfg.connection_window_size as i64,
260            conn_target: cfg.connection_window_size,
261            conn_unacked: 0,
262            stream_target: cfg.initial_window_size,
263            stream_effective: cfg.initial_window_size.max(DEFAULT_WINDOW),
264            first_settings_acked: false,
265            settings_unacked: 0,
266            settings_deadline: None,
267            next_stream_id: if role == Role::Client { 1 } else { 2 },
268            last_peer_stream: 0,
269            open_count: 0,
270            handlers: 0,
271            goaway_sent: None,
272            graceful_deadline: None,
273            goaway_recv: None,
274            close_code: None,
275            bdp_sent: false,
276            bdp_bytes: 0,
277            bdp_last: None,
278            meter: Meter::new(&cfg.budgets),
279            recent_closed: [0; CLOSED_WINDOW],
280            closed_pos: 0,
281            seen: [0; SEEN_WINDOW / 64],
282            blocked: Vec::new(),
283            cfg,
284        };
285        c.rx.allow_protocol = cfg!(feature = "connect-protocol") && role == Role::Server && c.cfg.enable_connect_protocol;
286        if role == Role::Client {
287            c.out.extend_from_slice(PREFACE);
288        }
289        frame::write_settings(&mut c.out, &local_settings(role, &c.cfg));
290        c.settings_unacked = 1;
291        if c.conn_target > DEFAULT_WINDOW {
292            frame::write_window_update(&mut c.out, 0, c.conn_target - DEFAULT_WINDOW);
293        }
294        c
295    }
296
297    /// A server connection. It expects the client preface; its own SETTINGS are already in
298    /// [`Connection::output`].
299    pub fn server(cfg: Config) -> Connection {
300        let mut c = Connection::new(Role::Server, cfg);
301        c.phase = Phase::Preface;
302        c
303    }
304
305    /// A client connection (h2c prior knowledge, or h2 after ALPN). The preface and SETTINGS are
306    /// already in [`Connection::output`], and requests can be sent at once.
307    pub fn client(cfg: Config) -> Connection {
308        Connection::new(Role::Client, cfg)
309    }
310
311    /// A server connection after an HTTP/1.1 `Upgrade: h2c` request (RFC 7540 §3.2) was
312    /// answered with `101 Switching Protocols`. `http2_settings` is the request's
313    /// `HTTP2-Settings` value. The request itself becomes stream 1, half-closed (remote) with
314    /// its handler running: answer it with [`Connection::send_response`] on stream 1.
315    pub fn server_upgrade(cfg: Config, http2_settings: &[u8]) -> Result<Connection, Error> {
316        let payload = base64url_decode(http2_settings).ok_or(Error::InvalidUpgradeSettings)?;
317        if payload.len() % 6 != 0 {
318            return Err(Error::InvalidUpgradeSettings);
319        }
320        let mut c = Connection::server(cfg);
321        if c.apply_settings(&payload).is_err() {
322            return Err(Error::InvalidUpgradeSettings);
323        }
324        let s = Stream {
325            send_window: c.peer_initial_window as i64,
326            recv_window: 0,
327            remote_end: true,
328            open: true,
329            handler: true,
330            ..Stream::default()
331        };
332        c.streams.insert(1, s);
333        c.open_count = 1;
334        c.handlers = 1;
335        c.mark_seen(1);
336        Ok(c)
337    }
338
339    /// A client connection after the server answered our HTTP/1.1 `Upgrade: h2c` request with
340    /// `101`. The upgrade request is stream 1, half-closed (local); its response arrives as
341    /// events for stream 1. `head` says whether that request was HEAD.
342    pub fn client_upgrade(cfg: Config, head: bool) -> Connection {
343        let mut c = Connection::client(cfg);
344        let s = Stream {
345            send_window: c.peer_initial_window as i64,
346            recv_window: c.stream_effective as i64,
347            local_end: true,
348            open: true,
349            final_sent: true,
350            head,
351            ..Stream::default()
352        };
353        c.streams.insert(1, s);
354        c.open_count = 1;
355        c.next_stream_id = 3;
356        c
357    }
358
359    // ------------------------------------------------------------------ output
360
361    /// Bytes waiting to be written to the transport.
362    pub fn output(&self) -> &[u8] {
363        &self.out[self.out_pos..]
364    }
365
366    /// Takes every byte of [`Connection::output`] as an owned buffer (no copy), leaving
367    /// `empty` (cleared) to collect the next output. Same as reading `output()` and calling
368    /// `advance_output` with its length.
369    pub fn take_output(&mut self, mut empty: Vec<u8>) -> Vec<u8> {
370        empty.clear();
371        let mut v = std::mem::replace(&mut self.out, empty);
372        if self.out_pos > 0 {
373            v.drain(..self.out_pos);
374            self.out_pos = 0;
375        }
376        v
377    }
378
379    /// Marks `n` bytes of [`Connection::output`] as written.
380    pub fn advance_output(&mut self, n: usize) {
381        self.out_pos = (self.out_pos + n).min(self.out.len());
382        if self.out_pos == self.out.len() {
383            self.out.clear();
384            self.out_pos = 0;
385            if self.out.capacity() > 4 * self.cfg.max_send_buffer {
386                self.out = Vec::with_capacity(16 * 1024);
387            }
388        } else if self.out_pos > 64 * 1024 && self.out_pos * 2 > self.out.len() {
389            self.out.drain(..self.out_pos);
390            self.out_pos = 0;
391        }
392    }
393
394    fn pending(&self) -> usize {
395        self.out.len() - self.out_pos
396    }
397
398    // ------------------------------------------------------------------ state
399
400    /// This end's role.
401    pub fn role(&self) -> Role {
402        self.role
403    }
404
405    /// True when the transport should be closed once [`Connection::output`] is flushed: after a
406    /// connection error, or after a GOAWAY (sent or received) once every stream is done.
407    pub fn wants_close(&self) -> bool {
408        // A server that received GOAWAY answers with its own graceful shutdown (see
409        // `on_goaway`) and closes once that is done, not at once: frames the peer sent after
410        // its GOAWAY (a PING, say) still get answered, and the socket is not closed under
411        // bytes still arriving, which would make the kernel reset the connection.
412        let goaway_done = self.goaway_sent.is_some() || (self.goaway_recv.is_some() && self.role == Role::Client);
413        self.phase == Phase::Closed || (goaway_done && self.streams.is_empty())
414    }
415
416    /// The error code of the GOAWAY we closed the connection with.
417    pub fn close_code(&self) -> Option<ErrorCode> {
418        self.close_code
419    }
420
421    /// Streams whose handler work is still running (server).
422    pub fn active_handlers(&self) -> u32 {
423        self.handlers
424    }
425
426    /// Streams open or half-closed.
427    pub fn open_streams(&self) -> u32 {
428        self.open_count
429    }
430
431    /// Streams the engine still tracks (open, or closed with work running).
432    pub fn tracked_streams(&self) -> usize {
433        self.streams.len()
434    }
435
436    /// The peer's SETTINGS_MAX_CONCURRENT_STREAMS.
437    pub fn peer_max_concurrent_streams(&self) -> u32 {
438        self.peer_max_concurrent
439    }
440
441    /// True when a client may open another stream now.
442    pub fn can_open_stream(&self) -> bool {
443        self.role == Role::Client
444            && self.phase != Phase::Closed
445            && self.goaway_recv.is_none()
446            && self.goaway_sent.is_none()
447            && self.open_count < self.peer_max_concurrent
448            && self.next_stream_id <= MAX_WINDOW
449    }
450
451    /// Bytes `stream` may send now: the smaller of its window, the connection window and the
452    /// room in the output buffer.
453    pub fn send_capacity(&self, stream: u32) -> usize {
454        match self.streams.get(&stream) {
455            Some(s) if !s.reset && !s.local_end => {
456                let room = self.cfg.max_send_buffer.saturating_sub(self.pending()) as i64;
457                s.send_window.min(self.send_window).min(room).max(0) as usize
458            }
459            _ => 0,
460        }
461    }
462
463    /// The connection's current receive targets (connection, per stream), after auto-tuning.
464    pub fn receive_windows(&self) -> (u32, u32) {
465        (self.conn_target, self.stream_target)
466    }
467
468    /// The next deadline (settings acknowledgement, graceful shutdown) for
469    /// [`Connection::handle_timeout`].
470    pub fn poll_timeout(&self) -> Option<u64> {
471        let t = match (self.settings_deadline, self.graceful_deadline) {
472            (Some(a), Some(b)) => Some(a.min(b)),
473            (a, b) => a.or(b),
474        };
475        match (t, self.keepalive_due()) {
476            (Some(a), Some(b)) => Some(a.min(b)),
477            (a, b) => a.or(b),
478        }
479    }
480
481    /// When the keepalive needs attention: the PING deadline, or the time to send one.
482    fn keepalive_due(&self) -> Option<u64> {
483        if !cfg!(feature = "keepalive") {
484            return None;
485        }
486        let interval = self.cfg.keepalive_interval_ms?;
487        if self.phase == Phase::Closed {
488            return None;
489        }
490        self.keepalive_deadline.or_else(|| self.last_recv.map(|t| t.saturating_add(interval)))
491    }
492
493    /// Sends a keepalive PING when the peer has been quiet for the interval, or closes the
494    /// connection when nothing came back in time.
495    fn keepalive(&mut self, now: u64, sink: &mut dyn FnMut(Event<'_>)) {
496        if !cfg!(feature = "keepalive") {
497            return;
498        }
499        let Some(interval) = self.cfg.keepalive_interval_ms else { return };
500        if self.phase == Phase::Closed {
501            return;
502        }
503        if let Some(d) = self.keepalive_deadline {
504            if now >= d {
505                self.conn_error(ErrorCode::NO_ERROR, "PING keepalive timeout", sink);
506            }
507            return;
508        }
509        let last = *self.last_recv.get_or_insert(now);
510        if now >= last.saturating_add(interval) {
511            frame::write_ping(&mut self.out, KEEPALIVE_PING, false);
512            self.keepalive_deadline = Some(now.saturating_add(self.cfg.keepalive_timeout_ms));
513        }
514    }
515
516    /// Fires due timers.
517    pub fn handle_timeout(&mut self, now: u64, sink: &mut dyn FnMut(Event<'_>)) {
518        self.now = now;
519        if self.phase == Phase::Closed {
520            return;
521        }
522        if self.settings_deadline.is_some_and(|d| now >= d) {
523            self.conn_error(ErrorCode::SETTINGS_TIMEOUT, "SETTINGS not acknowledged", sink);
524            return;
525        }
526        if self.graceful_deadline.is_some_and(|d| now >= d) {
527            self.final_goaway();
528        }
529        self.keepalive(now, sink);
530    }
531
532    // ------------------------------------------------------------------ input
533
534    /// Processes received bytes at time `now` (monotonic milliseconds from any origin).
535    /// Returns how many bytes were consumed; the caller keeps the rest and passes it again with
536    /// more data. A buffer of `max_frame_size + 9` bytes always makes progress. Input processing
537    /// pauses (returns early) while more than twice `max_send_buffer` of output is waiting, so a
538    /// peer that does not read cannot make us queue unbounded replies. After the connection is
539    /// closed all input is consumed and ignored.
540    pub fn recv(&mut self, input: &[u8], now: u64, sink: &mut dyn FnMut(Event<'_>)) -> usize {
541        self.now = now;
542        if cfg!(feature = "keepalive") && !input.is_empty() {
543            // anything from the peer shows it is alive
544            self.last_recv = Some(now);
545            self.keepalive_deadline = None;
546        }
547        if self.settings_unacked > 0 && self.settings_deadline.is_none() {
548            self.settings_deadline = Some(now + self.cfg.settings_timeout_ms);
549        }
550        let mut pos = 0;
551        while self.phase != Phase::Closed {
552            if self.pending() > 2 * self.cfg.max_send_buffer {
553                break;
554            }
555            let rest = &input[pos..];
556            if self.phase == Phase::Preface {
557                let n = rest.len().min(PREFACE.len());
558                if rest[..n] != PREFACE[..n] {
559                    self.conn_error(ErrorCode::PROTOCOL_ERROR, "invalid connection preface", sink);
560                    break;
561                }
562                if n < PREFACE.len() {
563                    break;
564                }
565                pos += n;
566                self.phase = Phase::Settings;
567                continue;
568            }
569            if rest.len() < HEADER_LEN {
570                break;
571            }
572            let h = FrameHeader::parse(rest);
573            if h.len > self.cfg.max_frame_size as usize {
574                self.conn_error(ErrorCode::FRAME_SIZE_ERROR, "frame larger than SETTINGS_MAX_FRAME_SIZE", sink);
575                break;
576            }
577            if rest.len() - HEADER_LEN < h.len {
578                break;
579            }
580            pos += HEADER_LEN + h.len;
581            if let Err((code, msg)) = self.on_frame(h, &rest[HEADER_LEN..HEADER_LEN + h.len], sink) {
582                self.conn_error(code, msg, sink);
583            }
584        }
585        if self.phase == Phase::Closed {
586            input.len()
587        } else {
588            pos
589        }
590    }
591
592    fn conn_error(&mut self, code: ErrorCode, msg: &'static str, sink: &mut dyn FnMut(Event<'_>)) {
593        if self.phase == Phase::Closed {
594            return;
595        }
596        frame::write_goaway(&mut self.out, self.last_peer_stream, code, msg.as_bytes());
597        self.phase = Phase::Closed;
598        self.close_code = Some(code);
599        self.hb = None;
600        self.settings_deadline = None;
601        self.graceful_deadline = None;
602        sink(Event::Closed { code });
603    }
604
605    fn hit(&mut self, b: Budget) -> bool {
606        self.meter.hit(b, self.now)
607    }
608
609    fn is_idle(&self, id: u32) -> bool {
610        let ours = (id & 1 == 1) == (self.role == Role::Client);
611        if ours {
612            id >= self.next_stream_id
613        } else {
614            id > self.last_peer_stream
615        }
616    }
617
618    fn recently_closed(&self, id: u32) -> bool {
619        self.recent_closed.contains(&id)
620    }
621
622    /// An untracked, non-idle stream id that did not close normally: we reset or refused it.
623    fn refused_or_reset(&self, id: u32) -> bool {
624        !self.is_idle(id) && !self.streams.contains_key(&id) && !self.recently_closed(id) && self.existed(id)
625    }
626
627    /// Whether a non-idle stream id was ever used: always for ours (we open them in order);
628    /// for the peer's, the bit in `seen` while the id is within the window below the highest
629    /// one, and yes beyond it (an old id there is treated as reset by us: ignored).
630    fn existed(&self, id: u32) -> bool {
631        let ours = (id & 1 == 1) == (self.role == Role::Client);
632        if ours || id > self.last_peer_stream {
633            return ours;
634        }
635        let back = (self.last_peer_stream - id) / 2;
636        if back as usize >= SEEN_WINDOW {
637            return true;
638        }
639        let slot = (id / 2) as usize % SEEN_WINDOW;
640        self.seen[slot / 64] & (1 << (slot % 64)) != 0
641    }
642
643    /// The peer opened (or tried to open) stream `id`, its highest so far: ids skipped since
644    /// the previous one never existed (they are implicitly closed, RFC 9113 §5.1.1).
645    fn mark_seen(&mut self, id: u32) {
646        let prev = self.last_peer_stream;
647        let gap = if prev == 0 { SEEN_WINDOW as u32 } else { (id - prev) / 2 };
648        if gap as usize >= SEEN_WINDOW {
649            self.seen = [0; SEEN_WINDOW / 64];
650        } else {
651            let mut k = prev + 2;
652            while k < id {
653                let slot = (k / 2) as usize % SEEN_WINDOW;
654                self.seen[slot / 64] &= !(1 << (slot % 64));
655                k += 2;
656            }
657        }
658        let slot = (id / 2) as usize % SEEN_WINDOW;
659        self.seen[slot / 64] |= 1 << (slot % 64);
660        self.last_peer_stream = id;
661    }
662
663    fn on_frame(&mut self, h: FrameHeader, p: &[u8], sink: &mut dyn FnMut(Event<'_>)) -> R {
664        if self.phase == Phase::Settings {
665            if h.kind != kind::SETTINGS || h.has(flag::ACK) {
666                return perr("the first frame must be SETTINGS");
667            }
668            self.phase = Phase::Open;
669        }
670        if let Some(b) = &self.hb {
671            if h.kind != kind::CONTINUATION || h.stream != b.stream {
672                return perr("expected CONTINUATION");
673            }
674        }
675        match h.kind {
676            kind::DATA => self.on_data(h, p, sink),
677            kind::HEADERS => self.on_headers(h, p, sink),
678            kind::PRIORITY => self.on_priority(h, p, sink),
679            kind::RST_STREAM => self.on_rst(h, p, sink),
680            kind::SETTINGS => self.on_settings(h, p, sink),
681            kind::PUSH_PROMISE => perr("PUSH_PROMISE is disabled"),
682            kind::PING => self.on_ping(h, p, sink),
683            kind::GOAWAY => self.on_goaway(h, p, sink),
684            kind::WINDOW_UPDATE => self.on_window_update(h, p, sink),
685            kind::CONTINUATION => self.on_continuation(h, p, sink),
686            _ => Ok(()), // unknown frame types are ignored (RFC 9113 §4.1)
687        }
688    }
689
690    fn unpad<'a>(h: &FrameHeader, p: &'a [u8]) -> Result<&'a [u8], (ErrorCode, &'static str)> {
691        if !h.has(flag::PADDED) {
692            return Ok(p);
693        }
694        let Some(&pad) = p.first() else {
695            return Err((ErrorCode::FRAME_SIZE_ERROR, "padded frame without pad length"));
696        };
697        if pad as usize >= p.len() {
698            return Err((ErrorCode::PROTOCOL_ERROR, "padding longer than the payload"));
699        }
700        Ok(&p[1..p.len() - pad as usize])
701    }
702
703    // ------------------------------------------------------------------ DATA
704
705    fn on_data(&mut self, h: FrameHeader, p: &[u8], sink: &mut dyn FnMut(Event<'_>)) -> R {
706        let id = h.stream;
707        if id == 0 {
708            return perr("DATA on stream 0");
709        }
710        let data = Self::unpad(&h, p)?;
711        let flen = p.len() as u32;
712        if flen as i64 > self.recv_window {
713            return Err((ErrorCode::FLOW_CONTROL_ERROR, "connection receive window exceeded"));
714        }
715        self.recv_window -= flen as i64;
716        let end = h.has(flag::END_STREAM);
717        if data.is_empty() && !end && self.hit(Budget::Empty) {
718            return calm("too many empty frames");
719        }
720        let idle = self.is_idle(id);
721        let client = self.role == Role::Client;
722        enum Next {
723            Closed,
724            Ignore,
725            StreamError(ErrorCode),
726            Deliver,
727        }
728        let next = match self.streams.get_mut(&id) {
729            None if idle => return perr("DATA on an idle stream"),
730            None => Next::Closed,
731            Some(s) if s.peer_reset || (s.remote_end && !s.reset) => Next::StreamError(ErrorCode::STREAM_CLOSED),
732            Some(s) if s.reset => Next::Ignore,
733            Some(s) if client && !s.final_recv => Next::StreamError(ErrorCode::PROTOCOL_ERROR),
734            Some(s) if flen as i64 > s.recv_window => Next::StreamError(ErrorCode::FLOW_CONTROL_ERROR),
735            Some(s) => {
736                s.recv_window -= flen as i64;
737                s.received += data.len() as u64;
738                let bad_length = match s.content_length {
739                    Some(cl) if !s.head => s.received > cl || (end && s.received != cl),
740                    _ => false,
741                };
742                if bad_length {
743                    Next::StreamError(ErrorCode::PROTOCOL_ERROR)
744                } else {
745                    s.unreleased += data.len() as u32;
746                    if end {
747                        s.remote_end = true;
748                    }
749                    Next::Deliver
750                }
751            }
752        };
753        match next {
754            Next::Closed => {
755                self.release_conn(flen);
756                if self.recently_closed(id) || !self.existed(id) {
757                    // a stream that closed normally (or the peer reset), or never existed: the
758                    // peer's error; any other forgotten stream was reset by us and late DATA is
759                    // ignored
760                    frame::write_rst(&mut self.out, id, ErrorCode::STREAM_CLOSED);
761                    if self.hit(Budget::RstSent) {
762                        return calm("too many stream errors");
763                    }
764                }
765            }
766            Next::Ignore => self.release_conn(flen),
767            Next::StreamError(code) => {
768                self.release_conn(flen);
769                self.stream_error(id, code, sink)?;
770            }
771            Next::Deliver => {
772                let pad = flen - data.len() as u32;
773                if pad > 0 {
774                    self.credit(id, pad);
775                }
776                sink(Event::Data { stream: id, data, end_stream: end });
777                if !data.is_empty() {
778                    self.bdp_on_data(data.len());
779                }
780                if end {
781                    self.update(id);
782                }
783            }
784        }
785        Ok(())
786    }
787
788    /// Returns `n` bytes of connection credit, announcing it once half the window is unused.
789    fn release_conn(&mut self, n: u32) {
790        if n == 0 || self.phase == Phase::Closed {
791            return;
792        }
793        self.conn_unacked += n;
794        if self.conn_unacked >= self.conn_target / 2 {
795            frame::write_window_update(&mut self.out, 0, self.conn_unacked);
796            self.recv_window += self.conn_unacked as i64;
797            self.conn_unacked = 0;
798        }
799    }
800
801    /// Returns `n` bytes of credit on a stream and the connection.
802    fn credit(&mut self, id: u32, n: u32) {
803        if let Some(s) = self.streams.get_mut(&id) {
804            if !s.reset && !s.remote_end && self.phase != Phase::Closed {
805                s.unacked += n;
806                if s.unacked >= self.stream_target / 2 {
807                    frame::write_window_update(&mut self.out, id, s.unacked);
808                    s.recv_window += s.unacked as i64;
809                    s.unacked = 0;
810                }
811            }
812        }
813        self.release_conn(n);
814    }
815
816    /// Tells the engine the application consumed `n` bytes of DATA on `stream`, so the peer may
817    /// send more. Releasing more than was delivered is ignored.
818    pub fn release(&mut self, stream: u32, n: usize) {
819        let Some(s) = self.streams.get_mut(&stream) else { return };
820        let n = n.min(s.unreleased as usize) as u32;
821        if n == 0 {
822            return;
823        }
824        s.unreleased -= n;
825        self.credit(stream, n);
826    }
827
828    fn bdp_on_data(&mut self, n: usize) {
829        if !self.cfg.window_autotune || self.phase == Phase::Closed {
830            return;
831        }
832        if self.bdp_sent {
833            self.bdp_bytes += n as u64;
834            return;
835        }
836        if self.conn_target >= self.cfg.max_connection_window && self.stream_target >= self.cfg.max_stream_window {
837            return;
838        }
839        if self.bdp_last.is_some_and(|t| self.now < t + BDP_INTERVAL_MS) {
840            return;
841        }
842        frame::write_ping(&mut self.out, BDP_PING, false);
843        self.bdp_sent = true;
844        self.bdp_bytes = n as u64;
845        self.bdp_last = Some(self.now);
846    }
847
848    /// A window-tuning PING came back: `bdp_bytes` arrived in about one round trip. Window
849    /// updates go out once half a window is released, so a flow held back by a window delivers
850    /// between half and all of it per round trip; at half or more the window doubles (towards
851    /// twice the sample), up to the configured cap.
852    fn bdp_ack(&mut self) {
853        self.bdp_sent = false;
854        let sample = self.bdp_bytes.min(MAX_WINDOW as u64) as u32;
855        let grow = |target: u32, max: u32| -> u32 {
856            if sample as u64 * 2 >= target as u64 {
857                (sample.saturating_mul(2)).max(target.saturating_mul(2)).min(max).max(target)
858            } else {
859                target
860            }
861        };
862        let conn = grow(self.conn_target, self.cfg.max_connection_window);
863        if conn > self.conn_target {
864            let delta = conn - self.conn_target;
865            self.conn_target = conn;
866            self.recv_window += delta as i64;
867            frame::write_window_update(&mut self.out, 0, delta);
868        }
869        let stream = grow(self.stream_target, self.cfg.max_stream_window);
870        if stream > self.stream_target {
871            let delta = (stream - self.stream_target) as i64;
872            self.stream_target = stream;
873            self.stream_effective = self.stream_effective.max(stream);
874            for s in self.streams.values_mut() {
875                if !s.remote_end && !s.reset {
876                    s.recv_window += delta;
877                }
878            }
879            frame::write_settings(&mut self.out, &[(setting::INITIAL_WINDOW_SIZE, stream)]);
880            self.settings_unacked += 1;
881            if self.settings_deadline.is_none() {
882                self.settings_deadline = Some(self.now + self.cfg.settings_timeout_ms);
883            }
884        }
885    }
886
887    // ------------------------------------------------------------------ resets
888
889    /// Sends RST_STREAM. `caused` marks resets the peer provoked; they count against the
890    /// rst_sent budget.
891    fn send_rst(&mut self, id: u32, code: ErrorCode, caused: bool) -> R {
892        frame::write_rst(&mut self.out, id, code);
893        if caused && self.hit(Budget::RstSent) {
894            return calm("too many stream errors");
895        }
896        Ok(())
897    }
898
899    /// Marks a stream reset and returns its unreleased connection credit. Reports whether the
900    /// application knows the stream.
901    fn mark_reset(&mut self, id: u32) -> bool {
902        let client = self.role == Role::Client;
903        let (credit, known) = match self.streams.get_mut(&id) {
904            Some(s) if !s.reset => {
905                s.reset = true;
906                let c = s.unreleased;
907                s.unreleased = 0;
908                (c, s.handler || client)
909            }
910            _ => return false,
911        };
912        self.release_conn(credit);
913        known
914    }
915
916    /// A stream error (RFC 9113 §5.4.2) the peer caused.
917    fn stream_error(&mut self, id: u32, code: ErrorCode, sink: &mut dyn FnMut(Event<'_>)) -> R {
918        if self.mark_reset(id) {
919            sink(Event::Reset { stream: id, code, remote: false });
920        }
921        let r = self.send_rst(id, code, true);
922        self.update(id);
923        r
924    }
925
926    /// Updates the open count and forgets the stream once it is closed and its work finished.
927    fn update(&mut self, id: u32) {
928        let Some(s) = self.streams.get_mut(&id) else { return };
929        if !s.closed() {
930            return;
931        }
932        if s.open {
933            s.open = false;
934            self.open_count -= 1;
935        }
936        if !s.handler {
937            let credit = s.unreleased;
938            // a stream we reset is not remembered: late frames on it are ignored
939            let reset_by_us = s.reset && !s.peer_reset;
940            self.streams.remove(&id);
941            if !reset_by_us {
942                self.recent_closed[self.closed_pos] = id;
943                self.closed_pos = (self.closed_pos + 1) % self.recent_closed.len();
944            }
945            self.release_conn(credit);
946        }
947    }
948
949    // ------------------------------------------------------------------ HEADERS
950
951    fn header_cap(&self) -> usize {
952        self.cfg.max_header_list_size as usize
953    }
954
955    /// Encoded header block bytes buffered before the connection is closed: twice the list
956    /// limit. A block between the two is still decoded (the decoder enforces the list limit,
957    /// keeps the HPACK state in sync and the request gets 431, plan §7.1); only a block that
958    /// cannot be a sane request is a connection error.
959    fn block_cap(&self) -> usize {
960        self.header_cap().saturating_mul(2)
961    }
962
963    fn on_headers(&mut self, h: FrameHeader, p: &[u8], sink: &mut dyn FnMut(Event<'_>)) -> R {
964        let id = h.stream;
965        if id == 0 {
966            return perr("HEADERS on stream 0");
967        }
968        let mut frag = Self::unpad(&h, p)?;
969        let mut self_dep = false;
970        if h.has(flag::PRIORITY) {
971            if frag.len() < 5 {
972                return Err((ErrorCode::FRAME_SIZE_ERROR, "HEADERS too short for its priority fields"));
973            }
974            self_dep = be32(frag) & 0x7fff_ffff == id;
975            frag = &frag[5..];
976        }
977        let end = h.has(flag::END_STREAM);
978        if h.has(flag::END_HEADERS) {
979            return self.on_block(id, end, self_dep, frag, sink);
980        }
981        if frag.is_empty() && self.hit(Budget::Empty) {
982            return calm("too many empty frames");
983        }
984        if frag.len() > self.block_cap() {
985            return calm("header block too large");
986        }
987        self.hb = Some(Block { stream: id, end_stream: end, self_dep, frames: 1 });
988        self.hb_buf.clear();
989        self.hb_buf.extend_from_slice(frag);
990        Ok(())
991    }
992
993    fn on_continuation(&mut self, h: FrameHeader, p: &[u8], sink: &mut dyn FnMut(Event<'_>)) -> R {
994        let Some(mut b) = self.hb.take() else {
995            return perr("CONTINUATION without HEADERS");
996        };
997        b.frames += 1;
998        if b.frames > self.cfg.max_continuation_frames + 1 {
999            return calm("too many CONTINUATION frames");
1000        }
1001        if p.is_empty() && !h.has(flag::END_HEADERS) && self.hit(Budget::Empty) {
1002            return calm("too many empty frames");
1003        }
1004        if self.hb_buf.len() + p.len() > self.block_cap() {
1005            return calm("header block too large");
1006        }
1007        self.hb_buf.extend_from_slice(p);
1008        if !h.has(flag::END_HEADERS) {
1009            self.hb = Some(b);
1010            return Ok(());
1011        }
1012        let buf = std::mem::take(&mut self.hb_buf);
1013        let r = self.on_block(b.stream, b.end_stream, b.self_dep, &buf, sink);
1014        self.hb_buf = buf;
1015        r
1016    }
1017
1018    /// A complete header block on stream `id`.
1019    fn on_block(&mut self, id: u32, end: bool, self_dep: bool, block: &[u8], sink: &mut dyn FnMut(Event<'_>)) -> R {
1020        if block.len() > self.block_cap() {
1021            return calm("header block too large");
1022        }
1023        let server = self.role == Role::Server;
1024        let existing = self.streams.get(&id).map(|s| (s.reset && !s.peer_reset, s.remote_end || s.peer_reset, s.final_recv));
1025        let kind = match existing {
1026            Some((_, _, final_recv)) if server || final_recv => HeadKind::Trailers,
1027            Some(_) => HeadKind::Response,
1028            None => HeadKind::Request,
1029        };
1030        // always decode: the HPACK context must stay in step even for blocks we refuse
1031        self.rx.reset(kind);
1032        let rx = &mut self.rx;
1033        let too_large = match self.dec.decode(block, &mut |n: &[u8], v: &[u8]| rx.push(n, v)) {
1034            Ok(()) => false,
1035            Err(HpackError::HeaderListTooLarge) => true,
1036            Err(_) => return Err((ErrorCode::COMPRESSION_ERROR, "HPACK decoding failed")),
1037        };
1038        self.rx.finish();
1039        let peer_initiated = (id & 1 == 1) == server;
1040        if !peer_initiated && server {
1041            return perr("client stream ids must be odd");
1042        }
1043        if peer_initiated && !server {
1044            return perr("server-initiated streams are not allowed (push is disabled)");
1045        }
1046        match existing {
1047            Some((true, _, _)) => Ok(()),
1048            Some((_, true, _)) => self.stream_error(id, ErrorCode::STREAM_CLOSED, sink),
1049            Some(_) if self_dep || too_large || self.rx.malformed().is_some() => {
1050                self.stream_error(id, ErrorCode::PROTOCOL_ERROR, sink)
1051            }
1052            Some(_) if kind == HeadKind::Trailers => {
1053                let s = self.streams.get_mut(&id).expect("stream exists");
1054                let bad_length = s.content_length.is_some_and(|cl| !s.head && cl != s.received);
1055                if !end || bad_length {
1056                    return self.stream_error(id, ErrorCode::PROTOCOL_ERROR, sink);
1057                }
1058                s.remote_end = true;
1059                sink(Event::Trailers { stream: id, trailers: &self.rx });
1060                self.update(id);
1061                Ok(())
1062            }
1063            Some(_) => {
1064                // client: a response
1065                let status = self.rx.status().unwrap_or(0);
1066                let s = self.streams.get_mut(&id).expect("stream exists");
1067                if status < 200 {
1068                    if end {
1069                        return self.stream_error(id, ErrorCode::PROTOCOL_ERROR, sink);
1070                    }
1071                    sink(Event::Headers { stream: id, headers: &self.rx, end_stream: false });
1072                    return Ok(());
1073                }
1074                s.final_recv = true;
1075                s.content_length = self.rx.content_length();
1076                if end && !s.head && s.content_length.is_some_and(|cl| cl != 0) {
1077                    return self.stream_error(id, ErrorCode::PROTOCOL_ERROR, sink);
1078                }
1079                s.remote_end = end;
1080                sink(Event::Headers { stream: id, headers: &self.rx, end_stream: end });
1081                if end {
1082                    self.update(id);
1083                }
1084                Ok(())
1085            }
1086            None if server => {
1087                if id <= self.last_peer_stream {
1088                    if self.recently_closed(id) {
1089                        return Err((ErrorCode::STREAM_CLOSED, "HEADERS on a closed stream"));
1090                    }
1091                    if self.refused_or_reset(id) {
1092                        // a stream we refused or reset, however long ago: a late header block
1093                        // (trailers, say) is ignored; it was decoded above for the HPACK state
1094                        return Ok(());
1095                    }
1096                    return perr("stream id lower than a previous one");
1097                }
1098                self.mark_seen(id);
1099                self.new_request(id, end, self_dep, too_large, sink)
1100            }
1101            None => {
1102                if self.is_idle(id) {
1103                    return perr("HEADERS on an idle stream");
1104                }
1105                Ok(())
1106            }
1107        }
1108    }
1109
1110    fn new_request(&mut self, id: u32, end: bool, self_dep: bool, too_large: bool, sink: &mut dyn FnMut(Event<'_>)) -> R {
1111        if self.goaway_sent.is_some_and(|last| id > last) {
1112            return Ok(()); // after our final GOAWAY: ignored (RFC 9113 §6.8)
1113        }
1114        if self_dep {
1115            return self.send_rst(id, ErrorCode::PROTOCOL_ERROR, true);
1116        }
1117        if too_large {
1118            // RFC 9113 §8.2.2 / RFC 6585: answer 431 without running a handler
1119            self.write_block(id, true, |enc, out| enc.field(b":status", b"431", out));
1120            if !end {
1121                return self.send_rst(id, ErrorCode::NO_ERROR, true);
1122            }
1123            if self.hit(Budget::RstSent) {
1124                return calm("too many refused requests");
1125            }
1126            return Ok(());
1127        }
1128        let max = self.cfg.max_concurrent_streams;
1129        if self.open_count >= max || self.handlers >= max {
1130            return self.send_rst(id, ErrorCode::REFUSED_STREAM, true);
1131        }
1132        if self.rx.malformed().is_some() || (end && self.rx.content_length().is_some_and(|cl| cl != 0)) {
1133            return self.send_rst(id, ErrorCode::PROTOCOL_ERROR, true);
1134        }
1135        let s = Stream {
1136            send_window: self.peer_initial_window as i64,
1137            recv_window: self.stream_effective as i64,
1138            remote_end: end,
1139            open: true,
1140            handler: true,
1141            content_length: self.rx.content_length(),
1142            head: self.rx.method() == Some(b"HEAD"),
1143            ..Stream::default()
1144        };
1145        self.streams.insert(id, s);
1146        self.open_count += 1;
1147        self.handlers += 1;
1148        sink(Event::Headers { stream: id, headers: &self.rx, end_stream: end });
1149        Ok(())
1150    }
1151
1152    // ------------------------------------------------------------------ control frames
1153
1154    fn on_priority(&mut self, h: FrameHeader, p: &[u8], sink: &mut dyn FnMut(Event<'_>)) -> R {
1155        if h.stream == 0 {
1156            return perr("PRIORITY on stream 0");
1157        }
1158        if self.hit(Budget::Priority) {
1159            return calm("too many PRIORITY frames");
1160        }
1161        if p.len() != 5 {
1162            return self.stream_error(h.stream, ErrorCode::FRAME_SIZE_ERROR, sink);
1163        }
1164        if be32(p) & 0x7fff_ffff == h.stream {
1165            return self.stream_error(h.stream, ErrorCode::PROTOCOL_ERROR, sink);
1166        }
1167        Ok(()) // priorities are not used (RFC 9113 §5.3.2)
1168    }
1169
1170    fn on_rst(&mut self, h: FrameHeader, p: &[u8], sink: &mut dyn FnMut(Event<'_>)) -> R {
1171        if h.stream == 0 {
1172            return perr("RST_STREAM on stream 0");
1173        }
1174        if p.len() != 4 {
1175            return Err((ErrorCode::FRAME_SIZE_ERROR, "RST_STREAM length"));
1176        }
1177        if self.is_idle(h.stream) {
1178            return perr("RST_STREAM on an idle stream");
1179        }
1180        if self.hit(Budget::RstReceived) {
1181            return calm("too many RST_STREAM frames");
1182        }
1183        if self.mark_reset(h.stream) {
1184            sink(Event::Reset { stream: h.stream, code: ErrorCode(be32(p)), remote: true });
1185        }
1186        if let Some(s) = self.streams.get_mut(&h.stream) {
1187            s.peer_reset = true;
1188        }
1189        self.update(h.stream);
1190        Ok(())
1191    }
1192
1193    /// Applies a SETTINGS payload from the peer.
1194    fn apply_settings(&mut self, p: &[u8]) -> R {
1195        for c in p.chunks_exact(6) {
1196            let id = u16::from_be_bytes([c[0], c[1]]);
1197            let v = be32(&c[2..]);
1198            match id {
1199                setting::HEADER_TABLE_SIZE => self.enc.set_peer_max_table_size(v as usize),
1200                setting::ENABLE_PUSH => {
1201                    if v > 1 || (v == 1 && self.role == Role::Client) {
1202                        return perr("invalid SETTINGS_ENABLE_PUSH");
1203                    }
1204                }
1205                setting::MAX_CONCURRENT_STREAMS => self.peer_max_concurrent = v,
1206                setting::INITIAL_WINDOW_SIZE => {
1207                    if v > MAX_WINDOW {
1208                        return Err((ErrorCode::FLOW_CONTROL_ERROR, "SETTINGS_INITIAL_WINDOW_SIZE too large"));
1209                    }
1210                    let delta = v as i64 - self.peer_initial_window as i64;
1211                    self.peer_initial_window = v;
1212                    let mut overflow = false;
1213                    for s in self.streams.values_mut() {
1214                        s.send_window += delta;
1215                        overflow |= s.send_window > MAX_WINDOW as i64;
1216                    }
1217                    if overflow {
1218                        return Err((ErrorCode::FLOW_CONTROL_ERROR, "stream window overflow"));
1219                    }
1220                }
1221                setting::MAX_FRAME_SIZE => {
1222                    if !(frame::MIN_FRAME_SIZE..=frame::MAX_FRAME_SIZE).contains(&v) {
1223                        return perr("invalid SETTINGS_MAX_FRAME_SIZE");
1224                    }
1225                    self.peer_max_frame = v as usize;
1226                }
1227                setting::MAX_HEADER_LIST_SIZE => self.peer_max_header_list = v,
1228                setting::ENABLE_CONNECT_PROTOCOL if cfg!(feature = "connect-protocol") => {
1229                    // RFC 8441 §3: 0 or 1, and never 0 after 1.
1230                    if v > 1 || (v == 0 && self.peer_connect_protocol) {
1231                        return perr("invalid SETTINGS_ENABLE_CONNECT_PROTOCOL");
1232                    }
1233                    self.peer_connect_protocol = v == 1;
1234                }
1235                _ => {} // unknown settings are ignored
1236            }
1237        }
1238        Ok(())
1239    }
1240
1241    fn on_settings(&mut self, h: FrameHeader, p: &[u8], sink: &mut dyn FnMut(Event<'_>)) -> R {
1242        if h.stream != 0 {
1243            return perr("SETTINGS on a stream");
1244        }
1245        if h.has(flag::ACK) {
1246            if !p.is_empty() {
1247                return Err((ErrorCode::FRAME_SIZE_ERROR, "SETTINGS ACK with a payload"));
1248            }
1249            if self.settings_unacked > 0 {
1250                self.settings_unacked -= 1;
1251                self.settings_deadline = if self.settings_unacked > 0 { Some(self.now + self.cfg.settings_timeout_ms) } else { None };
1252                if !self.first_settings_acked {
1253                    self.first_settings_acked = true;
1254                    self.dec.set_max_allowed(self.cfg.header_table_size as usize);
1255                    if self.stream_effective > self.stream_target {
1256                        let delta = self.stream_effective as i64 - self.stream_target as i64;
1257                        self.stream_effective = self.stream_target;
1258                        for s in self.streams.values_mut() {
1259                            s.recv_window -= delta;
1260                        }
1261                    }
1262                }
1263            }
1264            return Ok(());
1265        }
1266        if p.len() % 6 != 0 {
1267            return Err((ErrorCode::FRAME_SIZE_ERROR, "SETTINGS length"));
1268        }
1269        if self.hit(Budget::Settings) {
1270            return calm("too many SETTINGS frames");
1271        }
1272        self.apply_settings(p)?;
1273        frame::write_settings_ack(&mut self.out);
1274        sink(Event::Settings);
1275        Ok(())
1276    }
1277
1278    fn on_ping(&mut self, h: FrameHeader, p: &[u8], sink: &mut dyn FnMut(Event<'_>)) -> R {
1279        if h.stream != 0 {
1280            return perr("PING on a stream");
1281        }
1282        if p.len() != 8 {
1283            return Err((ErrorCode::FRAME_SIZE_ERROR, "PING length"));
1284        }
1285        let mut data = [0u8; 8];
1286        data.copy_from_slice(p);
1287        if h.has(flag::ACK) {
1288            if data == BDP_PING && self.bdp_sent {
1289                self.bdp_ack();
1290            } else if data == SHUTDOWN_PING && self.graceful_deadline.is_some() {
1291                self.final_goaway();
1292            } else if cfg!(feature = "keepalive") && data == KEEPALIVE_PING && self.cfg.keepalive_interval_ms.is_some() {
1293                self.keepalive_deadline = None;
1294            } else {
1295                if self.hit(Budget::Ping) {
1296                    return calm("too many PING frames");
1297                }
1298                sink(Event::Pong { data });
1299            }
1300            return Ok(());
1301        }
1302        if self.hit(Budget::Ping) {
1303            return calm("too many PING frames");
1304        }
1305        frame::write_ping(&mut self.out, data, true);
1306        Ok(())
1307    }
1308
1309    fn on_goaway(&mut self, h: FrameHeader, p: &[u8], sink: &mut dyn FnMut(Event<'_>)) -> R {
1310        if h.stream != 0 {
1311            return perr("GOAWAY on a stream");
1312        }
1313        if p.len() < 8 {
1314            return Err((ErrorCode::FRAME_SIZE_ERROR, "GOAWAY length"));
1315        }
1316        let last = be32(p) & 0x7fff_ffff;
1317        let code = ErrorCode(be32(&p[4..]));
1318        self.goaway_recv = Some(self.goaway_recv.map_or(last, |l| l.min(last)));
1319        sink(Event::GoAway { last_stream: last, code, debug: &p[8..] });
1320        // streams we opened above `last` were not processed: the application may retry them
1321        let client = self.role == Role::Client;
1322        let refused: Vec<u32> = self
1323            .streams
1324            .iter()
1325            .filter(|(&id, s)| (id & 1 == 1) == client && id > last && !s.reset)
1326            .map(|(&id, _)| id)
1327            .collect();
1328        for id in refused {
1329            if self.mark_reset(id) {
1330                sink(Event::Reset { stream: id, code: ErrorCode::REFUSED_STREAM, remote: true });
1331            }
1332            self.update(id);
1333        }
1334        if self.role == Role::Server {
1335            // GOAWAY, then a PING round trip, then the final GOAWAY (or the graceful timeout).
1336            self.shutdown(self.now);
1337        }
1338        Ok(())
1339    }
1340
1341    fn on_window_update(&mut self, h: FrameHeader, p: &[u8], sink: &mut dyn FnMut(Event<'_>)) -> R {
1342        if p.len() != 4 {
1343            return Err((ErrorCode::FRAME_SIZE_ERROR, "WINDOW_UPDATE length"));
1344        }
1345        let inc = be32(p) & 0x7fff_ffff;
1346        if inc < 1024 && self.hit(Budget::SmallWindowUpdate) {
1347            return calm("too many small WINDOW_UPDATE frames");
1348        }
1349        let id = h.stream;
1350        if id == 0 {
1351            if inc == 0 {
1352                return perr("WINDOW_UPDATE with a zero increment");
1353            }
1354            self.send_window += inc as i64;
1355            if self.send_window > MAX_WINDOW as i64 {
1356                return Err((ErrorCode::FLOW_CONTROL_ERROR, "connection window overflow"));
1357            }
1358            return Ok(());
1359        }
1360        if self.is_idle(id) {
1361            return perr("WINDOW_UPDATE on an idle stream");
1362        }
1363        let code = match self.streams.get_mut(&id) {
1364            None => return Ok(()),
1365            Some(s) if s.reset => return Ok(()),
1366            Some(_) if inc == 0 => ErrorCode::PROTOCOL_ERROR,
1367            Some(s) => {
1368                s.send_window += inc as i64;
1369                if s.send_window <= MAX_WINDOW as i64 {
1370                    return Ok(());
1371                }
1372                ErrorCode::FLOW_CONTROL_ERROR
1373            }
1374        };
1375        self.stream_error(id, code, sink)
1376    }
1377
1378    // ------------------------------------------------------------------ sending
1379
1380    /// Writes a header block on `id`, as HEADERS plus CONTINUATION frames when it is larger
1381    /// than the peer's maximum frame size.
1382    fn write_block(&mut self, id: u32, end: bool, fields: impl FnOnce(&mut Encoder, &mut Vec<u8>)) {
1383        let at = self.out.len();
1384        frame::write_header(&mut self.out, 0, kind::HEADERS, 0, id);
1385        self.enc.begin_block(&mut self.out);
1386        fields(&mut self.enc, &mut self.out);
1387        let len = self.out.len() - at - HEADER_LEN;
1388        let fl = if end { flag::END_STREAM } else { 0 };
1389        if len <= self.peer_max_frame {
1390            frame::patch_header(&mut self.out, at, len, fl | flag::END_HEADERS);
1391        } else {
1392            self.scratch.clear();
1393            self.scratch.extend_from_slice(&self.out[at + HEADER_LEN..]);
1394            self.out.truncate(at);
1395            frame::write_headers(&mut self.out, id, &self.scratch, end, self.peer_max_frame);
1396        }
1397    }
1398
1399    /// Refuses a header block larger than the peer's SETTINGS_MAX_HEADER_LIST_SIZE (RFC 9113
1400    /// §6.5.2: names and values uncompressed, plus 32 bytes a field, pseudo-fields included),
1401    /// before any state changes: the peer would refuse it (431, or a reset) anyway.
1402    fn check_list_size(&self, pseudo: &[(&[u8], &[u8])], fields: &[(&[u8], &[u8])]) -> Result<(), Error> {
1403        let size: u64 = pseudo.iter().chain(fields).map(|(n, v)| n.len() as u64 + v.len() as u64 + 32).sum();
1404        if size > u64::from(self.peer_max_header_list) {
1405            return Err(Error::HeaderListTooLarge);
1406        }
1407        Ok(())
1408    }
1409
1410    /// The peer's SETTINGS_MAX_HEADER_LIST_SIZE (`u32::MAX` until it announces one).
1411    pub fn peer_max_header_list_size(&self) -> u32 {
1412        self.peer_max_header_list
1413    }
1414
1415    /// The peer (a server) allows extended CONNECT: it sent SETTINGS_ENABLE_CONNECT_PROTOCOL
1416    /// = 1 (RFC 8441 §3). Known once its SETTINGS arrived ([`Event::Settings`]).
1417    pub fn peer_connect_protocol(&self) -> bool {
1418        self.peer_connect_protocol
1419    }
1420
1421    /// Client: opens an extended CONNECT stream (RFC 8441 §4), for example with
1422    /// `protocol = b"websocket"` for WebSocket over HTTP/2 (RFC 8441 §5). The stream stays open
1423    /// both ways; a 2xx response accepts the tunnel, whose bytes then travel as DATA. Fails with
1424    /// [`Error::ConnectProtocolDisabled`] unless the server enabled extended CONNECT.
1425    pub fn send_extended_connect(&mut self, protocol: &[u8], scheme: &[u8], authority: &[u8], path: &[u8], fields: &[(&[u8], &[u8])]) -> Result<u32, Error> {
1426        if self.role != Role::Client {
1427            return Err(Error::WrongRole);
1428        }
1429        if self.phase == Phase::Closed {
1430            return Err(Error::ConnectionClosed);
1431        }
1432        if self.goaway_recv.is_some() || self.goaway_sent.is_some() {
1433            return Err(Error::GoingAway);
1434        }
1435        if !self.peer_connect_protocol {
1436            return Err(Error::ConnectProtocolDisabled);
1437        }
1438        if self.next_stream_id > MAX_WINDOW {
1439            return Err(Error::StreamIdsExhausted);
1440        }
1441        if self.open_count >= self.peer_max_concurrent {
1442            return Err(Error::StreamLimit);
1443        }
1444        let ok = |v: &[u8]| !v.is_empty() && valid_value(v);
1445        if !ok(protocol) || !ok(scheme) || !ok(authority) || !ok(path) {
1446            return Err(Error::InvalidHeader);
1447        }
1448        Self::check_fields(fields)?;
1449        let pseudo: [(&[u8], &[u8]); 5] = [(b":method", b"CONNECT"), (b":protocol", protocol), (b":scheme", scheme), (b":authority", authority), (b":path", path)];
1450        self.check_list_size(&pseudo, fields)?;
1451        let id = self.next_stream_id;
1452        self.next_stream_id += 2;
1453        let s = Stream { send_window: self.peer_initial_window as i64, recv_window: self.stream_effective as i64, open: true, final_sent: true, ..Stream::default() };
1454        self.streams.insert(id, s);
1455        self.open_count += 1;
1456        self.write_block(id, false, |enc, out| {
1457            for (n, v) in pseudo {
1458                enc.field(n, v, out);
1459            }
1460            for (n, v) in fields {
1461                enc.field(n, v, out);
1462            }
1463        });
1464        Ok(id)
1465    }
1466
1467    fn check_fields(fields: &[(&[u8], &[u8])]) -> Result<(), Error> {
1468        for (n, v) in fields {
1469            if !valid_name(n) || connection_specific(n) || (*n == b"te" && *v != b"trailers") || !valid_value(v) {
1470                return Err(Error::InvalidHeader);
1471            }
1472        }
1473        Ok(())
1474    }
1475
1476    fn sendable(&self, stream: u32) -> Result<(), Error> {
1477        if self.phase == Phase::Closed {
1478            return Err(Error::ConnectionClosed);
1479        }
1480        match self.streams.get(&stream) {
1481            None => Err(Error::UnknownStream),
1482            Some(s) if s.reset => Err(Error::StreamReset),
1483            Some(s) if s.local_end => Err(Error::StreamClosed),
1484            Some(_) => Ok(()),
1485        }
1486    }
1487
1488    /// Server: sends response headers on `stream`. A status below 200 sends an informational
1489    /// response (101 is not allowed in HTTP/2); then the final one follows.
1490    pub fn send_response(&mut self, stream: u32, status: u16, fields: &[(&[u8], &[u8])], end_stream: bool) -> Result<(), Error> {
1491        if self.role != Role::Server {
1492            return Err(Error::WrongRole);
1493        }
1494        if !(100..1000).contains(&status) || status == 101 || (status < 200 && end_stream) {
1495            return Err(Error::InvalidHeader);
1496        }
1497        Self::check_fields(fields)?;
1498        self.sendable(stream)?;
1499        let digits = [b'0' + (status / 100) as u8, b'0' + (status / 10 % 10) as u8, b'0' + (status % 10) as u8];
1500        self.check_list_size(&[(b":status", &digits)], fields)?;
1501        let s = self.streams.get_mut(&stream).expect("checked");
1502        if s.final_sent {
1503            return Err(Error::HeadersAlreadySent);
1504        }
1505        if status >= 200 {
1506            s.final_sent = true;
1507        }
1508        if end_stream {
1509            s.local_end = true;
1510        }
1511        self.write_block(stream, end_stream, |enc, out| {
1512            enc.field(b":status", &digits, out);
1513            for (n, v) in fields {
1514                enc.field(n, v, out);
1515            }
1516        });
1517        if end_stream {
1518            self.update(stream);
1519        }
1520        Ok(())
1521    }
1522
1523    /// Client: opens a stream with a request. `authority` may be empty; `path` is ignored for
1524    /// CONNECT. Returns the new stream id.
1525    #[allow(clippy::too_many_arguments)]
1526    pub fn send_request(
1527        &mut self,
1528        method: &[u8],
1529        scheme: &[u8],
1530        authority: &[u8],
1531        path: &[u8],
1532        fields: &[(&[u8], &[u8])],
1533        end_stream: bool,
1534    ) -> Result<u32, Error> {
1535        if self.role != Role::Client {
1536            return Err(Error::WrongRole);
1537        }
1538        if self.phase == Phase::Closed {
1539            return Err(Error::ConnectionClosed);
1540        }
1541        if self.goaway_recv.is_some() || self.goaway_sent.is_some() {
1542            return Err(Error::GoingAway);
1543        }
1544        if self.next_stream_id > MAX_WINDOW {
1545            return Err(Error::StreamIdsExhausted);
1546        }
1547        if self.open_count >= self.peer_max_concurrent {
1548            return Err(Error::StreamLimit);
1549        }
1550        let connect = method == b"CONNECT";
1551        if method.is_empty()
1552            || !method.iter().all(|&b| b.is_ascii_alphanumeric() || b == b'-' || b == b'_')
1553            || !valid_value(scheme)
1554            || !valid_value(authority)
1555            || (!connect && (path.is_empty() || !valid_value(path)))
1556        {
1557            return Err(Error::InvalidHeader);
1558        }
1559        Self::check_fields(fields)?;
1560        // the pseudo-fields actually sent (CONNECT has no scheme or path; no empty authority)
1561        let pseudo: [(&[u8], &[u8]); 4] = [(b":method", method), (b":scheme", scheme), (b":authority", authority), (b":path", path)];
1562        let sent: Vec<(&[u8], &[u8])> = pseudo.into_iter().filter(|(n, v)| !(connect && (*n == b":scheme" || *n == b":path")) && !(*n == b":authority" && v.is_empty())).collect();
1563        self.check_list_size(&sent, fields)?;
1564        let id = self.next_stream_id;
1565        self.next_stream_id += 2;
1566        let s = Stream {
1567            send_window: self.peer_initial_window as i64,
1568            recv_window: self.stream_effective as i64,
1569            local_end: end_stream,
1570            open: true,
1571            final_sent: true,
1572            head: method == b"HEAD",
1573            ..Stream::default()
1574        };
1575        self.streams.insert(id, s);
1576        self.open_count += 1;
1577        self.write_block(id, end_stream, |enc, out| {
1578            enc.field(b":method", method, out);
1579            if !connect {
1580                enc.field(b":scheme", scheme, out);
1581            }
1582            if !authority.is_empty() {
1583                enc.field(b":authority", authority, out);
1584            }
1585            if !connect {
1586                enc.field(b":path", path, out);
1587            }
1588            for (n, v) in fields {
1589                enc.field(n, v, out);
1590            }
1591        });
1592        Ok(id)
1593    }
1594
1595    /// Sends trailers, ending the stream.
1596    pub fn send_trailers(&mut self, stream: u32, fields: &[(&[u8], &[u8])]) -> Result<(), Error> {
1597        Self::check_fields(fields)?;
1598        self.sendable(stream)?;
1599        self.check_list_size(&[], fields)?;
1600        let s = self.streams.get_mut(&stream).expect("checked");
1601        if !s.final_sent {
1602            return Err(Error::HeadersNotSent);
1603        }
1604        s.local_end = true;
1605        self.write_block(stream, true, |enc, out| {
1606            for (n, v) in fields {
1607                enc.field(n, v, out);
1608            }
1609        });
1610        self.update(stream);
1611        Ok(())
1612    }
1613
1614    /// Sends body bytes on `stream`, as much as the stream window, the connection window and
1615    /// the output buffer cap allow. Returns how many bytes were accepted; `end_stream` applies
1616    /// only when all of `data` was accepted. When fewer were accepted the stream is remembered,
1617    /// and [`Connection::poll_writable`] reports it once it can send again.
1618    pub fn send_data(&mut self, stream: u32, data: &[u8], end_stream: bool) -> Result<usize, Error> {
1619        self.sendable(stream)?;
1620        let room = self.cfg.max_send_buffer.saturating_sub(self.pending()) as i64;
1621        let max_frame = self.peer_max_frame;
1622        let s = self.streams.get_mut(&stream).expect("checked");
1623        if !s.final_sent {
1624            return Err(Error::HeadersNotSent);
1625        }
1626        let cap = s.send_window.min(self.send_window).min(room).max(0) as usize;
1627        let n = data.len().min(cap);
1628        let fin = end_stream && n == data.len();
1629        if n < data.len() && !s.blocked {
1630            s.blocked = true;
1631            self.blocked.push(stream);
1632        }
1633        if n == 0 && !fin {
1634            return Ok(0);
1635        }
1636        s.send_window -= n as i64;
1637        self.send_window -= n as i64;
1638        if n == 0 {
1639            frame::write_data(&mut self.out, stream, &[], true);
1640        } else {
1641            let mut chunks = data[..n].chunks(max_frame).peekable();
1642            while let Some(c) = chunks.next() {
1643                frame::write_data(&mut self.out, stream, c, fin && chunks.peek().is_none());
1644            }
1645        }
1646        if fin {
1647            s.local_end = true;
1648            self.update(stream);
1649        }
1650        Ok(n)
1651    }
1652
1653    /// A stream that was short of capacity in [`Connection::send_data`] and can send again.
1654    /// Call it after [`Connection::recv`] and [`Connection::advance_output`] until it returns
1655    /// `None`.
1656    pub fn poll_writable(&mut self) -> Option<u32> {
1657        if self.send_window <= 0 || self.pending() >= self.cfg.max_send_buffer || self.phase == Phase::Closed {
1658            return None;
1659        }
1660        let mut i = 0;
1661        while i < self.blocked.len() {
1662            let id = self.blocked[i];
1663            match self.streams.get_mut(&id) {
1664                Some(s) if s.blocked && !s.reset && !s.local_end => {
1665                    if s.send_window > 0 {
1666                        s.blocked = false;
1667                        self.blocked.swap_remove(i);
1668                        return Some(id);
1669                    }
1670                    i += 1;
1671                }
1672                Some(s) => {
1673                    s.blocked = false;
1674                    self.blocked.swap_remove(i);
1675                }
1676                None => {
1677                    self.blocked.swap_remove(i);
1678                }
1679            }
1680        }
1681        None
1682    }
1683
1684    /// Resets `stream` with `code` at the application's request.
1685    pub fn reset(&mut self, stream: u32, code: ErrorCode) {
1686        if self.phase == Phase::Closed || !self.streams.get(&stream).is_some_and(|s| !s.closed()) {
1687            return;
1688        }
1689        self.mark_reset(stream);
1690        let _ = self.send_rst(stream, code, false);
1691        self.update(stream);
1692    }
1693
1694    /// The application's work for `stream` is finished: it no longer counts against the
1695    /// concurrency limit. A stream we have not ended is reset with CANCEL; a request body that
1696    /// was not read to the end is cut off with RST_STREAM(NO_ERROR) (RFC 9113 §8.1).
1697    pub fn stream_finished(&mut self, stream: u32) {
1698        let Some(s) = self.streams.get_mut(&stream) else { return };
1699        if s.handler {
1700            s.handler = false;
1701            self.handlers -= 1;
1702        }
1703        if !s.closed() && self.phase != Phase::Closed {
1704            let code = if s.local_end { ErrorCode::NO_ERROR } else { ErrorCode::CANCEL };
1705            self.mark_reset(stream);
1706            let _ = self.send_rst(stream, code, false);
1707        }
1708        if let Some(s) = self.streams.get_mut(&stream) {
1709            if !s.closed() {
1710                // the connection is closed: just forget the stream
1711                s.reset = true;
1712            }
1713        }
1714        self.update(stream);
1715    }
1716
1717    /// Sends a PING; the answer arrives as [`Event::Pong`].
1718    pub fn ping(&mut self, data: [u8; 8]) {
1719        if self.phase != Phase::Closed {
1720            frame::write_ping(&mut self.out, data, false);
1721        }
1722    }
1723
1724    /// Starts a graceful shutdown (RFC 9113 §6.8). A server sends GOAWAY with the largest
1725    /// stream id and a PING, then, after the PING round trip (or `graceful_timeout_ms`), the
1726    /// final GOAWAY with the last stream it accepted. Streams already accepted run to the end;
1727    /// [`Connection::wants_close`] turns true when they are done.
1728    pub fn shutdown(&mut self, now: u64) {
1729        self.now = now;
1730        if self.phase == Phase::Closed || self.goaway_sent.is_some() || self.graceful_deadline.is_some() {
1731            return;
1732        }
1733        if self.role == Role::Server && self.phase == Phase::Open {
1734            frame::write_goaway(&mut self.out, MAX_WINDOW, ErrorCode::NO_ERROR, b"");
1735            frame::write_ping(&mut self.out, SHUTDOWN_PING, false);
1736            self.graceful_deadline = Some(now + self.cfg.graceful_timeout_ms);
1737        } else {
1738            self.final_goaway();
1739        }
1740    }
1741
1742    fn final_goaway(&mut self) {
1743        self.graceful_deadline = None;
1744        if self.goaway_sent.is_none() && self.phase != Phase::Closed {
1745            frame::write_goaway(&mut self.out, self.last_peer_stream, ErrorCode::NO_ERROR, b"");
1746            self.goaway_sent = Some(self.last_peer_stream);
1747        }
1748    }
1749
1750    /// Closes the connection at once with GOAWAY(`code`). No events follow.
1751    pub fn close(&mut self, code: ErrorCode, debug: &[u8]) {
1752        if self.phase == Phase::Closed {
1753            return;
1754        }
1755        frame::write_goaway(&mut self.out, self.last_peer_stream, code, debug);
1756        self.phase = Phase::Closed;
1757        self.close_code = Some(code);
1758        self.settings_deadline = None;
1759        self.graceful_deadline = None;
1760    }
1761}