diff --git a/src/rules/requests/request-step-definitions.ts b/src/rules/requests/request-step-definitions.ts index 5cfc867da..aa81c2c0c 100644 --- a/src/rules/requests/request-step-definitions.ts +++ b/src/rules/requests/request-step-definitions.ts @@ -942,7 +942,7 @@ export class PassThroughStep extends Serializable implements RequestStepDefiniti transformRequest: this.transformRequest ? { ...this.transformRequest, // Body is always serialized as a base64 buffer: - replaceBody: !!this.transformRequest?.replaceBody + replaceBody: this.transformRequest?.replaceBody !== undefined ? serializeBuffer(asBuffer(this.transformRequest.replaceBody)) : undefined, // Update objects need to capture undefined & null as distict values: @@ -977,7 +977,7 @@ export class PassThroughStep extends Serializable implements RequestStepDefiniti transformResponse: this.transformResponse ? { ...this.transformResponse, // Body is always serialized as a base64 buffer: - replaceBody: !!this.transformResponse?.replaceBody + replaceBody: this.transformResponse?.replaceBody !== undefined ? serializeBuffer(asBuffer(this.transformResponse.replaceBody)) : undefined, // Update objects need to capture undefined & null as distict values: diff --git a/src/rules/requests/request-step-impls.ts b/src/rules/requests/request-step-impls.ts index 07b5e0008..715af379d 100644 --- a/src/rules/requests/request-step-impls.ts +++ b/src/rules/requests/request-step-impls.ts @@ -547,7 +547,7 @@ export class PassThroughStepImpl extends PassThroughStep { rawHeaders = objectHeadersToRaw(replaceHeaders); } - if (replaceBody) { + if (replaceBody !== undefined) { // Note that we're replacing the body without actually waiting for the real one, so // this can result in sending a request much more quickly! reqBodyOverride = asBuffer(replaceBody); @@ -888,7 +888,7 @@ export class PassThroughStepImpl extends PassThroughStep { serverRawHeaders = objectHeadersToRaw(replaceHeaders); } - if (replaceBody) { + if (replaceBody !== undefined) { // Note that we're replacing the body without actually waiting for the real one, so // this can result in sending a request much more quickly! resBodyOverride = asBuffer(replaceBody); diff --git a/test/integration/proxying/https-proxying.spec.ts b/test/integration/proxying/https-proxying.spec.ts index e800dcdb1..ac338aa4c 100644 --- a/test/integration/proxying/https-proxying.spec.ts +++ b/test/integration/proxying/https-proxying.spec.ts @@ -561,6 +561,25 @@ nodeOnly(() => { expect(response.body.toString('utf8')).to.equal("Real HTTP/2 response"); }); + it("can replace an HTTP/2 request body with an empty string", async () => { + await server.forAnyRequest().thenPassThrough({ + ignoreHostHttpsErrors: ['localhost'], + transformRequest: { replaceBody: '' } + }); + + const response = await http2ProxyRequest( + server, + `https://localhost:${targetPort}`, + { + headers: { ':method': 'POST' }, + requestBody: 'initial-body' + } + ); + + expect(response.headers[':status']).to.equal(200); + expect(response.headers['received-body']).to.equal(''); + }); + it("can pass through response trailers successfully", async () => { await server.forAnyRequest().thenPassThrough({ ignoreHostHttpsErrors: ['localhost'] diff --git a/test/integration/proxying/proxy-transforms.spec.ts b/test/integration/proxying/proxy-transforms.spec.ts index 026b0db49..8ff8b7e30 100644 --- a/test/integration/proxying/proxy-transforms.spec.ts +++ b/test/integration/proxying/proxy-transforms.spec.ts @@ -886,6 +886,28 @@ nodeOnly(() => { expect(response.body).to.equal('replacement-body'); }); + it("can replace the body with an empty string", async () => { + await server.forAnyRequest().thenPassThrough({ + transformResponse: { + replaceBody: '' + } + }); + + let response = await request.post(remoteServerHttpUrl, { + resolveWithFullResponse: true, + simple: false + }); + + expect(response.statusCode).to.equal(200); + expect(response.headers).to.deep.equal({ + 'content-type': 'application/json', + 'content-length': '0', + 'connection': 'keep-alive', + 'custom-response-header': 'custom-value', + }); + expect(response.body).to.equal(''); + }); + it("can replace the body with a buffer", async () => { await server.forAnyRequest().thenPassThrough({ transformResponse: { diff --git a/test/integration/remote-client.spec.ts b/test/integration/remote-client.spec.ts index e9a398c0f..2c0534ca0 100644 --- a/test/integration/remote-client.spec.ts +++ b/test/integration/remote-client.spec.ts @@ -201,6 +201,34 @@ nodeOnly(() => { ); }); + it("should replace request & response bodies with empty strings", async () => { + await targetServer.forPost('/empty-request').thenCallback(async (req) => ({ + status: 200, + body: await req.body.getText() === '' ? 'empty' : 'not-empty' + })); + + await remoteServer.forPost(targetServer.urlFor('/empty-request')).thenPassThrough({ + transformRequest: { replaceBody: '' } + }); + + expect(await request.post(targetServer.urlFor('/empty-request'), { + proxy: remoteServer.urlFor('/'), + body: 'original-body' + })).to.equal('empty'); + + await targetServer.forPost('/empty-response').thenReply(200, 'original-body'); + await remoteServer.forPost(targetServer.urlFor('/empty-response')).thenPassThrough({ + transformResponse: { replaceBody: '' } + }); + + const response = await request.post(targetServer.urlFor('/empty-response'), { + proxy: remoteServer.urlFor('/'), + resolveWithFullResponse: true + }); + + expect(response.body).to.equal(''); + }); + it("should successfully update request & response body JSON", async () => { // Echo the incoming request await targetServer.forAnyRequest().thenCallback(async (req) => ({