xitca_web/middleware/
compress.rs1use crate::service::Service;
4
5#[derive(Clone)]
20pub struct Compress;
21
22impl<S, E> Service<Result<S, E>> for Compress {
23 type Response = service::CompressService<S>;
24 type Error = E;
25
26 async fn call(&self, res: Result<S, E>) -> Result<Self::Response, Self::Error> {
27 res.map(service::CompressService)
28 }
29}
30mod service {
31 use http_encoding::{Coder, ContentEncoding};
32
33 use crate::{
34 body::{BodyStream, SizeHint},
35 http::{BorrowReq, WebResponse, header::HeaderMap},
36 service::{Service, ready::ReadyService},
37 };
38
39 pub struct CompressService<S>(pub(super) S);
40
41 impl<S, Req, ResB> Service<Req> for CompressService<S>
42 where
43 Req: BorrowReq<HeaderMap>,
44 S: Service<Req, Response = WebResponse<ResB>>,
45 ResB: BodyStream,
46 {
47 type Response = WebResponse<Coder<ResB>>;
48 type Error = S::Error;
49
50 async fn call(&self, req: Req) -> Result<Self::Response, Self::Error> {
51 let mut encoding = ContentEncoding::from_headers(req.borrow());
52 let res = self.0.call(req).await?;
53
54 match res.body().size_hint() {
56 SizeHint::Exact(size) if size < 64 => encoding = ContentEncoding::Identity,
57 SizeHint::None => encoding = ContentEncoding::Identity,
58 _ => {}
59 }
60
61 Ok(encoding.try_encode(res))
62 }
63 }
64
65 impl<S> ReadyService for CompressService<S>
66 where
67 S: ReadyService,
68 {
69 type Ready = S::Ready;
70
71 #[inline]
72 async fn ready(&self) -> Self::Ready {
73 self.0.ready().await
74 }
75 }
76}
77
78#[cfg(test)]
79mod test {
80 use xitca_unsafe_collection::futures::NowOrPanic;
81
82 use crate::{App, handler::handler_service, http::WebRequest};
83
84 use super::*;
85
86 #[test]
87 fn build() {
88 async fn noop() -> &'static str {
89 "noop"
90 }
91
92 App::new()
93 .at("/", handler_service(noop))
94 .enclosed(Compress)
95 .finish()
96 .call(())
97 .now_or_panic()
98 .unwrap()
99 .call(WebRequest::default())
100 .now_or_panic()
101 .ok()
102 .unwrap();
103 }
104}