You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							394 lines
						
					
					
						
							9.0 KiB
						
					
					
				
			
		
		
	
	
							394 lines
						
					
					
						
							9.0 KiB
						
					
					
				| 'use strict'
 | |
| 
 | |
| const util = require('util')
 | |
| const test = require('tap').test
 | |
| const FormData = require('form-data')
 | |
| const Fastify = require('fastify')
 | |
| const multipart = require('..')
 | |
| const http = require('http')
 | |
| const stream = require('stream')
 | |
| const pump = util.promisify(stream.pipeline)
 | |
| 
 | |
| test('should parse JSON fields forms if content-type is set', function (t) {
 | |
|   t.plan(5)
 | |
| 
 | |
|   const fastify = Fastify()
 | |
|   t.teardown(fastify.close.bind(fastify))
 | |
| 
 | |
|   fastify.register(multipart)
 | |
| 
 | |
|   fastify.post('/', async function (req, reply) {
 | |
|     for await (const part of req.parts()) {
 | |
|       t.notOk(part.filename)
 | |
|       t.equal(part.mimetype, 'application/json')
 | |
|       t.same(part.value, { a: 'b' })
 | |
|     }
 | |
| 
 | |
|     reply.code(200).send()
 | |
|   })
 | |
| 
 | |
|   fastify.listen(0, async function () {
 | |
|     // 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, res => {
 | |
|       t.equal(res.statusCode, 200)
 | |
|       res.resume()
 | |
|       res.on('end', () => {
 | |
|         t.pass('res ended successfully')
 | |
|       })
 | |
|     })
 | |
| 
 | |
|     form.append('json', JSON.stringify({ a: 'b' }), { contentType: 'application/json' })
 | |
| 
 | |
|     try {
 | |
|       await pump(form, req)
 | |
|     } catch (error) {
 | |
|       t.error(error, 'formData request pump: no err')
 | |
|     }
 | |
|   })
 | |
| })
 | |
| 
 | |
| test('should not parse JSON fields forms if no content-type is set', function (t) {
 | |
|   t.plan(5)
 | |
| 
 | |
|   const fastify = Fastify()
 | |
|   t.teardown(fastify.close.bind(fastify))
 | |
| 
 | |
|   fastify.register(multipart)
 | |
| 
 | |
|   fastify.post('/', async function (req, reply) {
 | |
|     for await (const part of req.parts()) {
 | |
|       t.notOk(part.filename)
 | |
|       t.notOk(part.mimetype)
 | |
|       t.type(part.value, 'string')
 | |
|     }
 | |
| 
 | |
|     reply.code(200).send()
 | |
|   })
 | |
| 
 | |
|   fastify.listen(0, async function () {
 | |
|     // 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, res => {
 | |
|       t.equal(res.statusCode, 200)
 | |
|       res.resume()
 | |
|       res.on('end', () => {
 | |
|         t.pass('res ended successfully')
 | |
|       })
 | |
|     })
 | |
| 
 | |
|     form.append('json', JSON.stringify({ a: 'b' }))
 | |
| 
 | |
|     try {
 | |
|       await pump(form, req)
 | |
|     } catch (error) {
 | |
|       t.error(error, 'formData request pump: no err')
 | |
|     }
 | |
|   })
 | |
| })
 | |
| 
 | |
| test('should throw error when parsing JSON fields failed', function (t) {
 | |
|   t.plan(2)
 | |
| 
 | |
|   const fastify = Fastify()
 | |
|   t.teardown(fastify.close.bind(fastify))
 | |
| 
 | |
|   fastify.register(multipart)
 | |
| 
 | |
|   fastify.post('/', async function (req, reply) {
 | |
|     try {
 | |
|       for await (const part of req.parts()) {
 | |
|         t.type(part.value, 'string')
 | |
|       }
 | |
| 
 | |
|       reply.code(200).send()
 | |
|     } catch (error) {
 | |
|       t.ok(error instanceof fastify.multipartErrors.InvalidJSONFieldError)
 | |
|       reply.code(500).send()
 | |
|     }
 | |
|   })
 | |
| 
 | |
|   fastify.listen(0, async function () {
 | |
|     // 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, res => {
 | |
|       t.equal(res.statusCode, 500)
 | |
|       res.resume()
 | |
|       res.on('end', () => {
 | |
|         t.pass('res ended successfully')
 | |
|       })
 | |
|     })
 | |
| 
 | |
|     form.append('object', 'INVALID', { contentType: 'application/json' })
 | |
| 
 | |
|     try {
 | |
|       await pump(form, req)
 | |
|     } catch (error) {
 | |
|       t.error(error, 'formData request pump: no err')
 | |
|     }
 | |
|   })
 | |
| })
 | |
| 
 | |
| test('should always reject JSON parsing if the value was truncated', function (t) {
 | |
|   t.plan(2)
 | |
| 
 | |
|   const fastify = Fastify()
 | |
|   t.teardown(fastify.close.bind(fastify))
 | |
| 
 | |
|   fastify.register(multipart, { limits: { fieldSize: 2 } })
 | |
| 
 | |
|   fastify.post('/', async function (req, reply) {
 | |
|     try {
 | |
|       for await (const part of req.parts()) {
 | |
|         t.type(part.value, 'string')
 | |
|       }
 | |
| 
 | |
|       reply.code(200).send()
 | |
|     } catch (error) {
 | |
|       t.ok(error instanceof fastify.multipartErrors.InvalidJSONFieldError)
 | |
|       reply.code(500).send()
 | |
|     }
 | |
|   })
 | |
| 
 | |
|   fastify.listen(0, async function () {
 | |
|     // 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, res => {
 | |
|       t.equal(res.statusCode, 500)
 | |
|       res.resume()
 | |
|       res.on('end', () => {
 | |
|         t.pass('res ended successfully')
 | |
|       })
 | |
|     })
 | |
| 
 | |
|     form.append('object', JSON.stringify({ a: 'b' }), { contentType: 'application/json' })
 | |
| 
 | |
|     try {
 | |
|       await pump(form, req)
 | |
|     } catch (error) {
 | |
|       t.error(error, 'formData request pump: no err')
 | |
|     }
 | |
|   })
 | |
| })
 | |
| 
 | |
| test('should be able to use JSON schema to validate request when value is a string', function (t) {
 | |
|   t.plan(5)
 | |
| 
 | |
|   const fastify = Fastify()
 | |
|   t.teardown(fastify.close.bind(fastify))
 | |
| 
 | |
|   fastify.register(multipart, { attachFieldsToBody: true, sharedSchemaId: '#mySharedSchema' })
 | |
| 
 | |
|   fastify.post(
 | |
|     '/',
 | |
|     {
 | |
|       schema: {
 | |
|         body: {
 | |
|           type: 'object',
 | |
|           required: ['field'],
 | |
|           properties: {
 | |
|             field: {
 | |
|               allOf: [{ $ref: '#mySharedSchema' }, { properties: { value: { type: 'string' } } }]
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     },
 | |
|     async function (req, reply) {
 | |
|       t.ok(req.isMultipart())
 | |
| 
 | |
|       t.same(Object.keys(req.body), ['field'])
 | |
|       t.equal(req.body.field.value, '{"a":"b"}')
 | |
| 
 | |
|       reply.code(200).send()
 | |
|     }
 | |
|   )
 | |
| 
 | |
|   fastify.listen(0, async function () {
 | |
|     // 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, res => {
 | |
|       t.equal(res.statusCode, 200)
 | |
|       res.resume()
 | |
|       res.on('end', () => {
 | |
|         t.pass('res ended successfully')
 | |
|       })
 | |
|     })
 | |
| 
 | |
|     form.append('field', JSON.stringify({ a: 'b' }))
 | |
| 
 | |
|     try {
 | |
|       await pump(form, req)
 | |
|     } catch (error) {
 | |
|       t.error(error, 'formData request pump: no err')
 | |
|     }
 | |
|   })
 | |
| })
 | |
| 
 | |
| test('should be able to use JSON schema to validate request when value is a JSON', function (t) {
 | |
|   t.plan(5)
 | |
| 
 | |
|   const fastify = Fastify()
 | |
|   t.teardown(fastify.close.bind(fastify))
 | |
| 
 | |
|   fastify.register(multipart, { attachFieldsToBody: true, sharedSchemaId: '#mySharedSchema' })
 | |
| 
 | |
|   fastify.post(
 | |
|     '/',
 | |
|     {
 | |
|       schema: {
 | |
|         body: {
 | |
|           type: 'object',
 | |
|           required: ['field'],
 | |
|           properties: {
 | |
|             field: {
 | |
|               allOf: [{ $ref: '#mySharedSchema' }, { properties: { value: { type: 'object' } } }]
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     },
 | |
|     async function (req, reply) {
 | |
|       t.ok(req.isMultipart())
 | |
| 
 | |
|       t.same(Object.keys(req.body), ['field'])
 | |
|       t.same(req.body.field.value, { a: 'b' })
 | |
| 
 | |
|       reply.code(200).send()
 | |
|     }
 | |
|   )
 | |
| 
 | |
|   fastify.listen(0, async function () {
 | |
|     // 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, res => {
 | |
|       t.equal(res.statusCode, 200)
 | |
|       res.resume()
 | |
|       res.on('end', () => {
 | |
|         t.pass('res ended successfully')
 | |
|       })
 | |
|     })
 | |
| 
 | |
|     form.append('field', JSON.stringify({ a: 'b' }), { contentType: 'application/json' })
 | |
| 
 | |
|     try {
 | |
|       await pump(form, req)
 | |
|     } catch (error) {
 | |
|       t.error(error, 'formData request pump: no err')
 | |
|     }
 | |
|   })
 | |
| })
 | |
| 
 | |
| test('should return 400 when the field validation fails', function (t) {
 | |
|   t.plan(2)
 | |
| 
 | |
|   const fastify = Fastify()
 | |
|   t.teardown(fastify.close.bind(fastify))
 | |
| 
 | |
|   fastify.register(multipart, { attachFieldsToBody: true, sharedSchemaId: '#mySharedSchema' })
 | |
| 
 | |
|   fastify.post(
 | |
|     '/',
 | |
|     {
 | |
|       schema: {
 | |
|         body: {
 | |
|           type: 'object',
 | |
|           required: ['field'],
 | |
|           properties: {
 | |
|             field: {
 | |
|               allOf: [{ $ref: '#mySharedSchema' }, { properties: { value: { type: 'object' } } }]
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     },
 | |
|     async function (req, reply) {
 | |
|       t.ok(req.isMultipart())
 | |
|       reply.code(200).send()
 | |
|     }
 | |
|   )
 | |
| 
 | |
|   fastify.listen(0, async function () {
 | |
|     // 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, res => {
 | |
|       t.equal(res.statusCode, 400)
 | |
|       res.resume()
 | |
|       res.on('end', () => {
 | |
|         t.pass('res ended successfully')
 | |
|       })
 | |
|     })
 | |
| 
 | |
|     form.append('field', JSON.stringify('abc'), { contentType: 'application/json' })
 | |
| 
 | |
|     try {
 | |
|       await pump(form, req)
 | |
|     } catch (error) {
 | |
|       t.error(error, 'formData request pump: no err')
 | |
|     }
 | |
|   })
 | |
| })
 |