UNPKG

@fastify/cors

Version:
1,053 lines (933 loc) 28.5 kB
'use strict' const { test } = require('node:test') const { createReadStream, statSync, readFileSync } = require('node:fs') const Fastify = require('fastify') const cors = require('../') const { resolve } = require('node:path') const { setTimeout: sleep } = require('node:timers/promises') test('Should add cors headers', async t => { t.plan(4) const fastify = Fastify() fastify.register(cors) fastify.get('/', (_req, reply) => { reply.send('ok') }) const res = await fastify.inject({ method: 'GET', url: '/' }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 200) t.assert.strictEqual(res.payload, 'ok') t.assert.deepStrictEqual(res.headers['access-control-allow-origin'], '*' ) }) test('Should add cors headers when payload is a stream', async 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') const res = await fastify.inject({ method: 'GET', url: '/' }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 200) t.assert.strictEqual(res.payload, fileContent) const actualHeaders = { 'access-control-allow-origin': res.headers['access-control-allow-origin'], 'content-length': res.headers['content-length'] } t.assert.deepStrictEqual(actualHeaders, { 'access-control-allow-origin': '*', 'content-length': statSync(filePath).size.toString() }) }) test('Should add cors headers (custom values)', async 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') }) let res = await fastify.inject({ method: 'OPTIONS', url: '/', headers: { 'access-control-request-method': 'GET', origin: 'example.com' } }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 204) t.assert.strictEqual(res.payload, '') const actualHeaders = { 'access-control-allow-origin': res.headers['access-control-allow-origin'], 'access-control-allow-credentials': res.headers['access-control-allow-credentials'], 'access-control-expose-headers': res.headers['access-control-expose-headers'], 'access-control-allow-methods': res.headers['access-control-allow-methods'], 'access-control-allow-headers': res.headers['access-control-allow-headers'], 'access-control-max-age': res.headers['access-control-max-age'], 'cache-control': res.headers['cache-control'], 'content-length': res.headers['content-length'] } t.assert.deepStrictEqual(actualHeaders, { '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.assert.notDeepEqual(res.headers, { vary: 'Origin' }) res = await fastify.inject({ method: 'GET', url: '/' }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 200) t.assert.strictEqual(res.payload, 'ok') const actualHeaders2 = { 'access-control-allow-origin': res.headers['access-control-allow-origin'], 'access-control-allow-credentials': res.headers['access-control-allow-credentials'], 'access-control-expose-headers': res.headers['access-control-expose-headers'], 'content-length': res.headers['content-length'] } t.assert.deepStrictEqual(actualHeaders2, { 'access-control-allow-origin': 'example.com', 'access-control-allow-credentials': 'true', 'access-control-expose-headers': 'foo, bar', 'content-length': '2' }) t.assert.notDeepEqual(res.headers, { vary: 'Origin' }) }) test('Should support dynamic config (callback)', async 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 = async function (req, cb) { // request should have id t.assert.ok(req.id) // request should not have send t.assert.ifError(req.send) const config = configs[requestId] requestId++ if (config) { cb(null, config) } else { cb(new Error('ouch')) } } await fastify.register(cors, () => configDelegation) fastify.get('/', (_req, reply) => { reply.send('ok') }) let res = await fastify.inject({ method: 'GET', url: '/' }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 200) t.assert.strictEqual(res.payload, 'ok') const actualHeaders = { 'access-control-allow-origin': res.headers['access-control-allow-origin'], 'access-control-allow-credentials': res.headers['access-control-allow-credentials'], 'access-control-expose-headers': res.headers['access-control-expose-headers'], 'content-length': res.headers['content-length'], vary: res.headers.vary } // Sleep to wait for callback sleep() t.assert.deepStrictEqual(actualHeaders, { 'access-control-allow-origin': 'example.com', 'access-control-allow-credentials': 'true', 'access-control-expose-headers': 'foo, bar', 'content-length': '2', vary: 'Origin' }) res = await fastify.inject({ method: 'OPTIONS', url: '/', headers: { 'access-control-request-method': 'GET', origin: 'example.com' } }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 204) t.assert.strictEqual(res.payload, '') const actualHeaders2 = { 'access-control-allow-origin': res.headers['access-control-allow-origin'], 'access-control-allow-credentials': res.headers['access-control-allow-credentials'], 'access-control-expose-headers': res.headers['access-control-expose-headers'], 'access-control-allow-methods': res.headers['access-control-allow-methods'], 'access-control-allow-headers': res.headers['access-control-allow-headers'], 'access-control-max-age': res.headers['access-control-max-age'], 'cache-control': res.headers['cache-control'], 'content-length': res.headers['content-length'], vary: res.headers.vary } // Sleep to wait for callback sleep() t.assert.deepStrictEqual(actualHeaders2, { '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' }) res = await fastify.inject({ method: 'GET', url: '/', headers: { 'access-control-request-method': 'GET', origin: 'example.com' } }) t.assert.ok(res) t.assert.strictEqual(res.statusCode, 500) }) test('Should support dynamic config (Promise)', async 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 = async function (req) { // request should have id t.assert.ok(req.id) // request should not have send t.assert.ifError(req.send) const config = configs[requestId] requestId++ if (config) { return Promise.resolve(config) } else { return Promise.reject(new Error('ouch')) } } await fastify.register(cors, () => configDelegation) fastify.get('/', (_req, reply) => { reply.send('ok') }) let res = await fastify.inject({ method: 'GET', url: '/' }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 200) t.assert.strictEqual(res.payload, 'ok') const actualHeaders = { 'access-control-allow-origin': res.headers['access-control-allow-origin'], 'access-control-allow-credentials': res.headers['access-control-allow-credentials'], 'access-control-expose-headers': res.headers['access-control-expose-headers'], 'content-length': res.headers['content-length'], vary: res.headers.vary } t.assert.deepStrictEqual(actualHeaders, { 'access-control-allow-origin': 'example.com', 'access-control-allow-credentials': 'true', 'access-control-expose-headers': 'foo, bar', 'content-length': '2', vary: 'Origin' }) res = await fastify.inject({ method: 'OPTIONS', url: '/', headers: { 'access-control-request-method': 'GET', origin: 'sample.com' } }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 204) t.assert.strictEqual(res.payload, '') const acutalHeaders2 = { 'access-control-allow-origin': res.headers['access-control-allow-origin'], 'access-control-allow-credentials': res.headers['access-control-allow-credentials'], 'access-control-expose-headers': res.headers['access-control-expose-headers'], 'access-control-allow-methods': res.headers['access-control-allow-methods'], 'access-control-allow-headers': res.headers['access-control-allow-headers'], 'access-control-max-age': res.headers['access-control-max-age'], 'content-length': res.headers['content-length'], vary: res.headers.vary } t.assert.deepStrictEqual(acutalHeaders2, { '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.assert.strictEqual(res.headers['cache-control'], undefined, 'cache-control omitted (invalid value)') res = await fastify.inject({ method: 'OPTIONS', url: '/', headers: { 'access-control-request-method': 'GET', origin: 'example.com' } }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 204) t.assert.strictEqual(res.payload, '') const actualHeaders3 = { 'access-control-allow-origin': res.headers['access-control-allow-origin'], 'access-control-allow-credentials': res.headers['access-control-allow-credentials'], 'access-control-expose-headers': res.headers['access-control-expose-headers'], 'access-control-allow-methods': res.headers['access-control-allow-methods'], 'access-control-allow-headers': res.headers['access-control-allow-headers'], 'access-control-max-age': res.headers['access-control-max-age'], 'cache-control': res.headers['cache-control'], 'content-length': res.headers['content-length'], vary: res.headers.vary } t.assert.deepStrictEqual(actualHeaders3, { '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' }) res = await fastify.inject({ method: 'GET', url: '/', headers: { 'access-control-request-method': 'GET', origin: 'example.com' } }) t.assert.ok(res) t.assert.strictEqual(res.statusCode, 500) }) test('Should support dynamic config. (Invalid function)', async t => { t.plan(2) const fastify = Fastify() fastify.register(cors, () => () => {}) fastify.get('/', (_req, reply) => { reply.send('ok') }) const res = await fastify.inject({ method: 'GET', url: '/', headers: { 'access-control-request-method': 'GET', origin: 'example.com' } }) t.assert.ok(res) t.assert.strictEqual(res.statusCode, 500) }) test('Dynamic origin resolution (valid origin)', async t => { t.plan(6) const fastify = Fastify() const origin = function (header, cb) { t.assert.strictEqual(header, 'example.com') t.assert.equal(this, fastify) cb(null, true) } fastify.register(cors, { origin }) fastify.get('/', (_req, reply) => { reply.send('ok') }) const res = await fastify.inject({ method: 'GET', url: '/', headers: { origin: 'example.com' } }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 200) t.assert.strictEqual(res.payload, 'ok') const actualHeaders = { 'access-control-allow-origin': res.headers['access-control-allow-origin'], vary: res.headers.vary } t.assert.deepStrictEqual(actualHeaders, { 'access-control-allow-origin': 'example.com', vary: 'Origin' }) }) test('Dynamic origin resolution (not valid origin)', async t => { t.plan(5) const fastify = Fastify() const origin = (header, cb) => { t.assert.strictEqual(header, 'example.com') cb(null, false) } fastify.register(cors, { origin }) fastify.get('/', (_req, reply) => { reply.send('ok') }) const res = await fastify.inject({ method: 'GET', url: '/', headers: { origin: 'example.com' } }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 200) t.assert.strictEqual(res.payload, 'ok') const actualHeaders = { 'content-length': res.headers['content-length'], 'content-type': res.headers['content-type'], connection: res.headers.connection, vary: res.headers.vary } t.assert.deepStrictEqual(actualHeaders, { 'content-length': '2', 'content-type': 'text/plain; charset=utf-8', connection: 'keep-alive', vary: 'Origin' }) }) test('Dynamic origin resolution (errored)', async t => { t.plan(3) const fastify = Fastify() const origin = (header, cb) => { t.assert.strictEqual(header, 'example.com') cb(new Error('ouch')) } fastify.register(cors, { origin }) const res = await fastify.inject({ method: 'GET', url: '/', headers: { origin: 'example.com' } }) t.assert.ok(res) t.assert.strictEqual(res.statusCode, 500) }) test('Dynamic origin resolution (invalid result)', async t => { t.plan(3) const fastify = Fastify() const origin = (header, cb) => { t.assert.strictEqual(header, 'example.com') cb(null, undefined) } fastify.register(cors, { origin }) const res = await fastify.inject({ method: 'GET', url: '/', headers: { origin: 'example.com' } }) t.assert.ok(res) t.assert.strictEqual(res.statusCode, 500) }) test('Dynamic origin resolution (valid origin - promises)', async t => { t.plan(5) const fastify = Fastify() const origin = (header) => { return new Promise((resolve) => { t.assert.strictEqual(header, 'example.com') resolve(true) }) } fastify.register(cors, { origin }) fastify.get('/', (_req, reply) => { reply.send('ok') }) const res = await fastify.inject({ method: 'GET', url: '/', headers: { origin: 'example.com' } }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 200) t.assert.strictEqual(res.payload, 'ok') const actualHeaders = { 'access-control-allow-origin': res.headers['access-control-allow-origin'], vary: res.headers.vary } t.assert.deepStrictEqual(actualHeaders, { 'access-control-allow-origin': 'example.com', vary: 'Origin' }) }) test('Dynamic origin resolution (not valid origin - promises)', async t => { t.plan(5) const fastify = Fastify() const origin = (header) => { return new Promise((resolve) => { t.assert.strictEqual(header, 'example.com') resolve(false) }) } fastify.register(cors, { origin }) fastify.get('/', (_req, reply) => { reply.send('ok') }) const res = await fastify.inject({ method: 'GET', url: '/', headers: { origin: 'example.com' } }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 200) t.assert.strictEqual(res.payload, 'ok') const actualHeaders = { 'content-length': res.headers['content-length'], 'content-type': res.headers['content-type'], connection: res.headers.connection, vary: res.headers.vary } t.assert.deepStrictEqual(actualHeaders, { 'content-length': '2', 'content-type': 'text/plain; charset=utf-8', connection: 'keep-alive', vary: 'Origin' }) }) test('Dynamic origin resolution (errored - promises)', async t => { t.plan(3) const fastify = Fastify() const origin = (header) => { return new Promise((_resolve, reject) => { t.assert.strictEqual(header, 'example.com') reject(new Error('ouch')) }) } fastify.register(cors, { origin }) const res = await fastify.inject({ method: 'GET', url: '/', headers: { origin: 'example.com' } }) t.assert.ok(res) t.assert.strictEqual(res.statusCode, 500) }) test('Should reply 404 without cors headers when origin is false', async 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') }) let res = await fastify.inject({ method: 'OPTIONS', url: '/' }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 404) t.assert.strictEqual(res.payload, '{"message":"Route OPTIONS:/ not found","error":"Not Found","statusCode":404}') const actualHeaders = { 'content-length': res.headers['content-length'], 'content-type': res.headers['content-type'], connection: res.headers.connection } t.assert.deepStrictEqual(actualHeaders, { 'content-length': '76', 'content-type': 'application/json; charset=utf-8', connection: 'keep-alive' }) res = await fastify.inject({ method: 'GET', url: '/' }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 200) t.assert.strictEqual(res.payload, 'ok') t.assert.deepStrictEqual(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', async t => { t.plan(4) const fastify = Fastify() fastify.register(cors, { origin: '' }) const res = await fastify.inject({ method: 'GET', url: '/', headers: { origin: 'example.com' } }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 500) t.assert.deepStrictEqual(res.json(), { statusCode: 500, error: 'Internal Server Error', message: 'Invalid CORS origin option' }) const actualHeaders = { 'content-length': res.headers['content-length'], 'content-type': res.headers['content-type'], connection: res.headers.connection } t.assert.deepStrictEqual(actualHeaders, { 'content-length': '89', 'content-type': 'application/json; charset=utf-8', connection: 'keep-alive' }) }) test('Allow only request from a specific origin', async t => { t.plan(5) const fastify = Fastify() fastify.register(cors, { origin: 'other.io' }) fastify.get('/', (_req, reply) => { reply.send('ok') }) const res = await fastify.inject({ method: 'GET', url: '/', headers: { origin: 'example.com' } }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 200) t.assert.strictEqual(res.payload, 'ok') t.assert.deepStrictEqual(res.headers['access-control-allow-origin'], 'other.io' ) t.assert.notDeepEqual(res.headers, { vary: 'Origin' }) }) test('Allow only request from multiple specific origin', async t => { t.plan(9) const fastify = Fastify() fastify.register(cors, { origin: ['other.io', 'example.com'] }) fastify.get('/', (_req, reply) => { reply.send('ok') }) let res = await fastify.inject({ method: 'GET', url: '/', headers: { origin: 'other.io' } }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 200) t.assert.strictEqual(res.payload, 'ok') const actualHeaders = { 'access-control-allow-origin': res.headers['access-control-allow-origin'], vary: res.headers.vary } t.assert.deepStrictEqual(actualHeaders, { 'access-control-allow-origin': 'other.io', vary: 'Origin' }) res = await fastify.inject({ method: 'GET', url: '/', headers: { origin: 'foo.com' } }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 200) t.assert.strictEqual(res.payload, 'ok') t.assert.deepStrictEqual(res.headers.vary, 'Origin' ) t.assert.strictEqual(res.headers['access-control-allow-origin'], undefined) }) test('Allow only request from a specific origin using regex', async 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++) { const res = await fastify.inject({ method: 'GET', url: '/', headers: { origin: 'https://www.example.com/' } }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 200) t.assert.strictEqual(res.payload, 'ok') const actualHeaders = { 'access-control-allow-origin': res.headers['access-control-allow-origin'], vary: res.headers.vary } t.assert.deepStrictEqual(actualHeaders, { 'access-control-allow-origin': 'https://www.example.com/', vary: 'Origin' }) } }) test('Disable preflight', async t => { t.plan(7) const fastify = Fastify() fastify.register(cors, { preflight: false }) fastify.get('/', (_req, reply) => { reply.send('ok') }) let res = await fastify.inject({ method: 'OPTIONS', url: '/hello' }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 404) t.assert.strictEqual(res.headers['access-control-allow-origin'], '*' ) res = await fastify.inject({ method: 'GET', url: '/' }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 200) t.assert.strictEqual(res.payload, 'ok') t.assert.strictEqual(res.headers['access-control-allow-origin'], '*' ) }) test('Should always add vary header to `Origin` for reflected origin', async t => { t.plan(12) const fastify = Fastify() fastify.register(cors, { origin: true }) fastify.get('/', (_req, reply) => { reply.send('ok') }) // Invalid Preflight let res = await fastify.inject({ method: 'OPTIONS', url: '/' }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 400) t.assert.strictEqual(res.payload, 'Invalid Preflight Request') t.assert.strictEqual(res.headers.vary, 'Origin' ) // Valid Preflight res = await fastify.inject({ method: 'OPTIONS', url: '/', headers: { 'access-control-request-method': 'GET', origin: 'example.com' } }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 204) t.assert.strictEqual(res.payload, '') t.assert.strictEqual(res.headers.vary, 'Origin, Access-Control-Request-Headers' ) // Other Route res = await fastify.inject({ method: 'GET', url: '/' }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 200) t.assert.strictEqual(res.payload, 'ok') t.assert.strictEqual(res.headers.vary, 'Origin' ) }) test('Should always add vary header to `Origin` for reflected origin (vary is array)', async t => { t.plan(4) const fastify = Fastify() // Mock getHeader function fastify.decorateReply('getHeader', () => ['foo', 'bar']) fastify.register(cors, { origin: true }) fastify.get('/', (_req, reply) => { reply.send('ok') }) const res = await fastify.inject({ method: 'GET', url: '/' }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 200) t.assert.strictEqual(res.payload, 'ok') t.assert.strictEqual(res.headers.vary, 'foo, bar, Origin' ) }) test('Allow only request from with specific headers', async t => { t.plan(8) const fastify = Fastify() fastify.register(cors, { allowedHeaders: 'foo', exposedHeaders: 'bar' }) fastify.get('/', (_req, reply) => { reply.send('ok') }) let res = await fastify.inject({ method: 'OPTIONS', url: '/', headers: { 'access-control-request-method': 'GET', origin: 'example.com' } }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 204) t.assert.deepStrictEqual(res.headers['access-control-allow-headers'], 'foo' ) t.assert.notDeepEqual(res.headers.vary, 'Origin') res = await fastify.inject({ method: 'GET', url: '/' }) t.assert.ok(res) delete res.headers.date t.assert.strictEqual(res.statusCode, 200) t.assert.strictEqual(res.payload, 'ok') t.assert.strictEqual(res.headers['access-control-expose-headers'], 'bar' ) }) test('Should support wildcard config /1', async t => { t.plan(4) const fastify = Fastify() fastify.register(cors, { origin: '*' }) fastify.get('/', (_req, reply) => { reply.send('ok') }) const res = await fastify.inject({ method: 'GET', url: '/' }) t.assert.ok(res) t.assert.strictEqual(res.statusCode, 200) t.assert.strictEqual(res.payload, 'ok') t.assert.strictEqual(res.headers['access-control-allow-origin'], '*') }) test('Should support wildcard config /2', async t => { t.plan(4) const fastify = Fastify() fastify.register(cors, { origin: ['*'] }) fastify.get('/', (_req, reply) => { reply.send('ok') }) const res = await fastify.inject({ method: 'GET', url: '/' }) t.assert.ok(res) t.assert.strictEqual(res.statusCode, 200) t.assert.strictEqual(res.payload, 'ok') t.assert.strictEqual(res.headers['access-control-allow-origin'], '*') }) test('Should allow routes to disable CORS individually', async t => { t.plan(6) const fastify = Fastify() fastify.register(cors, { origin: '*' }) fastify.get('/cors-enabled', (_req, reply) => { reply.send('ok') }) fastify.get('/cors-disabled', { config: { cors: false } }, (_req, reply) => { reply.send('ok') }) // Test CORS enabled route let res = await fastify.inject({ method: 'GET', url: '/cors-enabled', headers: { origin: 'example.com' } }) t.assert.ok(res) t.assert.strictEqual(res.statusCode, 200) t.assert.strictEqual(res.headers['access-control-allow-origin'], '*') // Test CORS disabled route res = await fastify.inject({ method: 'GET', url: '/cors-disabled', headers: { origin: 'example.com' } }) t.assert.ok(res) t.assert.strictEqual(res.statusCode, 200) t.assert.strictEqual(res.headers['access-control-allow-origin'], undefined) })