tower_http/decompression/
service.rs

1use super::{DecompressionBody, DecompressionLayer, ResponseFuture};
2use crate::compression_utils::AcceptEncoding;
3use http::{
4    header::{self, ACCEPT_ENCODING},
5    Request, Response,
6};
7use http_body::Body;
8use std::task::{Context, Poll};
9use tower_service::Service;
10
11/// Decompresses response bodies of the underlying service.
12///
13/// This adds the `Accept-Encoding` header to requests and transparently decompresses response
14/// bodies based on the `Content-Encoding` header.
15///
16/// See the [module docs](crate::decompression) for more details.
17#[derive(Debug, Clone)]
18pub struct Decompression<S> {
19    pub(crate) inner: S,
20    pub(crate) accept: AcceptEncoding,
21}
22
23impl<S> Decompression<S> {
24    /// Creates a new `Decompression` wrapping the `service`.
25    pub fn new(service: S) -> Self {
26        Self {
27            inner: service,
28            accept: AcceptEncoding::default(),
29        }
30    }
31
32    define_inner_service_accessors!();
33
34    /// Returns a new [`Layer`] that wraps services with a `Decompression` middleware.
35    ///
36    /// [`Layer`]: tower_layer::Layer
37    pub fn layer() -> DecompressionLayer {
38        DecompressionLayer::new()
39    }
40
41    /// Sets whether to request the gzip encoding.
42    #[cfg(feature = "decompression-gzip")]
43    pub fn gzip(mut self, enable: bool) -> Self {
44        self.accept.set_gzip(enable);
45        self
46    }
47
48    /// Sets whether to request the Deflate encoding.
49    #[cfg(feature = "decompression-deflate")]
50    pub fn deflate(mut self, enable: bool) -> Self {
51        self.accept.set_deflate(enable);
52        self
53    }
54
55    /// Sets whether to request the Brotli encoding.
56    #[cfg(feature = "decompression-br")]
57    pub fn br(mut self, enable: bool) -> Self {
58        self.accept.set_br(enable);
59        self
60    }
61
62    /// Sets whether to request the Zstd encoding.
63    #[cfg(feature = "decompression-zstd")]
64    pub fn zstd(mut self, enable: bool) -> Self {
65        self.accept.set_zstd(enable);
66        self
67    }
68
69    /// Disables the gzip encoding.
70    ///
71    /// This method is available even if the `gzip` crate feature is disabled.
72    pub fn no_gzip(mut self) -> Self {
73        self.accept.set_gzip(false);
74        self
75    }
76
77    /// Disables the Deflate encoding.
78    ///
79    /// This method is available even if the `deflate` crate feature is disabled.
80    pub fn no_deflate(mut self) -> Self {
81        self.accept.set_deflate(false);
82        self
83    }
84
85    /// Disables the Brotli encoding.
86    ///
87    /// This method is available even if the `br` crate feature is disabled.
88    pub fn no_br(mut self) -> Self {
89        self.accept.set_br(false);
90        self
91    }
92
93    /// Disables the Zstd encoding.
94    ///
95    /// This method is available even if the `zstd` crate feature is disabled.
96    pub fn no_zstd(mut self) -> Self {
97        self.accept.set_zstd(false);
98        self
99    }
100}
101
102impl<S, ReqBody, ResBody> Service<Request<ReqBody>> for Decompression<S>
103where
104    S: Service<Request<ReqBody>, Response = Response<ResBody>>,
105    ResBody: Body,
106{
107    type Response = Response<DecompressionBody<ResBody>>;
108    type Error = S::Error;
109    type Future = ResponseFuture<S::Future>;
110
111    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
112        self.inner.poll_ready(cx)
113    }
114
115    fn call(&mut self, mut req: Request<ReqBody>) -> Self::Future {
116        if let header::Entry::Vacant(entry) = req.headers_mut().entry(ACCEPT_ENCODING) {
117            if let Some(accept) = self.accept.to_header_value() {
118                entry.insert(accept);
119            }
120        }
121
122        ResponseFuture {
123            inner: self.inner.call(req),
124            accept: self.accept,
125        }
126    }
127}