aboutsummaryrefslogtreecommitdiff
path: root/src/https.rs
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2021-12-10 16:40:05 +0100
committerAlex Auvolat <alex@adnab.me>2021-12-10 16:40:05 +0100
commit7488d8e907dadc3e91c8c8920fdc38f42c455b50 (patch)
treef679eee16671411aaf423dfc62f9b11c5812de22 /src/https.rs
parente3a030ceafb960ac378edbb8be9659c964ead0d8 (diff)
downloadtricot-7488d8e907dadc3e91c8c8920fdc38f42c455b50.tar.gz
tricot-7488d8e907dadc3e91c8c8920fdc38f42c455b50.zip
Exclude partial content from compression
Diffstat (limited to 'src/https.rs')
-rw-r--r--src/https.rs60
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))
}