Search for duplicate issues
Issue scope
Other: on-the-fly compression (compression)
Describe the bug
With compression = true (the default), a response compressed on the fly for Accept-Encoding: deflate is sent with Content-Encoding: deflate, but its body is a raw DEFLATE stream (RFC 1951). The HTTP deflate content coding is the zlib format (RFC 1950): a 2-byte header (0x78 ..), the DEFLATE data and an Adler-32 checksum (RFC 9110, section 8.4.1.2).
Cause: src/compression.rs uses async_compression::tokio::bufread::DeflateEncoder, which writes raw DEFLATE, instead of ZlibEncoder:
|
use async_compression::tokio::bufread::DeflateEncoder; |
|
let body = crate::body::stream(ReaderStream::new(DeflateEncoder::with_quality( |
|
StreamReader::new(body.into_data_stream()), |
|
level, |
|
))); |
Low severity: browsers and curl accept raw DEFLATE for deflate as a legacy workaround, and they normally prefer gzip, br or zstd anyway. Strict zlib decoders (for example Python's zlib.decompress or other HTTP client libraries) fail on the body.
How to reproduce it
mkdir public
for i in $(seq 50); do echo 'body { color: red; }'; done > public/main.css
docker run --rm -d --name sws-deflate -p 8787:8787 -v "$PWD/public:/public:ro" \
joseluisq/static-web-server:3.0.0-beta.1 --root /public
curl -sS -o body.bin -D - -H 'Accept-Encoding: deflate' http://127.0.0.1:8787/main.css | grep -iE '^(HTTP|content-encoding)'
head -c 16 body.bin | xxd
python3 -c '
import zlib
d = open("body.bin", "rb").read()
try:
zlib.decompress(d); print("zlib (RFC 1950): ok")
except zlib.error as e:
print("zlib (RFC 1950):", e)
print("raw DEFLATE (RFC 1951):", len(zlib.decompress(d, -15)), "bytes")
'
Observed:
HTTP/1.1 200 OK
content-encoding: deflate
00000000: edc8 b10d 0020 0804 c0de 297e 0edd 06b1 ..... ....)~....
zlib (RFC 1950): Error -3 while decompressing data: incorrect header check
raw DEFLATE (RFC 1951): 1050 bytes
Expected behavior
The body of a Content-Encoding: deflate response is a zlib stream: it starts with 0x78 and decodes with a zlib decoder.
Complementary information
Suggested fix: use async_compression::tokio::bufread::ZlibEncoder (the zlib feature of async-compression) for deflate, as tower-http and actix-web do. The 2.x branch has the same encoder (src/compression.rs, DeflateEncoder).
Pre-compressed files (compression-static) are a separate issue, #761.
Build target
Docker linux/arm64
Environment and specs
Search for duplicate issues
Issue scope
Other: on-the-fly compression (
compression)Describe the bug
With
compression = true(the default), a response compressed on the fly forAccept-Encoding: deflateis sent withContent-Encoding: deflate, but its body is a raw DEFLATE stream (RFC 1951). The HTTPdeflatecontent coding is the zlib format (RFC 1950): a 2-byte header (0x78 ..), the DEFLATE data and an Adler-32 checksum (RFC 9110, section 8.4.1.2).Cause:
src/compression.rsusesasync_compression::tokio::bufread::DeflateEncoder, which writes raw DEFLATE, instead ofZlibEncoder:static-web-server/src/compression.rs
Line 14 in 66b1288
static-web-server/src/compression.rs
Lines 231 to 234 in 66b1288
Low severity: browsers and curl accept raw DEFLATE for
deflateas a legacy workaround, and they normally prefergzip,brorzstdanyway. Strict zlib decoders (for example Python'szlib.decompressor other HTTP client libraries) fail on the body.How to reproduce it
Observed:
Expected behavior
The body of a
Content-Encoding: deflateresponse is a zlib stream: it starts with0x78and decodes with a zlib decoder.Complementary information
Suggested fix: use
async_compression::tokio::bufread::ZlibEncoder(thezlibfeature ofasync-compression) fordeflate, as tower-http and actix-web do. The2.xbranch has the same encoder (src/compression.rs,DeflateEncoder).Pre-compressed files (
compression-static) are a separate issue, #761.Build target
Docker linux/arm64
Environment and specs
joseluisq/static-web-server:3.0.0-beta.1, digestsha256:6e453304835955e47fc62dce4ff7050c707bce2d82b5f9f4687ba588df81bebd) andmaster66b1288zlib