Skip to content

Commit ebf1a96

Browse files
flenterdarrachequesne
authored andcommitted
[feat] Allow configuration of Access-Control-Allow-Origin value (#511)
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
1 parent 0151c6a commit ebf1a96

File tree

9 files changed

+42
-32
lines changed

9 files changed

+42
-32
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ to a single process.
228228
- `maxHttpBufferSize` (`Number`): how many bytes or characters a message
229229
can be, before closing the session (to avoid DoS). Default
230230
value is `10E7`.
231+
- `origins` (`String`): the allowed origins (`*`)
231232
- `allowRequest` (`Function`): A function that receives a given handshake
232233
or upgrade request as its first parameter, and can decide whether to
233234
continue or not. The second argument is a function that needs to be

lib/server.js

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ function Server (opts) {
4545
this.allowUpgrades = false !== opts.allowUpgrades;
4646
this.allowRequest = opts.allowRequest;
4747
this.cookie = false !== opts.cookie ? (opts.cookie || 'io') : false;
48+
this.origins = opts.origins || '*';
4849
this.cookiePath = false !== opts.cookiePath ? (opts.cookiePath || '/') : false;
4950
this.cookieHttpOnly = false !== opts.cookieHttpOnly;
5051
this.perMessageDeflate = false !== opts.perMessageDeflate ? (opts.perMessageDeflate || true) : false;
@@ -221,7 +222,7 @@ Server.prototype.handleRequest = function (req, res) {
221222
var self = this;
222223
this.verify(req, false, function (err, success) {
223224
if (!success) {
224-
sendErrorMessage(req, res, err);
225+
self.sendErrorMessage(req, res, err);
225226
return;
226227
}
227228

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

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

248249
var isForbidden = !Server.errorMessages.hasOwnProperty(code);
@@ -254,20 +255,21 @@ function sendErrorMessage (req, res, code) {
254255
}));
255256
return;
256257
}
258+
259+
headers['Access-Control-Allow-Origin'] = this.origins;
260+
headers['Vary'] = 'Origin';
257261
if (req.headers.origin) {
258262
headers['Access-Control-Allow-Credentials'] = 'true';
259-
headers['Access-Control-Allow-Origin'] = req.headers.origin;
260-
} else {
261-
headers['Access-Control-Allow-Origin'] = '*';
262263
}
264+
263265
if (res !== undefined) {
264266
res.writeHead(400, headers);
265267
res.end(JSON.stringify({
266268
code: code,
267269
message: Server.errorMessages[code]
268270
}));
269271
}
270-
}
272+
};
271273

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

295297
debug('handshaking client "%s"', id);
298+
var opts = {
299+
origins: this.origins
300+
};
296301

297302
try {
298-
var transport = new transports[transportName](req);
303+
var transport = new transports[transportName](req, opts);
299304
if ('polling' === transportName) {
300305
transport.maxHttpBufferSize = this.maxHttpBufferSize;
301306
transport.httpCompression = this.httpCompression;
@@ -309,7 +314,7 @@ Server.prototype.handshake = function (transportName, req) {
309314
transport.supportsBinary = true;
310315
}
311316
} catch (e) {
312-
sendErrorMessage(req, req.res, Server.errors.BAD_REQUEST);
317+
this.sendErrorMessage(req, req.res, Server.errors.BAD_REQUEST);
313318
return;
314319
}
315320
var socket = new Socket(id, this, transport, req);
@@ -404,7 +409,10 @@ Server.prototype.onWebSocket = function (req, socket) {
404409
// transport error handling takes over
405410
socket.removeListener('error', onUpgradeError);
406411

407-
var transport = new transports[req._query.transport](req);
412+
var opts = {
413+
origins: this.origins
414+
};
415+
var transport = new transports[req._query.transport](req, opts);
408416
if (req._query && req._query.b64) {
409417
transport.supportsBinary = false;
410418
} else {

lib/transport.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,14 @@ function noop () {}
2626
* Transport constructor.
2727
*
2828
* @param {http.IncomingMessage} request
29+
* @param {Object} opts allows the origins option to be passed along
2930
* @api public
3031
*/
3132

32-
function Transport (req) {
33+
function Transport (req, opts) {
3334
this.readyState = 'open';
3435
this.discarded = false;
36+
this.origins = opts.origins;
3537
}
3638

3739
/**

lib/transports/index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ exports.polling.upgradesTo = ['websocket'];
2727
* @api private
2828
*/
2929

30-
function polling (req) {
30+
function polling (req, opts) {
3131
if ('string' === typeof req._query.j) {
32-
return new JSONP(req);
32+
return new JSONP(req, opts);
3333
} else {
34-
return new XHR(req);
34+
return new XHR(req, opts);
3535
}
3636
}

lib/transports/polling-jsonp.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ module.exports = JSONP;
2121
* @api public
2222
*/
2323

24-
function JSONP (req) {
25-
Polling.call(this, req);
24+
function JSONP (req, opts) {
25+
Polling.call(this, req, opts);
2626

2727
this.head = '___eio[' + (req._query.j || '').replace(/[^0-9]/g, '') + '](';
2828
this.foot = ');';

lib/transports/polling-xhr.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ module.exports = XHR;
1818
* @api public
1919
*/
2020

21-
function XHR (req) {
22-
Polling.call(this, req);
21+
function XHR (req, opts) {
22+
Polling.call(this, req, opts);
2323
}
2424

2525
/**
@@ -58,11 +58,10 @@ XHR.prototype.onRequest = function (req) {
5858
XHR.prototype.headers = function (req, headers) {
5959
headers = headers || {};
6060

61+
headers['Access-Control-Allow-Origin'] = this.origins;
62+
headers['Vary'] = 'Origin';
6163
if (req.headers.origin) {
6264
headers['Access-Control-Allow-Credentials'] = 'true';
63-
headers['Access-Control-Allow-Origin'] = req.headers.origin;
64-
} else {
65-
headers['Access-Control-Allow-Origin'] = '*';
6665
}
6766

6867
return Polling.prototype.headers.call(this, req, headers);

lib/transports/polling.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ module.exports = Polling;
2727
* @api public.
2828
*/
2929

30-
function Polling (req) {
31-
Transport.call(this, req);
30+
function Polling (req, opts) {
31+
Transport.call(this, req, opts);
3232

3333
this.closeTimeout = 30 * 1000;
3434
this.maxHttpBufferSize = null;

lib/transports/websocket.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ module.exports = WebSocket;
2121
* @api public
2222
*/
2323

24-
function WebSocket (req) {
25-
Transport.call(this, req);
24+
function WebSocket (req, opts) {
25+
Transport.call(this, req, opts);
2626
var self = this;
2727
this.socket = req.websocket;
2828
this.socket.on('message', this.onData.bind(this));

test/server.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ describe('server', function () {
5858
expect(res.body.code).to.be(0);
5959
expect(res.body.message).to.be('Transport unknown');
6060
expect(res.header['access-control-allow-credentials']).to.be('true');
61-
expect(res.header['access-control-allow-origin']).to.be('http://engine.io');
61+
expect(res.header['access-control-allow-origin']).to.be('*');
6262
done();
6363
});
6464
});
@@ -75,7 +75,7 @@ describe('server', function () {
7575
expect(res.body.code).to.be(1);
7676
expect(res.body.message).to.be('Session ID unknown');
7777
expect(res.header['access-control-allow-credentials']).to.be('true');
78-
expect(res.header['access-control-allow-origin']).to.be('http://engine.io');
78+
expect(res.header['access-control-allow-origin']).to.be('*');
7979
done();
8080
});
8181
});
@@ -416,7 +416,7 @@ describe('server', function () {
416416
expect(res.body.code).to.be(3);
417417
expect(res.body.message).to.be('Bad request');
418418
expect(res.header['access-control-allow-credentials']).to.be('true');
419-
expect(res.header['access-control-allow-origin']).to.be('http://engine.io');
419+
expect(res.header['access-control-allow-origin']).to.be('*');
420420
done();
421421
});
422422
});
@@ -932,7 +932,7 @@ describe('server', function () {
932932
it('should trigger transport close before open for ws', function (done) {
933933
var opts = { transports: ['websocket'] };
934934
listen(opts, function (port) {
935-
var url = 'ws://%s:%d'.s('0.0.0.50', port);
935+
var url = 'ws://%s:%d'.s('0.0.0.0', port);
936936
var socket = new eioc.Socket(url);
937937
socket.on('open', function () {
938938
done(new Error('Test invalidation'));
@@ -2589,7 +2589,7 @@ describe('server', function () {
25892589

25902590
describe('cors', function () {
25912591
it('should handle OPTIONS requests', function (done) {
2592-
listen({handlePreflightRequest: true}, function (port) {
2592+
listen({handlePreflightRequest: true, origins: 'engine.io:*'}, function (port) {
25932593
request.options('http://localhost:%d/engine.io/default/'.s(port))
25942594
.set('Origin', 'http://engine.io')
25952595
.query({ transport: 'polling' })
@@ -2599,7 +2599,7 @@ describe('server', function () {
25992599
expect(res.body.code).to.be(2);
26002600
expect(res.body.message).to.be('Bad handshake method');
26012601
expect(res.header['access-control-allow-credentials']).to.be('true');
2602-
expect(res.header['access-control-allow-origin']).to.be('http://engine.io');
2602+
expect(res.header['access-control-allow-origin']).to.be('engine.io:*');
26032603
done();
26042604
});
26052605
});
@@ -2624,7 +2624,7 @@ describe('server', function () {
26242624
var headers = {};
26252625
if (req.headers.origin) {
26262626
headers['Access-Control-Allow-Credentials'] = 'true';
2627-
headers['Access-Control-Allow-Origin'] = req.headers.origin;
2627+
headers['Access-Control-Allow-Origin'] = '*';
26282628
} else {
26292629
headers['Access-Control-Allow-Origin'] = '*';
26302630
}
@@ -2642,7 +2642,7 @@ describe('server', function () {
26422642
expect(res.status).to.be(200);
26432643
expect(res.body).to.be.empty();
26442644
expect(res.header['access-control-allow-credentials']).to.be('true');
2645-
expect(res.header['access-control-allow-origin']).to.be('http://engine.io');
2645+
expect(res.header['access-control-allow-origin']).to.be('*');
26462646
expect(res.header['access-control-allow-methods']).to.be('GET,HEAD,PUT,PATCH,POST,DELETE');
26472647
expect(res.header['access-control-allow-headers']).to.be('origin, content-type, accept');
26482648
done();

0 commit comments

Comments
 (0)