Skip to main content

rama_http/layer/decompression/
layer.rs

1use super::{Decompression, service::DefaultDecompressionMatcher};
2use crate::headers::encoding::AcceptEncoding;
3use rama_core::Layer;
4
5/// Decompresses response bodies of the underlying service.
6///
7/// This adds the `Accept-Encoding` header to requests and transparently decompresses response
8/// bodies based on the `Content-Encoding` header.
9///
10/// See the [module docs](crate::layer::decompression) for more details.
11#[derive(Debug, Clone)]
12pub struct DecompressionLayer<M = DefaultDecompressionMatcher> {
13    accept: AcceptEncoding,
14    insert_accept_encoding_header: bool,
15    tolerate_decode_errors: bool,
16    matcher: M,
17}
18
19impl<M: Default> Default for DecompressionLayer<M> {
20    fn default() -> Self {
21        Self {
22            accept: Default::default(),
23            insert_accept_encoding_header: true,
24            tolerate_decode_errors: false,
25            matcher: Default::default(),
26        }
27    }
28}
29
30impl<S, M> Layer<S> for DecompressionLayer<M>
31where
32    M: Clone,
33{
34    type Service = Decompression<S, M>;
35
36    fn layer(&self, service: S) -> Self::Service {
37        Decompression {
38            inner: service,
39            accept: self.accept,
40            insert_accept_encoding_header: self.insert_accept_encoding_header,
41            tolerate_decode_errors: self.tolerate_decode_errors,
42            matcher: self.matcher.clone(),
43        }
44    }
45}
46
47impl DecompressionLayer {
48    /// Creates a new `DecompressionLayer`.
49    #[must_use]
50    pub fn new() -> Self {
51        Default::default()
52    }
53}
54
55impl<M> DecompressionLayer<M> {
56    rama_utils::macros::generate_set_and_with! {
57        /// Sets whether the layer inserts `Accept-Encoding` into requests when it is absent.
58        ///
59        /// By default it is `true`.
60        pub fn insert_accept_encoding_header(mut self, insert: bool) -> Self {
61            self.insert_accept_encoding_header = insert;
62            self
63        }
64    }
65
66    /// Replaces the request/response decompression matcher.
67    ///
68    /// The default matcher [`DefaultDecompressionMatcher`]
69    /// matches any response which has a response payload to be decompressed.
70    pub fn with_matcher<T>(self, matcher: T) -> DecompressionLayer<T> {
71        DecompressionLayer {
72            accept: self.accept,
73            insert_accept_encoding_header: self.insert_accept_encoding_header,
74            tolerate_decode_errors: self.tolerate_decode_errors,
75            matcher,
76        }
77    }
78
79    rama_utils::macros::generate_set_and_with! {
80        /// End a response body cleanly on a mid-stream decode error (after some
81        /// data decoded) instead of surfacing the error. Off by default.
82        ///
83        /// Intended for relays that decode → modify → re-encode a response (e.g. a
84        /// MITM HTML rewriter): a truncated upstream body then yields a short-but-
85        /// well-formed client stream rather than an aborted one.
86        pub fn tolerate_decode_errors(mut self, tolerate: bool) -> Self {
87            self.tolerate_decode_errors = tolerate;
88            self
89        }
90    }
91
92    rama_utils::macros::generate_set_and_with! {
93        /// Sets whether to request the gzip encoding.
94        pub fn gzip(mut self, enable: bool) -> Self {
95            self.accept.set_gzip(enable);
96            self
97        }
98    }
99
100    rama_utils::macros::generate_set_and_with! {
101        /// Sets whether to request the Deflate encoding.
102        pub fn deflate(mut self, enable: bool) -> Self {
103            self.accept.set_deflate(enable);
104            self
105        }
106    }
107
108    rama_utils::macros::generate_set_and_with! {
109        /// Sets whether to request the Brotli encoding.
110        pub fn br(mut self, enable: bool) -> Self {
111            self.accept.set_br(enable);
112            self
113        }
114    }
115
116    rama_utils::macros::generate_set_and_with! {
117        /// Sets whether to request the Zstd encoding.
118        pub fn zstd(mut self, enable: bool) -> Self {
119            self.accept.set_zstd(enable);
120            self
121        }
122    }
123}