Projektstart

This commit is contained in:
2026-01-22 15:49:12 +01:00
parent 7212eb6f7a
commit 57e5f652f8
10637 changed files with 2598792 additions and 64 deletions

941
backend/node_modules/@fastify/cors/test/cors.test.js generated vendored Normal file
View File

@@ -0,0 +1,941 @@
'use strict'
const { test } = require('tap')
const { createReadStream, statSync, readFileSync } = require('node:fs')
const Fastify = require('fastify')
const cors = require('../')
const { resolve } = require('node:path')
test('Should add cors headers', t => {
t.plan(4)
const fastify = Fastify()
fastify.register(cors)
fastify.get('/', (req, reply) => {
reply.send('ok')
})
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
'access-control-allow-origin': '*'
})
})
})
test('Should add cors headers when payload is a stream', t => {
t.plan(4)
const fastify = Fastify()
fastify.register(cors)
const filePath = resolve(__dirname, __filename)
fastify.get('/', (req, reply) => {
const stream = createReadStream(filePath)
reply
.type('application/json')
.header('Content-Length', statSync(filePath).size)
.send(stream)
})
const fileContent = readFileSync(filePath, 'utf-8')
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, fileContent)
t.match(res.headers, {
'access-control-allow-origin': '*',
'content-length': statSync(filePath).size
})
})
})
test('Should add cors headers (custom values)', t => {
t.plan(10)
const fastify = Fastify()
fastify.register(cors, {
origin: 'example.com',
methods: 'GET',
credentials: true,
exposedHeaders: ['foo', 'bar'],
allowedHeaders: ['baz', 'woo'],
maxAge: 123,
cacheControl: 321
})
fastify.get('/', (req, reply) => {
reply.send('ok')
})
fastify.inject({
method: 'OPTIONS',
url: '/',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 204)
t.equal(res.payload, '')
t.match(res.headers, {
'access-control-allow-origin': 'example.com',
'access-control-allow-credentials': 'true',
'access-control-expose-headers': 'foo, bar',
'access-control-allow-methods': 'GET',
'access-control-allow-headers': 'baz, woo',
'access-control-max-age': '123',
'cache-control': 'max-age=321',
'content-length': '0'
})
t.notMatch(res.headers, { vary: 'Origin' })
})
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
'access-control-allow-origin': 'example.com',
'access-control-allow-credentials': 'true',
'access-control-expose-headers': 'foo, bar',
'content-length': '2'
})
t.notMatch(res.headers, { vary: 'Origin' })
})
})
test('Should support dynamic config (callback)', t => {
t.plan(16)
const configs = [{
origin: 'example.com',
methods: 'GET',
credentials: true,
exposedHeaders: ['foo', 'bar'],
allowedHeaders: ['baz', 'woo'],
maxAge: 123,
cacheControl: 456
}, {
origin: 'sample.com',
methods: 'GET',
credentials: true,
exposedHeaders: ['zoo', 'bar'],
allowedHeaders: ['baz', 'foo'],
maxAge: 321,
cacheControl: '456'
}]
const fastify = Fastify()
let requestId = 0
const configDelegation = function (req, cb) {
// request should have id
t.ok(req.id)
// request should not have send
t.notOk(req.send)
const config = configs[requestId]
requestId++
if (config) {
cb(null, config)
} else {
cb(new Error('ouch'))
}
}
fastify.register(cors, () => configDelegation)
fastify.get('/', (req, reply) => {
reply.send('ok')
})
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
'access-control-allow-origin': 'example.com',
'access-control-allow-credentials': 'true',
'access-control-expose-headers': 'foo, bar',
'content-length': '2',
vary: 'Origin'
})
})
fastify.inject({
method: 'OPTIONS',
url: '/',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 204)
t.equal(res.payload, '')
t.match(res.headers, {
'access-control-allow-origin': 'sample.com',
'access-control-allow-credentials': 'true',
'access-control-expose-headers': 'zoo, bar',
'access-control-allow-methods': 'GET',
'access-control-allow-headers': 'baz, foo',
'access-control-max-age': '321',
'cache-control': '456',
'content-length': '0',
vary: 'Origin'
})
})
fastify.inject({
method: 'GET',
url: '/',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
t.equal(res.statusCode, 500)
})
})
test('Should support dynamic config (Promise)', t => {
t.plan(23)
const configs = [{
origin: 'example.com',
methods: 'GET',
credentials: true,
exposedHeaders: ['foo', 'bar'],
allowedHeaders: ['baz', 'woo'],
maxAge: 123,
cacheControl: 456
}, {
origin: 'sample.com',
methods: 'GET',
credentials: true,
exposedHeaders: ['zoo', 'bar'],
allowedHeaders: ['baz', 'foo'],
maxAge: 321,
cacheControl: true // Invalid value should be ignored
}, {
origin: 'sample.com',
methods: 'GET',
credentials: true,
exposedHeaders: ['zoo', 'bar'],
allowedHeaders: ['baz', 'foo'],
maxAge: 321,
cacheControl: 'public, max-age=456'
}]
const fastify = Fastify()
let requestId = 0
const configDelegation = function (req) {
// request should have id
t.ok(req.id)
// request should not have send
t.notOk(req.send)
const config = configs[requestId]
requestId++
if (config) {
return Promise.resolve(config)
} else {
return Promise.reject(new Error('ouch'))
}
}
fastify.register(cors, () => configDelegation)
fastify.get('/', (req, reply) => {
reply.send('ok')
})
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
'access-control-allow-origin': 'example.com',
'access-control-allow-credentials': 'true',
'access-control-expose-headers': 'foo, bar',
'content-length': '2',
vary: 'Origin'
})
})
fastify.inject({
method: 'OPTIONS',
url: '/',
headers: {
'access-control-request-method': 'GET',
origin: 'sample.com'
}
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 204)
t.equal(res.payload, '')
t.match(res.headers, {
'access-control-allow-origin': 'sample.com',
'access-control-allow-credentials': 'true',
'access-control-expose-headers': 'zoo, bar',
'access-control-allow-methods': 'GET',
'access-control-allow-headers': 'baz, foo',
'access-control-max-age': '321',
'content-length': '0',
vary: 'Origin'
})
t.equal(res.headers['cache-control'], undefined, 'cache-control omitted (invalid value)')
})
fastify.inject({
method: 'OPTIONS',
url: '/',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 204)
t.equal(res.payload, '')
t.match(res.headers, {
'access-control-allow-origin': 'sample.com',
'access-control-allow-credentials': 'true',
'access-control-expose-headers': 'zoo, bar',
'access-control-allow-methods': 'GET',
'access-control-allow-headers': 'baz, foo',
'access-control-max-age': '321',
'cache-control': 'public, max-age=456', // cache-control included (custom string)
'content-length': '0',
vary: 'Origin'
})
})
fastify.inject({
method: 'GET',
url: '/',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
t.equal(res.statusCode, 500)
})
})
test('Should support dynamic config. (Invalid function)', t => {
t.plan(2)
const fastify = Fastify()
fastify.register(cors, () => (a, b, c) => {})
fastify.get('/', (req, reply) => {
reply.send('ok')
})
fastify.inject({
method: 'GET',
url: '/',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
t.equal(res.statusCode, 500)
})
})
test('Dynamic origin resolution (valid origin)', t => {
t.plan(6)
const fastify = Fastify()
const origin = function (header, cb) {
t.equal(header, 'example.com')
t.same(this, fastify)
cb(null, true)
}
fastify.register(cors, { origin })
fastify.get('/', (req, reply) => {
reply.send('ok')
})
fastify.inject({
method: 'GET',
url: '/',
headers: { origin: 'example.com' }
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
'access-control-allow-origin': 'example.com',
vary: 'Origin'
})
})
})
test('Dynamic origin resolution (not valid origin)', t => {
t.plan(5)
const fastify = Fastify()
const origin = (header, cb) => {
t.equal(header, 'example.com')
cb(null, false)
}
fastify.register(cors, { origin })
fastify.get('/', (req, reply) => {
reply.send('ok')
})
fastify.inject({
method: 'GET',
url: '/',
headers: { origin: 'example.com' }
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.same(res.headers, {
'content-length': '2',
'content-type': 'text/plain; charset=utf-8',
connection: 'keep-alive',
vary: 'Origin'
})
})
})
test('Dynamic origin resolution (errored)', t => {
t.plan(3)
const fastify = Fastify()
const origin = (header, cb) => {
t.equal(header, 'example.com')
cb(new Error('ouch'))
}
fastify.register(cors, { origin })
fastify.inject({
method: 'GET',
url: '/',
headers: { origin: 'example.com' }
}, (err, res) => {
t.error(err)
t.equal(res.statusCode, 500)
})
})
test('Dynamic origin resolution (invalid result)', t => {
t.plan(3)
const fastify = Fastify()
const origin = (header, cb) => {
t.equal(header, 'example.com')
cb(null, undefined)
}
fastify.register(cors, { origin })
fastify.inject({
method: 'GET',
url: '/',
headers: { origin: 'example.com' }
}, (err, res) => {
t.error(err)
t.equal(res.statusCode, 500)
})
})
test('Dynamic origin resolution (valid origin - promises)', t => {
t.plan(5)
const fastify = Fastify()
const origin = (header, cb) => {
return new Promise((resolve, reject) => {
t.equal(header, 'example.com')
resolve(true)
})
}
fastify.register(cors, { origin })
fastify.get('/', (req, reply) => {
reply.send('ok')
})
fastify.inject({
method: 'GET',
url: '/',
headers: { origin: 'example.com' }
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
'access-control-allow-origin': 'example.com',
vary: 'Origin'
})
})
})
test('Dynamic origin resolution (not valid origin - promises)', t => {
t.plan(5)
const fastify = Fastify()
const origin = (header, cb) => {
return new Promise((resolve, reject) => {
t.equal(header, 'example.com')
resolve(false)
})
}
fastify.register(cors, { origin })
fastify.get('/', (req, reply) => {
reply.send('ok')
})
fastify.inject({
method: 'GET',
url: '/',
headers: { origin: 'example.com' }
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.same(res.headers, {
'content-length': '2',
'content-type': 'text/plain; charset=utf-8',
connection: 'keep-alive',
vary: 'Origin'
})
})
})
test('Dynamic origin resolution (errored - promises)', t => {
t.plan(3)
const fastify = Fastify()
const origin = (header, cb) => {
return new Promise((resolve, reject) => {
t.equal(header, 'example.com')
reject(new Error('ouch'))
})
}
fastify.register(cors, { origin })
fastify.inject({
method: 'GET',
url: '/',
headers: { origin: 'example.com' }
}, (err, res) => {
t.error(err)
t.equal(res.statusCode, 500)
})
})
test('Should reply 404 without cors headers when origin is false', t => {
t.plan(8)
const fastify = Fastify()
fastify.register(cors, {
origin: false,
methods: 'GET',
credentials: true,
exposedHeaders: ['foo', 'bar'],
allowedHeaders: ['baz', 'woo'],
maxAge: 123
})
fastify.get('/', (req, reply) => {
reply.send('ok')
})
fastify.inject({
method: 'OPTIONS',
url: '/'
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 404)
t.equal(res.payload, '{"message":"Route OPTIONS:/ not found","error":"Not Found","statusCode":404}')
t.same(res.headers, {
'content-length': '76',
'content-type': 'application/json; charset=utf-8',
connection: 'keep-alive'
})
})
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.same(res.headers, {
'content-length': '2',
'content-type': 'text/plain; charset=utf-8',
connection: 'keep-alive'
})
})
})
test('Server error if origin option is falsy but not false', t => {
t.plan(4)
const fastify = Fastify()
fastify.register(cors, { origin: '' })
fastify.inject({
method: 'GET',
url: '/',
headers: { origin: 'example.com' }
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 500)
t.same(res.json(), { statusCode: 500, error: 'Internal Server Error', message: 'Invalid CORS origin option' })
t.same(res.headers, {
'content-length': '89',
'content-type': 'application/json; charset=utf-8',
connection: 'keep-alive'
})
})
})
test('Allow only request from a specific origin', t => {
t.plan(5)
const fastify = Fastify()
fastify.register(cors, { origin: 'other.io' })
fastify.get('/', (req, reply) => {
reply.send('ok')
})
fastify.inject({
method: 'GET',
url: '/',
headers: { origin: 'example.com' }
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
'access-control-allow-origin': 'other.io'
})
t.notMatch(res.headers, { vary: 'Origin' })
})
})
test('Allow only request from multiple specific origin', t => {
t.plan(9)
const fastify = Fastify()
fastify.register(cors, { origin: ['other.io', 'example.com'] })
fastify.get('/', (req, reply) => {
reply.send('ok')
})
fastify.inject({
method: 'GET',
url: '/',
headers: { origin: 'other.io' }
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
'access-control-allow-origin': 'other.io',
vary: 'Origin'
})
})
fastify.inject({
method: 'GET',
url: '/',
headers: { origin: 'foo.com' }
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
vary: 'Origin'
})
t.equal(res.headers['access-control-allow-origin'], undefined)
})
})
test('Allow only request from a specific origin using regex', t => {
t.plan(8)
const fastify = Fastify()
fastify.register(cors, { origin: /(?:example|other)\.com/giu })
fastify.get('/', (req, reply) => {
reply.send('ok')
})
// .test was previously used, which caused 2 consecutive requests to return
// different results with global (e.g. /g) regexes. Therefore, check this
// twice to check consistency
for (let i = 0; i < 2; i++) {
fastify.inject({
method: 'GET',
url: '/',
headers: { origin: 'https://www.example.com/' }
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
'access-control-allow-origin': 'https://www.example.com/',
vary: 'Origin'
})
})
}
})
test('Disable preflight', t => {
t.plan(7)
const fastify = Fastify()
fastify.register(cors, { preflight: false })
fastify.get('/', (req, reply) => {
reply.send('ok')
})
fastify.inject({
method: 'OPTIONS',
url: '/hello'
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 404)
t.match(res.headers, {
'access-control-allow-origin': '*'
})
})
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
'access-control-allow-origin': '*'
})
})
})
test('Should always add vary header to `Origin` for reflected origin', t => {
t.plan(12)
const fastify = Fastify()
fastify.register(cors, { origin: true })
fastify.get('/', (req, reply) => {
reply.send('ok')
})
// Invalid Preflight
fastify.inject({
method: 'OPTIONS',
url: '/'
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 400)
t.equal(res.payload, 'Invalid Preflight Request')
t.match(res.headers, {
vary: 'Origin'
})
})
// Valid Preflight
fastify.inject({
method: 'OPTIONS',
url: '/',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 204)
t.equal(res.payload, '')
t.match(res.headers, {
vary: 'Origin'
})
})
// Other Route
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
vary: 'Origin'
})
})
})
test('Should always add vary header to `Origin` for reflected origin (vary is array)', t => {
t.plan(4)
const fastify = Fastify()
// Mock getHeader function
fastify.decorateReply('getHeader', (name) => ['foo', 'bar'])
fastify.register(cors, { origin: true })
fastify.get('/', (req, reply) => {
reply.send('ok')
})
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
vary: 'foo, bar, Origin'
})
})
})
test('Allow only request from with specific headers', t => {
t.plan(8)
const fastify = Fastify()
fastify.register(cors, {
allowedHeaders: 'foo',
exposedHeaders: 'bar'
})
fastify.get('/', (req, reply) => {
reply.send('ok')
})
fastify.inject({
method: 'OPTIONS',
url: '/',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 204)
t.match(res.headers, {
'access-control-allow-headers': 'foo'
})
t.notMatch(res.headers, { vary: 'Origin' })
})
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
'access-control-expose-headers': 'bar'
})
})
})
test('Should support wildcard config /1', t => {
t.plan(4)
const fastify = Fastify()
fastify.register(cors, { origin: '*' })
fastify.get('/', (req, reply) => {
reply.send('ok')
})
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.error(err)
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.equal(res.headers['access-control-allow-origin'], '*')
})
})
test('Should support wildcard config /2', t => {
t.plan(4)
const fastify = Fastify()
fastify.register(cors, { origin: ['*'] })
fastify.get('/', (req, reply) => {
reply.send('ok')
})
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.error(err)
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.equal(res.headers['access-control-allow-origin'], '*')
})
})

706
backend/node_modules/@fastify/cors/test/hooks.test.js generated vendored Normal file
View File

@@ -0,0 +1,706 @@
'use strict'
const { test } = require('tap')
const Fastify = require('fastify')
const kFastifyContext = require('fastify/lib/symbols').kRouteContext
const cors = require('..')
test('Should error on invalid hook option', async (t) => {
t.plan(1)
const fastify = Fastify()
t.rejects(fastify.register(cors, { hook: 'invalid' }), new TypeError('@fastify/cors: Invalid hook option provided.'))
})
test('Should set hook onRequest if hook option is not set', async (t) => {
t.plan(10)
const fastify = Fastify()
fastify.register(cors)
fastify.addHook('onResponse', (request, reply, done) => {
t.equal(request[kFastifyContext].onError, null)
t.equal(request[kFastifyContext].onRequest.length, 1)
t.equal(request[kFastifyContext].onSend, null)
t.equal(request[kFastifyContext].preHandler, null)
t.equal(request[kFastifyContext].preParsing, null)
t.equal(request[kFastifyContext].preSerialization, null)
t.equal(request[kFastifyContext].preValidation, null)
done()
})
fastify.get('/', (req, reply) => {
reply.send('ok')
})
await fastify.ready()
const res = await fastify.inject({
method: 'GET',
url: '/'
})
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
'access-control-allow-origin': '*'
})
})
test('Should set hook onRequest if hook option is set to onRequest', async (t) => {
t.plan(10)
const fastify = Fastify()
fastify.register(cors, {
hook: 'onRequest'
})
fastify.addHook('onResponse', (request, reply, done) => {
t.equal(request[kFastifyContext].onError, null)
t.equal(request[kFastifyContext].onRequest.length, 1)
t.equal(request[kFastifyContext].onSend, null)
t.equal(request[kFastifyContext].preHandler, null)
t.equal(request[kFastifyContext].preParsing, null)
t.equal(request[kFastifyContext].preSerialization, null)
t.equal(request[kFastifyContext].preValidation, null)
done()
})
fastify.get('/', (req, reply) => {
reply.send('ok')
})
await fastify.ready()
const res = await fastify.inject({
method: 'GET',
url: '/'
})
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
'access-control-allow-origin': '*'
})
})
test('Should set hook preParsing if hook option is set to preParsing', async (t) => {
t.plan(11)
const fastify = Fastify()
fastify.register(cors, {
hook: 'preParsing'
})
fastify.addHook('onResponse', (request, reply, done) => {
t.equal(request[kFastifyContext].onError, null)
t.equal(request[kFastifyContext].onRequest, null)
t.equal(request[kFastifyContext].onSend, null)
t.equal(request[kFastifyContext].preHandler, null)
t.equal(request[kFastifyContext].preParsing.length, 1)
t.equal(request[kFastifyContext].preSerialization, null)
t.equal(request[kFastifyContext].preValidation, null)
done()
})
fastify.get('/', (req, reply) => {
reply.send('ok')
})
await fastify.ready()
const res = await fastify.inject({
method: 'GET',
url: '/'
})
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
'access-control-allow-origin': '*'
})
t.notMatch(res.headers, { vary: 'Origin' })
})
test('Should set hook preValidation if hook option is set to preValidation', async (t) => {
t.plan(11)
const fastify = Fastify()
fastify.register(cors, {
hook: 'preValidation'
})
fastify.addHook('onResponse', (request, reply, done) => {
t.equal(request[kFastifyContext].onError, null)
t.equal(request[kFastifyContext].onRequest, null)
t.equal(request[kFastifyContext].onSend, null)
t.equal(request[kFastifyContext].preHandler, null)
t.equal(request[kFastifyContext].preParsing, null)
t.equal(request[kFastifyContext].preSerialization, null)
t.equal(request[kFastifyContext].preValidation.length, 1)
done()
})
fastify.get('/', (req, reply) => {
reply.send('ok')
})
await fastify.ready()
const res = await fastify.inject({
method: 'GET',
url: '/'
})
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
'access-control-allow-origin': '*'
})
t.notMatch(res.headers, { vary: 'Origin' })
})
test('Should set hook preParsing if hook option is set to preParsing', async (t) => {
t.plan(11)
const fastify = Fastify()
fastify.register(cors, {
hook: 'preParsing'
})
fastify.addHook('onResponse', (request, reply, done) => {
t.equal(request[kFastifyContext].onError, null)
t.equal(request[kFastifyContext].onRequest, null)
t.equal(request[kFastifyContext].onSend, null)
t.equal(request[kFastifyContext].preHandler, null)
t.equal(request[kFastifyContext].preParsing.length, 1)
t.equal(request[kFastifyContext].preSerialization, null)
t.equal(request[kFastifyContext].preValidation, null)
done()
})
fastify.get('/', (req, reply) => {
reply.send('ok')
})
await fastify.ready()
const res = await fastify.inject({
method: 'GET',
url: '/'
})
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
'access-control-allow-origin': '*'
})
t.notMatch(res.headers, { vary: 'Origin' })
})
test('Should set hook preHandler if hook option is set to preHandler', async (t) => {
t.plan(11)
const fastify = Fastify()
fastify.register(cors, {
hook: 'preHandler'
})
fastify.addHook('onResponse', (request, reply, done) => {
t.equal(request[kFastifyContext].onError, null)
t.equal(request[kFastifyContext].onRequest, null)
t.equal(request[kFastifyContext].onSend, null)
t.equal(request[kFastifyContext].preHandler.length, 1)
t.equal(request[kFastifyContext].preParsing, null)
t.equal(request[kFastifyContext].preSerialization, null)
t.equal(request[kFastifyContext].preValidation, null)
done()
})
fastify.get('/', (req, reply) => {
reply.send('ok')
})
await fastify.ready()
const res = await fastify.inject({
method: 'GET',
url: '/'
})
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
'access-control-allow-origin': '*'
})
t.notMatch(res.headers, { vary: 'Origin' })
})
test('Should set hook onSend if hook option is set to onSend', async (t) => {
t.plan(11)
const fastify = Fastify()
fastify.register(cors, {
hook: 'onSend'
})
fastify.addHook('onResponse', (request, reply, done) => {
t.equal(request[kFastifyContext].onError, null)
t.equal(request[kFastifyContext].onRequest, null)
t.equal(request[kFastifyContext].onSend.length, 1)
t.equal(request[kFastifyContext].preHandler, null)
t.equal(request[kFastifyContext].preParsing, null)
t.equal(request[kFastifyContext].preSerialization, null)
t.equal(request[kFastifyContext].preValidation, null)
done()
})
fastify.get('/', (req, reply) => {
reply.send('ok')
})
await fastify.ready()
const res = await fastify.inject({
method: 'GET',
url: '/'
})
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
'access-control-allow-origin': '*'
})
t.notMatch(res.headers, { vary: 'Origin' })
})
test('Should set hook preSerialization if hook option is set to preSerialization', async (t) => {
t.plan(11)
const fastify = Fastify()
fastify.register(cors, {
hook: 'preSerialization'
})
fastify.addHook('onResponse', (request, reply, done) => {
t.equal(request[kFastifyContext].onError, null)
t.equal(request[kFastifyContext].onRequest, null)
t.equal(request[kFastifyContext].onSend, null)
t.equal(request[kFastifyContext].preHandler, null)
t.equal(request[kFastifyContext].preParsing, null)
t.equal(request[kFastifyContext].preSerialization.length, 1)
t.equal(request[kFastifyContext].preValidation, null)
done()
})
fastify.get('/', (req, reply) => {
reply.send({ nonString: true })
})
await fastify.ready()
const res = await fastify.inject({
method: 'GET',
url: '/'
})
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, '{"nonString":true}')
t.match(res.headers, {
'access-control-allow-origin': '*'
})
t.notMatch(res.headers, { vary: 'Origin' })
})
test('Should support custom hook with dynamic config', t => {
t.plan(16)
const configs = [{
origin: 'example.com',
methods: 'GET',
credentials: true,
exposedHeaders: ['foo', 'bar'],
allowedHeaders: ['baz', 'woo'],
maxAge: 123
}, {
origin: 'sample.com',
methods: 'GET',
credentials: true,
exposedHeaders: ['zoo', 'bar'],
allowedHeaders: ['baz', 'foo'],
maxAge: 321
}]
const fastify = Fastify()
let requestId = 0
const configDelegation = function (req, cb) {
// request should have id
t.ok(req.id)
// request should not have send
t.notOk(req.send)
const config = configs[requestId]
requestId++
if (config) {
cb(null, config)
} else {
cb(new Error('ouch'))
}
}
fastify.register(cors, {
hook: 'preHandler',
delegator: configDelegation
})
fastify.get('/', (req, reply) => {
reply.send('ok')
})
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
'access-control-allow-origin': 'example.com',
'access-control-allow-credentials': 'true',
'access-control-expose-headers': 'foo, bar',
'content-length': '2',
vary: 'Origin'
})
})
fastify.inject({
method: 'OPTIONS',
url: '/',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 204)
t.equal(res.payload, '')
t.match(res.headers, {
'access-control-allow-origin': 'sample.com',
'access-control-allow-credentials': 'true',
'access-control-expose-headers': 'zoo, bar',
'access-control-allow-methods': 'GET',
'access-control-allow-headers': 'baz, foo',
'access-control-max-age': '321',
'content-length': '0',
vary: 'Origin'
})
})
fastify.inject({
method: 'GET',
url: '/',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
t.equal(res.statusCode, 500)
})
})
test('Should support custom hook with dynamic config (callback)', t => {
t.plan(16)
const configs = [{
origin: 'example.com',
methods: 'GET',
credentials: true,
exposedHeaders: ['foo', 'bar'],
allowedHeaders: ['baz', 'woo'],
maxAge: 123
}, {
origin: 'sample.com',
methods: 'GET',
credentials: true,
exposedHeaders: ['zoo', 'bar'],
allowedHeaders: ['baz', 'foo'],
maxAge: 321
}]
const fastify = Fastify()
let requestId = 0
const configDelegation = function (req, cb) {
// request should have id
t.ok(req.id)
// request should not have send
t.notOk(req.send)
const config = configs[requestId]
requestId++
if (config) {
cb(null, config)
} else {
cb(new Error('ouch'))
}
}
fastify.register(cors, {
hook: 'preParsing',
delegator: configDelegation
})
fastify.get('/', (req, reply) => {
reply.send('ok')
})
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
'access-control-allow-origin': 'example.com',
'access-control-allow-credentials': 'true',
'access-control-expose-headers': 'foo, bar',
'content-length': '2',
vary: 'Origin'
})
})
fastify.inject({
method: 'OPTIONS',
url: '/',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 204)
t.equal(res.payload, '')
t.match(res.headers, {
'access-control-allow-origin': 'sample.com',
'access-control-allow-credentials': 'true',
'access-control-expose-headers': 'zoo, bar',
'access-control-allow-methods': 'GET',
'access-control-allow-headers': 'baz, foo',
'access-control-max-age': '321',
'content-length': '0',
vary: 'Origin'
})
})
fastify.inject({
method: 'GET',
url: '/',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
t.equal(res.statusCode, 500)
})
})
test('Should support custom hook with dynamic config (Promise)', t => {
t.plan(16)
const configs = [{
origin: 'example.com',
methods: 'GET',
credentials: true,
exposedHeaders: ['foo', 'bar'],
allowedHeaders: ['baz', 'woo'],
maxAge: 123
}, {
origin: 'sample.com',
methods: 'GET',
credentials: true,
exposedHeaders: ['zoo', 'bar'],
allowedHeaders: ['baz', 'foo'],
maxAge: 321
}]
const fastify = Fastify()
let requestId = 0
const configDelegation = function (req) {
// request should have id
t.ok(req.id)
// request should not have send
t.notOk(req.send)
const config = configs[requestId]
requestId++
if (config) {
return Promise.resolve(config)
} else {
return Promise.reject(new Error('ouch'))
}
}
fastify.register(cors, {
hook: 'preParsing',
delegator: configDelegation
})
fastify.get('/', (req, reply) => {
reply.send('ok')
})
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
'access-control-allow-origin': 'example.com',
'access-control-allow-credentials': 'true',
'access-control-expose-headers': 'foo, bar',
'content-length': '2',
vary: 'Origin'
})
})
fastify.inject({
method: 'OPTIONS',
url: '/',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 204)
t.equal(res.payload, '')
t.match(res.headers, {
'access-control-allow-origin': 'sample.com',
'access-control-allow-credentials': 'true',
'access-control-expose-headers': 'zoo, bar',
'access-control-allow-methods': 'GET',
'access-control-allow-headers': 'baz, foo',
'access-control-max-age': '321',
'content-length': '0',
vary: 'Origin'
})
})
fastify.inject({
method: 'GET',
url: '/',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
t.equal(res.statusCode, 500)
})
})
test('Should support custom hook with dynamic config (Promise), but should error /1', t => {
t.plan(6)
const fastify = Fastify()
const configDelegation = function () {
return false
}
fastify.register(cors, {
hook: 'preParsing',
delegator: configDelegation
})
fastify.get('/', (req, reply) => {
reply.send('ok')
})
fastify.inject({
method: 'OPTIONS',
url: '/',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 500)
t.equal(res.payload, '{"statusCode":500,"error":"Internal Server Error","message":"Invalid CORS origin option"}')
t.match(res.headers, {
'content-length': '89'
})
})
fastify.inject({
method: 'GET',
url: '/',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
t.equal(res.statusCode, 500)
})
})
test('Should support custom hook with dynamic config (Promise), but should error /2', t => {
t.plan(6)
const fastify = Fastify()
const configDelegation = function () {
return false
}
fastify.register(cors, {
delegator: configDelegation
})
fastify.get('/', (req, reply) => {
reply.send('ok')
})
fastify.inject({
method: 'OPTIONS',
url: '/',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 500)
t.equal(res.payload, '{"statusCode":500,"error":"Internal Server Error","message":"Invalid CORS origin option"}')
t.match(res.headers, {
'content-length': '89'
})
})
fastify.inject({
method: 'GET',
url: '/',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
t.equal(res.statusCode, 500)
})
})

View File

@@ -0,0 +1,435 @@
'use strict'
const { test } = require('tap')
const Fastify = require('fastify')
const cors = require('../')
test('Should reply to preflight requests', t => {
t.plan(4)
const fastify = Fastify()
fastify.register(cors)
fastify.inject({
method: 'OPTIONS',
url: '/',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 204)
t.equal(res.payload, '')
t.match(res.headers, {
'access-control-allow-origin': '*',
'access-control-allow-methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
vary: 'Access-Control-Request-Headers',
'content-length': '0'
})
})
})
test('Should add access-control-allow-headers to response if preflight req has access-control-request-headers', t => {
t.plan(4)
const fastify = Fastify()
fastify.register(cors)
fastify.inject({
method: 'OPTIONS',
url: '/',
headers: {
'access-control-request-headers': 'x-requested-with',
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 204)
t.equal(res.payload, '')
t.match(res.headers, {
'access-control-allow-origin': '*',
'access-control-allow-methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
'access-control-allow-headers': 'x-requested-with',
vary: 'Access-Control-Request-Headers',
'content-length': '0'
})
})
})
test('Should reply to preflight requests with custom status code', t => {
t.plan(4)
const fastify = Fastify()
fastify.register(cors, { optionsSuccessStatus: 200 })
fastify.inject({
method: 'OPTIONS',
url: '/',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, '')
t.match(res.headers, {
'access-control-allow-origin': '*',
'access-control-allow-methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
vary: 'Access-Control-Request-Headers',
'content-length': '0'
})
})
})
test('Should be able to override preflight response with a route', t => {
t.plan(5)
const fastify = Fastify()
fastify.register(cors, { preflightContinue: true })
fastify.options('/', (req, reply) => {
reply.send('ok')
})
fastify.inject({
method: 'OPTIONS',
url: '/',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
// Only the base cors headers and no preflight headers
'access-control-allow-origin': '*'
})
t.notMatch(res.headers, { vary: 'Origin' })
})
})
test('Should reply to all options requests', t => {
t.plan(4)
const fastify = Fastify()
fastify.register(cors)
fastify.inject({
method: 'OPTIONS',
url: '/hello',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 204)
t.equal(res.payload, '')
t.match(res.headers, {
'access-control-allow-origin': '*',
'access-control-allow-methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
vary: 'Access-Control-Request-Headers',
'content-length': '0'
})
})
})
test('Should support a prefix for preflight requests', t => {
t.plan(6)
const fastify = Fastify()
fastify.register((instance, opts, next) => {
instance.register(cors)
next()
}, { prefix: '/subsystem' })
fastify.inject({
method: 'OPTIONS',
url: '/hello'
}, (err, res) => {
t.error(err)
t.equal(res.statusCode, 404)
})
fastify.inject({
method: 'OPTIONS',
url: '/subsystem/hello',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 204)
t.equal(res.payload, '')
t.match(res.headers, {
'access-control-allow-origin': '*',
'access-control-allow-methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
vary: 'Access-Control-Request-Headers',
'content-length': '0'
})
})
})
test('hide options route by default', t => {
t.plan(2)
const fastify = Fastify()
fastify.addHook('onRoute', (route) => {
if (route.method === 'OPTIONS' && route.url === '*') {
t.equal(route.schema.hide, true)
}
})
fastify.register(cors)
fastify.ready(err => {
t.error(err)
})
})
test('show options route', t => {
t.plan(2)
const fastify = Fastify()
fastify.addHook('onRoute', (route) => {
if (route.method === 'OPTIONS' && route.url === '*') {
t.equal(route.schema.hide, false)
}
})
fastify.register(cors, { hideOptionsRoute: false })
fastify.ready(err => {
t.error(err)
})
})
test('Allow only request from with specific methods', t => {
t.plan(4)
const fastify = Fastify()
fastify.register(cors, { methods: ['GET', 'POST'] })
fastify.inject({
method: 'OPTIONS',
url: '/',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 204)
t.match(res.headers, {
'access-control-allow-methods': 'GET, POST'
})
t.notMatch(res.headers, { vary: 'Origin' })
})
})
test('Should reply with 400 error to OPTIONS requests missing origin header when default strictPreflight', t => {
t.plan(3)
const fastify = Fastify()
fastify.register(cors)
fastify.inject({
method: 'OPTIONS',
url: '/',
headers: {
'access-control-request-method': 'GET'
}
}, (err, res) => {
t.error(err)
t.equal(res.statusCode, 400)
t.equal(res.payload, 'Invalid Preflight Request')
})
})
test('Should reply with 400 to OPTIONS requests when missing Access-Control-Request-Method header when default strictPreflight', t => {
t.plan(3)
const fastify = Fastify()
fastify.register(cors, {
strictPreflight: true
})
fastify.inject({
method: 'OPTIONS',
url: '/',
headers: {
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
t.equal(res.statusCode, 400)
t.equal(res.payload, 'Invalid Preflight Request')
})
})
test('Should reply to all preflight requests when strictPreflight is disabled', t => {
t.plan(4)
const fastify = Fastify()
fastify.register(cors, { strictPreflight: false })
fastify.inject({
method: 'OPTIONS',
url: '/'
// No access-control-request-method or origin headers
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 204)
t.equal(res.payload, '')
t.match(res.headers, {
'access-control-allow-origin': '*',
'access-control-allow-methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
vary: 'Access-Control-Request-Headers',
'content-length': '0'
})
})
})
test('Default empty 200 response with preflightContinue on OPTIONS routes', t => {
t.plan(4)
const fastify = Fastify()
fastify.register(cors, { preflightContinue: true })
fastify.inject({
method: 'OPTIONS',
url: '/doesnotexist',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, '')
t.match(res.headers, {
'access-control-allow-origin': '*',
'access-control-allow-methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
vary: 'Access-Control-Request-Headers'
})
})
})
test('Can override preflight response with preflightContinue', t => {
t.plan(4)
const fastify = Fastify()
fastify.register(cors, { preflightContinue: true })
fastify.options('/', (req, reply) => {
reply.send('ok')
})
fastify.inject({
method: 'OPTIONS',
url: '/',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 200)
t.equal(res.payload, 'ok')
t.match(res.headers, {
'access-control-allow-origin': '*',
'access-control-allow-methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
vary: 'Access-Control-Request-Headers'
})
})
})
test('Should support ongoing prefix ', t => {
t.plan(12)
const fastify = Fastify()
fastify.register(async (instance) => {
instance.register(cors)
}, { prefix: '/prefix' })
// support prefixed route
fastify.inject({
method: 'OPTIONS',
url: '/prefix',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 204)
t.equal(res.payload, '')
t.match(res.headers, {
'access-control-allow-origin': '*',
'access-control-allow-methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
vary: 'Access-Control-Request-Headers',
'content-length': '0'
})
})
// support prefixed route without / continue
fastify.inject({
method: 'OPTIONS',
url: '/prefixfoo',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 204)
t.equal(res.payload, '')
t.match(res.headers, {
'access-control-allow-origin': '*',
'access-control-allow-methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
vary: 'Access-Control-Request-Headers',
'content-length': '0'
})
})
// support prefixed route with / continue
fastify.inject({
method: 'OPTIONS',
url: '/prefix/foo',
headers: {
'access-control-request-method': 'GET',
origin: 'example.com'
}
}, (err, res) => {
t.error(err)
delete res.headers.date
t.equal(res.statusCode, 204)
t.equal(res.payload, '')
t.match(res.headers, {
'access-control-allow-origin': '*',
'access-control-allow-methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
vary: 'Access-Control-Request-Headers',
'content-length': '0'
})
})
})

229
backend/node_modules/@fastify/cors/test/vary.test.js generated vendored Normal file
View File

@@ -0,0 +1,229 @@
'use strict'
const test = require('tap').test
const createAddFieldnameToVary = require('../vary').createAddFieldnameToVary
const parse = require('../vary').parse
test('Should set * even if we set a specific field', t => {
t.plan(1)
const addOriginToVary = createAddFieldnameToVary('Origin')
const replyMock = {
getHeader (name) {
return '*'
},
header (name, value) {
t.fail('Should not be here')
}
}
addOriginToVary(replyMock)
t.pass()
})
test('Should set * even if we set a specific field', t => {
t.plan(2)
const addWildcardToVary = createAddFieldnameToVary('*')
const replyMock = {
getHeader (name) {
return 'Origin'
},
header (name, value) {
t.same(name, 'Vary')
t.same(value, '*')
}
}
addWildcardToVary(replyMock)
})
test('Should set * when field contains a *', t => {
t.plan(3)
const addOriginToVary = createAddFieldnameToVary('Origin')
const replyMock = {
getHeader (name) {
return ['Origin', '*', 'Access-Control-Request-Headers']
},
header (name, value) {
t.same(name, 'Vary')
t.same(value, '*')
}
}
addOriginToVary(replyMock)
t.pass()
})
test('Should concat vary values', t => {
t.plan(3)
const addOriginToVary = createAddFieldnameToVary('Origin')
const replyMock = {
getHeader (name) {
return 'Access-Control-Request-Headers'
},
header (name, value) {
t.same(name, 'Vary')
t.same(value, 'Access-Control-Request-Headers, Origin')
}
}
addOriginToVary(replyMock)
t.pass()
})
test('Should concat vary values ignoring consecutive commas', t => {
t.plan(3)
const addOriginToVary = createAddFieldnameToVary('Origin')
const replyMock = {
getHeader (name) {
return ' Access-Control-Request-Headers,Access-Control-Request-Method'
},
header (name, value) {
t.same(name, 'Vary')
t.same(value, ' Access-Control-Request-Headers,Access-Control-Request-Method, Origin')
}
}
addOriginToVary(replyMock)
t.pass()
})
test('Should concat vary values ignoring whitespace', t => {
t.plan(3)
const addOriginToVary = createAddFieldnameToVary('Origin')
const replyMock = {
getHeader (name) {
return ' Access-Control-Request-Headers ,Access-Control-Request-Method'
},
header (name, value) {
t.same(name, 'Vary')
t.same(value, ' Access-Control-Request-Headers ,Access-Control-Request-Method, Origin')
}
}
addOriginToVary(replyMock)
t.pass()
})
test('Should set the field as value for vary if no vary is defined', t => {
t.plan(2)
const addOriginToVary = createAddFieldnameToVary('Origin')
const replyMock = {
getHeader (name) {
return undefined
},
header (name, value) {
t.same(name, 'Vary')
t.same(value, 'Origin')
}
}
addOriginToVary(replyMock)
})
test('Should set * as value for vary if vary contains *', t => {
t.plan(2)
const addOriginToVary = createAddFieldnameToVary('Origin')
const replyMock = {
getHeader (name) {
return 'Accept,*'
},
header (name, value) {
t.same(name, 'Vary')
t.same(value, '*')
}
}
addOriginToVary(replyMock)
})
test('Should set Accept-Encoding as value for vary if vary is empty string', t => {
t.plan(2)
const addAcceptEncodingToVary = createAddFieldnameToVary('Accept-Encoding')
const replyMock = {
getHeader (name) {
return ''
},
header (name, value) {
t.same(name, 'Vary')
t.same(value, 'Accept-Encoding')
}
}
addAcceptEncodingToVary(replyMock)
})
test('Should have no issues with values containing dashes', t => {
t.plan(2)
const addXFooToVary = createAddFieldnameToVary('X-Foo')
const replyMock = {
value: 'Accept-Encoding',
getHeader (name) {
return this.value
},
header (name, value) {
t.same(name, 'Vary')
t.same(value, 'Accept-Encoding, X-Foo')
this.value = value
}
}
addXFooToVary(replyMock)
addXFooToVary(replyMock)
})
test('Should ignore the header as value for vary if it is already in vary', t => {
t.plan(1)
const addOriginToVary = createAddFieldnameToVary('Origin')
const replyMock = {
getHeader (name) {
return 'Origin'
},
header (name, value) {
t.fail('Should not be here')
}
}
addOriginToVary(replyMock)
addOriginToVary(replyMock)
t.pass()
})
test('parse', t => {
t.plan(18)
t.same(parse(''), [])
t.same(parse('a'), ['a'])
t.same(parse('a,b'), ['a', 'b'])
t.same(parse(' a,b'), ['a', 'b'])
t.same(parse('a,b '), ['a', 'b'])
t.same(parse('a,b,c'), ['a', 'b', 'c'])
t.same(parse('A,b,c'), ['a', 'b', 'c'])
t.same(parse('a,b,c,'), ['a', 'b', 'c'])
t.same(parse('a,b,c, '), ['a', 'b', 'c'])
t.same(parse(',a,b,c'), ['a', 'b', 'c'])
t.same(parse(' ,a,b,c'), ['a', 'b', 'c'])
t.same(parse('a,,b,c'), ['a', 'b', 'c'])
t.same(parse('a,,,b,,c'), ['a', 'b', 'c'])
t.same(parse('a, b,c'), ['a', 'b', 'c'])
t.same(parse('a, b,c'), ['a', 'b', 'c'])
t.same(parse('a, , b,c'), ['a', 'b', 'c'])
t.same(parse('a, , b,c'), ['a', 'b', 'c'])
// one for the cache
t.same(parse('A,b,c'), ['a', 'b', 'c'])
})
test('createAddFieldnameToVary', t => {
t.plan(2)
t.same(typeof createAddFieldnameToVary('valid-header'), 'function')
t.throws(() => createAddFieldnameToVary('invalid:header'), TypeError, 'Field contains invalid characters.')
})