123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747 |
- (function () {
- /*global describe, it*/
- 'use strict';
- var should = require('should'),
- cors = require('../lib');
- var fakeRequest = function (headers) {
- return {
- headers: headers || {
- 'origin': 'request.com',
- 'access-control-request-headers': 'requestedHeader1,requestedHeader2'
- },
- pause: function () {
- // do nothing
- return;
- },
- resume: function () {
- // do nothing
- return;
- }
- };
- },
- fakeResponse = function () {
- var headers = {};
- return {
- allHeaders: function () {
- return headers;
- },
- getHeader: function (key) {
- return headers[key];
- },
- setHeader: function (key, value) {
- headers[key] = value;
- return;
- },
- get: function (key) {
- return headers[key];
- }
- };
- };
- describe('cors', function () {
- it('does not alter `options` configuration object', function () {
- var options = Object.freeze({
- origin: 'custom-origin'
- });
- (function () {
- cors(options);
- }).should.not.throw();
- });
- it('passes control to next middleware', function (done) {
- // arrange
- var req, res, next;
- req = fakeRequest();
- res = fakeResponse();
- next = function () {
- done();
- };
- // act
- cors()(req, res, next);
- });
- it('shortcircuits preflight requests', function (done) {
- // arrange
- var req, res, next;
- req = fakeRequest();
- req.method = 'OPTIONS';
- res = fakeResponse();
- res.end = function () {
- // assert
- res.statusCode.should.equal(204);
- done();
- };
- next = function () {
- // assert
- done('should not be called');
- };
- // act
- cors()(req, res, next);
- });
- it('can configure preflight success response status code', function (done) {
- // arrange
- var req, res, next;
- req = fakeRequest();
- req.method = 'OPTIONS';
- res = fakeResponse();
- res.end = function () {
- // assert
- res.statusCode.should.equal(200);
- done();
- };
- next = function () {
- // assert
- done('should not be called');
- };
- // act
- cors({optionsSuccessStatus: 200})(req, res, next);
- });
- it('doesn\'t shortcircuit preflight requests with preflightContinue option', function (done) {
- // arrange
- var req, res, next;
- req = fakeRequest();
- req.method = 'OPTIONS';
- res = fakeResponse();
- res.end = function () {
- // assert
- done('should not be called');
- };
- next = function () {
- // assert
- done();
- };
- // act
- cors({preflightContinue: true})(req, res, next);
- });
- it('normalizes method names', function (done) {
- // arrange
- var req, res, next;
- req = fakeRequest();
- req.method = 'options';
- res = fakeResponse();
- res.end = function () {
- // assert
- res.statusCode.should.equal(204);
- done();
- };
- next = function () {
- // assert
- done('should not be called');
- };
- // act
- cors()(req, res, next);
- });
- it('includes Content-Length response header', function (done) {
- // arrange
- var req, res, next;
- req = fakeRequest();
- req.method = 'options';
- res = fakeResponse();
- res.end = function () {
- // assert
- res.getHeader('Content-Length').should.equal('0');
- done();
- };
- next = function () {
- // assert
- done('should not be called');
- };
- // act
- cors()(req, res, next);
- });
- it('no options enables default CORS to all origins', function (done) {
- // arrange
- var req, res, next;
- req = fakeRequest();
- res = fakeResponse();
- next = function () {
- // assert
- res.getHeader('Access-Control-Allow-Origin').should.equal('*');
- should.not.exist(res.getHeader('Access-Control-Allow-Methods'));
- done();
- };
- // act
- cors()(req, res, next);
- });
- it('OPTION call with no options enables default CORS to all origins and methods', function (done) {
- // arrange
- var req, res, next;
- req = fakeRequest();
- req.method = 'OPTIONS';
- res = fakeResponse();
- res.end = function () {
- // assert
- res.statusCode.should.equal(204);
- done();
- };
- next = function () {
- // assert
- res.getHeader('Access-Control-Allow-Origin').should.equal('*');
- res.getHeader('Access-Control-Allow-Methods').should.equal('GET,PUT,PATCH,POST,DELETE');
- done();
- };
- // act
- cors()(req, res, next);
- });
- describe('passing static options', function () {
- it('overrides defaults', function (done) {
- // arrange
- var req, res, next, options;
- options = {
- origin: 'example.com',
- methods: ['FOO', 'bar'],
- headers: ['FIZZ', 'buzz'],
- credentials: true,
- maxAge: 123
- };
- req = fakeRequest();
- req.method = 'OPTIONS';
- res = fakeResponse();
- res.end = function () {
- // assert
- res.statusCode.should.equal(204);
- done();
- };
- next = function () {
- // assert
- res.getHeader('Access-Control-Allow-Origin').should.equal('example.com');
- res.getHeader('Access-Control-Allow-Methods').should.equal('FOO,bar');
- res.getHeader('Access-Control-Allow-Headers').should.equal('FIZZ,buzz');
- res.getHeader('Access-Control-Allow-Credentials').should.equal('true');
- res.getHeader('Access-Control-Max-Age').should.equal('123');
- done();
- };
- // act
- cors(options)(req, res, next);
- });
- it('matches request origin against regexp', function(done) {
- var req = fakeRequest();
- var res = fakeResponse();
- var options = { origin: /^(.+\.)?request.com$/ };
- cors(options)(req, res, function(err) {
- should.not.exist(err);
- res.getHeader('Access-Control-Allow-Origin').should.equal(req.headers.origin);
- should.exist(res.getHeader('Vary'));
- res.getHeader('Vary').should.equal('Origin');
- return done();
- });
- });
- it('matches request origin against array of origin checks', function(done) {
- var req = fakeRequest();
- var res = fakeResponse();
- var options = { origin: [ /foo\.com$/, 'request.com' ] };
- cors(options)(req, res, function(err) {
- should.not.exist(err);
- res.getHeader('Access-Control-Allow-Origin').should.equal(req.headers.origin);
- should.exist(res.getHeader('Vary'));
- res.getHeader('Vary').should.equal('Origin');
- return done();
- });
- });
- it('doesn\'t match request origin against array of invalid origin checks', function(done) {
- var req = fakeRequest();
- var res = fakeResponse();
- var options = { origin: [ /foo\.com$/, 'bar.com' ] };
- cors(options)(req, res, function(err) {
- should.not.exist(err);
- should.not.exist(res.getHeader('Access-Control-Allow-Origin'));
- should.exist(res.getHeader('Vary'));
- res.getHeader('Vary').should.equal('Origin');
- return done();
- });
- });
- it('origin of false disables cors', function (done) {
- // arrange
- var req, res, next, options;
- options = {
- origin: false,
- methods: ['FOO', 'bar'],
- headers: ['FIZZ', 'buzz'],
- credentials: true,
- maxAge: 123
- };
- req = fakeRequest();
- res = fakeResponse();
- next = function () {
- // assert
- should.not.exist(res.getHeader('Access-Control-Allow-Origin'));
- should.not.exist(res.getHeader('Access-Control-Allow-Methods'));
- should.not.exist(res.getHeader('Access-Control-Allow-Headers'));
- should.not.exist(res.getHeader('Access-Control-Allow-Credentials'));
- should.not.exist(res.getHeader('Access-Control-Max-Age'));
- done();
- };
- // act
- cors(options)(req, res, next);
- });
- it('can override origin', function (done) {
- // arrange
- var req, res, next, options;
- options = {
- origin: 'example.com'
- };
- req = fakeRequest();
- res = fakeResponse();
- next = function () {
- // assert
- res.getHeader('Access-Control-Allow-Origin').should.equal('example.com');
- done();
- };
- // act
- cors(options)(req, res, next);
- });
- it('includes Vary header for specific origins', function (done) {
- // arrange
- var req, res, next, options;
- options = {
- origin: 'example.com'
- };
- req = fakeRequest();
- res = fakeResponse();
- next = function () {
- // assert
- should.exist(res.getHeader('Vary'));
- res.getHeader('Vary').should.equal('Origin');
- done();
- };
- // act
- cors(options)(req, res, next);
- });
- it('appends to an existing Vary header', function (done) {
- // arrange
- var req, res, next, options;
- options = {
- origin: 'example.com'
- };
- req = fakeRequest();
- res = fakeResponse();
- res.setHeader('Vary', 'Foo');
- next = function () {
- // assert
- res.getHeader('Vary').should.equal('Foo, Origin');
- done();
- };
- // act
- cors(options)(req, res, next);
- });
- it('origin defaults to *', function (done) {
- // arrange
- var req, res, next, options;
- options = {
- };
- req = fakeRequest();
- res = fakeResponse();
- next = function () {
- // assert
- res.getHeader('Access-Control-Allow-Origin').should.equal('*');
- done();
- };
- // act
- cors(options)(req, res, next);
- });
- it('specifying true for origin reflects requesting origin', function (done) {
- // arrange
- var req, res, next, options;
- options = {
- origin: true
- };
- req = fakeRequest();
- res = fakeResponse();
- next = function () {
- // assert
- res.getHeader('Access-Control-Allow-Origin').should.equal('request.com');
- done();
- };
- // act
- cors(options)(req, res, next);
- });
- it('should allow origin when callback returns true', function (done) {
- var req, res, next, options;
- options = {
- origin: function (sentOrigin, cb) {
- sentOrigin.should.equal('request.com');
- cb(null, true);
- }
- };
- req = fakeRequest();
- res = fakeResponse();
- next = function () {
- res.getHeader('Access-Control-Allow-Origin').should.equal('request.com');
- done();
- };
- cors(options)(req, res, next);
- });
- it('should not allow origin when callback returns false', function (done) {
- var req, res, next, options;
- options = {
- origin: function (sentOrigin, cb) {
- sentOrigin.should.equal('request.com');
- cb(null, false);
- }
- };
- req = fakeRequest();
- res = fakeResponse();
- next = function () {
- should.not.exist(res.getHeader('Access-Control-Allow-Origin'));
- should.not.exist(res.getHeader('Access-Control-Allow-Methods'));
- should.not.exist(res.getHeader('Access-Control-Allow-Headers'));
- should.not.exist(res.getHeader('Access-Control-Allow-Credentials'));
- should.not.exist(res.getHeader('Access-Control-Max-Age'));
- done();
- };
- cors(options)(req, res, next);
- });
- it('should not override options.origin callback', function (done) {
- var req, res, next, options;
- options = {
- origin: function (sentOrigin, cb) {
- var isValid = sentOrigin === 'request.com';
- cb(null, isValid);
- }
- };
- req = fakeRequest();
- res = fakeResponse();
- next = function () {
- res.getHeader('Access-Control-Allow-Origin').should.equal('request.com');
- };
- cors(options)(req, res, next);
- req = fakeRequest({
- 'origin': 'invalid-request.com'
- });
- res = fakeResponse();
- next = function () {
- should.not.exist(res.getHeader('Access-Control-Allow-Origin'));
- should.not.exist(res.getHeader('Access-Control-Allow-Methods'));
- should.not.exist(res.getHeader('Access-Control-Allow-Headers'));
- should.not.exist(res.getHeader('Access-Control-Allow-Credentials'));
- should.not.exist(res.getHeader('Access-Control-Max-Age'));
- done();
- };
- cors(options)(req, res, next);
- });
- it('can override methods', function (done) {
- // arrange
- var req, res, next, options;
- options = {
- methods: ['method1', 'method2']
- };
- req = fakeRequest();
- req.method = 'OPTIONS';
- res = fakeResponse();
- res.end = function () {
- // assert
- res.statusCode.should.equal(204);
- done();
- };
- next = function () {
- // assert
- res.getHeader('Access-Control-Allow-Methods').should.equal('method1,method2');
- done();
- };
- // act
- cors(options)(req, res, next);
- });
- it('methods defaults to GET, PUT, PATCH, POST, DELETE', function (done) {
- // arrange
- var req, res, next, options;
- options = {
- };
- req = fakeRequest();
- req.method = 'OPTIONS';
- res = fakeResponse();
- res.end = function () {
- // assert
- res.statusCode.should.equal(204);
- done();
- };
- next = function () {
- // assert
- res.getHeader('Access-Control-Allow-Methods').should.equal('GET,PUT,PATCH,POST,DELETE');
- done();
- };
- // act
- cors(options)(req, res, next);
- });
- it('can specify allowed headers', function (done) {
- // arrange
- var req, res, options;
- options = {
- allowedHeaders: ['header1', 'header2']
- };
- req = fakeRequest();
- req.method = 'OPTIONS';
- res = fakeResponse();
- res.end = function () {
- // assert
- res.getHeader('Access-Control-Allow-Headers').should.equal('header1,header2');
- should.not.exist(res.getHeader('Vary'));
- done();
- };
- // act
- cors(options)(req, res, null);
- });
- it('specifying an empty list or string of allowed headers will result in no response header for allowed headers', function (done) {
- // arrange
- var req, res, next, options;
- options = {
- allowedHeaders: []
- };
- req = fakeRequest();
- res = fakeResponse();
- next = function () {
- // assert
- should.not.exist(res.getHeader('Access-Control-Allow-Headers'));
- should.not.exist(res.getHeader('Vary'));
- done();
- };
- // act
- cors(options)(req, res, next);
- });
- it('if no allowed headers are specified, defaults to requested allowed headers', function (done) {
- // arrange
- var req, res, options;
- options = {
- };
- req = fakeRequest();
- req.method = 'OPTIONS';
- res = fakeResponse();
- res.end = function () {
- // assert
- res.getHeader('Access-Control-Allow-Headers').should.equal('requestedHeader1,requestedHeader2');
- should.exist(res.getHeader('Vary'));
- res.getHeader('Vary').should.equal('Access-Control-Request-Headers');
- done();
- };
- // act
- cors(options)(req, res, null);
- });
- it('can specify exposed headers', function (done) {
- // arrange
- var req, res, options, next;
- options = {
- exposedHeaders: ['custom-header1', 'custom-header2']
- };
- req = fakeRequest();
- res = fakeResponse();
- next = function () {
- // assert
- res.getHeader('Access-Control-Expose-Headers').should.equal('custom-header1,custom-header2');
- done();
- };
- // act
- cors(options)(req, res, next);
- });
- it('specifying an empty list or string of exposed headers will result in no response header for exposed headers', function (done) {
- // arrange
- var req, res, next, options;
- options = {
- exposedHeaders: []
- };
- req = fakeRequest();
- res = fakeResponse();
- next = function () {
- // assert
- should.not.exist(res.getHeader('Access-Control-Expose-Headers'));
- done();
- };
- // act
- cors(options)(req, res, next);
- });
- it('includes credentials if explicitly enabled', function (done) {
- // arrange
- var req, res, options;
- options = {
- credentials: true
- };
- req = fakeRequest();
- req.method = 'OPTIONS';
- res = fakeResponse();
- res.end = function () {
- // assert
- res.getHeader('Access-Control-Allow-Credentials').should.equal('true');
- done();
- };
- // act
- cors(options)(req, res, null);
- });
- it('does not includes credentials unless explicitly enabled', function (done) {
- // arrange
- var req, res, next, options;
- options = {
- };
- req = fakeRequest();
- res = fakeResponse();
- next = function () {
- // assert
- should.not.exist(res.getHeader('Access-Control-Allow-Credentials'));
- done();
- };
- // act
- cors(options)(req, res, next);
- });
- it('includes maxAge when specified', function (done) {
- // arrange
- var req, res, options;
- options = {
- maxAge: 456
- };
- req = fakeRequest();
- req.method = 'OPTIONS';
- res = fakeResponse();
- res.end = function () {
- // assert
- res.getHeader('Access-Control-Max-Age').should.equal('456');
- done();
- };
- // act
- cors(options)(req, res, null);
- });
- it('does not includes maxAge unless specified', function (done) {
- // arrange
- var req, res, next, options;
- options = {
- };
- req = fakeRequest();
- res = fakeResponse();
- next = function () {
- // assert
- should.not.exist(res.getHeader('Access-Control-Max-Age'));
- done();
- };
- // act
- cors(options)(req, res, next);
- });
- });
- describe('passing a function to build options', function () {
- it('handles options specified via callback', function (done) {
- // arrange
- var req, res, next, delegate;
- delegate = function (req2, cb) {
- cb(null, {
- origin: 'delegate.com'
- });
- };
- req = fakeRequest();
- res = fakeResponse();
- next = function () {
- // assert
- res.getHeader('Access-Control-Allow-Origin').should.equal('delegate.com');
- done();
- };
- // act
- cors(delegate)(req, res, next);
- });
- it('handles options specified via callback for preflight', function (done) {
- // arrange
- var req, res, delegate;
- delegate = function (req2, cb) {
- cb(null, {
- origin: 'delegate.com',
- maxAge: 1000
- });
- };
- req = fakeRequest();
- req.method = 'OPTIONS';
- res = fakeResponse();
- res.end = function () {
- // assert
- res.getHeader('Access-Control-Allow-Origin').should.equal('delegate.com');
- res.getHeader('Access-Control-Max-Age').should.equal('1000');
- done();
- };
- // act
- cors(delegate)(req, res, null);
- });
- it('handles error specified via callback', function (done) {
- // arrange
- var req, res, next, delegate;
- delegate = function (req2, cb) {
- cb('some error');
- };
- req = fakeRequest();
- res = fakeResponse();
- next = function (err) {
- // assert
- err.should.equal('some error');
- done();
- };
- // act
- cors(delegate)(req, res, next);
- });
- });
- });
- }());
|