Skip to content

Commit

Permalink
[feat] Allow configuration of Access-Control-Allow-Origin value (#511)
Browse files Browse the repository at this point in the history
It's now possible to specify an origins value (default value is '*') when initialising the engine. This value will be returned as the Access-Control-Allow-Origin value.

Related: #449
  • Loading branch information
flenter authored and darrachequesne committed Nov 2, 2018
1 parent 0151c6a commit ebf1a96
Show file tree
Hide file tree
Showing 9 changed files with 42 additions and 32 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ to a single process.
- `maxHttpBufferSize` (`Number`): how many bytes or characters a message
can be, before closing the session (to avoid DoS). Default
value is `10E7`.
- `origins` (`String`): the allowed origins (`*`)
- `allowRequest` (`Function`): A function that receives a given handshake
or upgrade request as its first parameter, and can decide whether to
continue or not. The second argument is a function that needs to be
Expand Down
26 changes: 17 additions & 9 deletions lib/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ function Server (opts) {
this.allowUpgrades = false !== opts.allowUpgrades;
this.allowRequest = opts.allowRequest;
this.cookie = false !== opts.cookie ? (opts.cookie || 'io') : false;
this.origins = opts.origins || '*';
this.cookiePath = false !== opts.cookiePath ? (opts.cookiePath || '/') : false;
this.cookieHttpOnly = false !== opts.cookieHttpOnly;
this.perMessageDeflate = false !== opts.perMessageDeflate ? (opts.perMessageDeflate || true) : false;
Expand Down Expand Up @@ -221,7 +222,7 @@ Server.prototype.handleRequest = function (req, res) {
var self = this;
this.verify(req, false, function (err, success) {
if (!success) {
sendErrorMessage(req, res, err);
self.sendErrorMessage(req, res, err);
return;
}

Expand All @@ -242,7 +243,7 @@ Server.prototype.handleRequest = function (req, res) {
* @api private
*/

function sendErrorMessage (req, res, code) {
Server.prototype.sendErrorMessage = function (req, res, code) {
var headers = { 'Content-Type': 'application/json' };

var isForbidden = !Server.errorMessages.hasOwnProperty(code);
Expand All @@ -254,20 +255,21 @@ function sendErrorMessage (req, res, code) {
}));
return;
}

headers['Access-Control-Allow-Origin'] = this.origins;
headers['Vary'] = 'Origin';
if (req.headers.origin) {
headers['Access-Control-Allow-Credentials'] = 'true';
headers['Access-Control-Allow-Origin'] = req.headers.origin;
} else {
headers['Access-Control-Allow-Origin'] = '*';
}

if (res !== undefined) {
res.writeHead(400, headers);
res.end(JSON.stringify({
code: code,
message: Server.errorMessages[code]
}));
}
}
};

/**
* generate a socket id.
Expand All @@ -293,9 +295,12 @@ Server.prototype.handshake = function (transportName, req) {
var id = this.generateId(req);

debug('handshaking client "%s"', id);
var opts = {
origins: this.origins
};

try {
var transport = new transports[transportName](req);
var transport = new transports[transportName](req, opts);
if ('polling' === transportName) {
transport.maxHttpBufferSize = this.maxHttpBufferSize;
transport.httpCompression = this.httpCompression;
Expand All @@ -309,7 +314,7 @@ Server.prototype.handshake = function (transportName, req) {
transport.supportsBinary = true;
}
} catch (e) {
sendErrorMessage(req, req.res, Server.errors.BAD_REQUEST);
this.sendErrorMessage(req, req.res, Server.errors.BAD_REQUEST);
return;
}
var socket = new Socket(id, this, transport, req);
Expand Down Expand Up @@ -404,7 +409,10 @@ Server.prototype.onWebSocket = function (req, socket) {
// transport error handling takes over
socket.removeListener('error', onUpgradeError);

var transport = new transports[req._query.transport](req);
var opts = {
origins: this.origins
};
var transport = new transports[req._query.transport](req, opts);
if (req._query && req._query.b64) {
transport.supportsBinary = false;
} else {
Expand Down
4 changes: 3 additions & 1 deletion lib/transport.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@ function noop () {}
* Transport constructor.
*
* @param {http.IncomingMessage} request
* @param {Object} opts allows the origins option to be passed along
* @api public
*/

function Transport (req) {
function Transport (req, opts) {
this.readyState = 'open';
this.discarded = false;
this.origins = opts.origins;
}

/**
Expand Down
6 changes: 3 additions & 3 deletions lib/transports/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ exports.polling.upgradesTo = ['websocket'];
* @api private
*/

function polling (req) {
function polling (req, opts) {
if ('string' === typeof req._query.j) {
return new JSONP(req);
return new JSONP(req, opts);
} else {
return new XHR(req);
return new XHR(req, opts);
}
}
4 changes: 2 additions & 2 deletions lib/transports/polling-jsonp.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ module.exports = JSONP;
* @api public
*/

function JSONP (req) {
Polling.call(this, req);
function JSONP (req, opts) {
Polling.call(this, req, opts);

this.head = '___eio[' + (req._query.j || '').replace(/[^0-9]/g, '') + '](';
this.foot = ');';
Expand Down
9 changes: 4 additions & 5 deletions lib/transports/polling-xhr.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ module.exports = XHR;
* @api public
*/

function XHR (req) {
Polling.call(this, req);
function XHR (req, opts) {
Polling.call(this, req, opts);
}

/**
Expand Down Expand Up @@ -58,11 +58,10 @@ XHR.prototype.onRequest = function (req) {
XHR.prototype.headers = function (req, headers) {
headers = headers || {};

headers['Access-Control-Allow-Origin'] = this.origins;
headers['Vary'] = 'Origin';
if (req.headers.origin) {
headers['Access-Control-Allow-Credentials'] = 'true';
headers['Access-Control-Allow-Origin'] = req.headers.origin;
} else {
headers['Access-Control-Allow-Origin'] = '*';
}

return Polling.prototype.headers.call(this, req, headers);
Expand Down
4 changes: 2 additions & 2 deletions lib/transports/polling.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ module.exports = Polling;
* @api public.
*/

function Polling (req) {
Transport.call(this, req);
function Polling (req, opts) {
Transport.call(this, req, opts);

this.closeTimeout = 30 * 1000;
this.maxHttpBufferSize = null;
Expand Down
4 changes: 2 additions & 2 deletions lib/transports/websocket.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ module.exports = WebSocket;
* @api public
*/

function WebSocket (req) {
Transport.call(this, req);
function WebSocket (req, opts) {
Transport.call(this, req, opts);
var self = this;
this.socket = req.websocket;
this.socket.on('message', this.onData.bind(this));
Expand Down
16 changes: 8 additions & 8 deletions test/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ describe('server', function () {
expect(res.body.code).to.be(0);
expect(res.body.message).to.be('Transport unknown');
expect(res.header['access-control-allow-credentials']).to.be('true');
expect(res.header['access-control-allow-origin']).to.be('http://engine.io');
expect(res.header['access-control-allow-origin']).to.be('*');
done();
});
});
Expand All @@ -75,7 +75,7 @@ describe('server', function () {
expect(res.body.code).to.be(1);
expect(res.body.message).to.be('Session ID unknown');
expect(res.header['access-control-allow-credentials']).to.be('true');
expect(res.header['access-control-allow-origin']).to.be('http://engine.io');
expect(res.header['access-control-allow-origin']).to.be('*');
done();
});
});
Expand Down Expand Up @@ -416,7 +416,7 @@ describe('server', function () {
expect(res.body.code).to.be(3);
expect(res.body.message).to.be('Bad request');
expect(res.header['access-control-allow-credentials']).to.be('true');
expect(res.header['access-control-allow-origin']).to.be('http://engine.io');
expect(res.header['access-control-allow-origin']).to.be('*');
done();
});
});
Expand Down Expand Up @@ -932,7 +932,7 @@ describe('server', function () {
it('should trigger transport close before open for ws', function (done) {
var opts = { transports: ['websocket'] };
listen(opts, function (port) {
var url = 'ws://%s:%d'.s('0.0.0.50', port);
var url = 'ws://%s:%d'.s('0.0.0.0', port);
var socket = new eioc.Socket(url);
socket.on('open', function () {
done(new Error('Test invalidation'));
Expand Down Expand Up @@ -2589,7 +2589,7 @@ describe('server', function () {

describe('cors', function () {
it('should handle OPTIONS requests', function (done) {
listen({handlePreflightRequest: true}, function (port) {
listen({handlePreflightRequest: true, origins: 'engine.io:*'}, function (port) {
request.options('http://localhost:%d/engine.io/default/'.s(port))
.set('Origin', 'http://engine.io')
.query({ transport: 'polling' })
Expand All @@ -2599,7 +2599,7 @@ describe('server', function () {
expect(res.body.code).to.be(2);
expect(res.body.message).to.be('Bad handshake method');
expect(res.header['access-control-allow-credentials']).to.be('true');
expect(res.header['access-control-allow-origin']).to.be('http://engine.io');
expect(res.header['access-control-allow-origin']).to.be('engine.io:*');
done();
});
});
Expand All @@ -2624,7 +2624,7 @@ describe('server', function () {
var headers = {};
if (req.headers.origin) {
headers['Access-Control-Allow-Credentials'] = 'true';
headers['Access-Control-Allow-Origin'] = req.headers.origin;
headers['Access-Control-Allow-Origin'] = '*';
} else {
headers['Access-Control-Allow-Origin'] = '*';
}
Expand All @@ -2642,7 +2642,7 @@ describe('server', function () {
expect(res.status).to.be(200);
expect(res.body).to.be.empty();
expect(res.header['access-control-allow-credentials']).to.be('true');
expect(res.header['access-control-allow-origin']).to.be('http://engine.io');
expect(res.header['access-control-allow-origin']).to.be('*');
expect(res.header['access-control-allow-methods']).to.be('GET,HEAD,PUT,PATCH,POST,DELETE');
expect(res.header['access-control-allow-headers']).to.be('origin, content-type, accept');
done();
Expand Down

0 comments on commit ebf1a96

Please sign in to comment.