diff --git a/src/RequestExecutor/HttpRequestExecutor.spec.ts b/src/RequestExecutor/HttpRequestExecutor.spec.ts index a30ae437..eecc3b7b 100644 --- a/src/RequestExecutor/HttpRequestExecutor.spec.ts +++ b/src/RequestExecutor/HttpRequestExecutor.spec.ts @@ -234,6 +234,29 @@ describe('HttpRequestExecutor', () => { expect(response.body).toEqual(expected); }); + it('should prevent decoding response body if decompress option is disabled', async () => { + when(spiedExecutorOptions.maxContentLength).thenReturn(1); + when(spiedExecutorOptions.whitelistMimes).thenReturn(['text/plain']); + const { request, requestOptions } = createRequest({ + decompress: false, + encoding: 'base64' + }); + const expected = 'x'.repeat(100); + const body = await promisify(gzip)(expected, { + flush: constants.Z_SYNC_FLUSH, + finishFlush: constants.Z_SYNC_FLUSH + }); + nock(requestOptions.url).get('/').reply(200, body, { + 'content-type': 'text/plain', + 'content-encoding': 'gzip' + }); + + const response = await executor.execute(request); + + expect(response.body).toEqual(body.toString('base64')); + expect(response.headers).toMatchObject({ 'content-encoding': 'gzip' }); + }); + it('should decode response body if content-encoding is gzip', async () => { when(spiedExecutorOptions.maxContentLength).thenReturn(1); when(spiedExecutorOptions.whitelistMimes).thenReturn(['text/plain']); diff --git a/src/RequestExecutor/HttpRequestExecutor.ts b/src/RequestExecutor/HttpRequestExecutor.ts index 96a5803d..ece1d610 100644 --- a/src/RequestExecutor/HttpRequestExecutor.ts +++ b/src/RequestExecutor/HttpRequestExecutor.ts @@ -191,26 +191,37 @@ export class HttpRequestExecutor implements RequestExecutor { ); } - private async truncateResponse(req: Request, res: IncomingMessage) { + private async truncateResponse( + { decompress, encoding, maxContentSize }: Request, + res: IncomingMessage + ) { if (this.responseHasNoBody(res)) { logger.debug('The response does not contain any body.'); return { res, body: '' }; } - const { type, encoding } = this.parseContentType(res); + const contentType = this.parseContentType(res); + const { type } = contentType; const requiresTruncating = !this.options.whitelistMimes?.some( (mime: string) => type.startsWith(mime) ); const maxBodySize = - (req.maxContentSize ?? this.options.maxContentLength) * 1024; - const body = await this.parseBody(res, { maxBodySize, requiresTruncating }); + (maxContentSize ?? this.options.maxContentLength) * 1024; + const body = await this.parseBody(res, { + maxBodySize, + requiresTruncating, + decompress + }); res.headers['content-length'] = body.byteLength.toFixed(); - delete res.headers['content-encoding']; - return { res, body: iconv.decode(body, req.encoding ?? encoding) }; + if (decompress) { + delete res.headers['content-encoding']; + } + + return { res, body: iconv.decode(body, encoding ?? contentType.encoding) }; } private parseContentType(res: IncomingMessage): { @@ -276,11 +287,16 @@ export class HttpRequestExecutor implements RequestExecutor { private async parseBody( res: IncomingMessage, - options: { maxBodySize: number; requiresTruncating: boolean } + options: { + maxBodySize: number; + requiresTruncating: boolean; + decompress: boolean; + } ): Promise { const chunks: Buffer[] = []; + const stream = options.decompress ? this.unzipBody(res) : res; - for await (const chuck of this.unzipBody(res)) { + for await (const chuck of stream) { chunks.push(chuck); } diff --git a/src/RequestExecutor/Request.ts b/src/RequestExecutor/Request.ts index b02968f9..9af97bad 100644 --- a/src/RequestExecutor/Request.ts +++ b/src/RequestExecutor/Request.ts @@ -19,6 +19,7 @@ export interface RequestOptions { encoding?: 'base64'; maxContentSize?: number; timeout?: number; + decompress?: boolean; } export interface Cert { @@ -51,6 +52,7 @@ export class Request { public readonly correlationIdRegex?: RegExp; public readonly encoding?: 'base64'; public readonly maxContentSize?: number; + public readonly decompress?: boolean; public readonly timeout?: number; private _method: string; @@ -99,6 +101,7 @@ export class Request { correlationIdRegex, maxContentSize, encoding, + decompress = true, headers = {} }: RequestOptions) { this.protocol = protocol; @@ -127,6 +130,7 @@ export class Request { this.encoding = encoding; this.timeout = timeout; this.maxContentSize = maxContentSize; + this.decompress = !!decompress; } public setHeaders(headers: Record): void {