diff --git a/.github/funding.yml b/.github/funding.yml deleted file mode 100644 index 66956b3..0000000 --- a/.github/funding.yml +++ /dev/null @@ -1,4 +0,0 @@ -github: sindresorhus -open_collective: sindresorhus -custom: https://sindresorhus.com/donate -tidelift: npm/decompress-response diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3b8aa86..6cb6898 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,8 +14,8 @@ jobs: - 14 - 12 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - run: npm install diff --git a/index.d.ts b/index.d.ts index cd3e045..8791de8 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,12 +1,12 @@ -import {IncomingMessage, IncomingHttpHeaders} from 'node:http'; +import {type IncomingMessage, type IncomingHttpHeaders} from 'node:http'; -export interface UncompressedIncomingHttpHeaders extends IncomingHttpHeaders { +export type UncompressedIncomingHttpHeaders = { 'content-encoding'?: never; -} +} & IncomingHttpHeaders; -export interface UncompressedIncomingMessage extends IncomingMessage { +export type UncompressedIncomingMessage = { headers: UncompressedIncomingHttpHeaders; -} +} & IncomingMessage; /** Decompress a HTTP response if needed. diff --git a/index.js b/index.js index bc57fd8..c5fb6ac 100644 --- a/index.js +++ b/index.js @@ -9,9 +9,11 @@ export default function decompressResponse(response) { return response; } - delete response.headers['content-encoding']; - let isEmpty = true; + let finalStream = new PassThroughStream(); + + // Clone headers to avoid modifying the original response headers + const headers = {...response.headers}; function handleContentEncoding(data) { const decompressStream = contentEncoding === 'br' @@ -51,7 +53,7 @@ export default function decompressResponse(response) { }, }); - const finalStream = new PassThroughStream({ + finalStream = new PassThroughStream({ autoDestroy: false, destroy(error, callback) { response.destroy(); @@ -60,6 +62,10 @@ export default function decompressResponse(response) { }, }); + delete headers['content-encoding']; + delete headers['content-length']; + finalStream.headers = headers; + mimicResponse(response, finalStream); response.pipe(checker); diff --git a/index.test-d.ts b/index.test-d.ts index 84c2629..7aee3fe 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -1,7 +1,7 @@ -import http from 'node:http'; +import http, {type IncomingMessage} from 'node:http'; import {expectType} from 'tsd'; -import decompressResponse, {UncompressedIncomingMessage} from './index.js'; +import decompressResponse, {type UncompressedIncomingMessage} from './index.js'; -http.get('localhost', response => { +http.get('localhost', (response: IncomingMessage) => { expectType(decompressResponse(response)); }); diff --git a/package.json b/package.json index e7157a7..1fa37d5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "decompress-response", - "version": "8.1.0", + "version": "9.0.0", "description": "Decompress a HTTP response if needed", "license": "MIT", "repository": "sindresorhus/decompress-response", @@ -11,9 +11,13 @@ "url": "https://sindresorhus.com" }, "type": "module", - "exports": "./index.js", + "exports": { + "types": "./index.d.ts", + "default": "./index.js" + }, + "sideEffects": false, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "scripts": { "test": "xo && ava && tsd" @@ -43,12 +47,11 @@ "mimic-response": "^4.0.0" }, "devDependencies": { - "@types/node": "^16.11.6", - "ava": "^3.15.0", - "get-stream": "^6.0.1", - "pify": "^5.0.0", - "tsd": "^0.18.0", - "typescript": "^4.4.4", - "xo": "^0.45.0" + "@types/node": "^20.12.12", + "ava": "^6.1.3", + "get-stream": "^8.0.1", + "pify": "^6.1.0", + "tsd": "^0.31.0", + "xo": "^0.58.0" } } diff --git a/readme.md b/readme.md index 033538a..7fa68f6 100644 --- a/readme.md +++ b/readme.md @@ -34,15 +34,3 @@ Returns the decompressed HTTP response stream. Type: [`http.IncomingMessage`](https://nodejs.org/api/http.html#http_class_http_incomingmessage) The HTTP incoming stream with compressed data. - ---- - -
- - Get professional support for this package with a Tidelift subscription - -
- - Tidelift helps make open source sustainable for maintainers while giving companies
assurances about security, maintenance, and licensing for their dependencies. -
-
diff --git a/test/test.js b/test/test.js index 68998f7..0a67ae3 100644 --- a/test/test.js +++ b/test/test.js @@ -24,14 +24,14 @@ test.before('setup', async () => { server.on('/deflate', async (request, response) => { response.statusCode = 200; - response.setHeader('content-encoding-type', 'text/plain'); + response.setHeader('content-type', 'text/plain'); response.setHeader('content-encoding', 'deflate'); response.end(await zlibP.deflate(fixture)); }); server.on('/deflateRaw', async (request, response) => { response.statusCode = 200; - response.setHeader('content-encoding-type', 'text/plain'); + response.setHeader('content-type', 'text/plain'); response.setHeader('content-encoding', 'deflate'); response.end(await zlibP.deflateRaw(fixture)); }); @@ -45,9 +45,10 @@ test.before('setup', async () => { server.on('/missing-data', async (request, response) => { response.statusCode = 200; - response.setHeader('content-encoding-type', 'text/plain'); + response.setHeader('content-type', 'text/plain'); response.setHeader('content-encoding', 'gzip'); - response.end((await zlibP.gzip(fixture)).slice(0, -1)); + const gzipped = await zlibP.gzip(fixture); + response.end(gzipped.slice(0, -1)); }); server.on('/non-compressed', async (request, response) => { @@ -153,3 +154,17 @@ test('passthrough on non-compressed data', async t => { t.is(await getStream(response), fixture); }); + +test('original response retains content-encoding and content-length headers', async t => { + const originalResponse = await httpGetP(server.url); + const decompressedResponse = decompressResponse(originalResponse); + + t.is(originalResponse.headers['content-encoding'], 'gzip'); + t.truthy(originalResponse.headers['content-length']); + t.is(decompressedResponse.headers['content-encoding'], undefined); + t.is(decompressedResponse.headers['content-length'], undefined); + + decompressedResponse.setEncoding('utf8'); + + t.is(await getStream(decompressedResponse), fixture); +});