Spaces:
Sleeping
Sleeping
| (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 === '*') { | |
| // allow any origin | |
| headers.push([{ | |
| key: 'Access-Control-Allow-Origin', | |
| value: '*' | |
| }]); | |
| } else if (isString(options.origin)) { | |
| // fixed origin | |
| headers.push([{ | |
| key: 'Access-Control-Allow-Origin', | |
| value: options.origin | |
| }]); | |
| headers.push([{ | |
| key: 'Vary', | |
| value: 'Origin' | |
| }]); | |
| } else { | |
| isAllowed = isOriginAllowed(requestOrigin, options.origin); | |
| // reflect 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(','); // .methods is an array, so turn it into a string | |
| } | |
| 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 wasn't specified, so reflect the request headers | |
| headers.push([{ | |
| key: 'Vary', | |
| value: 'Access-Control-Request-Headers' | |
| }]); | |
| } else if (allowedHeaders.join) { | |
| allowedHeaders = allowedHeaders.join(','); // .headers is an array, so turn it into a string | |
| } | |
| 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(','); // .headers is an array, so turn it into a string | |
| } | |
| 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') { | |
| // preflight | |
| headers.push(configureOrigin(options, req)); | |
| headers.push(configureCredentials(options, req)); | |
| headers.push(configureMethods(options, req)); | |
| headers.push(configureAllowedHeaders(options, req)); | |
| headers.push(configureMaxAge(options, req)); | |
| headers.push(configureExposedHeaders(options, req)); | |
| applyHeaders(headers, res); | |
| if (options.preflightContinue) { | |
| next(); | |
| } else { | |
| // Safari (and potentially other browsers) need content-length 0, | |
| // for 204 or they just hang waiting for a body | |
| res.statusCode = options.optionsSuccessStatus; | |
| res.setHeader('Content-Length', '0'); | |
| res.end(); | |
| } | |
| } else { | |
| // actual response | |
| headers.push(configureOrigin(options, req)); | |
| headers.push(configureCredentials(options, req)); | |
| headers.push(configureExposedHeaders(options, req)); | |
| applyHeaders(headers, res); | |
| next(); | |
| } | |
| } | |
| function middlewareWrapper(o) { | |
| // if options are static (either via defaults or custom options passed in), wrap in a function | |
| 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(); | |
| } | |
| } | |
| }); | |
| }; | |
| } | |
| // can pass either an options hash, an options delegate, or nothing | |
| module.exports = middlewareWrapper; | |
| }()); | |