/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 | | } |