diff --git a/packages/node/src/body.test.ts b/packages/node/src/body.test.ts index a7a6ae1..4cf99bc 100644 --- a/packages/node/src/body.test.ts +++ b/packages/node/src/body.test.ts @@ -284,28 +284,44 @@ describe('toStandardBody', () => { }) }) - describe.each(['utf8', 'base64'] as const)('request with %s encoding set', (encoding) => { - let standardBody: any + describe.each(['utf8', 'latin1', 'base64', 'hex'] as const)( + 'request with %s encoding set', + (encoding) => { + // utf8 decodes invalid byte sequences to U+FFFD, so only valid text survives it + const bytes = + encoding === 'utf8' ? Buffer.from('emoji=😀') : Buffer.from([0xff, 0xfe, 0x00, 0x80, 0x41]) + let standardBody: any - async function handler(req: IncomingMessage, res: ServerResponse): Promise { - req.setEncoding(encoding) - standardBody = await toStandardBody(req) - res.end() - } + async function handler(req: IncomingMessage, res: ServerResponse): Promise { + req.setEncoding(encoding) + standardBody = await toStandardBody(req) + res.end() + } - it('json', async () => { - await request(handler).post('/').set('standard-server', 'json').send('{"emoji":"😀"}') + it('json', async () => { + await request(handler).post('/').set('standard-server', 'json').send('{"emoji":"😀"}') - expect(standardBody).toEqual({ emoji: '😀' }) - }) + expect(standardBody).toEqual({ emoji: '😀' }) + }) - it('file', async () => { - await request(handler).post('/').set('standard-server', 'file').send('emoji=😀') + it('file', async () => { + await request(handler).post('/').set('standard-server', 'file').send(bytes) - expect(standardBody).toBeInstanceOf(File) - expect(await standardBody.text()).toBe('emoji=😀') - }) - }) + expect(standardBody).toBeInstanceOf(File) + expect(new Uint8Array(await standardBody.arrayBuffer())).toEqual(new Uint8Array(bytes)) + }) + + it('form-data', async () => { + await request(handler).post('/').field('emoji', '😀').attach('file', bytes, 'foo.bin') + + expect(standardBody).toBeInstanceOf(FormData) + expect(standardBody.get('emoji')).toBe('😀') + expect(new Uint8Array(await standardBody.get('file').arrayBuffer())).toEqual( + new Uint8Array(bytes), + ) + }) + }, + ) describe('http2', () => { /** @@ -462,6 +478,13 @@ describe('toStandardBody', () => { expect(await reader.read()).toEqual({ done: false, value: 'hello' }) }) + it('lets the parser reject form-data without content-type', async () => { + const req = Readable.from([Buffer.from('--X--\r\n')]) as IncomingMessage + req.headers = { 'standard-server': 'form-data' } + + await expect(toStandardBody(req)).rejects.toThrow(TypeError) + }) + it('falls back to the content headers if the body hint is invalid', async () => { let standardBody: any diff --git a/packages/node/src/body.ts b/packages/node/src/body.ts index 054ae79..ca3a24f 100644 --- a/packages/node/src/body.ts +++ b/packages/node/src/body.ts @@ -162,9 +162,9 @@ export function toNodeHttpBody( } function _streamToFormData(stream: Readable, contentType: string | undefined): Promise { - const response = new Response(stream, { + const response = new Response(toWebReadableStream(stream), { headers: { - 'content-type': contentType, + 'content-type': contentType ?? '', }, })