/src/h2/src/codec/framed_write.rs
Line | Count | Source |
1 | | use crate::codec::UserError; |
2 | | use crate::codec::UserError::*; |
3 | | use crate::frame::{self, Frame, FrameSize}; |
4 | | use crate::hpack; |
5 | | |
6 | | use bytes::{Buf, BufMut, BytesMut}; |
7 | | use std::pin::Pin; |
8 | | use std::task::{Context, Poll}; |
9 | | use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; |
10 | | use tokio_util::io::poll_write_buf; |
11 | | |
12 | | use std::io::{self, Cursor}; |
13 | | |
14 | | // A macro to get around a method needing to borrow &mut self |
15 | | macro_rules! limited_write_buf { |
16 | | ($self:expr) => {{ |
17 | | let limit = $self.max_frame_size() + frame::HEADER_LEN; |
18 | | $self.buf.get_mut().limit(limit) |
19 | | }}; |
20 | | } |
21 | | |
22 | | #[derive(Debug)] |
23 | | pub struct FramedWrite<T, B> { |
24 | | /// Upstream `AsyncWrite` |
25 | | inner: T, |
26 | | final_flush_done: bool, |
27 | | |
28 | | encoder: Encoder<B>, |
29 | | } |
30 | | |
31 | | #[derive(Debug)] |
32 | | struct Encoder<B> { |
33 | | /// HPACK encoder |
34 | | hpack: hpack::Encoder, |
35 | | |
36 | | /// Write buffer |
37 | | /// |
38 | | /// TODO: Should this be a ring buffer? |
39 | | buf: Cursor<BytesMut>, |
40 | | |
41 | | /// Next frame to encode |
42 | | next: Option<Next<B>>, |
43 | | |
44 | | /// Last data frame |
45 | | last_data_frame: Option<frame::Data<B>>, |
46 | | |
47 | | /// Max frame size, this is specified by the peer |
48 | | max_frame_size: FrameSize, |
49 | | |
50 | | /// Chain payloads bigger than this. |
51 | | chain_threshold: usize, |
52 | | |
53 | | /// Min buffer required to attempt to write a frame |
54 | | min_buffer_capacity: usize, |
55 | | } |
56 | | |
57 | | #[derive(Debug)] |
58 | | enum Next<B> { |
59 | | Data(frame::Data<B>), |
60 | | Continuation(frame::Continuation), |
61 | | } |
62 | | |
63 | | /// Initialize the connection with this amount of write buffer. |
64 | | /// |
65 | | /// The minimum MAX_FRAME_SIZE is 16kb, so always be able to send a HEADERS |
66 | | /// frame that big. |
67 | | const DEFAULT_BUFFER_CAPACITY: usize = 16 * 1_024; |
68 | | |
69 | | /// Chain payloads bigger than this when vectored I/O is enabled. The remote |
70 | | /// will never advertise a max frame size less than this (well, the spec says |
71 | | /// the max frame size can't be less than 16kb, so not even close). |
72 | | const CHAIN_THRESHOLD: usize = 256; |
73 | | |
74 | | /// Chain payloads bigger than this when vectored I/O is **not** enabled. |
75 | | /// A larger value in this scenario will reduce the number of small and |
76 | | /// fragmented data being sent, and hereby improve the throughput. |
77 | | const CHAIN_THRESHOLD_WITHOUT_VECTORED_IO: usize = 1024; |
78 | | |
79 | | // TODO: Make generic |
80 | | impl<T, B> FramedWrite<T, B> |
81 | | where |
82 | | T: AsyncWrite + Unpin, |
83 | | B: Buf, |
84 | | { |
85 | 13.7k | pub fn new(inner: T) -> FramedWrite<T, B> { |
86 | 13.7k | let chain_threshold = if inner.is_write_vectored() { |
87 | 0 | CHAIN_THRESHOLD |
88 | | } else { |
89 | 13.7k | CHAIN_THRESHOLD_WITHOUT_VECTORED_IO |
90 | | }; |
91 | 13.7k | FramedWrite { |
92 | 13.7k | inner, |
93 | 13.7k | final_flush_done: false, |
94 | 13.7k | encoder: Encoder { |
95 | 13.7k | hpack: hpack::Encoder::default(), |
96 | 13.7k | buf: Cursor::new(BytesMut::with_capacity(DEFAULT_BUFFER_CAPACITY)), |
97 | 13.7k | next: None, |
98 | 13.7k | last_data_frame: None, |
99 | 13.7k | max_frame_size: frame::DEFAULT_MAX_FRAME_SIZE, |
100 | 13.7k | chain_threshold, |
101 | 13.7k | min_buffer_capacity: chain_threshold + frame::HEADER_LEN, |
102 | 13.7k | }, |
103 | 13.7k | } |
104 | 13.7k | } Unexecuted instantiation: <h2::codec::framed_write::FramedWrite<_, _>>::new <h2::codec::framed_write::FramedWrite<h2_support::mock::Mock, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::new Line | Count | Source | 85 | 863 | pub fn new(inner: T) -> FramedWrite<T, B> { | 86 | 863 | let chain_threshold = if inner.is_write_vectored() { | 87 | 0 | CHAIN_THRESHOLD | 88 | | } else { | 89 | 863 | CHAIN_THRESHOLD_WITHOUT_VECTORED_IO | 90 | | }; | 91 | 863 | FramedWrite { | 92 | 863 | inner, | 93 | 863 | final_flush_done: false, | 94 | 863 | encoder: Encoder { | 95 | 863 | hpack: hpack::Encoder::default(), | 96 | 863 | buf: Cursor::new(BytesMut::with_capacity(DEFAULT_BUFFER_CAPACITY)), | 97 | 863 | next: None, | 98 | 863 | last_data_frame: None, | 99 | 863 | max_frame_size: frame::DEFAULT_MAX_FRAME_SIZE, | 100 | 863 | chain_threshold, | 101 | 863 | min_buffer_capacity: chain_threshold + frame::HEADER_LEN, | 102 | 863 | }, | 103 | 863 | } | 104 | 863 | } |
<h2::codec::framed_write::FramedWrite<h2_support::mock::Pipe, bytes::bytes::Bytes>>::new Line | Count | Source | 85 | 863 | pub fn new(inner: T) -> FramedWrite<T, B> { | 86 | 863 | let chain_threshold = if inner.is_write_vectored() { | 87 | 0 | CHAIN_THRESHOLD | 88 | | } else { | 89 | 863 | CHAIN_THRESHOLD_WITHOUT_VECTORED_IO | 90 | | }; | 91 | 863 | FramedWrite { | 92 | 863 | inner, | 93 | 863 | final_flush_done: false, | 94 | 863 | encoder: Encoder { | 95 | 863 | hpack: hpack::Encoder::default(), | 96 | 863 | buf: Cursor::new(BytesMut::with_capacity(DEFAULT_BUFFER_CAPACITY)), | 97 | 863 | next: None, | 98 | 863 | last_data_frame: None, | 99 | 863 | max_frame_size: frame::DEFAULT_MAX_FRAME_SIZE, | 100 | 863 | chain_threshold, | 101 | 863 | min_buffer_capacity: chain_threshold + frame::HEADER_LEN, | 102 | 863 | }, | 103 | 863 | } | 104 | 863 | } |
<h2::codec::framed_write::FramedWrite<fuzz_e2e::MockIo, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::new Line | Count | Source | 85 | 12.0k | pub fn new(inner: T) -> FramedWrite<T, B> { | 86 | 12.0k | let chain_threshold = if inner.is_write_vectored() { | 87 | 0 | CHAIN_THRESHOLD | 88 | | } else { | 89 | 12.0k | CHAIN_THRESHOLD_WITHOUT_VECTORED_IO | 90 | | }; | 91 | 12.0k | FramedWrite { | 92 | 12.0k | inner, | 93 | 12.0k | final_flush_done: false, | 94 | 12.0k | encoder: Encoder { | 95 | 12.0k | hpack: hpack::Encoder::default(), | 96 | 12.0k | buf: Cursor::new(BytesMut::with_capacity(DEFAULT_BUFFER_CAPACITY)), | 97 | 12.0k | next: None, | 98 | 12.0k | last_data_frame: None, | 99 | 12.0k | max_frame_size: frame::DEFAULT_MAX_FRAME_SIZE, | 100 | 12.0k | chain_threshold, | 101 | 12.0k | min_buffer_capacity: chain_threshold + frame::HEADER_LEN, | 102 | 12.0k | }, | 103 | 12.0k | } | 104 | 12.0k | } |
|
105 | | |
106 | | /// Returns `Ready` when `send` is able to accept a frame |
107 | | /// |
108 | | /// Calling this function may result in the current contents of the buffer |
109 | | /// to be flushed to `T`. |
110 | 1.13M | pub fn poll_ready(&mut self, cx: &mut Context) -> Poll<io::Result<()>> { |
111 | 1.13M | if !self.encoder.has_capacity() { |
112 | | // Try flushing |
113 | 478k | ready!(self.flush(cx))?; |
114 | | |
115 | 2.87k | if !self.encoder.has_capacity() { |
116 | 0 | return Poll::Pending; |
117 | 2.87k | } |
118 | 660k | } |
119 | | |
120 | 662k | Poll::Ready(Ok(())) |
121 | 1.13M | } Unexecuted instantiation: <h2::codec::framed_write::FramedWrite<_, _>>::poll_ready <h2::codec::framed_write::FramedWrite<fuzz_e2e::MockIo, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::poll_ready Line | Count | Source | 110 | 1.13M | pub fn poll_ready(&mut self, cx: &mut Context) -> Poll<io::Result<()>> { | 111 | 1.13M | if !self.encoder.has_capacity() { | 112 | | // Try flushing | 113 | 478k | ready!(self.flush(cx))?; | 114 | | | 115 | 2.87k | if !self.encoder.has_capacity() { | 116 | 0 | return Poll::Pending; | 117 | 2.87k | } | 118 | 660k | } | 119 | | | 120 | 662k | Poll::Ready(Ok(())) | 121 | 1.13M | } |
|
122 | | |
123 | | /// Buffer a frame. |
124 | | /// |
125 | | /// `poll_ready` must be called first to ensure that a frame may be |
126 | | /// accepted. |
127 | 288k | pub fn buffer(&mut self, item: Frame<B>) -> Result<(), UserError> { |
128 | 288k | self.encoder.buffer(item) |
129 | 288k | } Unexecuted instantiation: <h2::codec::framed_write::FramedWrite<_, _>>::buffer <h2::codec::framed_write::FramedWrite<h2_support::mock::Mock, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::buffer Line | Count | Source | 127 | 863 | pub fn buffer(&mut self, item: Frame<B>) -> Result<(), UserError> { | 128 | 863 | self.encoder.buffer(item) | 129 | 863 | } |
<h2::codec::framed_write::FramedWrite<fuzz_e2e::MockIo, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::buffer Line | Count | Source | 127 | 288k | pub fn buffer(&mut self, item: Frame<B>) -> Result<(), UserError> { | 128 | 288k | self.encoder.buffer(item) | 129 | 288k | } |
|
130 | | |
131 | | /// Flush buffered data to the wire |
132 | 680k | pub fn flush(&mut self, cx: &mut Context) -> Poll<io::Result<()>> { |
133 | 680k | let span = tracing::trace_span!("FramedWrite::flush"); |
134 | 680k | let _e = span.enter(); |
135 | | |
136 | | loop { |
137 | 693k | while !self.encoder.is_empty() { |
138 | 482k | let n = match self.encoder.next { |
139 | 482k | Some(Next::Data(ref mut frame)) => { |
140 | 482k | tracing::trace!(queued_data_frame = true); |
141 | 482k | let mut buf = (&mut self.encoder.buf).chain(frame.payload_mut()); |
142 | 482k | ready!(poll_write_buf(Pin::new(&mut self.inner), cx, &mut buf))? |
143 | | } |
144 | | _ => { |
145 | 27.7k | tracing::trace!(queued_data_frame = false); |
146 | 27.7k | ready!(poll_write_buf( |
147 | 27.7k | Pin::new(&mut self.inner), |
148 | 27.7k | cx, |
149 | 27.7k | &mut self.encoder.buf |
150 | 27.7k | ))? |
151 | | } |
152 | | }; |
153 | 12.5k | if n == 0 { |
154 | | // No progress is possible; retrying would busy-loop. |
155 | 0 | tracing::trace!("write returned zero, but non-zero bytes remaining"); |
156 | 0 | return Poll::Ready(Err(io::ErrorKind::WriteZero.into())); |
157 | 12.5k | } |
158 | | } |
159 | | |
160 | 183k | match self.encoder.unset_frame() { |
161 | 0 | ControlFlow::Continue => (), |
162 | 183k | ControlFlow::Break => break, |
163 | | } |
164 | | } |
165 | | |
166 | 183k | tracing::trace!("flushing buffer"); |
167 | | // Flush the upstream |
168 | 183k | ready!(Pin::new(&mut self.inner).poll_flush(cx))?; |
169 | | |
170 | 183k | Poll::Ready(Ok(())) |
171 | 680k | } Unexecuted instantiation: <h2::codec::framed_write::FramedWrite<_, _>>::flush <h2::codec::framed_write::FramedWrite<h2_support::mock::Pipe, bytes::bytes::Bytes>>::flush Line | Count | Source | 132 | 863 | pub fn flush(&mut self, cx: &mut Context) -> Poll<io::Result<()>> { | 133 | 863 | let span = tracing::trace_span!("FramedWrite::flush"); | 134 | 863 | let _e = span.enter(); | 135 | | | 136 | | loop { | 137 | 863 | while !self.encoder.is_empty() { | 138 | 0 | let n = match self.encoder.next { | 139 | 0 | Some(Next::Data(ref mut frame)) => { | 140 | 0 | tracing::trace!(queued_data_frame = true); | 141 | 0 | let mut buf = (&mut self.encoder.buf).chain(frame.payload_mut()); | 142 | 0 | ready!(poll_write_buf(Pin::new(&mut self.inner), cx, &mut buf))? | 143 | | } | 144 | | _ => { | 145 | 0 | tracing::trace!(queued_data_frame = false); | 146 | 0 | ready!(poll_write_buf( | 147 | 0 | Pin::new(&mut self.inner), | 148 | 0 | cx, | 149 | 0 | &mut self.encoder.buf | 150 | 0 | ))? | 151 | | } | 152 | | }; | 153 | 0 | if n == 0 { | 154 | | // No progress is possible; retrying would busy-loop. | 155 | 0 | tracing::trace!("write returned zero, but non-zero bytes remaining"); | 156 | 0 | return Poll::Ready(Err(io::ErrorKind::WriteZero.into())); | 157 | 0 | } | 158 | | } | 159 | | | 160 | 863 | match self.encoder.unset_frame() { | 161 | 0 | ControlFlow::Continue => (), | 162 | 863 | ControlFlow::Break => break, | 163 | | } | 164 | | } | 165 | | | 166 | 863 | tracing::trace!("flushing buffer"); | 167 | | // Flush the upstream | 168 | 863 | ready!(Pin::new(&mut self.inner).poll_flush(cx))?; | 169 | | | 170 | 863 | Poll::Ready(Ok(())) | 171 | 863 | } |
<h2::codec::framed_write::FramedWrite<fuzz_e2e::MockIo, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::flush Line | Count | Source | 132 | 679k | pub fn flush(&mut self, cx: &mut Context) -> Poll<io::Result<()>> { | 133 | 679k | let span = tracing::trace_span!("FramedWrite::flush"); | 134 | 679k | let _e = span.enter(); | 135 | | | 136 | | loop { | 137 | 692k | while !self.encoder.is_empty() { | 138 | 482k | let n = match self.encoder.next { | 139 | 482k | Some(Next::Data(ref mut frame)) => { | 140 | 482k | tracing::trace!(queued_data_frame = true); | 141 | 482k | let mut buf = (&mut self.encoder.buf).chain(frame.payload_mut()); | 142 | 482k | ready!(poll_write_buf(Pin::new(&mut self.inner), cx, &mut buf))? | 143 | | } | 144 | | _ => { | 145 | 27.7k | tracing::trace!(queued_data_frame = false); | 146 | 27.7k | ready!(poll_write_buf( | 147 | 27.7k | Pin::new(&mut self.inner), | 148 | 27.7k | cx, | 149 | 27.7k | &mut self.encoder.buf | 150 | 27.7k | ))? | 151 | | } | 152 | | }; | 153 | 12.5k | if n == 0 { | 154 | | // No progress is possible; retrying would busy-loop. | 155 | 0 | tracing::trace!("write returned zero, but non-zero bytes remaining"); | 156 | 0 | return Poll::Ready(Err(io::ErrorKind::WriteZero.into())); | 157 | 12.5k | } | 158 | | } | 159 | | | 160 | 182k | match self.encoder.unset_frame() { | 161 | 0 | ControlFlow::Continue => (), | 162 | 182k | ControlFlow::Break => break, | 163 | | } | 164 | | } | 165 | | | 166 | 182k | tracing::trace!("flushing buffer"); | 167 | | // Flush the upstream | 168 | 182k | ready!(Pin::new(&mut self.inner).poll_flush(cx))?; | 169 | | | 170 | 182k | Poll::Ready(Ok(())) | 171 | 679k | } |
|
172 | | |
173 | | /// Close the codec |
174 | 10.5k | pub fn shutdown(&mut self, cx: &mut Context) -> Poll<io::Result<()>> { |
175 | 10.5k | if !self.final_flush_done { |
176 | 10.5k | ready!(self.flush(cx))?; |
177 | 1.58k | self.final_flush_done = true; |
178 | 0 | } |
179 | 1.58k | Pin::new(&mut self.inner).poll_shutdown(cx) |
180 | 10.5k | } Unexecuted instantiation: <h2::codec::framed_write::FramedWrite<_, _>>::shutdown <h2::codec::framed_write::FramedWrite<h2_support::mock::Pipe, bytes::bytes::Bytes>>::shutdown Line | Count | Source | 174 | 863 | pub fn shutdown(&mut self, cx: &mut Context) -> Poll<io::Result<()>> { | 175 | 863 | if !self.final_flush_done { | 176 | 863 | ready!(self.flush(cx))?; | 177 | 863 | self.final_flush_done = true; | 178 | 0 | } | 179 | 863 | Pin::new(&mut self.inner).poll_shutdown(cx) | 180 | 863 | } |
<h2::codec::framed_write::FramedWrite<fuzz_e2e::MockIo, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::shutdown Line | Count | Source | 174 | 9.68k | pub fn shutdown(&mut self, cx: &mut Context) -> Poll<io::Result<()>> { | 175 | 9.68k | if !self.final_flush_done { | 176 | 9.68k | ready!(self.flush(cx))?; | 177 | 725 | self.final_flush_done = true; | 178 | 0 | } | 179 | 725 | Pin::new(&mut self.inner).poll_shutdown(cx) | 180 | 9.68k | } |
|
181 | | } |
182 | | |
183 | | #[must_use] |
184 | | enum ControlFlow { |
185 | | Continue, |
186 | | Break, |
187 | | } |
188 | | |
189 | | impl<B> Encoder<B> |
190 | | where |
191 | | B: Buf, |
192 | | { |
193 | 183k | fn unset_frame(&mut self) -> ControlFlow { |
194 | | // Clear internal buffer |
195 | 183k | self.buf.set_position(0); |
196 | 183k | self.buf.get_mut().clear(); |
197 | | |
198 | | // The data frame has been written, so unset it |
199 | 183k | match self.next.take() { |
200 | 2.74k | Some(Next::Data(frame)) => { |
201 | 2.74k | self.last_data_frame = Some(frame); |
202 | 2.74k | debug_assert!(self.is_empty()); |
203 | 2.74k | ControlFlow::Break |
204 | | } |
205 | 0 | Some(Next::Continuation(frame)) => { |
206 | | // Buffer the continuation frame, then try to write again |
207 | 0 | let mut buf = limited_write_buf!(self); |
208 | 0 | if let Some(continuation) = frame.encode(&mut buf) { |
209 | 0 | self.next = Some(Next::Continuation(continuation)); |
210 | 0 | } |
211 | 0 | ControlFlow::Continue |
212 | | } |
213 | 180k | None => ControlFlow::Break, |
214 | | } |
215 | 183k | } Unexecuted instantiation: <h2::codec::framed_write::Encoder<_>>::unset_frame <h2::codec::framed_write::Encoder<bytes::bytes::Bytes>>::unset_frame Line | Count | Source | 193 | 863 | fn unset_frame(&mut self) -> ControlFlow { | 194 | | // Clear internal buffer | 195 | 863 | self.buf.set_position(0); | 196 | 863 | self.buf.get_mut().clear(); | 197 | | | 198 | | // The data frame has been written, so unset it | 199 | 863 | match self.next.take() { | 200 | 0 | Some(Next::Data(frame)) => { | 201 | 0 | self.last_data_frame = Some(frame); | 202 | 0 | debug_assert!(self.is_empty()); | 203 | 0 | ControlFlow::Break | 204 | | } | 205 | 0 | Some(Next::Continuation(frame)) => { | 206 | | // Buffer the continuation frame, then try to write again | 207 | 0 | let mut buf = limited_write_buf!(self); | 208 | 0 | if let Some(continuation) = frame.encode(&mut buf) { | 209 | 0 | self.next = Some(Next::Continuation(continuation)); | 210 | 0 | } | 211 | 0 | ControlFlow::Continue | 212 | | } | 213 | 863 | None => ControlFlow::Break, | 214 | | } | 215 | 863 | } |
<h2::codec::framed_write::Encoder<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::unset_frame Line | Count | Source | 193 | 182k | fn unset_frame(&mut self) -> ControlFlow { | 194 | | // Clear internal buffer | 195 | 182k | self.buf.set_position(0); | 196 | 182k | self.buf.get_mut().clear(); | 197 | | | 198 | | // The data frame has been written, so unset it | 199 | 182k | match self.next.take() { | 200 | 2.74k | Some(Next::Data(frame)) => { | 201 | 2.74k | self.last_data_frame = Some(frame); | 202 | 2.74k | debug_assert!(self.is_empty()); | 203 | 2.74k | ControlFlow::Break | 204 | | } | 205 | 0 | Some(Next::Continuation(frame)) => { | 206 | | // Buffer the continuation frame, then try to write again | 207 | 0 | let mut buf = limited_write_buf!(self); | 208 | 0 | if let Some(continuation) = frame.encode(&mut buf) { | 209 | 0 | self.next = Some(Next::Continuation(continuation)); | 210 | 0 | } | 211 | 0 | ControlFlow::Continue | 212 | | } | 213 | 179k | None => ControlFlow::Break, | 214 | | } | 215 | 182k | } |
|
216 | | |
217 | 288k | fn buffer(&mut self, item: Frame<B>) -> Result<(), UserError> { |
218 | | // Ensure that we have enough capacity to accept the write. |
219 | 288k | assert!(self.has_capacity()); |
220 | 288k | let span = tracing::trace_span!("FramedWrite::buffer", frame = ?item); |
221 | 288k | let _e = span.enter(); |
222 | | |
223 | 288k | tracing::debug!(frame = ?item, "send"); |
224 | | |
225 | 288k | match item { |
226 | 18.9k | Frame::Data(mut v) => { |
227 | | // Ensure that the payload is not greater than the max frame. |
228 | 18.9k | let len = v.payload().remaining(); |
229 | | |
230 | 18.9k | if len > self.max_frame_size() { |
231 | 0 | return Err(PayloadTooBig); |
232 | 18.9k | } |
233 | | |
234 | 18.9k | if len >= self.chain_threshold { |
235 | 4.18k | let head = v.head(); |
236 | | |
237 | | // Encode the frame head to the buffer |
238 | 4.18k | head.encode(len, self.buf.get_mut()); |
239 | | |
240 | 4.18k | if self.buf.get_ref().remaining() < self.chain_threshold { |
241 | 2.47k | let extra_bytes = self.chain_threshold - self.buf.remaining(); |
242 | 2.47k | self.buf.get_mut().put(v.payload_mut().take(extra_bytes)); |
243 | 2.47k | } |
244 | | |
245 | | // Save the data frame |
246 | 4.18k | self.next = Some(Next::Data(v)); |
247 | | } else { |
248 | 14.7k | v.encode_chunk(self.buf.get_mut()); |
249 | | |
250 | | // The chunk has been fully encoded, so there is no need to |
251 | | // keep it around |
252 | 14.7k | assert_eq!(v.payload().remaining(), 0, "chunk not fully encoded"); |
253 | | |
254 | | // Save off the last frame... |
255 | 14.7k | self.last_data_frame = Some(v); |
256 | | } |
257 | | } |
258 | 236k | Frame::Headers(v) => { |
259 | 236k | let mut buf = limited_write_buf!(self); |
260 | 236k | if let Some(continuation) = v.encode(&mut self.hpack, &mut buf) { |
261 | 0 | self.next = Some(Next::Continuation(continuation)); |
262 | 236k | } |
263 | | } |
264 | 0 | Frame::PushPromise(v) => { |
265 | 0 | let mut buf = limited_write_buf!(self); |
266 | 0 | if let Some(continuation) = v.encode(&mut self.hpack, &mut buf) { |
267 | 0 | self.next = Some(Next::Continuation(continuation)); |
268 | 0 | } |
269 | | } |
270 | 19.1k | Frame::Settings(v) => { |
271 | 19.1k | v.encode(self.buf.get_mut()); |
272 | 19.1k | tracing::trace!(rem = self.buf.remaining(), "encoded settings"); |
273 | | } |
274 | 6.66k | Frame::GoAway(v) => { |
275 | 6.66k | v.encode(self.buf.get_mut()); |
276 | 6.66k | tracing::trace!(rem = self.buf.remaining(), "encoded go_away"); |
277 | | } |
278 | 473 | Frame::Ping(v) => { |
279 | 473 | v.encode(self.buf.get_mut()); |
280 | 473 | tracing::trace!(rem = self.buf.remaining(), "encoded ping"); |
281 | | } |
282 | 48 | Frame::WindowUpdate(v) => { |
283 | 48 | v.encode(self.buf.get_mut()); |
284 | 48 | tracing::trace!(rem = self.buf.remaining(), "encoded window_update"); |
285 | | } |
286 | | |
287 | | Frame::Priority(_) => { |
288 | | /* |
289 | | v.encode(self.buf.get_mut()); |
290 | | tracing::trace!("encoded priority; rem={:?}", self.buf.remaining()); |
291 | | */ |
292 | 0 | unimplemented!(); |
293 | | } |
294 | 7.42k | Frame::Reset(v) => { |
295 | 7.42k | v.encode(self.buf.get_mut()); |
296 | 7.42k | tracing::trace!(rem = self.buf.remaining(), "encoded reset"); |
297 | | } |
298 | | } |
299 | | |
300 | 288k | Ok(()) |
301 | 288k | } Unexecuted instantiation: <h2::codec::framed_write::Encoder<_>>::buffer <h2::codec::framed_write::Encoder<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::buffer Line | Count | Source | 217 | 863 | fn buffer(&mut self, item: Frame<B>) -> Result<(), UserError> { | 218 | | // Ensure that we have enough capacity to accept the write. | 219 | 863 | assert!(self.has_capacity()); | 220 | 863 | let span = tracing::trace_span!("FramedWrite::buffer", frame = ?item); | 221 | 863 | let _e = span.enter(); | 222 | | | 223 | 863 | tracing::debug!(frame = ?item, "send"); | 224 | | | 225 | 863 | match item { | 226 | 0 | Frame::Data(mut v) => { | 227 | | // Ensure that the payload is not greater than the max frame. | 228 | 0 | let len = v.payload().remaining(); | 229 | | | 230 | 0 | if len > self.max_frame_size() { | 231 | 0 | return Err(PayloadTooBig); | 232 | 0 | } | 233 | | | 234 | 0 | if len >= self.chain_threshold { | 235 | 0 | let head = v.head(); | 236 | | | 237 | | // Encode the frame head to the buffer | 238 | 0 | head.encode(len, self.buf.get_mut()); | 239 | | | 240 | 0 | if self.buf.get_ref().remaining() < self.chain_threshold { | 241 | 0 | let extra_bytes = self.chain_threshold - self.buf.remaining(); | 242 | 0 | self.buf.get_mut().put(v.payload_mut().take(extra_bytes)); | 243 | 0 | } | 244 | | | 245 | | // Save the data frame | 246 | 0 | self.next = Some(Next::Data(v)); | 247 | | } else { | 248 | 0 | v.encode_chunk(self.buf.get_mut()); | 249 | | | 250 | | // The chunk has been fully encoded, so there is no need to | 251 | | // keep it around | 252 | 0 | assert_eq!(v.payload().remaining(), 0, "chunk not fully encoded"); | 253 | | | 254 | | // Save off the last frame... | 255 | 0 | self.last_data_frame = Some(v); | 256 | | } | 257 | | } | 258 | 0 | Frame::Headers(v) => { | 259 | 0 | let mut buf = limited_write_buf!(self); | 260 | 0 | if let Some(continuation) = v.encode(&mut self.hpack, &mut buf) { | 261 | 0 | self.next = Some(Next::Continuation(continuation)); | 262 | 0 | } | 263 | | } | 264 | 0 | Frame::PushPromise(v) => { | 265 | 0 | let mut buf = limited_write_buf!(self); | 266 | 0 | if let Some(continuation) = v.encode(&mut self.hpack, &mut buf) { | 267 | 0 | self.next = Some(Next::Continuation(continuation)); | 268 | 0 | } | 269 | | } | 270 | 863 | Frame::Settings(v) => { | 271 | 863 | v.encode(self.buf.get_mut()); | 272 | 863 | tracing::trace!(rem = self.buf.remaining(), "encoded settings"); | 273 | | } | 274 | 0 | Frame::GoAway(v) => { | 275 | 0 | v.encode(self.buf.get_mut()); | 276 | 0 | tracing::trace!(rem = self.buf.remaining(), "encoded go_away"); | 277 | | } | 278 | 0 | Frame::Ping(v) => { | 279 | 0 | v.encode(self.buf.get_mut()); | 280 | 0 | tracing::trace!(rem = self.buf.remaining(), "encoded ping"); | 281 | | } | 282 | 0 | Frame::WindowUpdate(v) => { | 283 | 0 | v.encode(self.buf.get_mut()); | 284 | 0 | tracing::trace!(rem = self.buf.remaining(), "encoded window_update"); | 285 | | } | 286 | | | 287 | | Frame::Priority(_) => { | 288 | | /* | 289 | | v.encode(self.buf.get_mut()); | 290 | | tracing::trace!("encoded priority; rem={:?}", self.buf.remaining()); | 291 | | */ | 292 | 0 | unimplemented!(); | 293 | | } | 294 | 0 | Frame::Reset(v) => { | 295 | 0 | v.encode(self.buf.get_mut()); | 296 | 0 | tracing::trace!(rem = self.buf.remaining(), "encoded reset"); | 297 | | } | 298 | | } | 299 | | | 300 | 863 | Ok(()) | 301 | 863 | } |
<h2::codec::framed_write::Encoder<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::buffer Line | Count | Source | 217 | 288k | fn buffer(&mut self, item: Frame<B>) -> Result<(), UserError> { | 218 | | // Ensure that we have enough capacity to accept the write. | 219 | 288k | assert!(self.has_capacity()); | 220 | 288k | let span = tracing::trace_span!("FramedWrite::buffer", frame = ?item); | 221 | 288k | let _e = span.enter(); | 222 | | | 223 | 288k | tracing::debug!(frame = ?item, "send"); | 224 | | | 225 | 288k | match item { | 226 | 18.9k | Frame::Data(mut v) => { | 227 | | // Ensure that the payload is not greater than the max frame. | 228 | 18.9k | let len = v.payload().remaining(); | 229 | | | 230 | 18.9k | if len > self.max_frame_size() { | 231 | 0 | return Err(PayloadTooBig); | 232 | 18.9k | } | 233 | | | 234 | 18.9k | if len >= self.chain_threshold { | 235 | 4.18k | let head = v.head(); | 236 | | | 237 | | // Encode the frame head to the buffer | 238 | 4.18k | head.encode(len, self.buf.get_mut()); | 239 | | | 240 | 4.18k | if self.buf.get_ref().remaining() < self.chain_threshold { | 241 | 2.47k | let extra_bytes = self.chain_threshold - self.buf.remaining(); | 242 | 2.47k | self.buf.get_mut().put(v.payload_mut().take(extra_bytes)); | 243 | 2.47k | } | 244 | | | 245 | | // Save the data frame | 246 | 4.18k | self.next = Some(Next::Data(v)); | 247 | | } else { | 248 | 14.7k | v.encode_chunk(self.buf.get_mut()); | 249 | | | 250 | | // The chunk has been fully encoded, so there is no need to | 251 | | // keep it around | 252 | 14.7k | assert_eq!(v.payload().remaining(), 0, "chunk not fully encoded"); | 253 | | | 254 | | // Save off the last frame... | 255 | 14.7k | self.last_data_frame = Some(v); | 256 | | } | 257 | | } | 258 | 236k | Frame::Headers(v) => { | 259 | 236k | let mut buf = limited_write_buf!(self); | 260 | 236k | if let Some(continuation) = v.encode(&mut self.hpack, &mut buf) { | 261 | 0 | self.next = Some(Next::Continuation(continuation)); | 262 | 236k | } | 263 | | } | 264 | 0 | Frame::PushPromise(v) => { | 265 | 0 | let mut buf = limited_write_buf!(self); | 266 | 0 | if let Some(continuation) = v.encode(&mut self.hpack, &mut buf) { | 267 | 0 | self.next = Some(Next::Continuation(continuation)); | 268 | 0 | } | 269 | | } | 270 | 18.3k | Frame::Settings(v) => { | 271 | 18.3k | v.encode(self.buf.get_mut()); | 272 | 18.3k | tracing::trace!(rem = self.buf.remaining(), "encoded settings"); | 273 | | } | 274 | 6.66k | Frame::GoAway(v) => { | 275 | 6.66k | v.encode(self.buf.get_mut()); | 276 | 6.66k | tracing::trace!(rem = self.buf.remaining(), "encoded go_away"); | 277 | | } | 278 | 473 | Frame::Ping(v) => { | 279 | 473 | v.encode(self.buf.get_mut()); | 280 | 473 | tracing::trace!(rem = self.buf.remaining(), "encoded ping"); | 281 | | } | 282 | 48 | Frame::WindowUpdate(v) => { | 283 | 48 | v.encode(self.buf.get_mut()); | 284 | 48 | tracing::trace!(rem = self.buf.remaining(), "encoded window_update"); | 285 | | } | 286 | | | 287 | | Frame::Priority(_) => { | 288 | | /* | 289 | | v.encode(self.buf.get_mut()); | 290 | | tracing::trace!("encoded priority; rem={:?}", self.buf.remaining()); | 291 | | */ | 292 | 0 | unimplemented!(); | 293 | | } | 294 | 7.42k | Frame::Reset(v) => { | 295 | 7.42k | v.encode(self.buf.get_mut()); | 296 | 7.42k | tracing::trace!(rem = self.buf.remaining(), "encoded reset"); | 297 | | } | 298 | | } | 299 | | | 300 | 288k | Ok(()) | 301 | 288k | } |
|
302 | | |
303 | 1.42M | fn has_capacity(&self) -> bool { |
304 | 1.42M | self.next.is_none() |
305 | 953k | && (self.buf.get_ref().capacity() - self.buf.get_ref().len() |
306 | 953k | >= self.min_buffer_capacity) |
307 | 1.42M | } Unexecuted instantiation: <h2::codec::framed_write::Encoder<_>>::has_capacity <h2::codec::framed_write::Encoder<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::has_capacity Line | Count | Source | 303 | 863 | fn has_capacity(&self) -> bool { | 304 | 863 | self.next.is_none() | 305 | 863 | && (self.buf.get_ref().capacity() - self.buf.get_ref().len() | 306 | 863 | >= self.min_buffer_capacity) | 307 | 863 | } |
<h2::codec::framed_write::Encoder<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::has_capacity Line | Count | Source | 303 | 1.42M | fn has_capacity(&self) -> bool { | 304 | 1.42M | self.next.is_none() | 305 | 952k | && (self.buf.get_ref().capacity() - self.buf.get_ref().len() | 306 | 952k | >= self.min_buffer_capacity) | 307 | 1.42M | } |
|
308 | | |
309 | 693k | fn is_empty(&self) -> bool { |
310 | 484k | match self.next { |
311 | 484k | Some(Next::Data(ref frame)) => !frame.payload().has_remaining(), |
312 | 208k | _ => !self.buf.has_remaining(), |
313 | | } |
314 | 693k | } Unexecuted instantiation: <h2::codec::framed_write::Encoder<_>>::is_empty <h2::codec::framed_write::Encoder<bytes::bytes::Bytes>>::is_empty Line | Count | Source | 309 | 863 | fn is_empty(&self) -> bool { | 310 | 0 | match self.next { | 311 | 0 | Some(Next::Data(ref frame)) => !frame.payload().has_remaining(), | 312 | 863 | _ => !self.buf.has_remaining(), | 313 | | } | 314 | 863 | } |
<h2::codec::framed_write::Encoder<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::is_empty Line | Count | Source | 309 | 692k | fn is_empty(&self) -> bool { | 310 | 484k | match self.next { | 311 | 484k | Some(Next::Data(ref frame)) => !frame.payload().has_remaining(), | 312 | 207k | _ => !self.buf.has_remaining(), | 313 | | } | 314 | 692k | } |
|
315 | | } |
316 | | |
317 | | impl<B> Encoder<B> { |
318 | 449k | fn max_frame_size(&self) -> usize { |
319 | 449k | self.max_frame_size as usize |
320 | 449k | } Unexecuted instantiation: <h2::codec::framed_write::Encoder<_>>::max_frame_size Unexecuted instantiation: <h2::codec::framed_write::Encoder<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::max_frame_size Unexecuted instantiation: <h2::codec::framed_write::Encoder<bytes::bytes::Bytes>>::max_frame_size <h2::codec::framed_write::Encoder<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::max_frame_size Line | Count | Source | 318 | 449k | fn max_frame_size(&self) -> usize { | 319 | 449k | self.max_frame_size as usize | 320 | 449k | } |
|
321 | | } |
322 | | |
323 | | impl<T, B> FramedWrite<T, B> { |
324 | | /// Returns the max frame size that can be sent |
325 | 194k | pub fn max_frame_size(&self) -> usize { |
326 | 194k | self.encoder.max_frame_size() |
327 | 194k | } Unexecuted instantiation: <h2::codec::framed_write::FramedWrite<_, _>>::max_frame_size <h2::codec::framed_write::FramedWrite<fuzz_e2e::MockIo, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::max_frame_size Line | Count | Source | 325 | 194k | pub fn max_frame_size(&self) -> usize { | 326 | 194k | self.encoder.max_frame_size() | 327 | 194k | } |
|
328 | | |
329 | | /// Set the peer's max frame size. |
330 | 155 | pub fn set_max_frame_size(&mut self, val: usize) { |
331 | 155 | assert!(val <= frame::MAX_MAX_FRAME_SIZE as usize); |
332 | 155 | self.encoder.max_frame_size = val as FrameSize; |
333 | 155 | } Unexecuted instantiation: <h2::codec::framed_write::FramedWrite<_, _>>::set_max_frame_size <h2::codec::framed_write::FramedWrite<fuzz_e2e::MockIo, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::set_max_frame_size Line | Count | Source | 330 | 155 | pub fn set_max_frame_size(&mut self, val: usize) { | 331 | 155 | assert!(val <= frame::MAX_MAX_FRAME_SIZE as usize); | 332 | 155 | self.encoder.max_frame_size = val as FrameSize; | 333 | 155 | } |
|
334 | | |
335 | | /// Set the peer's header table size. |
336 | 1.61k | pub fn set_header_table_size(&mut self, val: usize) { |
337 | 1.61k | self.encoder.hpack.update_max_size(val); |
338 | 1.61k | } Unexecuted instantiation: <h2::codec::framed_write::FramedWrite<_, _>>::set_header_table_size <h2::codec::framed_write::FramedWrite<fuzz_e2e::MockIo, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::set_header_table_size Line | Count | Source | 336 | 1.61k | pub fn set_header_table_size(&mut self, val: usize) { | 337 | 1.61k | self.encoder.hpack.update_max_size(val); | 338 | 1.61k | } |
|
339 | | |
340 | | /// Retrieve the last data frame that has been sent |
341 | 633k | pub fn take_last_data_frame(&mut self) -> Option<frame::Data<B>> { |
342 | 633k | self.encoder.last_data_frame.take() |
343 | 633k | } Unexecuted instantiation: <h2::codec::framed_write::FramedWrite<_, _>>::take_last_data_frame <h2::codec::framed_write::FramedWrite<fuzz_e2e::MockIo, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::take_last_data_frame Line | Count | Source | 341 | 633k | pub fn take_last_data_frame(&mut self) -> Option<frame::Data<B>> { | 342 | 633k | self.encoder.last_data_frame.take() | 343 | 633k | } |
|
344 | | |
345 | 863 | pub fn get_mut(&mut self) -> &mut T { |
346 | 863 | &mut self.inner |
347 | 863 | } Unexecuted instantiation: <h2::codec::framed_write::FramedWrite<_, _>>::get_mut <h2::codec::framed_write::FramedWrite<h2_support::mock::Pipe, bytes::bytes::Bytes>>::get_mut Line | Count | Source | 345 | 863 | pub fn get_mut(&mut self) -> &mut T { | 346 | 863 | &mut self.inner | 347 | 863 | } |
|
348 | | } |
349 | | |
350 | | impl<T: AsyncRead + Unpin, B> AsyncRead for FramedWrite<T, B> { |
351 | 678k | fn poll_read( |
352 | 678k | mut self: Pin<&mut Self>, |
353 | 678k | cx: &mut Context<'_>, |
354 | 678k | buf: &mut ReadBuf, |
355 | 678k | ) -> Poll<io::Result<()>> { |
356 | 678k | Pin::new(&mut self.inner).poll_read(cx, buf) |
357 | 678k | } Unexecuted instantiation: <h2::codec::framed_write::FramedWrite<_, _> as tokio::io::async_read::AsyncRead>::poll_read Unexecuted instantiation: <h2::codec::framed_write::FramedWrite<h2_support::mock::Pipe, bytes::bytes::Bytes> as tokio::io::async_read::AsyncRead>::poll_read <h2::codec::framed_write::FramedWrite<fuzz_e2e::MockIo, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>> as tokio::io::async_read::AsyncRead>::poll_read Line | Count | Source | 351 | 678k | fn poll_read( | 352 | 678k | mut self: Pin<&mut Self>, | 353 | 678k | cx: &mut Context<'_>, | 354 | 678k | buf: &mut ReadBuf, | 355 | 678k | ) -> Poll<io::Result<()>> { | 356 | 678k | Pin::new(&mut self.inner).poll_read(cx, buf) | 357 | 678k | } |
|
358 | | } |
359 | | |
360 | | // We never project the Pin to `B`. |
361 | | impl<T: Unpin, B> Unpin for FramedWrite<T, B> {} |
362 | | |
363 | | #[cfg(feature = "unstable")] |
364 | | mod unstable { |
365 | | use super::*; |
366 | | |
367 | | impl<T, B> FramedWrite<T, B> { |
368 | 0 | pub fn get_ref(&self) -> &T { |
369 | 0 | &self.inner |
370 | 0 | } |
371 | | } |
372 | | } |