« index
Coverage for /Users/yunong/workspace/node-restify/lib/plugins/cors.js : 91%
127 lines |
116 run |
11 missing |
0 partial |
11 blocks |
6 blocks run |
5 blocks missing
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | // Copyright 2013 Mark Cavage, Inc. All rights reserved. var assert = require('assert-plus'); ///--- Globals var ALLOW_HEADERS = [ 'accept', 'accept-version', 'content-type', 'request-id', 'origin', 'x-api-version', 'x-request-id' ]; var EXPOSE_HEADERS = [ 'api-version', 'content-length', 'content-md5', 'content-type', 'date', 'request-id', 'response-time' ]; // Normal var AC_ALLOW_ORIGIN = 'Access-Control-Allow-Origin'; var AC_ALLOW_CREDS = 'Access-Control-Allow-Credentials'; var AC_EXPOSE_HEADERS = 'Access-Control-Expose-Headers'; ///--- Internal Functions function matchOrigin(req, origins) { var origin = req.headers['origin']; function belongs(o) { if (origin === o || o === '*') { origin = o; return (true); } return (false); } return ((origin && origins.some(belongs)) ? origin : false); } ///--- API // // From http://www.w3.org/TR/cors/#resource-processing-model // // If "simple" request (paraphrased): // // 1. If the Origin header is not set, or if the value of Origin is not a // case-sensitive match to any values listed in `opts.origins`, do not // send any CORS headers // // 2. If the resource supports credentials add a single // 'Access-Control-Allow-Credentials' header with the value as "true", and // ensure 'AC-Allow-Origin' is not '*', but is the request header value, // otherwise add a single Access-Control-Allow-Origin header, with either the // value of the Origin header or the string "*" as value // // 3. Add Access-Control-Expose-Headers as appropriate // // Pre-flight requests are handled by the router internally // function cors(opts) { assert.optionalObject(opts, 'options'); opts = opts || {}; assert.optionalArrayOfString(opts.origins, 'options.origins'); assert.optionalBool(opts.credentials, 'options.credentials'); assert.optionalArrayOfString(opts.headers, 'options.headers'); cors.credentials = opts.credentials; cors.origins = opts.origins || ['*']; var headers = (opts.headers || []).slice(0); var origins = opts.origins || ['*']; EXPOSE_HEADERS.forEach(function (h) { if (headers.indexOf(h) === -1) headers.push(h); }); // Handler for simple requests function restifyCORSSimple(req, res, next) { var origin; if (!(origin = matchOrigin(req, origins))) { next(); return; } function corsOnHeader() { origin = req.headers['origin']; if (opts.credentials) { res.setHeader(AC_ALLOW_ORIGIN, origin); res.setHeader(AC_ALLOW_CREDS, 'true'); } else { res.setHeader(AC_ALLOW_ORIGIN, origin); } res.setHeader(AC_EXPOSE_HEADERS, headers.join(', ')); } res.once('header', corsOnHeader); next(); } return (restifyCORSSimple); } ///--- Exports module.exports = cors; // All of these are needed for the pre-flight code over in lib/router.js cors.ALLOW_HEADERS = ALLOW_HEADERS; cors.EXPOSE_HEADERS = EXPOSE_HEADERS; cors.credentials = false; cors.origins = []; cors.matchOrigin = matchOrigin; |