From e09485c0003733c43c47c90f21b2251ef52f555f Mon Sep 17 00:00:00 2001 From: Thomas Hebb Date: Thu, 4 Sep 2025 15:04:46 -0400 Subject: [PATCH] Recompute Content-Length on compression Content-Length holds the number of bytes in an HTTP response after encoding and compression. Our compress_response() function breaks that: when the response it's compressing already includes a Content-Length header, it may shorten the body but leave the header unchanged. I noticed this because of #465, since the textual error message proxied from Reddit gets compressed but already has Content-Length. The issue is masked in normal operation because we don't compress the binary image data that Reddit is supposed to return. In debug builds, hyper catches the issue[1] and panics, but in release builds we return a nonconformant HTTP response. Fix the issue by removing the header if we choose to compress, letting hyper compute the new value for us. [1] https://github.com/hyperium/hyper/blob/v0.14.32/src/proto/h1/role.rs#L708-L725 --- src/server.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/server.rs b/src/server.rs index 32b0bd45..de9c7478 100644 --- a/src/server.rs +++ b/src/server.rs @@ -668,8 +668,12 @@ async fn compress_response(req_headers: &HeaderMap, res: &m Ok(compressed) => { // We get here iff the compression was successful. Replace the body // with the compressed payload, and add the appropriate - // Content-Encoding header in the response. - res.headers_mut().insert(header::CONTENT_ENCODING, compressor.to_string().parse().unwrap()); + // Content-Encoding header in the response. Remove any precomputed + // Content-Length, as it will no longer be valid. + let headers = res.headers_mut(); + headers.insert(header::CONTENT_ENCODING, compressor.to_string().parse().unwrap()); + headers.remove(header::CONTENT_LENGTH); + *(res.body_mut()) = Body::from(compressed); }