| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 | (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;}());
 |