| (function () {
|
|
|
| 'use strict';
|
|
|
| var assign = require('object-assign');
|
| var vary = require('vary');
|
|
|
| var defaults = {
|
| origin: '*',
|
| methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
|
| preflightContinue: false,
|
| optionsSuccessStatus: 204
|
| };
|
|
|
| function isString(s) {
|
| return typeof s === 'string' || s instanceof String;
|
| }
|
|
|
| function isOriginAllowed(origin, allowedOrigin) {
|
| if (Array.isArray(allowedOrigin)) {
|
| for (var i = 0; i < allowedOrigin.length; ++i) {
|
| if (isOriginAllowed(origin, allowedOrigin[i])) {
|
| return true;
|
| }
|
| }
|
| return false;
|
| } else if (isString(allowedOrigin)) {
|
| return origin === allowedOrigin;
|
| } else if (allowedOrigin instanceof RegExp) {
|
| return allowedOrigin.test(origin);
|
| } else {
|
| return !!allowedOrigin;
|
| }
|
| }
|
|
|
| function configureOrigin(options, req) {
|
| var requestOrigin = req.headers.origin,
|
| headers = [],
|
| isAllowed;
|
|
|
| if (!options.origin || options.origin === '*') {
|
|
|
| headers.push([{
|
| key: 'Access-Control-Allow-Origin',
|
| value: '*'
|
| }]);
|
| } else if (isString(options.origin)) {
|
|
|
| headers.push([{
|
| key: 'Access-Control-Allow-Origin',
|
| value: options.origin
|
| }]);
|
| headers.push([{
|
| key: 'Vary',
|
| value: 'Origin'
|
| }]);
|
| } else {
|
| isAllowed = isOriginAllowed(requestOrigin, options.origin);
|
|
|
| headers.push([{
|
| key: 'Access-Control-Allow-Origin',
|
| value: isAllowed ? requestOrigin : false
|
| }]);
|
| headers.push([{
|
| key: 'Vary',
|
| value: 'Origin'
|
| }]);
|
| }
|
|
|
| return headers;
|
| }
|
|
|
| function configureMethods(options) {
|
| var methods = options.methods;
|
| if (methods.join) {
|
| methods = options.methods.join(',');
|
| }
|
| return {
|
| key: 'Access-Control-Allow-Methods',
|
| value: methods
|
| };
|
| }
|
|
|
| function configureCredentials(options) {
|
| if (options.credentials === true) {
|
| return {
|
| key: 'Access-Control-Allow-Credentials',
|
| value: 'true'
|
| };
|
| }
|
| return null;
|
| }
|
|
|
| function configureAllowedHeaders(options, req) {
|
| var allowedHeaders = options.allowedHeaders || options.headers;
|
| var headers = [];
|
|
|
| if (!allowedHeaders) {
|
| allowedHeaders = req.headers['access-control-request-headers'];
|
| headers.push([{
|
| key: 'Vary',
|
| value: 'Access-Control-Request-Headers'
|
| }]);
|
| } else if (allowedHeaders.join) {
|
| allowedHeaders = allowedHeaders.join(',');
|
| }
|
| if (allowedHeaders && allowedHeaders.length) {
|
| headers.push([{
|
| key: 'Access-Control-Allow-Headers',
|
| value: allowedHeaders
|
| }]);
|
| }
|
|
|
| return headers;
|
| }
|
|
|
| function configureExposedHeaders(options) {
|
| var headers = options.exposedHeaders;
|
| if (!headers) {
|
| return null;
|
| } else if (headers.join) {
|
| headers = headers.join(',');
|
| }
|
| if (headers && headers.length) {
|
| return {
|
| key: 'Access-Control-Expose-Headers',
|
| value: headers
|
| };
|
| }
|
| return null;
|
| }
|
|
|
| function configureMaxAge(options) {
|
| var maxAge = (typeof options.maxAge === 'number' || options.maxAge) && options.maxAge.toString()
|
| if (maxAge && maxAge.length) {
|
| return {
|
| key: 'Access-Control-Max-Age',
|
| value: maxAge
|
| };
|
| }
|
| return null;
|
| }
|
|
|
| function applyHeaders(headers, res) {
|
| for (var i = 0, n = headers.length; i < n; i++) {
|
| var header = headers[i];
|
| if (header) {
|
| if (Array.isArray(header)) {
|
| applyHeaders(header, res);
|
| } else if (header.key === 'Vary' && header.value) {
|
| vary(res, header.value);
|
| } else if (header.value) {
|
| res.setHeader(header.key, header.value);
|
| }
|
| }
|
| }
|
| }
|
|
|
| function cors(options, req, res, next) {
|
| var headers = [],
|
| method = req.method && req.method.toUpperCase && req.method.toUpperCase();
|
|
|
| if (method === 'OPTIONS') {
|
|
|
| headers.push(configureOrigin(options, req));
|
| headers.push(configureCredentials(options))
|
| headers.push(configureMethods(options))
|
| headers.push(configureAllowedHeaders(options, req));
|
| headers.push(configureMaxAge(options))
|
| headers.push(configureExposedHeaders(options))
|
| applyHeaders(headers, res);
|
|
|
| if (options.preflightContinue) {
|
| next();
|
| } else {
|
|
|
|
|
| res.statusCode = options.optionsSuccessStatus;
|
| res.setHeader('Content-Length', '0');
|
| res.end();
|
| }
|
| } else {
|
|
|
| headers.push(configureOrigin(options, req));
|
| headers.push(configureCredentials(options))
|
| headers.push(configureExposedHeaders(options))
|
| applyHeaders(headers, res);
|
| next();
|
| }
|
| }
|
|
|
| function middlewareWrapper(o) {
|
|
|
| var optionsCallback = null;
|
| if (typeof o === 'function') {
|
| optionsCallback = o;
|
| } else {
|
| optionsCallback = function (req, cb) {
|
| cb(null, o);
|
| };
|
| }
|
|
|
| return function corsMiddleware(req, res, next) {
|
| optionsCallback(req, function (err, options) {
|
| if (err) {
|
| next(err);
|
| } else {
|
| var corsOptions = assign({}, defaults, options);
|
| var originCallback = null;
|
| if (corsOptions.origin && typeof corsOptions.origin === 'function') {
|
| originCallback = corsOptions.origin;
|
| } else if (corsOptions.origin) {
|
| originCallback = function (origin, cb) {
|
| cb(null, corsOptions.origin);
|
| };
|
| }
|
|
|
| if (originCallback) {
|
| originCallback(req.headers.origin, function (err2, origin) {
|
| if (err2 || !origin) {
|
| next(err2);
|
| } else {
|
| corsOptions.origin = origin;
|
| cors(corsOptions, req, res, next);
|
| }
|
| });
|
| } else {
|
| next();
|
| }
|
| }
|
| });
|
| };
|
| }
|
|
|
|
|
| module.exports = middlewareWrapper;
|
|
|
| }());
|
|
|