Jonatan Nilsson
d5459cbcb9
All checks were successful
continuous-integration/appveyor/branch AppVeyor build succeeded
749 lines
25 KiB
JavaScript
749 lines
25 KiB
JavaScript
import os from 'os'
|
|
import path from 'path'
|
|
import { Buffer } from 'buffer'
|
|
import { Eltro as t, assert, stub} from 'eltro'
|
|
import { QueryHandler, JsonHandler, FormidableHandler, HttpError, CorsHandler } from '../flaska.mjs'
|
|
import { createCtx } from './helper.mjs'
|
|
import { finished } from 'stream'
|
|
import { setTimeout } from 'timers/promises'
|
|
|
|
t.describe('#QueryHandler()', function() {
|
|
let queryHandler = QueryHandler()
|
|
|
|
t.test('should return a handler', function() {
|
|
assert.strictEqual(typeof(queryHandler), 'function')
|
|
})
|
|
|
|
t.test('should support separating query from request url', function() {
|
|
const assertItem1 = 'safdsfdsag'
|
|
const assertItem2 = 'hello%20world'
|
|
const ctx = {
|
|
req: {
|
|
url: `/some/path?item1=${assertItem1}&ITEM2=${assertItem2}`
|
|
}
|
|
}
|
|
|
|
queryHandler(ctx)
|
|
assert.strictEqual(ctx.query.get('item1'), assertItem1)
|
|
assert.strictEqual(ctx.query.get('ITEM2'), 'hello world')
|
|
})
|
|
})
|
|
|
|
|
|
t.describe('#CorsHandler()', function() {
|
|
let corsHandler
|
|
let ctx
|
|
|
|
t.test('should return a handler', function() {
|
|
corsHandler = CorsHandler()
|
|
assert.strictEqual(typeof(corsHandler), 'function')
|
|
})
|
|
|
|
t.describe('OPTIONS', function() {
|
|
t.beforeEach(function() {
|
|
ctx = createCtx()
|
|
ctx.method = 'OPTIONS'
|
|
})
|
|
|
|
t.test('should set status and headers', function() {
|
|
const assertOrigin = 'http://my.site.here'
|
|
const assertRequestHeaders = 'asdf,foobar'
|
|
|
|
corsHandler = CorsHandler({
|
|
allowedOrigins: [assertOrigin],
|
|
})
|
|
ctx.req.headers['origin'] = assertOrigin
|
|
ctx.req.headers['access-control-request-method'] = 'GET'
|
|
ctx.req.headers['access-control-request-headers'] = assertRequestHeaders
|
|
|
|
assert.notOk(ctx.headers['Vary'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Origin'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Methods'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Headers'])
|
|
|
|
corsHandler(ctx)
|
|
|
|
assert.strictEqual(ctx.headers['Vary'], 'Origin')
|
|
assert.strictEqual(ctx.headers['Access-Control-Allow-Origin'], assertOrigin)
|
|
assert.strictEqual(ctx.headers['Access-Control-Allow-Methods'], 'GET,HEAD,PUT,POST,DELETE,PATCH')
|
|
assert.strictEqual(ctx.headers['Access-Control-Allow-Headers'], assertRequestHeaders)
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Credentials'])
|
|
assert.notOk(ctx.headers['Access-Control-Max-Age'])
|
|
assert.strictEqual(ctx.status, 204)
|
|
})
|
|
|
|
t.test('should set Allow-Credentials if credentials is specified', function() {
|
|
const assertOrigin = 'http://my.site.here'
|
|
const assertRequestHeaders = 'asdf,foobar'
|
|
|
|
corsHandler = CorsHandler({
|
|
allowedOrigins: [assertOrigin],
|
|
credentials: true,
|
|
})
|
|
ctx.req.headers['origin'] = assertOrigin
|
|
ctx.req.headers['access-control-request-method'] = 'GET'
|
|
ctx.req.headers['access-control-request-headers'] = assertRequestHeaders
|
|
|
|
assert.notOk(ctx.headers['Vary'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Origin'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Methods'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Headers'])
|
|
|
|
corsHandler(ctx)
|
|
|
|
assert.strictEqual(ctx.headers['Vary'], 'Origin')
|
|
assert.strictEqual(ctx.headers['Access-Control-Allow-Credentials'], 'true')
|
|
assert.strictEqual(ctx.headers['Access-Control-Allow-Origin'], assertOrigin)
|
|
assert.strictEqual(ctx.headers['Access-Control-Allow-Methods'], 'GET,HEAD,PUT,POST,DELETE,PATCH')
|
|
assert.strictEqual(ctx.headers['Access-Control-Allow-Headers'], assertRequestHeaders)
|
|
assert.notOk(ctx.headers['Access-Control-Max-Age'])
|
|
assert.strictEqual(ctx.status, 204)
|
|
})
|
|
|
|
t.test('should set Max-Age if maxAge is specified', function() {
|
|
const assertOrigin = 'http://my.site.here'
|
|
const assertRequestHeaders = 'asdf,foobar'
|
|
const assertMaxAge = '600'
|
|
|
|
corsHandler = CorsHandler({
|
|
allowedOrigins: [assertOrigin],
|
|
maxAge: assertMaxAge,
|
|
})
|
|
ctx.req.headers['origin'] = assertOrigin
|
|
ctx.req.headers['access-control-request-method'] = 'GET'
|
|
ctx.req.headers['access-control-request-headers'] = assertRequestHeaders
|
|
|
|
assert.notOk(ctx.headers['Vary'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Origin'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Methods'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Headers'])
|
|
|
|
corsHandler(ctx)
|
|
|
|
assert.strictEqual(ctx.headers['Vary'], 'Origin')
|
|
assert.strictEqual(ctx.headers['Access-Control-Allow-Origin'], assertOrigin)
|
|
assert.strictEqual(ctx.headers['Access-Control-Max-Age'], assertMaxAge)
|
|
assert.strictEqual(ctx.headers['Access-Control-Allow-Methods'], 'GET,HEAD,PUT,POST,DELETE,PATCH')
|
|
assert.strictEqual(ctx.headers['Access-Control-Allow-Headers'], assertRequestHeaders)
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Credentials'])
|
|
assert.strictEqual(ctx.status, 204)
|
|
})
|
|
|
|
t.test('should support custom allowed methods and headers', function() {
|
|
const assertOrigin = 'http://my.site.here'
|
|
const assertAllowedMethods = 'GET,HEAD'
|
|
const assertAllowedHeaders = 'test1,test2'
|
|
|
|
corsHandler = CorsHandler({
|
|
allowedOrigins: [assertOrigin],
|
|
allowedMethods: assertAllowedMethods,
|
|
allowedHeaders: assertAllowedHeaders,
|
|
})
|
|
ctx.req.headers['origin'] = assertOrigin
|
|
ctx.req.headers['access-control-request-method'] = 'GET'
|
|
ctx.req.headers['access-control-request-headers'] = 'asdfasdfasdfsfad'
|
|
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Origin'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Methods'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Headers'])
|
|
|
|
corsHandler(ctx)
|
|
|
|
assert.strictEqual(ctx.headers['Vary'], 'Origin')
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Credentials'])
|
|
assert.strictEqual(ctx.headers['Access-Control-Allow-Origin'], assertOrigin)
|
|
assert.strictEqual(ctx.headers['Access-Control-Allow-Methods'], assertAllowedMethods)
|
|
assert.strictEqual(ctx.headers['Access-Control-Allow-Headers'], assertAllowedHeaders)
|
|
assert.strictEqual(ctx.status, 204)
|
|
})
|
|
|
|
t.test('should not set any allowed headers if allowedHeaders is explicitly false', function() {
|
|
const assertOrigin = 'http://my.site.here'
|
|
const assertAllowedMethods = 'GET,HEAD'
|
|
|
|
corsHandler = CorsHandler({
|
|
allowedOrigins: [assertOrigin],
|
|
allowedMethods: assertAllowedMethods,
|
|
allowedHeaders: false,
|
|
})
|
|
ctx.req.headers['origin'] = assertOrigin
|
|
ctx.req.headers['access-control-request-method'] = 'GET'
|
|
ctx.req.headers['access-control-request-headers'] = 'asdfasdfasdfsfad'
|
|
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Origin'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Methods'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Headers'])
|
|
|
|
corsHandler(ctx)
|
|
|
|
assert.strictEqual(ctx.headers['Vary'], 'Origin')
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Credentials'])
|
|
assert.strictEqual(ctx.headers['Access-Control-Allow-Origin'], assertOrigin)
|
|
assert.strictEqual(ctx.headers['Access-Control-Allow-Methods'], assertAllowedMethods)
|
|
assert.strictEqual(ctx.headers['Access-Control-Allow-Headers'], undefined)
|
|
assert.strictEqual(ctx.status, 204)
|
|
})
|
|
|
|
t.test('should not add any headers if origin missing', function() {
|
|
corsHandler = CorsHandler({
|
|
allowedOrigins: ['https://test.com'],
|
|
})
|
|
ctx.req.headers['origin'] = null
|
|
ctx.req.headers['access-control-request-method'] = 'GET'
|
|
ctx.req.headers['access-control-request-headers'] = 'asdfasdfasdfsfad'
|
|
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Origin'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Methods'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Headers'])
|
|
|
|
corsHandler(ctx)
|
|
|
|
assert.strictEqual(ctx.headers['Vary'], 'Origin')
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Origin'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Methods'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Headers'])
|
|
assert.strictEqual(ctx.status, 204)
|
|
})
|
|
|
|
t.test('should not add any headers if origin not found', function() {
|
|
const assertOrigin = 'http://my.site.here'
|
|
const assertAllowedMethods = 'GET,HEAD'
|
|
|
|
corsHandler = CorsHandler({
|
|
allowedOrigins: ['https://my.site.here'],
|
|
allowedMethods: assertAllowedMethods,
|
|
allowedHeaders: false,
|
|
})
|
|
ctx.req.headers['origin'] = assertOrigin
|
|
ctx.req.headers['access-control-request-method'] = 'GET'
|
|
ctx.req.headers['access-control-request-headers'] = 'asdfasdfasdfsfad'
|
|
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Origin'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Methods'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Headers'])
|
|
|
|
corsHandler(ctx)
|
|
|
|
assert.strictEqual(ctx.headers['Vary'], 'Origin')
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Origin'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Methods'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Headers'])
|
|
assert.strictEqual(ctx.status, 204)
|
|
})
|
|
|
|
t.test('should not add any headers if request-method is missing', function() {
|
|
const assertOrigin = 'http://my.site.here'
|
|
|
|
corsHandler = CorsHandler({
|
|
allowedOrigins: ['http://my.site.here'],
|
|
})
|
|
ctx.req.headers['origin'] = assertOrigin
|
|
delete ctx.req.headers['access-control-request-method']
|
|
ctx.req.headers['access-control-request-headers'] = 'asdfasdfasdfsfad'
|
|
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Origin'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Methods'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Headers'])
|
|
|
|
corsHandler(ctx)
|
|
|
|
assert.strictEqual(ctx.headers['Vary'], 'Origin')
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Origin'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Methods'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Headers'])
|
|
assert.strictEqual(ctx.status, 204)
|
|
})
|
|
|
|
t.test('should set headers if allowedOrigins has a *', function() {
|
|
const assertOrigin = 'http://my.site.here'
|
|
|
|
corsHandler = CorsHandler({
|
|
allowedOrigins: ['*'],
|
|
})
|
|
ctx.req.headers['origin'] = assertOrigin
|
|
ctx.req.headers['access-control-request-method'] = 'GET'
|
|
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Origin'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Methods'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Headers'])
|
|
|
|
corsHandler(ctx)
|
|
|
|
assert.strictEqual(ctx.headers['Vary'], 'Origin')
|
|
assert.strictEqual(ctx.headers['Access-Control-Allow-Origin'], assertOrigin)
|
|
assert.ok(ctx.headers['Access-Control-Allow-Methods'])
|
|
assert.strictEqual(ctx.status, 204)
|
|
})
|
|
})
|
|
|
|
t.describe('GET/POST/DELETE/PATCH/PUT', function() {
|
|
let testMethods = ['GET', 'POST', 'DELETE', 'PATCH', 'PUT']
|
|
|
|
t.test('should set header but no status', function() {
|
|
testMethods.forEach(function(method) {
|
|
ctx = createCtx()
|
|
ctx.method = method
|
|
ctx.status = method
|
|
|
|
const assertOrigin = 'http://my.site.here'
|
|
|
|
corsHandler = CorsHandler({
|
|
allowedOrigins: [assertOrigin],
|
|
})
|
|
ctx.req.headers['origin'] = assertOrigin
|
|
ctx.req.headers['access-control-request-headers'] = 'asdfasdfasdfsfad'
|
|
|
|
assert.notOk(ctx.headers['Vary'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Origin'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Methods'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Headers'])
|
|
|
|
corsHandler(ctx)
|
|
|
|
assert.strictEqual(ctx.headers['Vary'], 'Origin')
|
|
assert.strictEqual(ctx.headers['Access-Control-Allow-Origin'], assertOrigin)
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Credentials'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Methods'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Headers'])
|
|
assert.notOk(ctx.headers['Access-Control-Expose-Headers'])
|
|
assert.strictEqual(ctx.status, method)
|
|
})
|
|
})
|
|
|
|
t.test('should set credential header if specifed', function() {
|
|
testMethods.forEach(function(method) {
|
|
ctx = createCtx()
|
|
ctx.method = method
|
|
ctx.status = method
|
|
|
|
const assertOrigin = 'http://my.site.here'
|
|
|
|
corsHandler = CorsHandler({
|
|
allowedOrigins: [assertOrigin],
|
|
credentials: true,
|
|
})
|
|
ctx.req.headers['origin'] = assertOrigin
|
|
|
|
assert.notOk(ctx.headers['Vary'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Origin'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Methods'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Headers'])
|
|
|
|
corsHandler(ctx)
|
|
|
|
assert.strictEqual(ctx.headers['Vary'], 'Origin')
|
|
assert.strictEqual(ctx.headers['Access-Control-Allow-Credentials'], 'true')
|
|
assert.strictEqual(ctx.headers['Access-Control-Allow-Origin'], assertOrigin)
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Methods'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Headers'])
|
|
assert.notOk(ctx.headers['Access-Control-Expose-Headers'])
|
|
assert.strictEqual(ctx.status, method)
|
|
})
|
|
})
|
|
|
|
t.test('should set expose headers if specifed', function() {
|
|
testMethods.forEach(function(method) {
|
|
const assertExposeHeaders = 'Some, Test, Here'
|
|
ctx = createCtx()
|
|
ctx.method = method
|
|
ctx.status = method
|
|
|
|
const assertOrigin = 'http://my.site.here'
|
|
|
|
corsHandler = CorsHandler({
|
|
allowedOrigins: [assertOrigin],
|
|
exposeHeaders: assertExposeHeaders,
|
|
})
|
|
ctx.req.headers['origin'] = assertOrigin
|
|
|
|
assert.notOk(ctx.headers['Vary'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Origin'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Methods'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Headers'])
|
|
|
|
corsHandler(ctx)
|
|
|
|
assert.strictEqual(ctx.headers['Vary'], 'Origin')
|
|
assert.strictEqual(ctx.headers['Access-Control-Allow-Origin'], assertOrigin)
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Credentials'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Methods'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Headers'])
|
|
assert.strictEqual(ctx.headers['Access-Control-Expose-Headers'], assertExposeHeaders)
|
|
assert.strictEqual(ctx.status, method)
|
|
})
|
|
})
|
|
|
|
t.test('should not add any headers if origin missing', function() {
|
|
testMethods.forEach(function(method) {
|
|
ctx = createCtx()
|
|
ctx.method = method
|
|
ctx.status = method
|
|
|
|
corsHandler = CorsHandler({
|
|
allowedOrigins: ['https://test.com'],
|
|
})
|
|
ctx.req.headers['origin'] = null
|
|
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Origin'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Methods'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Headers'])
|
|
|
|
corsHandler(ctx)
|
|
|
|
assert.strictEqual(ctx.headers['Vary'], 'Origin')
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Origin'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Methods'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Headers'])
|
|
assert.notOk(ctx.headers['Access-Control-Expose-Headers'])
|
|
assert.strictEqual(ctx.status, method)
|
|
})
|
|
})
|
|
|
|
t.test('should not add any headers if origin not found', function() {
|
|
testMethods.forEach(function(method) {
|
|
ctx = createCtx()
|
|
ctx.method = method
|
|
ctx.status = method
|
|
|
|
const assertOrigin = 'http://my.site.here'
|
|
const assertAllowedMethods = 'GET,HEAD'
|
|
|
|
corsHandler = CorsHandler({
|
|
allowedOrigins: ['https://my.site.here'],
|
|
allowedMethods: assertAllowedMethods,
|
|
allowedHeaders: false,
|
|
})
|
|
ctx.req.headers['origin'] = assertOrigin
|
|
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Origin'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Methods'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Headers'])
|
|
|
|
corsHandler(ctx)
|
|
|
|
assert.strictEqual(ctx.headers['Vary'], 'Origin')
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Origin'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Methods'])
|
|
assert.notOk(ctx.headers['Access-Control-Allow-Headers'])
|
|
assert.notOk(ctx.headers['Access-Control-Expose-Headers'])
|
|
assert.strictEqual(ctx.status, method)
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
t.describe('#JsonHandler()', function() {
|
|
let jsonHandler = JsonHandler()
|
|
let ctx
|
|
|
|
t.beforeEach(function() {
|
|
ctx = createCtx()
|
|
})
|
|
|
|
t.test('should return a handler', function() {
|
|
assert.strictEqual(typeof(jsonHandler), 'function')
|
|
})
|
|
|
|
t.test('should support fetching body from request', async function() {
|
|
const assertBody = { a: 1, temp: 'test', hello: 'world'}
|
|
let parsed = JSON.stringify(assertBody)
|
|
let finished = false
|
|
let err = null
|
|
|
|
jsonHandler(ctx).catch(function(error) {
|
|
err = error
|
|
}).then(function() {
|
|
finished = true
|
|
})
|
|
|
|
assert.ok(ctx.req.on.called)
|
|
assert.strictEqual(ctx.req.on.firstCall[0], 'data')
|
|
assert.strictEqual(ctx.req.on.secondCall[0], 'end')
|
|
|
|
assert.strictEqual(finished, false)
|
|
|
|
ctx.req.on.firstCall[1](Buffer.from(parsed.slice(0, parsed.length / 2)))
|
|
|
|
assert.strictEqual(finished, false)
|
|
|
|
ctx.req.on.firstCall[1](Buffer.from(parsed.slice(parsed.length / 2)))
|
|
|
|
assert.strictEqual(finished, false)
|
|
|
|
ctx.req.on.secondCall[1]()
|
|
|
|
await setTimeout(10)
|
|
|
|
assert.strictEqual(finished, true)
|
|
assert.strictEqual(err, null)
|
|
|
|
assert.notStrictEqual(ctx.req.body, assertBody)
|
|
assert.deepStrictEqual(ctx.req.body, assertBody)
|
|
})
|
|
|
|
t.test('should throw if buffer grows too large', async function() {
|
|
let defaultLimit = 10 * 1024
|
|
let segmentSize = 100
|
|
|
|
let finished = false
|
|
let err = null
|
|
|
|
jsonHandler(ctx).catch(function(error) {
|
|
err = error
|
|
}).then(function() {
|
|
finished = true
|
|
})
|
|
|
|
for (let i = 0; i < defaultLimit; i += segmentSize) {
|
|
ctx.req.on.firstCall[1](Buffer.alloc(segmentSize, 'a'))
|
|
}
|
|
|
|
await setTimeout(10)
|
|
|
|
assert.strictEqual(finished, true)
|
|
assert.notStrictEqual(err, null)
|
|
|
|
assert.ok(err instanceof HttpError)
|
|
assert.strictEqual(err.status, 413)
|
|
assert.match(err.message, new RegExp(100 * 103))
|
|
assert.match(err.message, new RegExp(defaultLimit))
|
|
})
|
|
|
|
t.test('should throw if buffer is not valid json', async function() {
|
|
let finished = false
|
|
let err = null
|
|
|
|
jsonHandler(ctx).catch(function(error) {
|
|
err = error
|
|
}).then(function() {
|
|
finished = true
|
|
})
|
|
|
|
ctx.req.on.firstCall[1](Buffer.alloc(10, 'X'))
|
|
ctx.req.on.firstCall[1](Buffer.alloc(10, 'X'))
|
|
ctx.req.on.secondCall[1]()
|
|
|
|
await setTimeout(10)
|
|
|
|
assert.strictEqual(finished, true)
|
|
assert.notStrictEqual(err, null)
|
|
|
|
assert.ok(err instanceof HttpError)
|
|
assert.strictEqual(err.status, 400)
|
|
assert.match(err.message, /JSON/)
|
|
assert.match(err.message, /Unexpected token[^X]+X/i)
|
|
assert.strictEqual(err.body.status, 400)
|
|
assert.match(err.body.message, /Invalid JSON/i)
|
|
assert.match(err.body.message, /Unexpected token[^X]+X/i)
|
|
assert.strictEqual(err.body.request, 'XXXXXXXXXXXXXXXXXXXX')
|
|
})
|
|
|
|
t.test('should not throw if body is empty', async function() {
|
|
let finished = false
|
|
let err = null
|
|
|
|
jsonHandler(ctx).catch(function(error) {
|
|
err = error
|
|
}).then(function() {
|
|
finished = true
|
|
})
|
|
|
|
assert.ok(ctx.req.on.called)
|
|
assert.strictEqual(ctx.req.on.firstCall[0], 'data')
|
|
assert.strictEqual(ctx.req.on.secondCall[0], 'end')
|
|
|
|
assert.strictEqual(finished, false)
|
|
|
|
ctx.req.on.secondCall[1]()
|
|
|
|
await setTimeout(10)
|
|
|
|
assert.strictEqual(finished, true)
|
|
assert.strictEqual(err, null)
|
|
|
|
assert.deepStrictEqual(ctx.req.body, {})
|
|
})
|
|
})
|
|
|
|
t.describe('#FormidableHandler()', function() {
|
|
let formidable
|
|
let incomingForm
|
|
let ctx
|
|
|
|
t.beforeEach(function() {
|
|
ctx = createCtx()
|
|
formidable = {
|
|
IncomingForm: stub(),
|
|
fsRename: stub().resolves(),
|
|
}
|
|
|
|
incomingForm = {
|
|
parse: stub().returnWith(function(req, cb) {
|
|
cb(null, {}, { file: { name: 'asdf.png' } })
|
|
})
|
|
}
|
|
|
|
formidable.IncomingForm.returns(incomingForm)
|
|
})
|
|
|
|
t.test('should call formidable with correct defaults', async function() {
|
|
let handler = FormidableHandler(formidable)
|
|
await handler(ctx)
|
|
|
|
assert.strictEqual(incomingForm.uploadDir, os.tmpdir())
|
|
assert.strictEqual(incomingForm.maxFileSize, 8 * 1024 * 1024)
|
|
assert.strictEqual(incomingForm.maxFieldsSize, 10 * 1024)
|
|
assert.strictEqual(incomingForm.maxFields, 50)
|
|
assert.strictEqual(incomingForm.parse.firstCall[0], ctx.req)
|
|
})
|
|
|
|
t.test('should apply fields and rename file before returning', async function() {
|
|
const assertFilename = 'Lets love.png'
|
|
const assertOriginalPath = 'Hitoshi/Fujima/Yuigi.png'
|
|
const assertFile = { a: 1, name: assertFilename, path: assertOriginalPath }
|
|
const assertFields = { b: 2, c: 3 }
|
|
let handler = FormidableHandler(formidable)
|
|
|
|
incomingForm.parse.returnWith(function(req, cb) {
|
|
cb(null, assertFields, { file: assertFile })
|
|
})
|
|
|
|
assert.notOk(ctx.req.body)
|
|
assert.notOk(ctx.req.file)
|
|
let prefix = new Date().toISOString().replace(/-/g, '').replace('T', '_').replace(/:/g, '').split('.')[0]
|
|
await handler(ctx)
|
|
|
|
assert.strictEqual(ctx.req.body, assertFields)
|
|
assert.strictEqual(ctx.req.file, assertFile)
|
|
assert.strictEqual(ctx.req.file.path, path.join(os.tmpdir(), ctx.req.file.filename))
|
|
assert.match(ctx.req.file.filename, new RegExp(prefix))
|
|
assert.match(ctx.req.file.filename, new RegExp(assertFilename))
|
|
|
|
assert.ok(formidable.fsRename.called)
|
|
assert.strictEqual(formidable.fsRename.firstCall[0], assertOriginalPath)
|
|
assert.strictEqual(formidable.fsRename.firstCall[1], ctx.req.file.path)
|
|
})
|
|
|
|
t.test('should throw parse error if parse fails', async function() {
|
|
const assertError = new Error('Aozora')
|
|
|
|
|
|
let handler = FormidableHandler(formidable)
|
|
|
|
incomingForm.parse.returnWith(function(req, cb) {
|
|
cb(assertError)
|
|
})
|
|
|
|
let err = await assert.isRejected(handler(ctx))
|
|
|
|
assert.notStrictEqual(err, assertError)
|
|
assert.ok(err instanceof HttpError)
|
|
assert.strictEqual(err.message, assertError.message)
|
|
assert.strictEqual(err.status, 400)
|
|
})
|
|
|
|
t.test('should throw rename error if rename fails', async function() {
|
|
const assertError = new Error('Aozora')
|
|
formidable.fsRename.rejects(assertError)
|
|
|
|
let handler = FormidableHandler(formidable)
|
|
let err = await assert.isRejected(handler(ctx))
|
|
|
|
assert.strictEqual(err, assertError)
|
|
})
|
|
|
|
t.test('should not call rename if no file is present', async function() {
|
|
const assertNotError = new Error('Aozora')
|
|
const assertFields = { a: 1 }
|
|
formidable.fsRename.rejects(assertNotError)
|
|
|
|
let handler = FormidableHandler(formidable)
|
|
|
|
incomingForm.parse.returnWith(function(req, cb) {
|
|
cb(null, assertFields, null)
|
|
})
|
|
|
|
await handler(ctx)
|
|
|
|
assert.strictEqual(ctx.req.body, assertFields)
|
|
assert.strictEqual(ctx.req.file, null)
|
|
|
|
incomingForm.parse.returnWith(function(req, cb) {
|
|
cb(null, assertFields, { file: null })
|
|
})
|
|
|
|
await handler(ctx)
|
|
|
|
assert.strictEqual(ctx.req.body, assertFields)
|
|
assert.strictEqual(ctx.req.file, null)
|
|
})
|
|
|
|
t.test('should throw filename error if filename fails', async function() {
|
|
const assertError = new Error('Dallaglio Piano')
|
|
|
|
let handler = FormidableHandler(formidable, {
|
|
filename: function() {
|
|
throw assertError
|
|
}
|
|
})
|
|
|
|
let err = await assert.isRejected(handler(ctx))
|
|
|
|
assert.strictEqual(err, assertError)
|
|
})
|
|
|
|
t.test('should default to original name of filename returns null', async function() {
|
|
const assertFilename = 'Herrscher.png'
|
|
|
|
let handler = FormidableHandler(formidable, {
|
|
filename: function() {
|
|
return null
|
|
}
|
|
})
|
|
|
|
incomingForm.parse.returnWith(function(req, cb) {
|
|
cb(null, { }, { file: { name: assertFilename } })
|
|
})
|
|
|
|
await handler(ctx)
|
|
|
|
assert.strictEqual(ctx.req.file.filename, assertFilename)
|
|
})
|
|
|
|
t.test('should support multiple filename calls in same second', async function() {
|
|
const assertFilename = 'Herrscher.png'
|
|
|
|
let handler = FormidableHandler(formidable)
|
|
|
|
await handler(ctx)
|
|
|
|
let file1 = ctx.req.file
|
|
|
|
await handler(ctx)
|
|
|
|
let file2 = ctx.req.file
|
|
|
|
assert.notStrictEqual(file1, file2)
|
|
assert.notStrictEqual(file1.filename, file2.filename)
|
|
})
|
|
|
|
|
|
t.test('should support parsing fields as json', async function() {
|
|
const assertFields = { b: '2', c: '3', e: 'asdf', f: '{"a": 1}' }
|
|
let handler = FormidableHandler(formidable, {
|
|
parseFields: true,
|
|
})
|
|
|
|
incomingForm.parse.returnWith(function(req, cb) {
|
|
cb(null, assertFields, { file: { name: 'test.png' } })
|
|
})
|
|
|
|
await handler(ctx)
|
|
|
|
assert.strictEqual(ctx.req.body, assertFields)
|
|
assert.strictEqual(ctx.req.body.b, 2)
|
|
assert.strictEqual(ctx.req.body.c, 3)
|
|
assert.strictEqual(ctx.req.body.e, 'asdf')
|
|
assert.deepStrictEqual(ctx.req.body.f, {a: 1})
|
|
})
|
|
})
|