From b3e9ef244a7542cdc9f6975fdc183b263bd6f305 Mon Sep 17 00:00:00 2001 From: Nathan Friedly Date: Wed, 20 Dec 2023 15:17:28 -0500 Subject: [PATCH] WIP Brotli support may be related to https://github.com/nfriedly/node-unblocker/issues/243 --- lib/decompress.js | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/lib/decompress.js b/lib/decompress.js index 7f25fc37..3ddbb50f 100644 --- a/lib/decompress.js +++ b/lib/decompress.js @@ -5,14 +5,26 @@ var zlib = require("zlib"); var contentTypes = require("./content-types.js"); var debug = require("debug")("unblocker:decompress"); +const SUPPORTED_ENCODINGS = [ + 'deflate', + 'gzip', + 'br' // brotli +]; + +const REQUESTED_ENCODINGS = [ + // deflate is tricky, so we don't request it + 'gzip', + 'br' +] + module.exports = function (config) { function acceptableCompression(data) { - // deflate is tricky so we're only going to ask for gzip if the client allows it - if ( - data.headers["accept-encoding"] && - data.headers["accept-encoding"].includes("gzip") - ) { - data.headers["accept-encoding"] = "gzip"; + var encodings = (data.headers["accept-encoding"] || '') + .split(',') + .map(s => s.trim()) + .filter(s => REQUESTED_ENCODINGS.includes(s)); + if (encodings.length) { + data.headers["accept-encoding"] = encodings.join(', '); } else { delete data.headers["accept-encoding"]; } @@ -31,11 +43,8 @@ module.exports = function (config) { return false; } - // decompress if it's gzipped or deflate'd - return ( - headers["content-encoding"] == "gzip" || - headers["content-encoding"] == "deflate" - ); + // decompress if it's in a supported encoding + return SUPPORTED_ENCODINGS.includes(headers["content-encoding"]); } function decompressResponse(data) { @@ -54,6 +63,11 @@ module.exports = function (config) { var placeHolder = new PassThrough(); data.stream = placeHolder; + const encoding = data.headers["content-encoding"]; + + // we're decoding it here, so this won't by the time it gets to the client + delete data.headers["content-encoding"]; + var handleData = function handleData() { var firstChunk = sourceStream.read(); @@ -65,11 +79,13 @@ module.exports = function (config) { } var decompressStream; - if (data.headers["content-encoding"] == "deflate") { + if (encoding == "deflate") { // https://github.com/nfriedly/node-unblocker/issues/12 // inflateRaw seems to work here wheras inflate and unzip do not. // todo: validate this against other sites - if some require raw and others require non-raw, then maybe just rewrite the accept-encoding header to gzip only decompressStream = zlib.createInflateRaw(); + } else if (encoding == 'br') { + decompressStream = zlib.createBrotliDecompress(); } else { decompressStream = zlib.createUnzip(); } @@ -83,7 +99,6 @@ module.exports = function (config) { // if we do get data, create a decompression stream and pipe through it sourceStream.once("readable", handleData); - delete data.headers["content-encoding"]; } }