Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ var corsOptions = {
optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
}

// Adds headers: Access-Control-Allow-Origin: http://example.com, Vary: Origin
// Adds headers: Access-Control-Allow-Origin: http://example.com
app.get('/products/:id', cors(corsOptions), function (req, res, next) {
res.json({msg: 'Hello'})
})
Expand Down Expand Up @@ -189,7 +189,7 @@ Here’s an example that handles both public routes and restricted, credential-s
var dynamicCorsOptions = function(req, callback) {
var corsOptions;
if (req.path.startsWith('/auth/connect/')) {
// Access-Control-Allow-Origin: http://mydomain.com, Access-Control-Allow-Credentials: true, Vary: Origin
// Access-Control-Allow-Origin: http://mydomain.com, Access-Control-Allow-Credentials: true
corsOptions = {
origin: 'http://mydomain.com',
credentials: true
Expand Down Expand Up @@ -226,6 +226,8 @@ app.listen(80, function () {
- `RegExp` - set `origin` to a regular expression pattern which will be used to test the request origin. If it's a match, the request origin will be reflected. For example the pattern `/example\.com$/` will reflect any request that is coming from an origin ending with "example.com".
- `Array` - set `origin` to an array of valid origins. Each origin can be a `String` or a `RegExp`. For example `["http://example1.com", /\.example2\.com$/]` will accept any request from "http://example1.com" or from a subdomain of "example2.com".
- `Function` - set `origin` to a function implementing some custom logic. The function takes the request origin as the first parameter and a callback (called as `callback(err, origin)`, where `origin` is a non-function value of the `origin` option) as the second.

`Vary: Origin` is added when the allowed origin is reflected from the request origin, such as with `origin: true`, a `RegExp`, an `Array`, or an origin callback. It is not added for `origin: "*"`, `origin: false`, or a static string origin.
* `methods`: Configures the **Access-Control-Allow-Methods** CORS header. Expects a comma-delimited string (ex: 'GET,PUT,POST') or an array (ex: `['GET', 'PUT', 'POST']`).
* `allowedHeaders`: Configures the **Access-Control-Allow-Headers** CORS header. Expects a comma-delimited string (ex: 'Content-Type,Authorization') or an array (ex: `['Content-Type', 'Authorization']`). If not specified, defaults to reflecting the headers specified in the request's **Access-Control-Request-Headers** header.
* `exposedHeaders`: Configures the **Access-Control-Expose-Headers** CORS header. Expects a comma-delimited string (ex: 'Content-Range,X-Content-Range') or an array (ex: `['Content-Range', 'X-Content-Range']`). If not specified, no custom headers are exposed.
Expand Down
12 changes: 8 additions & 4 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,12 @@
key: 'Access-Control-Allow-Origin',
value: options.origin
}]);
headers.push([{
key: 'Vary',
value: 'Origin'
}]);
if (options._originFromCallback) {
headers.push([{
key: 'Vary',
value: 'Origin'
}]);
}
} else {
isAllowed = isOriginAllowed(requestOrigin, options.origin);
// reflect origin
Expand Down Expand Up @@ -216,11 +218,13 @@
}

if (originCallback) {
var originFromCallback = typeof corsOptions.origin === 'function';
originCallback(req.headers.origin, function (err2, origin) {
if (err2 || !origin) {
next(err2);
} else {
corsOptions.origin = origin;
corsOptions._originFromCallback = originFromCallback;
cors(corsOptions, req, res, next);
}
});
Expand Down
26 changes: 22 additions & 4 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ var util = require('util')
cors(options)(req, res, next);
});

it('includes Vary header for specific origins', function (done) {
it('does not include Vary header for static origins', function (done) {
// arrange
var req, res, next, options;
options = {
Expand All @@ -268,15 +268,15 @@ var util = require('util')
res = fakeResponse();
next = function () {
// assert
assert.equal(res.getHeader('Vary'), 'Origin')
assert.equal(res.getHeader('Vary'), undefined)
done();
};

// act
cors(options)(req, res, next);
});

it('appends to an existing Vary header', function (done) {
it('does not append Origin to an existing Vary header for static origins', function (done) {
// arrange
var req, res, next, options;
options = {
Expand All @@ -287,7 +287,7 @@ var util = require('util')
res.setHeader('Vary', 'Foo');
next = function () {
// assert
assert.equal(res.getHeader('Vary'), 'Foo, Origin')
assert.equal(res.getHeader('Vary'), 'Foo')
done();
};

Expand Down Expand Up @@ -345,6 +345,24 @@ var util = require('util')
cors(options)(req, res, next);
});

it('includes Vary header when origin callback returns a specific origin', function (done) {
var req, res, next, options;
options = {
origin: function (sentOrigin, cb) {
cb(null, sentOrigin);
}
};
req = fakeRequest('GET');
res = fakeResponse();
next = function () {
assert.equal(res.getHeader('Access-Control-Allow-Origin'), 'http://example.com')
assert.equal(res.getHeader('Vary'), 'Origin')
done();
};

cors(options)(req, res, next);
});

it('should not allow origin when callback returns false', function (done) {
var req, res, next, options;
options = {
Expand Down