Skip to main content

grpc_core/http2/
send.rs

1//! Outbound header ordering, incremental body scheduling and peer window accounting.
2use super::*;
3
4fn wire_type(kind: FrameType) -> u8 {
5    match kind {
6        FrameType::Data => 0,
7        FrameType::Headers => 1,
8        FrameType::Priority => 2,
9        FrameType::RstStream => 3,
10        FrameType::Settings => 4,
11        FrameType::PushPromise => 5,
12        FrameType::Ping => 6,
13        FrameType::GoAway => 7,
14        FrameType::WindowUpdate => 8,
15        FrameType::Continuation => 9,
16        FrameType::Unknown(value) => value,
17    }
18}
19fn append_frame(out: &mut Vec<u8>, id: i32, kind: FrameType, flags: u8, payload: &[u8]) {
20    let length = (payload.len() as u32).to_be_bytes();
21    out.extend_from_slice(&length[1..]);
22    out.extend_from_slice(&[wire_type(kind), flags]);
23    out.extend_from_slice(&(id as u32).to_be_bytes());
24    out.extend_from_slice(payload);
25}
26impl Http2Session {
27    pub(super) fn queue_frame(&mut self, id: i32, kind: FrameType, flags: u8, payload: &[u8]) {
28        let mut bytes = Vec::with_capacity(9 + payload.len());
29        append_frame(&mut bytes, id, kind, flags, payload);
30        self.outgoing.push_back(Outgoing::Frame {
31            bytes,
32            id,
33            kind,
34            flags,
35        });
36    }
37    fn queue_headers(&mut self, id: i32, fields: &[HeaderField<'_>], end: bool) -> Result<()> {
38        let mut size = 0usize;
39        let fields = fields
40            .iter()
41            .map(|field| {
42                size = size
43                    .saturating_add(field.name.len())
44                    .saturating_add(field.value.len())
45                    .saturating_add(32);
46                let name = std::str::from_utf8(field.name).map_err(|e| error(1, e.to_string()))?;
47                let value =
48                    std::str::from_utf8(field.value).map_err(|e| error(1, e.to_string()))?;
49                Ok((name.to_owned(), value.to_owned()))
50            })
51            .collect::<Result<Vec<_>>>()?;
52        if size > self.peer.max_header_list_size as usize {
53            return Err(error(11, "peer header budget exceeded"));
54        }
55        let mut block = BytesMut::new();
56        self.encoder.encode(&fields, &mut block);
57        self.outgoing.push_back(Outgoing::Headers {
58            id,
59            block: block.as_slice().to_vec(),
60            end,
61        });
62        Ok(())
63    }
64    /// Opens a client stream, retaining the body source until EOF or reset.
65    /// # Errors
66    /// Rejects draining connections, exhausted IDs and peer concurrency limits.
67    pub fn submit_request(
68        &mut self,
69        fields: &[HeaderField<'_>],
70        provider: Option<DataProvider>,
71    ) -> Result<i32> {
72        self.check_live()?;
73        if self.role != Http2Role::Client
74            || self.sent_goaway.is_some()
75            || self.received_goaway.is_some()
76        {
77            return Err(error(7, "connection cannot open another request"));
78        }
79        if self.streams.values().filter(|s| !s.close_emitted).count()
80            >= self.peer.max_concurrent_streams as usize
81        {
82            return Err(error(7, "peer concurrency limit reached"));
83        }
84        let id = self.next_id;
85        let next = id
86            .checked_add(2)
87            .ok_or_else(|| error(7, "stream IDs exhausted"))?;
88        self.queue_headers(id, fields, provider.is_none())?;
89        let mut stream = Stream::new(self.local, self.peer);
90        stream.provider = provider;
91        self.streams.insert(id, stream);
92        self.next_id = next;
93        Ok(id)
94    }
95    /// Queues response headers, with an optional incremental body producer.
96    /// # Errors
97    /// Rejects unknown or closed streams and invalid outgoing headers.
98    pub fn submit_response(
99        &mut self,
100        id: i32,
101        fields: &[HeaderField<'_>],
102        provider: Option<DataProvider>,
103    ) -> Result<()> {
104        self.check_stream_send(id)?;
105        self.queue_headers(id, fields, provider.is_none())?;
106        self.streams
107            .get_mut(&id)
108            .ok_or_else(|| error(5, "unknown stream"))?
109            .provider = provider;
110        Ok(())
111    }
112    /// Queues an informational or final header block with explicit END_STREAM.
113    /// # Errors
114    /// Rejects unknown or closed streams and invalid outgoing headers.
115    pub fn submit_headers(&mut self, flags: u8, id: i32, fields: &[HeaderField<'_>]) -> Result<()> {
116        self.check_stream_send(id)?;
117        self.queue_headers(id, fields, flags & 1 != 0)
118    }
119    /// Queues the final trailer block after the body source has finished.
120    /// # Errors
121    /// Rejects closed streams or a body source that has not reached EOF.
122    pub fn submit_trailer(&mut self, id: i32, fields: &[HeaderField<'_>]) -> Result<()> {
123        self.check_stream_send(id)?;
124        if self.streams[&id].provider.is_some() {
125            return Err(error(1, "body source has not finished"));
126        }
127        self.queue_headers(id, fields, true)
128    }
129    fn check_stream_send(&self, id: i32) -> Result<()> {
130        self.check_live()?;
131        if self
132            .streams
133            .get(&id)
134            .is_none_or(|s| s.local_closed || s.reset)
135        {
136            return Err(error(5, "stream cannot send"));
137        }
138        Ok(())
139    }
140    /// Resumes a body source that returned Deferred.
141    /// # Errors
142    /// Rejects unknown or reset streams.
143    pub fn resume_data(&mut self, id: i32) -> Result<()> {
144        self.check_stream_send(id)?;
145        self.streams
146            .get_mut(&id)
147            .ok_or_else(|| error(5, "unknown stream"))?
148            .deferred = false;
149        Ok(())
150    }
151    /// Queues a reset without discarding previously encoded HPACK context.
152    /// # Errors
153    /// Rejects an unknown stream.
154    pub fn submit_rst_stream(&mut self, id: i32, code: u32) -> Result<()> {
155        let stream = self
156            .streams
157            .get_mut(&id)
158            .ok_or_else(|| error(1, "unknown reset stream"))?;
159        if stream.reset || stream.close_emitted {
160            return Ok(());
161        }
162        stream.provider = None;
163        stream.reset = true;
164        let unconsumed = std::mem::take(&mut stream.unconsumed);
165        self.credit_connection(unconsumed)?;
166        self.queue_frame(id, FrameType::RstStream, 0, &code.to_be_bytes());
167        Ok(())
168    }
169    /// Starts graceful shutdown while allowing accepted streams to finish.
170    /// # Errors
171    /// Rejects invalid boundaries and oversized debug payloads.
172    pub fn submit_goaway(&mut self, last: i32, code: u32, debug: &[u8]) -> Result<()> {
173        if last < 0 || debug.len() + 8 > self.peer.max_frame_size as usize {
174            return Err(error(6, "invalid GOAWAY"));
175        }
176        let last = self.sent_goaway.map_or(last, |old| old.min(last));
177        let mut bytes = Vec::with_capacity(8 + debug.len());
178        bytes.extend_from_slice(&(last as u32).to_be_bytes());
179        bytes.extend_from_slice(&code.to_be_bytes());
180        bytes.extend_from_slice(debug);
181        self.queue_frame(0, FrameType::GoAway, 0, &bytes);
182        self.sent_goaway = Some(last);
183        Ok(())
184    }
185    /// Serializes one queued control/header block or one flow-controlled DATA frame.
186    /// # Errors
187    /// Returns a sticky connection failure or an invalid body-source result.
188    pub fn mem_send(&mut self) -> Result<&[u8]> {
189        self.check_live()?;
190        self.output.clear();
191        if let Some(item) = self.outgoing.pop_front() {
192            self.serialize(item);
193        } else {
194            self.send_body()?;
195        }
196        Ok(&self.output)
197    }
198    fn serialize(&mut self, item: Outgoing) {
199        let (id, kind, flags) = match item {
200            Outgoing::Frame {
201                bytes,
202                id,
203                kind,
204                flags,
205            } => {
206                self.output.extend_from_slice(&bytes);
207                (id, kind, flags)
208            }
209            Outgoing::Headers { id, block, end } => {
210                let max = self.peer.max_frame_size as usize;
211                let total = block.len().max(1).div_ceil(max);
212                if block.is_empty() {
213                    append_frame(
214                        &mut self.output,
215                        id,
216                        FrameType::Headers,
217                        4 | u8::from(end),
218                        &[],
219                    );
220                }
221                for (index, chunk) in block.chunks(max).enumerate() {
222                    let kind = if index == 0 {
223                        FrameType::Headers
224                    } else {
225                        FrameType::Continuation
226                    };
227                    let flags = if index == 0 { u8::from(end) } else { 0 }
228                        | if index + 1 == total { 4 } else { 0 };
229                    append_frame(&mut self.output, id, kind, flags, chunk);
230                }
231                (id, FrameType::Headers, u8::from(end))
232            }
233        };
234        self.events.push_back(SessionEvent::FrameSend {
235            stream_id: id,
236            frame_type: kind,
237            flags,
238        });
239        if kind == FrameType::RstStream {
240            if let Some(stream) = self.streams.get_mut(&id)
241                && !stream.close_emitted
242            {
243                stream.close_emitted = true;
244                let code =
245                    u32::from_be_bytes(self.output[9..13].try_into().expect("reset payload"));
246                self.events.push_back(SessionEvent::StreamClose {
247                    stream_id: id,
248                    error_code: code,
249                });
250            }
251        } else if flags & 1 != 0 && matches!(kind, FrameType::Headers | FrameType::Data) {
252            if let Some(stream) = self.streams.get_mut(&id) {
253                stream.local_closed = true;
254            }
255            self.close_if_complete(id);
256        }
257    }
258    fn send_body(&mut self) -> Result<()> {
259        let ids: Vec<_> = self
260            .streams
261            .range((
262                std::ops::Bound::Excluded(self.last_sent),
263                std::ops::Bound::Unbounded,
264            ))
265            .chain(self.streams.range(..=self.last_sent))
266            .map(|(id, _)| *id)
267            .collect();
268        for id in ids {
269            let stream = self.streams.get_mut(&id).expect("existing stream");
270            if stream.deferred || stream.reset || stream.local_closed {
271                continue;
272            }
273            let Some(provider) = &mut stream.provider else {
274                continue;
275            };
276            let max = self
277                .send_window
278                .min(stream.send_window)
279                .max(0)
280                .min(self.peer.max_frame_size.into()) as usize;
281            let (data, eof, trailers) = match provider.0.read(max) {
282                DataPoll::Copy(bytes) => {
283                    if bytes.len() > max {
284                        return Err(error(2, "body producer exceeded permitted length"));
285                    }
286                    if bytes.is_empty() {
287                        continue;
288                    }
289                    (bytes.to_vec(), false, false)
290                }
291                DataPoll::Deferred => {
292                    stream.deferred = true;
293                    continue;
294                }
295                DataPoll::Eof => (Vec::new(), true, false),
296                DataPoll::EofWithTrailers => (Vec::new(), true, true),
297            };
298            if eof {
299                stream.provider = None;
300            }
301            if trailers {
302                continue;
303            }
304            stream.send_window -= data.len() as i64;
305            self.send_window -= data.len() as i64;
306            let mut bytes = Vec::with_capacity(9 + data.len());
307            append_frame(&mut bytes, id, FrameType::Data, u8::from(eof), &data);
308            self.last_sent = id;
309            self.serialize(Outgoing::Frame {
310                bytes,
311                id,
312                kind: FrameType::Data,
313                flags: u8::from(eof),
314            });
315            break;
316        }
317        Ok(())
318    }
319}