From 037e46bb51d67210f4928cad4dd12df3dee1fe05 Mon Sep 17 00:00:00 2001 From: Aaron O'Mullan Date: Tue, 17 May 2022 14:02:45 +0200 Subject: [PATCH] fix(ext/http): skip auto-compression if content-encoding present (#14641) Regression from #14552 --- cli/tests/unit/http_test.ts | 58 +++++++++++++++++++++++++++++++++++++ ext/http/lib.rs | 3 ++ 2 files changed, 61 insertions(+) diff --git a/cli/tests/unit/http_test.ts b/cli/tests/unit/http_test.ts index 3f9141470a..2a4b7df010 100644 --- a/cli/tests/unit/http_test.ts +++ b/cli/tests/unit/http_test.ts @@ -1978,6 +1978,64 @@ Deno.test({ }, }); +Deno.test({ + name: "http server custom content-encoding is left untouched", + permissions: { net: true, run: true }, + async fn() { + const hostname = "localhost"; + const port = 4501; + let contentLength: string; + + async function server() { + const listener = Deno.listen({ hostname, port }); + const tcpConn = await listener.accept(); + const httpConn = Deno.serveHttp(tcpConn); + const e = await httpConn.nextRequest(); + assert(e); + const { request, respondWith } = e; + assertEquals(request.headers.get("Accept-Encoding"), "deflate, gzip"); + const body = new Uint8Array([3, 1, 4, 1]); + contentLength = String(body.length); + const response = new Response( + body, + { + headers: { + "content-length": contentLength, + "content-encoding": "arbitrary", + }, + }, + ); + await respondWith(response); + httpConn.close(); + listener.close(); + } + + async function client() { + const url = `http://${hostname}:${port}/`; + const cmd = [ + "curl", + "-i", + "--request", + "GET", + "--url", + url, + // "--compressed", // Windows curl does not support --compressed + "--header", + "Accept-Encoding: deflate, gzip", + ]; + const proc = Deno.run({ cmd, stdout: "piped", stderr: "null" }); + const status = await proc.status(); + assert(status.success); + const output = decoder.decode(await proc.output()); + assert(output.includes("vary: Accept-Encoding\r\n")); + assert(output.includes("content-encoding: arbitrary\r\n")); + proc.close(); + } + + await Promise.all([server(), client()]); + }, +}); + Deno.test("upgradeHttp tcp", async () => { async function client() { const tcpConn = await Deno.connect({ port: 4501 }); diff --git a/ext/http/lib.rs b/ext/http/lib.rs index edc4c1e836..42211105d6 100644 --- a/ext/http/lib.rs +++ b/ext/http/lib.rs @@ -680,8 +680,11 @@ fn should_compress(headers: &hyper::HeaderMap) -> bool { // indicates the contents of the body were negotiated based directly // with the user code and we can't compress the response let content_range = headers.contains_key(hyper::header::CONTENT_RANGE); + // assume body is already compressed if Content-Encoding header present, thus avoid recompressing + let is_precompressed = headers.contains_key(hyper::header::CONTENT_ENCODING); !content_range + && !is_precompressed && !cache_control_no_transform(headers).unwrap_or_default() && headers .get(hyper::header::CONTENT_TYPE)