Skip to content

Commit

Permalink
fix: Remove content-encoding header from already decompressed respons…
Browse files Browse the repository at this point in the history
…es (#54)

When the `compress` flag is set to true, the fetch implementation sends an Accept-Encoding header and decompresses the response.

However, the decompressed body is put into a `Response` that still has a `Content-Encoding` that no longer matches the actual encoding of the body.

This causes issues if this `Response` object is used downstream (i.e. sent back to a browser), and there is another attempt to decode the body based on the content-encoding header.

Co-authored-by: Jacob Ebey <jacob.ebey@live.com>
  • Loading branch information
benbrandt and jacob-ebey committed Feb 14, 2024
1 parent 6ce472d commit 822a3c3
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/dirty-moles-exercise.md
@@ -0,0 +1,5 @@
---
"@remix-run/web-fetch": patch
---

fix: Remove content-encoding header from already decompressed responses. This eases the use of fetch in senarios where you wish to use it as a sort of makeshift proxy.
3 changes: 3 additions & 0 deletions packages/fetch/src/fetch.js
Expand Up @@ -277,6 +277,7 @@ async function fetch(url, options_ = {}) {

// For gzip
if (codings === 'gzip' || codings === 'x-gzip') {
responseOptions.headers.delete("Content-Encoding");
body = pump(body, zlib.createGunzip(zlibOptions), reject);
response = new Response(fromAsyncIterable(body), responseOptions);
resolve(response);
Expand All @@ -285,6 +286,7 @@ async function fetch(url, options_ = {}) {

// For deflate
if (codings === 'deflate' || codings === 'x-deflate') {
responseOptions.headers.delete("Content-Encoding");
// Handle the infamous raw deflate response from old servers
// a hack for old IIS and Apache servers
const raw = pump(response_, new PassThrough(), reject);
Expand All @@ -304,6 +306,7 @@ async function fetch(url, options_ = {}) {

// For br
if (codings === 'br') {
responseOptions.headers.delete("Content-Encoding");
body = pump(body, zlib.createBrotliDecompress(), reject);
response = new Response(fromAsyncIterable(body), responseOptions);
resolve(response);
Expand Down
8 changes: 6 additions & 2 deletions packages/fetch/test/main.js
Expand Up @@ -818,6 +818,7 @@ describe("node-fetch", () => {
const url = `${base}gzip`;
return fetch(url).then((res) => {
expect(res.headers.get("content-type")).to.equal("text/plain");
expect(res.headers.get("content-encoding")).to.be.null;
return res.text().then((result) => {
expect(result).to.be.a("string");
expect(result).to.equal("hello world");
Expand All @@ -836,10 +837,9 @@ describe("node-fetch", () => {
});
});

it("should make capitalised Content-Encoding lowercase", () => {
it("should decompress capitalised Content-Encoding", () => {
const url = `${base}gzip-capital`;
return fetch(url).then((res) => {
expect(res.headers.get("content-encoding")).to.equal("gzip");
return res.text().then((result) => {
expect(result).to.be.a("string");
expect(result).to.equal("hello world");
Expand All @@ -851,6 +851,7 @@ describe("node-fetch", () => {
const url = `${base}deflate`;
return fetch(url).then((res) => {
expect(res.headers.get("content-type")).to.equal("text/plain");
expect(res.headers.get("content-encoding")).to.be.null;
return res.text().then((result) => {
expect(result).to.be.a("string");
expect(result).to.equal("hello world");
Expand All @@ -877,6 +878,7 @@ describe("node-fetch", () => {
const url = `${base}brotli`;
return fetch(url).then((res) => {
expect(res.headers.get("content-type")).to.equal("text/plain");
expect(res.headers.get("content-encoding")).to.be.null;
return res.text().then((result) => {
expect(result).to.be.a("string");
expect(result).to.equal("hello world");
Expand Down Expand Up @@ -906,6 +908,7 @@ describe("node-fetch", () => {
const url = `${base}sdch`;
return fetch(url).then((res) => {
expect(res.headers.get("content-type")).to.equal("text/plain");
expect(res.headers.get("content-encoding")).to.equal("sdch");
return res.text().then((result) => {
expect(result).to.be.a("string");
expect(result).to.equal("fake sdch string");
Expand Down Expand Up @@ -957,6 +960,7 @@ describe("node-fetch", () => {
};
return fetch(url, options).then((res) => {
expect(res.headers.get("content-type")).to.equal("text/plain");
expect(res.headers.get("content-encoding")).to.equal("gzip");
return res.text().then((result) => {
expect(result).to.be.a("string");
expect(result).to.not.equal("hello world");
Expand Down

0 comments on commit 822a3c3

Please sign in to comment.