diff --git a/lib/server/routesHandlers/postResponseHandler.ts b/lib/server/routesHandlers/postResponseHandler.ts index b6cc9684e..fcbbc3cdd 100644 --- a/lib/server/routesHandlers/postResponseHandler.ts +++ b/lib/server/routesHandlers/postResponseHandler.ts @@ -39,7 +39,7 @@ export const handlePostResponse = (req: Request, res: Response) => { .on('data', function (data) { try { logger.trace( - { ...logContext, dataLength: data.length }, + { ...logContext, dataLength: Buffer.byteLength(data, 'utf8') }, 'Received data event', ); let bytesRead = 0; @@ -52,12 +52,16 @@ export const handlePostResponse = (req: Request, res: Response) => { ); } + let statusAndHeadersLength = Buffer.byteLength( + statusAndHeaders, + 'utf8', + ); if ( statusAndHeadersSize > 0 && - statusAndHeaders.length < statusAndHeadersSize + statusAndHeadersLength < statusAndHeadersSize ) { const endPosition = Math.min( - bytesRead + statusAndHeadersSize - statusAndHeaders.length, + bytesRead + statusAndHeadersSize - statusAndHeadersLength, data.length, ); logger.trace( @@ -66,8 +70,8 @@ export const handlePostResponse = (req: Request, res: Response) => { ); statusAndHeaders += data.toString('utf8', bytesRead, endPosition); bytesRead = endPosition; - - if (statusAndHeaders.length === statusAndHeadersSize) { + statusAndHeadersLength = Buffer.byteLength(statusAndHeaders, 'utf8'); + if (statusAndHeadersLength === statusAndHeadersSize) { logger.trace( { ...logContext, statusAndHeaders }, 'Converting to json', @@ -92,7 +96,7 @@ export const handlePostResponse = (req: Request, res: Response) => { logger.trace( { ...logContext, - currentSize: statusAndHeaders.length, + currentSize: statusAndHeadersLength, expectedSize: statusAndHeadersSize, }, 'Was unable to fit all information into a single data object', diff --git a/test/fixtures/client/filters.json b/test/fixtures/client/filters.json index fe14659df..60eb673df 100644 --- a/test/fixtures/client/filters.json +++ b/test/fixtures/client/filters.json @@ -62,6 +62,12 @@ "origin": "http://localhost:9000" }, + { + "path": "/echo-with-unicode", + "method": "POST", + "origin": "http://localhost:9000" + }, + { "path": "/echo-body/filtered", "method": "POST", diff --git a/test/functional/server-client.test.ts b/test/functional/server-client.test.ts index 73aec4f2e..5e3025360 100644 --- a/test/functional/server-client.test.ts +++ b/test/functional/server-client.test.ts @@ -164,6 +164,22 @@ describe('proxy requests originating from behind the broker server', () => { expect(Buffer.from(response.data)).toEqual(body); expect(response.headers['x-broker-ws-response']).not.toBeNull(); }); + + it('successfully broker POST with unicode body and header values', async () => { + const response = await axiosClient.post( + `http://localhost:${bs.port}/broker/${brokerToken}/echo-with-unicode`, + { some: { example: 'json' } }, + ); + expect(decodeURIComponent(response.headers.test)).toEqual( + 'Special-Char-碰撞.proj', + ); + expect(response.status).toEqual(200); + expect(response.data).toStrictEqual({ + some: { example: 'json' }, + test: 'Special-Char-碰撞.proj', + }); + }); + it('successfully broker GET', async () => { const response = await axiosClient.get( `http://localhost:${bs.port}/broker/${brokerToken}/echo-param/xyz`, diff --git a/test/setup/test-web-server.ts b/test/setup/test-web-server.ts index 24c5e69a8..cb43e4ac6 100644 --- a/test/setup/test-web-server.ts +++ b/test/setup/test-web-server.ts @@ -240,6 +240,21 @@ const applyEchoRoutes = (app: Express) => { }, ); + echoRouter.post( + '/echo-with-unicode/:param?', + (req: express.Request, resp: express.Response) => { + const unicodeValue = 'Special-Char-碰撞.proj'; + const body = JSON.parse(req.body); + body.test = unicodeValue; + const contentType = req.get('Content-Type'); + if (contentType) { + resp.type(contentType); + } + resp.setHeader('test', encodeURIComponent(unicodeValue)); + resp.send(JSON.stringify(body)); + }, + ); + // mimics functionality of https://httpbin.org/headers echoRouter.get( '/echo-headers/httpbin',