tower_http/decompression/
mod.rs1mod request;
95
96mod body;
97mod future;
98mod layer;
99mod service;
100
101pub use self::{
102 body::DecompressionBody, future::ResponseFuture, layer::DecompressionLayer,
103 service::Decompression,
104};
105
106pub use self::request::future::RequestDecompressionFuture;
107pub use self::request::layer::RequestDecompressionLayer;
108pub use self::request::service::RequestDecompression;
109
110#[cfg(test)]
111mod tests {
112 use std::convert::Infallible;
113 use std::io::Write;
114
115 use super::*;
116 use crate::test_helpers::Body;
117 use crate::{compression::Compression, test_helpers::WithTrailers};
118 use http::Response;
119 use http::{HeaderMap, HeaderName, Request};
120 use http_body_util::BodyExt;
121 use tower::{service_fn, Service, ServiceExt};
122
123 #[tokio::test]
124 async fn works() {
125 let mut client = Decompression::new(Compression::new(service_fn(handle)));
126
127 let req = Request::builder()
128 .header("accept-encoding", "gzip")
129 .body(Body::empty())
130 .unwrap();
131 let res = client.ready().await.unwrap().call(req).await.unwrap();
132
133 let body = res.into_body();
135 let collected = body.collect().await.unwrap();
136 let trailers = collected.trailers().cloned().unwrap();
137 let decompressed_data = String::from_utf8(collected.to_bytes().to_vec()).unwrap();
138
139 assert_eq!(decompressed_data, "Hello, World!");
140
141 assert_eq!(trailers["foo"], "bar");
143 }
144
145 async fn handle(_req: Request<Body>) -> Result<Response<WithTrailers<Body>>, Infallible> {
146 let mut trailers = HeaderMap::new();
147 trailers.insert(HeaderName::from_static("foo"), "bar".parse().unwrap());
148 let body = Body::from("Hello, World!").with_trailers(trailers);
149 Ok(Response::builder().body(body).unwrap())
150 }
151
152 #[tokio::test]
153 async fn decompress_multi_zstd() {
154 let mut client = Decompression::new(service_fn(handle_multi_zstd));
155
156 let req = Request::builder()
157 .header("accept-encoding", "zstd")
158 .body(Body::empty())
159 .unwrap();
160 let res = client.ready().await.unwrap().call(req).await.unwrap();
161
162 let body = res.into_body();
164 let decompressed_data =
165 String::from_utf8(body.collect().await.unwrap().to_bytes().to_vec()).unwrap();
166
167 assert_eq!(decompressed_data, "Hello, World!");
168 }
169
170 async fn handle_multi_zstd(_req: Request<Body>) -> Result<Response<Body>, Infallible> {
171 let mut buf = Vec::new();
172 let mut enc1 = zstd::Encoder::new(&mut buf, Default::default()).unwrap();
173 enc1.write_all(b"Hello, ").unwrap();
174 enc1.finish().unwrap();
175
176 let mut enc2 = zstd::Encoder::new(&mut buf, Default::default()).unwrap();
177 enc2.write_all(b"World!").unwrap();
178 enc2.finish().unwrap();
179
180 let mut res = Response::new(Body::from(buf));
181 res.headers_mut()
182 .insert("content-encoding", "zstd".parse().unwrap());
183 Ok(res)
184 }
185
186 #[allow(dead_code)]
187 async fn is_compatible_with_hyper() {
188 let client =
189 hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new())
190 .build_http();
191 let mut client = Decompression::new(client);
192
193 let req = Request::new(Body::empty());
194
195 let _: Response<DecompressionBody<_>> =
196 client.ready().await.unwrap().call(req).await.unwrap();
197 }
198
199 #[tokio::test]
200 async fn decompress_empty() {
201 let mut client = Decompression::new(Compression::new(service_fn(handle_empty)));
202
203 let req = Request::builder()
204 .header("accept-encoding", "gzip")
205 .body(Body::empty())
206 .unwrap();
207 let res = client.ready().await.unwrap().call(req).await.unwrap();
208
209 let body = res.into_body();
210 let decompressed_data =
211 String::from_utf8(body.collect().await.unwrap().to_bytes().to_vec()).unwrap();
212
213 assert_eq!(decompressed_data, "");
214 }
215
216 async fn handle_empty(_req: Request<Body>) -> Result<Response<Body>, Infallible> {
217 let mut res = Response::new(Body::empty());
218 res.headers_mut()
219 .insert("content-encoding", "gzip".parse().unwrap());
220 Ok(res)
221 }
222
223 #[tokio::test]
224 async fn decompress_empty_with_trailers() {
225 let mut client =
226 Decompression::new(Compression::new(service_fn(handle_empty_with_trailers)));
227
228 let req = Request::builder()
229 .header("accept-encoding", "gzip")
230 .body(Body::empty())
231 .unwrap();
232 let res = client.ready().await.unwrap().call(req).await.unwrap();
233
234 let body = res.into_body();
235 let collected = body.collect().await.unwrap();
236 let trailers = collected.trailers().cloned().unwrap();
237 let decompressed_data = String::from_utf8(collected.to_bytes().to_vec()).unwrap();
238
239 assert_eq!(decompressed_data, "");
240 assert_eq!(trailers["foo"], "bar");
241 }
242
243 async fn handle_empty_with_trailers(
244 _req: Request<Body>,
245 ) -> Result<Response<WithTrailers<Body>>, Infallible> {
246 let mut trailers = HeaderMap::new();
247 trailers.insert(HeaderName::from_static("foo"), "bar".parse().unwrap());
248 let body = Body::empty().with_trailers(trailers);
249 Ok(Response::builder()
250 .header("content-encoding", "gzip")
251 .body(body)
252 .unwrap())
253 }
254}