-
-
Notifications
You must be signed in to change notification settings - Fork 105
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support for saveRequestFiles with attachFieldsToBody set true (#409)
* wip: failing test added * fix: save request files from body added * chore: test assertions extended * feat: saveRequestFiles error on null buff added * chore: fixed linting * chore: fixed linting * chore: async removed from filesFromFields generator
- Loading branch information
Showing
2 changed files
with
177 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
'use strict' | ||
|
||
const test = require('tap').test | ||
const FormData = require('form-data') | ||
const Fastify = require('fastify') | ||
const multipart = require('..') | ||
const http = require('http') | ||
const path = require('path') | ||
const fs = require('fs') | ||
const { access } = require('fs').promises | ||
const EventEmitter = require('events') | ||
const { once } = EventEmitter | ||
|
||
const filePath = path.join(__dirname, '../README.md') | ||
|
||
test('should store file on disk, remove on response when attach fields to body is true', async function (t) { | ||
t.plan(22) | ||
|
||
const fastify = Fastify() | ||
t.teardown(fastify.close.bind(fastify)) | ||
|
||
fastify.register(multipart, { | ||
attachFieldsToBody: true | ||
}) | ||
|
||
fastify.post('/', async function (req, reply) { | ||
t.ok(req.isMultipart()) | ||
|
||
const files = await req.saveRequestFiles() | ||
|
||
t.ok(files[0].filepath) | ||
t.equal(files[0].fieldname, 'upload') | ||
t.equal(files[0].filename, 'README.md') | ||
t.equal(files[0].encoding, '7bit') | ||
t.equal(files[0].mimetype, 'text/markdown') | ||
t.ok(files[0].fields.upload) | ||
t.ok(files[1].filepath) | ||
t.equal(files[1].fieldname, 'upload') | ||
t.equal(files[1].filename, 'README.md') | ||
t.equal(files[1].encoding, '7bit') | ||
t.equal(files[1].mimetype, 'text/markdown') | ||
t.ok(files[1].fields.upload) | ||
t.ok(files[2].filepath) | ||
t.equal(files[2].fieldname, 'other') | ||
t.equal(files[2].filename, 'README.md') | ||
t.equal(files[2].encoding, '7bit') | ||
t.equal(files[2].mimetype, 'text/markdown') | ||
t.ok(files[2].fields.upload) | ||
|
||
await access(files[0].filepath, fs.constants.F_OK) | ||
await access(files[1].filepath, fs.constants.F_OK) | ||
await access(files[2].filepath, fs.constants.F_OK) | ||
|
||
reply.code(200).send() | ||
}) | ||
const ee = new EventEmitter() | ||
|
||
// ensure that file is removed after response | ||
fastify.addHook('onResponse', async (request, reply) => { | ||
try { | ||
await access(request.tmpUploads[0], fs.constants.F_OK) | ||
} catch (error) { | ||
t.equal(error.code, 'ENOENT') | ||
t.pass('Temp file was removed after response') | ||
ee.emit('response') | ||
} | ||
}) | ||
|
||
await fastify.listen({ port: 0 }) | ||
// request | ||
const form = new FormData() | ||
const opts = { | ||
protocol: 'http:', | ||
hostname: 'localhost', | ||
port: fastify.server.address().port, | ||
path: '/', | ||
headers: form.getHeaders(), | ||
method: 'POST' | ||
} | ||
|
||
const req = http.request(opts) | ||
form.append('upload', fs.createReadStream(filePath)) | ||
form.append('upload', fs.createReadStream(filePath)) | ||
form.append('other', fs.createReadStream(filePath)) | ||
|
||
form.pipe(req) | ||
|
||
const [res] = await once(req, 'response') | ||
t.equal(res.statusCode, 200) | ||
res.resume() | ||
await once(res, 'end') | ||
await once(ee, 'response') | ||
}) | ||
|
||
test('should throw on saving request files when attach fields to body is true but buffer is not stored', async function (t) { | ||
t.plan(3) | ||
|
||
const fastify = Fastify() | ||
t.teardown(fastify.close.bind(fastify)) | ||
|
||
fastify.register(multipart, { | ||
attachFieldsToBody: true, | ||
onFile: async (part) => { | ||
for await (const chunk of part.file) { | ||
chunk.toString() | ||
} | ||
} | ||
}) | ||
|
||
fastify.post('/', async function (req, reply) { | ||
t.ok(req.isMultipart()) | ||
|
||
try { | ||
await req.saveRequestFiles() | ||
reply.code(200).send() | ||
} catch (error) { | ||
t.ok(error instanceof fastify.multipartErrors.FileBufferNotFoundError) | ||
reply.code(500).send() | ||
} | ||
}) | ||
|
||
await fastify.listen({ port: 0 }) | ||
// request | ||
const form = new FormData() | ||
const opts = { | ||
protocol: 'http:', | ||
hostname: 'localhost', | ||
port: fastify.server.address().port, | ||
path: '/', | ||
headers: form.getHeaders(), | ||
method: 'POST' | ||
} | ||
|
||
const req = http.request(opts) | ||
form.append('upload', fs.createReadStream(filePath)) | ||
|
||
form.pipe(req) | ||
|
||
const [res] = await once(req, 'response') | ||
t.equal(res.statusCode, 500) | ||
res.resume() | ||
await once(res, 'end') | ||
}) |