diff options
author | Alex Auvolat <alex@adnab.me> | 2021-12-10 16:40:05 +0100 |
---|---|---|
committer | Alex Auvolat <alex@adnab.me> | 2021-12-10 16:40:05 +0100 |
commit | 7488d8e907dadc3e91c8c8920fdc38f42c455b50 (patch) | |
tree | f679eee16671411aaf423dfc62f9b11c5812de22 /src/https.rs | |
parent | e3a030ceafb960ac378edbb8be9659c964ead0d8 (diff) | |
download | tricot-7488d8e907dadc3e91c8c8920fdc38f42c455b50.tar.gz tricot-7488d8e907dadc3e91c8c8920fdc38f42c455b50.zip |
Exclude partial content from compression
Diffstat (limited to 'src/https.rs')
-rw-r--r-- | src/https.rs | 60 |
1 files changed, 35 insertions, 25 deletions
diff --git a/src/https.rs b/src/https.rs index 09234ff..a9f2cc1 100644 --- a/src/https.rs +++ b/src/https.rs @@ -10,6 +10,7 @@ use async_compression::tokio::bufread::*; use futures::StreamExt; use futures::TryStreamExt; use http::header::{HeaderName, HeaderValue}; +use http::method::Method; use hyper::server::conn::Http; use hyper::service::service_fn; use hyper::{header, Body, Request, Response, StatusCode}; @@ -164,7 +165,7 @@ async fn handle( info!("{} {} {}", method, response.status().as_u16(), uri); if https_config.enable_compression { - try_compress(response, accept_encoding, &https_config).await + try_compress(response, method, accept_encoding, &https_config).await } else { Ok(response) } @@ -180,9 +181,21 @@ async fn handle( async fn try_compress( response: Response<Body>, + method: Method, accept_encoding: Vec<(Option<Encoding>, f32)>, https_config: &HttpsConfig, ) -> Result<Response<Body>> { + // Don't bother compressing successfull responses for HEAD and PUT (they should have an empty body) + // Don't compress partial content, that would be wierd + // If already compressed, return as is + if (response.status().is_success() && (method == Method::HEAD || method == Method::PUT)) + || response.status() == StatusCode::PARTIAL_CONTENT + || response.headers().get(header::CONTENT_ENCODING).is_some() + { + return Ok(response); + } + + // Select preferred encoding among those proposed in accept_encoding let max_q: f32 = accept_encoding .iter() .max_by_key(|(_, q)| (q * 10000f32) as i64) @@ -208,11 +221,6 @@ async fn try_compress( Some(enc) => enc, }; - // If already compressed, return as is - if response.headers().get(header::CONTENT_ENCODING).is_some() { - return Ok(response); - } - // If content type not in mime types for which to compress, return as is match response.headers().get(header::CONTENT_TYPE) { Some(ct) => { @@ -229,7 +237,7 @@ async fn try_compress( return Ok(response); } } - None => return Ok(response), + None => return Ok(response), // don't compress if unknown mime type }; let (mut head, mut body) = response.into_parts(); @@ -257,34 +265,36 @@ async fn try_compress( let body_rd = StreamReader::new(body.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))); - debug!( + trace!( "Compressing response body as {:?} (at least {} bytes)", - encoding, sum_lengths + encoding, + sum_lengths ); + + // we don't know the compressed content-length so remove that header head.headers.remove(header::CONTENT_LENGTH); - let compressed_body = match encoding { - Encoding::Gzip => { - head.headers - .insert(header::CONTENT_ENCODING, "gzip".parse()?); - Body::wrap_stream(ReaderStream::new(GzipEncoder::new(body_rd))) - } + let (encoding, compressed_body) = match encoding { + Encoding::Gzip => ( + "gzip", + Body::wrap_stream(ReaderStream::new(GzipEncoder::new(body_rd))), + ), // Encoding::Brotli => { // head.headers.insert(header::CONTENT_ENCODING, "br".parse()?); // Body::wrap_stream(ReaderStream::new(BrotliEncoder::new(body_rd))) // } - Encoding::Deflate => { - head.headers - .insert(header::CONTENT_ENCODING, "deflate".parse()?); - Body::wrap_stream(ReaderStream::new(DeflateEncoder::new(body_rd))) - } - Encoding::Zstd => { - head.headers - .insert(header::CONTENT_ENCODING, "zstd".parse()?); - Body::wrap_stream(ReaderStream::new(ZstdEncoder::new(body_rd))) - } + Encoding::Deflate => ( + "deflate", + Body::wrap_stream(ReaderStream::new(DeflateEncoder::new(body_rd))), + ), + Encoding::Zstd => ( + "zstd", + Body::wrap_stream(ReaderStream::new(ZstdEncoder::new(body_rd))), + ), _ => unreachable!(), }; + head.headers + .insert(header::CONTENT_ENCODING, encoding.parse()?); Ok(Response::from_parts(head, compressed_body)) } |