Coverage Report

Created: 2025-08-28 07:05

/src/h2/src/proto/settings.rs
Line
Count
Source (jump to first uncovered line)
1
use crate::codec::UserError;
2
use crate::error::Reason;
3
use crate::proto::*;
4
use std::task::{Context, Poll};
5
6
#[derive(Debug)]
7
pub(crate) struct Settings {
8
    /// Our local SETTINGS sync state with the remote.
9
    local: Local,
10
    /// Received SETTINGS frame pending processing. The ACK must be written to
11
    /// the socket first then the settings applied **before** receiving any
12
    /// further frames.
13
    remote: Option<frame::Settings>,
14
    /// Whether the connection has received the initial SETTINGS frame from the
15
    /// remote peer.
16
    has_received_remote_initial_settings: bool,
17
}
18
19
#[derive(Debug)]
20
enum Local {
21
    /// We want to send these SETTINGS to the remote when the socket is ready.
22
    ToSend(frame::Settings),
23
    /// We have sent these SETTINGS and are waiting for the remote to ACK
24
    /// before we apply them.
25
    WaitingAck(frame::Settings),
26
    /// Our local settings are in sync with the remote.
27
    Synced,
28
}
29
30
impl Settings {
31
12.9k
    pub(crate) fn new(local: frame::Settings) -> Self {
32
12.9k
        Settings {
33
12.9k
            // We assume the initial local SETTINGS were flushed during
34
12.9k
            // the handshake process.
35
12.9k
            local: Local::WaitingAck(local),
36
12.9k
            remote: None,
37
12.9k
            has_received_remote_initial_settings: false,
38
12.9k
        }
39
12.9k
    }
40
41
7.45k
    pub(crate) fn recv_settings<T, B, C, P>(
42
7.45k
        &mut self,
43
7.45k
        frame: frame::Settings,
44
7.45k
        codec: &mut Codec<T, B>,
45
7.45k
        streams: &mut Streams<C, P>,
46
7.45k
    ) -> Result<(), Error>
47
7.45k
    where
48
7.45k
        T: AsyncWrite + Unpin,
49
7.45k
        B: Buf,
50
7.45k
        C: Buf,
51
7.45k
        P: Peer,
52
7.45k
    {
53
7.45k
        if frame.is_ack() {
54
12
            match &self.local {
55
11
                Local::WaitingAck(local) => {
56
11
                    tracing::debug!("received settings ACK; applying {:?}", local);
57
58
11
                    if let Some(max) = local.max_frame_size() {
59
0
                        codec.set_max_recv_frame_size(max as usize);
60
11
                    }
61
62
11
                    if let Some(max) = local.max_header_list_size() {
63
0
                        codec.set_max_recv_header_list_size(max as usize);
64
11
                    }
65
66
11
                    if let Some(val) = local.header_table_size() {
67
0
                        codec.set_recv_header_table_size(val as usize);
68
11
                    }
69
70
11
                    streams.apply_local_settings(local)?;
71
11
                    self.local = Local::Synced;
72
11
                    Ok(())
73
                }
74
                Local::ToSend(..) | Local::Synced => {
75
                    // We haven't sent any SETTINGS frames to be ACKed, so
76
                    // this is very bizarre! Remote is either buggy or malicious.
77
1
                    proto_err!(conn: "received unexpected settings ack");
78
1
                    Err(Error::library_go_away(Reason::PROTOCOL_ERROR))
79
                }
80
            }
81
        } else {
82
            // We always ACK before reading more frames, so `remote` should
83
            // always be none!
84
7.44k
            assert!(self.remote.is_none());
85
7.44k
            self.remote = Some(frame);
86
7.44k
            Ok(())
87
        }
88
7.45k
    }
Unexecuted instantiation: <h2::proto::settings::Settings>::recv_settings::<_, _, _, _>
<h2::proto::settings::Settings>::recv_settings::<fuzz_e2e::MockIo, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>, bytes::bytes::Bytes, h2::client::Peer>
Line
Count
Source
41
7.45k
    pub(crate) fn recv_settings<T, B, C, P>(
42
7.45k
        &mut self,
43
7.45k
        frame: frame::Settings,
44
7.45k
        codec: &mut Codec<T, B>,
45
7.45k
        streams: &mut Streams<C, P>,
46
7.45k
    ) -> Result<(), Error>
47
7.45k
    where
48
7.45k
        T: AsyncWrite + Unpin,
49
7.45k
        B: Buf,
50
7.45k
        C: Buf,
51
7.45k
        P: Peer,
52
7.45k
    {
53
7.45k
        if frame.is_ack() {
54
12
            match &self.local {
55
11
                Local::WaitingAck(local) => {
56
11
                    tracing::debug!("received settings ACK; applying {:?}", local);
57
58
11
                    if let Some(max) = local.max_frame_size() {
59
0
                        codec.set_max_recv_frame_size(max as usize);
60
11
                    }
61
62
11
                    if let Some(max) = local.max_header_list_size() {
63
0
                        codec.set_max_recv_header_list_size(max as usize);
64
11
                    }
65
66
11
                    if let Some(val) = local.header_table_size() {
67
0
                        codec.set_recv_header_table_size(val as usize);
68
11
                    }
69
70
11
                    streams.apply_local_settings(local)?;
71
11
                    self.local = Local::Synced;
72
11
                    Ok(())
73
                }
74
                Local::ToSend(..) | Local::Synced => {
75
                    // We haven't sent any SETTINGS frames to be ACKed, so
76
                    // this is very bizarre! Remote is either buggy or malicious.
77
1
                    proto_err!(conn: "received unexpected settings ack");
78
1
                    Err(Error::library_go_away(Reason::PROTOCOL_ERROR))
79
                }
80
            }
81
        } else {
82
            // We always ACK before reading more frames, so `remote` should
83
            // always be none!
84
7.44k
            assert!(self.remote.is_none());
85
7.44k
            self.remote = Some(frame);
86
7.44k
            Ok(())
87
        }
88
7.45k
    }
89
90
0
    pub(crate) fn send_settings(&mut self, frame: frame::Settings) -> Result<(), UserError> {
91
0
        assert!(!frame.is_ack());
92
0
        match &self.local {
93
0
            Local::ToSend(..) | Local::WaitingAck(..) => Err(UserError::SendSettingsWhilePending),
94
            Local::Synced => {
95
0
                tracing::trace!("queue to send local settings: {:?}", frame);
96
0
                self.local = Local::ToSend(frame);
97
0
                Ok(())
98
            }
99
        }
100
0
    }
101
102
    /// Sets `true` to `self.has_received_remote_initial_settings`.
103
    /// Returns `true` if this method is called for the first time.
104
    /// (i.e. it is the initial SETTINGS frame from the remote peer)
105
7.35k
    fn mark_remote_initial_settings_as_received(&mut self) -> bool {
106
7.35k
        let has_received = self.has_received_remote_initial_settings;
107
7.35k
        self.has_received_remote_initial_settings = true;
108
7.35k
        !has_received
109
7.35k
    }
110
111
2.41M
    pub(crate) fn poll_send<T, B, C, P>(
112
2.41M
        &mut self,
113
2.41M
        cx: &mut Context,
114
2.41M
        dst: &mut Codec<T, B>,
115
2.41M
        streams: &mut Streams<C, P>,
116
2.41M
    ) -> Poll<Result<(), Error>>
117
2.41M
    where
118
2.41M
        T: AsyncWrite + Unpin,
119
2.41M
        B: Buf,
120
2.41M
        C: Buf,
121
2.41M
        P: Peer,
122
2.41M
    {
123
2.41M
        if let Some(settings) = self.remote.clone() {
124
14.4k
            if !dst.poll_ready(cx)?.is_ready() {
125
7.02k
                return Poll::Pending;
126
7.35k
            }
127
7.35k
128
7.35k
            // Create an ACK settings frame
129
7.35k
            let frame = frame::Settings::ack();
130
7.35k
131
7.35k
            // Buffer the settings frame
132
7.35k
            dst.buffer(frame.into()).expect("invalid settings frame");
133
7.35k
134
7.35k
            tracing::trace!("ACK sent; applying settings");
135
136
7.35k
            let is_initial = self.mark_remote_initial_settings_as_received();
137
7.35k
            streams.apply_remote_settings(&settings, is_initial)?;
138
139
7.35k
            if let Some(val) = settings.header_table_size() {
140
1.69k
                dst.set_send_header_table_size(val as usize);
141
5.66k
            }
142
143
7.35k
            if let Some(val) = settings.max_frame_size() {
144
322
                dst.set_max_send_frame_size(val as usize);
145
7.03k
            }
146
2.40M
        }
147
148
2.40M
        self.remote = None;
149
2.40M
150
2.40M
        match &self.local {
151
0
            Local::ToSend(settings) => {
152
0
                if !dst.poll_ready(cx)?.is_ready() {
153
0
                    return Poll::Pending;
154
0
                }
155
0
156
0
                // Buffer the settings frame
157
0
                dst.buffer(settings.clone().into())
158
0
                    .expect("invalid settings frame");
159
0
                tracing::trace!("local settings sent; waiting for ack: {:?}", settings);
160
161
0
                self.local = Local::WaitingAck(settings.clone());
162
            }
163
2.40M
            Local::WaitingAck(..) | Local::Synced => {}
164
        }
165
166
2.40M
        Poll::Ready(Ok(()))
167
2.41M
    }
Unexecuted instantiation: <h2::proto::settings::Settings>::poll_send::<_, _, _, _>
<h2::proto::settings::Settings>::poll_send::<fuzz_e2e::MockIo, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>, bytes::bytes::Bytes, h2::client::Peer>
Line
Count
Source
111
2.41M
    pub(crate) fn poll_send<T, B, C, P>(
112
2.41M
        &mut self,
113
2.41M
        cx: &mut Context,
114
2.41M
        dst: &mut Codec<T, B>,
115
2.41M
        streams: &mut Streams<C, P>,
116
2.41M
    ) -> Poll<Result<(), Error>>
117
2.41M
    where
118
2.41M
        T: AsyncWrite + Unpin,
119
2.41M
        B: Buf,
120
2.41M
        C: Buf,
121
2.41M
        P: Peer,
122
2.41M
    {
123
2.41M
        if let Some(settings) = self.remote.clone() {
124
14.4k
            if !dst.poll_ready(cx)?.is_ready() {
125
7.02k
                return Poll::Pending;
126
7.35k
            }
127
7.35k
128
7.35k
            // Create an ACK settings frame
129
7.35k
            let frame = frame::Settings::ack();
130
7.35k
131
7.35k
            // Buffer the settings frame
132
7.35k
            dst.buffer(frame.into()).expect("invalid settings frame");
133
7.35k
134
7.35k
            tracing::trace!("ACK sent; applying settings");
135
136
7.35k
            let is_initial = self.mark_remote_initial_settings_as_received();
137
7.35k
            streams.apply_remote_settings(&settings, is_initial)?;
138
139
7.35k
            if let Some(val) = settings.header_table_size() {
140
1.69k
                dst.set_send_header_table_size(val as usize);
141
5.66k
            }
142
143
7.35k
            if let Some(val) = settings.max_frame_size() {
144
322
                dst.set_max_send_frame_size(val as usize);
145
7.03k
            }
146
2.40M
        }
147
148
2.40M
        self.remote = None;
149
2.40M
150
2.40M
        match &self.local {
151
0
            Local::ToSend(settings) => {
152
0
                if !dst.poll_ready(cx)?.is_ready() {
153
0
                    return Poll::Pending;
154
0
                }
155
0
156
0
                // Buffer the settings frame
157
0
                dst.buffer(settings.clone().into())
158
0
                    .expect("invalid settings frame");
159
0
                tracing::trace!("local settings sent; waiting for ack: {:?}", settings);
160
161
0
                self.local = Local::WaitingAck(settings.clone());
162
            }
163
2.40M
            Local::WaitingAck(..) | Local::Synced => {}
164
        }
165
166
2.40M
        Poll::Ready(Ok(()))
167
2.41M
    }
168
}