http_response_compression/
service.rs

1use crate::codec::Codec;
2use crate::future::ResponseFuture;
3use http::Request;
4use std::task::{Context, Poll};
5use tower::Service;
6
7/// A Tower service that compresses HTTP response bodies.
8#[derive(Debug, Clone)]
9pub struct CompressionService<S> {
10    inner: S,
11    min_size: usize,
12}
13
14impl<S> CompressionService<S> {
15    /// Creates a new compression service wrapping the given inner service.
16    pub fn new(inner: S, min_size: usize) -> Self {
17        Self { inner, min_size }
18    }
19
20    /// Returns a reference to the inner service.
21    pub fn inner(&self) -> &S {
22        &self.inner
23    }
24
25    /// Returns a mutable reference to the inner service.
26    pub fn inner_mut(&mut self) -> &mut S {
27        &mut self.inner
28    }
29
30    /// Consumes this service, returning the inner service.
31    pub fn into_inner(self) -> S {
32        self.inner
33    }
34}
35
36impl<S, ReqBody, ResBody> Service<Request<ReqBody>> for CompressionService<S>
37where
38    S: Service<Request<ReqBody>, Response = http::Response<ResBody>>,
39{
40    type Response = http::Response<crate::body::CompressionBody<ResBody>>;
41    type Error = S::Error;
42    type Future = ResponseFuture<S::Future>;
43
44    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
45        self.inner.poll_ready(cx)
46    }
47
48    fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
49        // Extract accepted codec from Accept-Encoding header
50        let accepted_codec = req
51            .headers()
52            .get(http::header::ACCEPT_ENCODING)
53            .and_then(|v| v.to_str().ok())
54            .and_then(Codec::from_accept_encoding);
55
56        let inner = self.inner.call(req);
57
58        ResponseFuture::new(inner, accepted_codec, self.min_size)
59    }
60}