1use std::error::Error;
20use std::fmt;
21use std::io::{self};
22use std::pin::Pin;
23
24use async_compression::tokio::bufread::{BrotliDecoder, GzipDecoder, ZlibDecoder, ZstdDecoder};
25use bytes::Bytes;
26use futures::stream::Peekable;
27use futures::task::{Context, Poll};
28use futures::{Future, Stream};
29use futures_util::StreamExt;
30use headers::{ContentLength, HeaderMapExt};
31use http_body_util::BodyExt;
32use hyper::Response;
33use hyper::body::Body;
34use hyper::header::{CONTENT_ENCODING, HeaderValue, TRANSFER_ENCODING};
35use tokio_util::codec::{BytesCodec, FramedRead};
36use tokio_util::io::StreamReader;
37
38use crate::connector::BoxedBody;
39
40pub const DECODER_BUFFER_SIZE: usize = 8192;
41
42#[derive(Debug)]
44pub struct BodyStreamError(pub Box<dyn Error + Send + Sync>);
45
46impl fmt::Display for BodyStreamError {
47 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
48 self.0.fmt(f)
49 }
50}
51
52impl Error for BodyStreamError {
53 fn source(&self) -> Option<&(dyn Error + 'static)> {
54 Some(self.0.as_ref())
55 }
56}
57
58pub fn map_decode_error(err: io::Error) -> io::Error {
61 if err.kind() == io::ErrorKind::InvalidData {
62 return err;
63 }
64
65 let mut source: Option<&(dyn Error + 'static)> = err.get_ref().map(|e| e as _);
66 while let Some(e) = source {
67 if e.is::<BodyStreamError>() {
68 return err;
69 }
70
71 source = match e.downcast_ref::<io::Error>() {
72 Some(io_error) => io_error.get_ref().map(|e| e as _),
73 None => e.source(),
74 };
75 }
76 io::Error::new(io::ErrorKind::InvalidData, err)
77}
78
79pub struct Decoder {
83 inner: Inner,
84}
85
86#[derive(PartialEq)]
87enum DecoderType {
88 Gzip,
89 Brotli,
90 Deflate,
91 Zstd,
92}
93
94enum Inner {
95 PlainText(BodyStream),
97 Gzip(FramedRead<GzipDecoder<StreamReader<Peekable<BodyStream>, Bytes>>, BytesCodec>),
99 Deflate(FramedRead<ZlibDecoder<StreamReader<Peekable<BodyStream>, Bytes>>, BytesCodec>),
101 Brotli(FramedRead<BrotliDecoder<StreamReader<Peekable<BodyStream>, Bytes>>, BytesCodec>),
103 Zstd(FramedRead<ZstdDecoder<StreamReader<Peekable<BodyStream>, Bytes>>, BytesCodec>),
105 Pending(Pending),
107}
108
109struct Pending {
111 body: Peekable<BodyStream>,
112 type_: DecoderType,
113}
114
115impl fmt::Debug for Decoder {
116 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
117 f.debug_struct("Decoder").finish()
118 }
119}
120
121impl Decoder {
122 #[inline]
126 fn plain_text(
127 body: BoxedBody,
128 is_secure_scheme: bool,
129 content_length: Option<ContentLength>,
130 ) -> Decoder {
131 Decoder {
132 inner: Inner::PlainText(BodyStream::new(body, is_secure_scheme, content_length)),
133 }
134 }
135
136 #[inline]
140 fn pending(
141 body: BoxedBody,
142 type_: DecoderType,
143 is_secure_scheme: bool,
144 content_length: Option<ContentLength>,
145 ) -> Decoder {
146 Decoder {
147 inner: Inner::Pending(Pending {
148 body: BodyStream::new(body, is_secure_scheme, content_length).peekable(),
149 type_,
150 }),
151 }
152 }
153
154 pub fn detect(response: Response<BoxedBody>, is_secure_scheme: bool) -> Response<Decoder> {
161 let values = response
162 .headers()
163 .get_all(CONTENT_ENCODING)
164 .iter()
165 .chain(response.headers().get_all(TRANSFER_ENCODING).iter());
166 let decoder = values.fold(None, |acc, enc| {
167 acc.or_else(|| {
168 if enc == HeaderValue::from_static("gzip") {
169 Some(DecoderType::Gzip)
170 } else if enc == HeaderValue::from_static("br") {
171 Some(DecoderType::Brotli)
172 } else if enc == HeaderValue::from_static("deflate") {
173 Some(DecoderType::Deflate)
174 } else if enc == HeaderValue::from_static("zstd") {
175 Some(DecoderType::Zstd)
176 } else {
177 None
178 }
179 })
180 });
181 let content_length = response.headers().typed_get::<ContentLength>();
182 match decoder {
183 Some(type_) => {
184 response.map(|r| Decoder::pending(r, type_, is_secure_scheme, content_length))
185 },
186 None => response.map(|r| Decoder::plain_text(r, is_secure_scheme, content_length)),
187 }
188 }
189}
190
191impl Stream for Decoder {
192 type Item = Result<Bytes, io::Error>;
193
194 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
195 match self.inner {
197 Inner::Pending(ref mut future) => match futures_core::ready!(Pin::new(future).poll(cx))
198 {
199 Ok(inner) => {
200 self.inner = inner;
201 self.poll_next(cx)
202 },
203 Err(e) => Poll::Ready(Some(Err(e))),
204 },
205 Inner::PlainText(ref mut body) => Pin::new(body).poll_next(cx),
206 Inner::Gzip(ref mut decoder) => {
207 match futures_core::ready!(Pin::new(decoder).poll_next(cx)) {
208 Some(Ok(bytes)) => Poll::Ready(Some(Ok(bytes.freeze()))),
209 Some(Err(err)) => Poll::Ready(Some(Err(map_decode_error(err)))),
210 None => Poll::Ready(None),
211 }
212 },
213 Inner::Brotli(ref mut decoder) => {
214 match futures_core::ready!(Pin::new(decoder).poll_next(cx)) {
215 Some(Ok(bytes)) => Poll::Ready(Some(Ok(bytes.freeze()))),
216 Some(Err(err)) => Poll::Ready(Some(Err(map_decode_error(err)))),
217 None => Poll::Ready(None),
218 }
219 },
220 Inner::Deflate(ref mut decoder) => {
221 match futures_core::ready!(Pin::new(decoder).poll_next(cx)) {
222 Some(Ok(bytes)) => Poll::Ready(Some(Ok(bytes.freeze()))),
223 Some(Err(err)) => Poll::Ready(Some(Err(map_decode_error(err)))),
224 None => Poll::Ready(None),
225 }
226 },
227 Inner::Zstd(ref mut decoder) => {
228 match futures_core::ready!(Pin::new(decoder).poll_next(cx)) {
229 Some(Ok(bytes)) => Poll::Ready(Some(Ok(bytes.freeze()))),
230 Some(Err(err)) => Poll::Ready(Some(Err(map_decode_error(err)))),
231 None => Poll::Ready(None),
232 }
233 },
234 }
235 }
236}
237
238impl Future for Pending {
239 type Output = Result<Inner, io::Error>;
240
241 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
242 match futures_core::ready!(Pin::new(&mut self.body).poll_peek(cx)) {
243 Some(Ok(_)) => {
244 },
246 Some(Err(_e)) => {
247 return Poll::Ready(Err(futures_core::ready!(
249 Pin::new(&mut self.body).poll_next(cx)
250 )
251 .expect("just peeked Some")
252 .unwrap_err()));
253 },
254 None => return Poll::Ready(Ok(Inner::PlainText(BodyStream::empty()))),
255 };
256
257 let body = std::mem::replace(&mut self.body, BodyStream::empty().peekable());
258
259 match self.type_ {
260 DecoderType::Brotli => Poll::Ready(Ok(Inner::Brotli(FramedRead::with_capacity(
261 BrotliDecoder::new(StreamReader::new(body)),
262 BytesCodec::new(),
263 DECODER_BUFFER_SIZE,
264 )))),
265 DecoderType::Gzip => Poll::Ready(Ok(Inner::Gzip(FramedRead::with_capacity(
266 GzipDecoder::new(StreamReader::new(body)),
267 BytesCodec::new(),
268 DECODER_BUFFER_SIZE,
269 )))),
270 DecoderType::Deflate => Poll::Ready(Ok(Inner::Deflate(FramedRead::with_capacity(
271 ZlibDecoder::new(StreamReader::new(body)),
272 BytesCodec::new(),
273 DECODER_BUFFER_SIZE,
274 )))),
275 DecoderType::Zstd => Poll::Ready(Ok(Inner::Zstd(FramedRead::with_capacity(
276 ZstdDecoder::new(StreamReader::new(body)),
277 BytesCodec::new(),
278 DECODER_BUFFER_SIZE,
279 )))),
280 }
281 }
282}
283
284struct BodyStream {
285 body: BoxedBody,
286 is_secure_scheme: bool,
287 content_length: Option<ContentLength>,
288 total_read: u64,
289}
290
291impl BodyStream {
292 fn empty() -> Self {
293 BodyStream {
294 body: http_body_util::Empty::new()
295 .map_err(|_| unreachable!())
296 .boxed(),
297 is_secure_scheme: false,
298 content_length: None,
299 total_read: 0,
300 }
301 }
302
303 fn new(body: BoxedBody, is_secure_scheme: bool, content_length: Option<ContentLength>) -> Self {
304 BodyStream {
305 body,
306 is_secure_scheme,
307 content_length,
308 total_read: 0,
309 }
310 }
311}
312
313impl Stream for BodyStream {
314 type Item = Result<Bytes, io::Error>;
315
316 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
317 match futures_core::ready!(Pin::new(&mut self.body).poll_frame(cx)) {
318 Some(Ok(bytes)) => {
319 let Ok(bytes) = bytes.into_data() else {
320 return Poll::Ready(None);
321 };
322 self.total_read += bytes.len() as u64;
323 Poll::Ready(Some(Ok(bytes)))
324 },
325 Some(Err(err)) => {
326 let all_content_read = self.content_length.is_some_and(|c| c.0 == self.total_read);
333 if self.is_secure_scheme && all_content_read {
334 let source = err.source();
335 let is_unexpected_eof = source
336 .and_then(|e| e.downcast_ref::<io::Error>())
337 .is_some_and(|e| e.kind() == io::ErrorKind::UnexpectedEof);
338 if is_unexpected_eof {
339 return Poll::Ready(None);
340 }
341 }
342 Poll::Ready(Some(Err(io::Error::other(BodyStreamError(err.into())))))
343 },
344 None => Poll::Ready(None),
345 }
346 }
347}