From 7488d8e907dadc3e91c8c8920fdc38f42c455b50 Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Fri, 10 Dec 2021 16:40:05 +0100 Subject: [PATCH] Exclude partial content from compression --- src/cert_store.rs | 8 +++---- src/https.rs | 60 +++++++++++++++++++++++++++-------------------- 2 files changed, 39 insertions(+), 29 deletions(-) diff --git a/src/cert_store.rs b/src/cert_store.rs index 2095660..c272759 100644 --- a/src/cert_store.rs +++ b/src/cert_store.rs @@ -93,7 +93,7 @@ impl CertStore { for dom in domains.iter() { match t_last_check.get(dom) { - Some(t) if Instant::now() - *t < Duration::from_secs(3600) => continue, + Some(t) if Instant::now() - *t < Duration::from_secs(60) => continue, _ => t_last_check.insert(dom.to_string(), Instant::now()), }; @@ -179,7 +179,7 @@ impl CertStore { } // ---- Acquire lock ---- - // the lock is acquired for fifteen minutes, + // the lock is acquired for half an hour, // so that in case of an error we won't retry before // that delay expires @@ -190,8 +190,8 @@ impl CertStore { .create_session(&ConsulSessionRequest { name: lock_name.clone(), node: None, - lock_delay: Some("15m".into()), - ttl: Some("30m".into()), + lock_delay: Some("30m".into()), + ttl: Some("45m".into()), behavior: Some("delete".into()), }) .await?; 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, + method: Method, accept_encoding: Vec<(Option, f32)>, https_config: &HttpsConfig, ) -> Result> { + // 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)) }