h3/client/stream.rs
1use bytes::Buf;
2use futures_util::future;
3use http::{HeaderMap, Response};
4use quic::StreamId;
5#[cfg(feature = "tracing")]
6use tracing::instrument;
7
8use crate::{
9 connection::{self},
10 error::{
11 connection_error_creators::{CloseStream, HandleFrameStreamErrorOnRequestStream},
12 internal_error::InternalConnectionError,
13 Code, StreamError,
14 },
15 proto::{frame::Frame, headers::Header},
16 qpack,
17 quic::{self},
18 shared_state::{ConnectionState, SharedState},
19};
20use std::{
21 convert::TryFrom,
22 task::{Context, Poll},
23};
24
25/// Manage request bodies transfer, response and trailers.
26///
27/// Once a request has been sent via [`crate::client::SendRequest::send_request()`], a response can be awaited by calling
28/// [`RequestStream::recv_response()`]. A body for this request can be sent with [`RequestStream::send_data()`], then the request
29/// shall be completed by either sending trailers with [`RequestStream::finish()`].
30///
31/// After receiving the response's headers, it's body can be read by [`RequestStream::recv_data()`] until it returns
32/// `None`. Then the trailers will eventually be available via [`RequestStream::recv_trailers()`].
33///
34/// TODO: If data is polled before the response has been received, an error will be thrown.
35///
36/// TODO: If trailers are polled but the body hasn't been fully received, an UNEXPECT_FRAME error will be
37/// thrown
38///
39/// Whenever the client wants to cancel this request, it can call [`RequestStream::stop_sending()`], which will
40/// put an end to any transfer concerning it.
41///
42/// # Examples
43///
44/// ```rust
45/// # use h3::{quic, client::*};
46/// # use http::{Request, Response};
47/// # use bytes::Buf;
48/// # use tokio::io::AsyncWriteExt;
49/// # async fn doc<T,B>(mut req_stream: RequestStream<T, B>) -> Result<(), Box<dyn std::error::Error>>
50/// # where
51/// # T: quic::RecvStream,
52/// # {
53/// // Prepare the HTTP request to send to the server
54/// let request = Request::get("https://www.example.com/").body(())?;
55///
56/// // Receive the response
57/// let response = req_stream.recv_response().await?;
58/// // Receive the body
59/// while let Some(mut chunk) = req_stream.recv_data().await? {
60/// let mut out = tokio::io::stdout();
61/// out.write_all_buf(&mut chunk).await?;
62/// out.flush().await?;
63/// }
64/// # Ok(())
65/// # }
66/// # pub fn main() {}
67/// ```
68///
69/// [`send_request()`]: struct.SendRequest.html#method.send_request
70/// [`recv_response()`]: #method.recv_response
71/// [`recv_data()`]: #method.recv_data
72/// [`send_data()`]: #method.send_data
73/// [`send_trailers()`]: #method.send_trailers
74/// [`recv_trailers()`]: #method.recv_trailers
75/// [`finish()`]: #method.finish
76/// [`stop_sending()`]: #method.stop_sending
77pub struct RequestStream<S, B> {
78 pub(super) inner: connection::RequestStream<S, B>,
79}
80
81impl<S, B> ConnectionState for RequestStream<S, B> {
82 fn shared_state(&self) -> &SharedState {
83 &self.inner.conn_state
84 }
85}
86
87impl<S, B> CloseStream for RequestStream<S, B> {}
88
89impl<S, B> RequestStream<S, B>
90where
91 S: quic::RecvStream,
92{
93 /// Receive the HTTP/3 response
94 ///
95 /// This should be called before trying to receive any data with [`recv_data()`].
96 ///
97 /// [`recv_data()`]: #method.recv_data
98 #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))]
99 pub async fn recv_response(&mut self) -> Result<Response<()>, StreamError> {
100 let mut frame = future::poll_fn(|cx| self.inner.stream.poll_next(cx))
101 .await
102 .map_err(|e| self.handle_frame_stream_error_on_request_stream(e))?
103 .ok_or_else(|| {
104 //= https://www.rfc-editor.org/rfc/rfc9114#section-4.1
105 //# Receipt of an invalid sequence of frames MUST be treated as a
106 //# connection error of type H3_FRAME_UNEXPECTED.
107 self.handle_connection_error_on_stream(InternalConnectionError::new(
108 Code::H3_FRAME_UNEXPECTED,
109 "Stream finished without receiving response headers".to_string(),
110 ))
111 })?;
112
113 //= https://www.rfc-editor.org/rfc/rfc9114#section-7.2.5
114 //= type=TODO
115 //# A client MUST treat
116 //# receipt of a PUSH_PROMISE frame that contains a larger push ID than
117 //# the client has advertised as a connection error of H3_ID_ERROR.
118
119 //= https://www.rfc-editor.org/rfc/rfc9114#section-7.2.5
120 //= type=TODO
121 //# If a client
122 //# receives a push ID that has already been promised and detects a
123 //# mismatch, it MUST respond with a connection error of type
124 //# H3_GENERAL_PROTOCOL_ERROR.
125
126 let decoded = if let Frame::Headers(ref mut encoded) = frame {
127 match qpack::decode_stateless(encoded, self.inner.max_field_section_size) {
128 //= https://www.rfc-editor.org/rfc/rfc9114#section-4.2.2
129 //# An HTTP/3 implementation MAY impose a limit on the maximum size of
130 //# the message header it will accept on an individual HTTP message.
131 Err(qpack::DecoderError::HeaderTooLong(cancel_size)) => {
132 self.inner.stop_sending(Code::H3_REQUEST_CANCELLED);
133 return Err(StreamError::HeaderTooBig {
134 actual_size: cancel_size,
135 max_size: self.inner.max_field_section_size,
136 });
137 }
138 Ok(decoded) => decoded,
139 Err(_e) => {
140 return Err(
141 self.handle_connection_error_on_stream(InternalConnectionError {
142 code: Code::QPACK_DECOMPRESSION_FAILED,
143 message: "Failed to decode headers".to_string(),
144 }),
145 )
146 }
147 }
148 } else {
149 //= https://www.rfc-editor.org/rfc/rfc9114#section-4.1
150 //# Receipt of an invalid sequence of frames MUST be treated as a
151 //# connection error of type H3_FRAME_UNEXPECTED.
152
153 return Err(
154 self.handle_connection_error_on_stream(InternalConnectionError::new(
155 Code::H3_FRAME_UNEXPECTED,
156 "First response frame is not headers".to_string(),
157 )),
158 );
159 };
160
161 let qpack::Decoded { fields, .. } = decoded;
162
163 let (status, headers) = Header::try_from(fields)
164 .map_err(|_e| {
165 self.inner.stream.stop_sending(Code::H3_REQUEST_CANCELLED);
166 StreamError::StreamError {
167 code: Code::H3_MESSAGE_ERROR,
168 reason: "Received malformed header".to_string(),
169 }
170 })?
171 .into_response_parts()
172 .map_err(|_e| {
173 self.inner.stream.stop_sending(Code::H3_REQUEST_CANCELLED);
174 StreamError::StreamError {
175 code: Code::H3_MESSAGE_ERROR,
176 reason: "Received malformed header".to_string(),
177 }
178 })?;
179 let mut resp = Response::new(());
180 *resp.status_mut() = status;
181 *resp.headers_mut() = headers;
182 *resp.version_mut() = http::Version::HTTP_3;
183
184 Ok(resp)
185 }
186
187 /// Receive some of the request body.
188 // TODO what if called before recv_response ?
189 #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))]
190 pub async fn recv_data(&mut self) -> Result<Option<impl Buf>, StreamError> {
191 future::poll_fn(|cx| self.poll_recv_data(cx)).await
192 }
193
194 /// Receive request body
195 pub fn poll_recv_data(
196 &mut self,
197 cx: &mut Context<'_>,
198 ) -> Poll<Result<Option<impl Buf>, StreamError>> {
199 self.inner.poll_recv_data(cx)
200 }
201
202 /// Receive an optional set of trailers for the response.
203 #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))]
204 pub async fn recv_trailers(&mut self) -> Result<Option<HeaderMap>, StreamError> {
205 future::poll_fn(|cx| self.poll_recv_trailers(cx)).await
206 }
207
208 /// Poll receive an optional set of trailers for the response.
209 #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))]
210 pub fn poll_recv_trailers(
211 &mut self,
212 cx: &mut Context<'_>,
213 ) -> Poll<Result<Option<HeaderMap>, StreamError>> {
214 let res = self.inner.poll_recv_trailers(cx);
215 if let Poll::Ready(Err(e)) = &res {
216 if let StreamError::HeaderTooBig { .. } = e {
217 self.inner.stream.stop_sending(Code::H3_REQUEST_CANCELLED);
218 }
219 }
220 res
221 }
222
223 /// Tell the peer to stop sending into the underlying QUIC stream
224 #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))]
225 pub fn stop_sending(&mut self, error_code: Code) {
226 // TODO take by value to prevent any further call as this request is cancelled
227 // rename `cancel()` ?
228 self.inner.stream.stop_sending(error_code)
229 }
230
231 /// Returns the underlying stream id
232 pub fn id(&self) -> StreamId {
233 self.inner.stream.id()
234 }
235}
236
237impl<S, B> RequestStream<S, B>
238where
239 S: quic::SendStream<B>,
240 B: Buf,
241{
242 /// Send some data on the request body.
243 #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))]
244 pub async fn send_data(&mut self, buf: B) -> Result<(), StreamError> {
245 self.inner.send_data(buf).await
246 }
247
248 /// Stop a stream with an error code
249 ///
250 /// The code can be [`Code::H3_NO_ERROR`].
251 pub fn stop_stream(&mut self, error_code: Code) {
252 self.inner.stop_stream(error_code);
253 }
254
255 /// Send a set of trailers to end the request.
256 ///
257 /// [`RequestStream::finish()`] must be called to finalize a request.
258 #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))]
259 pub async fn send_trailers(&mut self, trailers: HeaderMap) -> Result<(), StreamError> {
260 self.inner.send_trailers(trailers).await
261 }
262
263 /// End the request without trailers.
264 ///
265 /// [`RequestStream::finish()`] must be called to finalize a request.
266 #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))]
267 pub async fn finish(&mut self) -> Result<(), StreamError> {
268 self.inner.finish().await
269 }
270
271 //= https://www.rfc-editor.org/rfc/rfc9114#section-4.1.1
272 //= type=TODO
273 //# Implementations SHOULD cancel requests by abruptly terminating any
274 //# directions of a stream that are still open. To do so, an
275 //# implementation resets the sending parts of streams and aborts reading
276 //# on the receiving parts of streams; see Section 2.4 of
277 //# [QUIC-TRANSPORT].
278}
279
280impl<S, B> RequestStream<S, B>
281where
282 S: quic::BidiStream<B>,
283 B: Buf,
284{
285 /// Split this stream into two halves that can be driven independently.
286 pub fn split(
287 self,
288 ) -> (
289 RequestStream<S::SendStream, B>,
290 RequestStream<S::RecvStream, B>,
291 ) {
292 let (send, recv) = self.inner.split();
293 (RequestStream { inner: send }, RequestStream { inner: recv })
294 }
295}