tower_http/decompression/request/
future.rs1use crate::body::UnsyncBoxBody;
2use crate::compression_utils::AcceptEncoding;
3use crate::BoxError;
4use bytes::Buf;
5use http::{header, HeaderValue, Response, StatusCode};
6use http_body::Body;
7use http_body_util::BodyExt;
8use http_body_util::Empty;
9use pin_project_lite::pin_project;
10use std::future::Future;
11use std::pin::Pin;
12use std::task::Context;
13use std::task::Poll;
14
15pin_project! {
16 #[derive(Debug)]
17 pub struct RequestDecompressionFuture<F, B, E>
19 where
20 F: Future<Output = Result<Response<B>, E>>,
21 B: Body
22 {
23 #[pin]
24 kind: Kind<F, B, E>,
25 }
26}
27
28pin_project! {
29 #[derive(Debug)]
30 #[project = StateProj]
31 enum Kind<F, B, E>
32 where
33 F: Future<Output = Result<Response<B>, E>>,
34 B: Body
35 {
36 Inner {
37 #[pin]
38 fut: F
39 },
40 Unsupported {
41 #[pin]
42 accept: AcceptEncoding
43 },
44 }
45}
46
47impl<F, B, E> RequestDecompressionFuture<F, B, E>
48where
49 F: Future<Output = Result<Response<B>, E>>,
50 B: Body,
51{
52 #[must_use]
53 pub(super) fn unsupported_encoding(accept: AcceptEncoding) -> Self {
54 Self {
55 kind: Kind::Unsupported { accept },
56 }
57 }
58
59 #[must_use]
60 pub(super) fn inner(fut: F) -> Self {
61 Self {
62 kind: Kind::Inner { fut },
63 }
64 }
65}
66
67impl<F, B, E> Future for RequestDecompressionFuture<F, B, E>
68where
69 F: Future<Output = Result<Response<B>, E>>,
70 B: Body + Send + 'static,
71 B::Data: Buf + 'static,
72 B::Error: Into<BoxError> + 'static,
73{
74 type Output = Result<Response<UnsyncBoxBody<B::Data, BoxError>>, E>;
75
76 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
77 match self.project().kind.project() {
78 StateProj::Inner { fut } => fut.poll(cx).map_ok(|res| {
79 res.map(|body| UnsyncBoxBody::new(body.map_err(Into::into).boxed_unsync()))
80 }),
81 StateProj::Unsupported { accept } => {
82 let res = Response::builder()
83 .header(
84 header::ACCEPT_ENCODING,
85 accept
86 .to_header_value()
87 .unwrap_or(HeaderValue::from_static("identity")),
88 )
89 .status(StatusCode::UNSUPPORTED_MEDIA_TYPE)
90 .body(UnsyncBoxBody::new(
91 Empty::new().map_err(Into::into).boxed_unsync(),
92 ))
93 .unwrap();
94 Poll::Ready(Ok(res))
95 }
96 }
97 }
98}