UNPKG

2.99 kBJavaScriptView Raw
1/**
2 * CORS middleware for koa2
3 *
4 * @param {Object} [options]
5 * - {String|Function(ctx)} origin `Access-Control-Allow-Origin`, default is request Origin header
6 * - {Array} exposeHeaders `Access-Control-Expose-Headers`
7 * - {String|Number} maxAge `Access-Control-Max-Age` in seconds
8 * - {Boolean} credentials `Access-Control-Allow-Credentials`
9 * - {Array} allowMethods `Access-Control-Allow-Methods`, default is ['GET', 'PUT', 'POST', 'DELETE', 'HEAD', 'OPTIONS']
10 * - {Array} allowHeaders `Access-Control-Allow-Headers`
11 * @return {Function}
12 * @api public
13 */
14module.exports = function crossOrigin(options = {}) {
15 const defaultOptions = {
16 allowMethods: ['GET', 'PUT', 'POST', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'],
17 };
18
19 // set defaultOptions to options
20 for (let key in defaultOptions) {
21 if (!Object.prototype.hasOwnProperty.call(options, key)) {
22 options[key] = defaultOptions[key];
23 }
24 }
25
26 return async function (ctx, next) {
27 let origin;
28 if (typeof options.origin === 'function') {
29 origin = options.origin(ctx);
30 } else {
31 origin = options.origin || ctx.get('Origin') || '*';
32 }
33 if (!origin) {
34 return await next();
35 }
36
37 // Access-Control-Allow-Origin
38 ctx.set('Access-Control-Allow-Origin', origin);
39
40 if (ctx.method === 'OPTIONS') {
41 // Preflight Request
42 if (!ctx.get('Access-Control-Request-Method')) {
43 return await next();
44 }
45
46 // Access-Control-Max-Age
47 if (options.maxAge) {
48 ctx.set('Access-Control-Max-Age', String(options.maxAge));
49 }
50
51 // Access-Control-Allow-Credentials
52 if (options.credentials === true) {
53 // When used as part of a response to a preflight request,
54 // this indicates whether or not the actual request can be made using credentials.
55 ctx.set('Access-Control-Allow-Credentials', 'true');
56 }
57
58 // Access-Control-Allow-Methods
59 if (options.allowMethods) {
60 ctx.set('Access-Control-Allow-Methods', options.allowMethods.join(','));
61 }
62
63 // Access-Control-Allow-Headers
64 if (options.allowHeaders) {
65 ctx.set('Access-Control-Allow-Headers', options.allowHeaders.join(','));
66 } else {
67 ctx.set('Access-Control-Allow-Headers', ctx.get('Access-Control-Request-Headers'));
68 }
69
70 ctx.status = 204; // No Content
71 } else {
72 // Request
73 // Access-Control-Allow-Credentials
74 if (options.credentials === true) {
75 if (origin === '*') {
76 // `credentials` can't be true when the `origin` is set to `*`
77 ctx.remove('Access-Control-Allow-Credentials');
78 } else {
79 ctx.set('Access-Control-Allow-Credentials', 'true');
80 }
81 }
82
83 // Access-Control-Expose-Headers
84 if (options.exposeHeaders) {
85 ctx.set('Access-Control-Expose-Headers', options.exposeHeaders.join(','));
86 }
87
88 try {
89 await next();
90 } catch (err) {
91 throw err;
92 }
93 }
94 };
95};