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')
 | 
						|
    }
 | 
						|
  })
 | 
						|
})
 |