diff --git a/src/handlers/fix-request-body.ts b/src/handlers/fix-request-body.ts index 4fe1e458..1286ce54 100644 --- a/src/handlers/fix-request-body.ts +++ b/src/handlers/fix-request-body.ts @@ -30,4 +30,23 @@ export function fixRequestBody( if (contentType && contentType.includes('application/x-www-form-urlencoded')) { writeBody(querystring.stringify(requestBody)); } + + if (contentType && contentType.includes('multipart/form-data')) { + writeBody(handlerFormDataBodyData(contentType, requestBody)); + } +} + +/** + * format FormData data + * @param contentType + * @param data + * @returns + */ +function handlerFormDataBodyData(contentType: string, data: any) { + const boundary = contentType.replace(/^.*boundary=(.*)$/, '$1'); + let str = ''; + for (const [key, value] of Object.entries(data)) { + str += `--${boundary}\r\nContent-Disposition: form-data; name="${key}"\r\n\r\n${value}\r\n`; + } + return str; } diff --git a/test/unit/fix-request-body.spec.ts b/test/unit/fix-request-body.spec.ts index b176506e..2f1b6608 100644 --- a/test/unit/fix-request-body.spec.ts +++ b/test/unit/fix-request-body.spec.ts @@ -1,7 +1,6 @@ import { Socket } from 'net'; import { ClientRequest, IncomingMessage } from 'http'; import * as querystring from 'querystring'; - import { fixRequestBody, BodyParserLikeRequest } from '../../src/handlers/fix-request-body'; const fakeProxyRequest = (): ClientRequest => { @@ -17,6 +16,15 @@ const createRequestWithBody = (body: unknown): BodyParserLikeRequest => { return req; }; +const handlerFormDataBodyData = (contentType: string, data: { [key: string]: any }) => { + const boundary = contentType.replace(/^.*boundary=(.*)$/, '$1'); + let str = ''; + for (const [key, value] of Object.entries(data)) { + str += `--${boundary}\r\nContent-Disposition: form-data; name="${key}"\r\n\r\n${value}\r\n`; + } + return str; +}; + describe('fixRequestBody', () => { it('should not write when body is undefined', () => { const proxyRequest = fakeProxyRequest(); @@ -57,6 +65,55 @@ describe('fixRequestBody', () => { expect(proxyRequest.write).toHaveBeenCalledWith(expectedBody); }); + it('should write when body is not empty and Content-Type is multipart/form-data', () => { + const proxyRequest = fakeProxyRequest(); + proxyRequest.setHeader('content-type', 'multipart/form-data'); + + jest.spyOn(proxyRequest, 'setHeader'); + jest.spyOn(proxyRequest, 'write'); + + fixRequestBody(proxyRequest, createRequestWithBody({ someField: 'some value' })); + + const expectedBody = handlerFormDataBodyData('multipart/form-data', { + someField: 'some value', + }); + + expect(expectedBody).toMatchInlineSnapshot(` + "--multipart/form-data + Content-Disposition: form-data; name="someField" + + some value + " + `); + expect(proxyRequest.setHeader).toHaveBeenCalledWith('Content-Length', expectedBody.length); + expect(proxyRequest.write).toHaveBeenCalledWith(expectedBody); + }); + + it('should write when body is not empty and Content-Type includes multipart/form-data', () => { + const proxyRequest = fakeProxyRequest(); + proxyRequest.setHeader('content-type', 'multipart/form-data'); + + jest.spyOn(proxyRequest, 'setHeader'); + jest.spyOn(proxyRequest, 'write'); + + fixRequestBody(proxyRequest, createRequestWithBody({ someField: 'some value' })); + + const expectedBody = handlerFormDataBodyData('multipart/form-data', { + someField: 'some value', + }); + + expect(expectedBody).toMatchInlineSnapshot(` + "--multipart/form-data + Content-Disposition: form-data; name="someField" + + some value + " + `); + + expect(proxyRequest.setHeader).toHaveBeenCalledWith('Content-Length', expectedBody.length); + expect(proxyRequest.write).toHaveBeenCalledWith(expectedBody); + }); + it('should write when body is not empty and Content-Type ends with +json', () => { const proxyRequest = fakeProxyRequest(); proxyRequest.setHeader('content-type', 'application/merge-patch+json; charset=utf-8'); @@ -65,7 +122,6 @@ describe('fixRequestBody', () => { jest.spyOn(proxyRequest, 'write'); fixRequestBody(proxyRequest, createRequestWithBody({ someField: 'some value' })); - const expectedBody = JSON.stringify({ someField: 'some value' }); expect(proxyRequest.setHeader).toHaveBeenCalledWith('Content-Length', expectedBody.length); expect(proxyRequest.write).toHaveBeenCalledWith(expectedBody);