From f072e920a6c8b5f3bd77681de74c3ab9265ef40f Mon Sep 17 00:00:00 2001 From: Emilien Kenler Date: Mon, 27 Feb 2017 12:39:08 +0900 Subject: [PATCH 1/5] Add an option to toggle handling of OPTIONS requests --- README.md | 1 + lib/server.js | 3 +++ 2 files changed, 4 insertions(+) diff --git a/README.md b/README.md index c744f395e..da027a8b5 100644 --- a/README.md +++ b/README.md @@ -254,6 +254,7 @@ to a single process. - `path` (`String`): name of the path to capture (`/engine.io`). - `destroyUpgrade` (`Boolean`): destroy unhandled upgrade requests (`true`) - `destroyUpgradeTimeout` (`Number`): milliseconds after which unhandled requests are ended (`1000`) + - `enableOptions` (`Boolean`): let engine.io handle the OPTIONS requests (`true`) - `generateId` - Generate a socket id. - Overwrite this method to generate your custom socket id. diff --git a/lib/server.js b/lib/server.js index 8ea195d1c..e3ac891d9 100644 --- a/lib/server.js +++ b/lib/server.js @@ -417,6 +417,9 @@ Server.prototype.attach = function (server, options) { path += '/'; function check (req) { + if ('OPTIONS' === req.method && false === options.enableOptions) { + return false; + } return path === req.url.substr(0, path.length); } From 6890481eaf9ec02d5ac3c4afff68f012cd6bfb2d Mon Sep 17 00:00:00 2001 From: Emilien Kenler Date: Tue, 28 Feb 2017 11:08:56 +0900 Subject: [PATCH 2/5] Allow to specify a function to handle the OPTIONS requests --- README.md | 2 +- lib/server.js | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index da027a8b5..f86295b83 100644 --- a/README.md +++ b/README.md @@ -254,7 +254,7 @@ to a single process. - `path` (`String`): name of the path to capture (`/engine.io`). - `destroyUpgrade` (`Boolean`): destroy unhandled upgrade requests (`true`) - `destroyUpgradeTimeout` (`Number`): milliseconds after which unhandled requests are ended (`1000`) - - `enableOptions` (`Boolean`): let engine.io handle the OPTIONS requests (`true`) + - `handlePreflightRequest` (`Boolean|Function`): let engine.io handle the OPTIONS requests. You can also pass a custom function to handle the requests (`true`) - `generateId` - Generate a socket id. - Overwrite this method to generate your custom socket id. diff --git a/lib/server.js b/lib/server.js index e3ac891d9..acb46a242 100644 --- a/lib/server.js +++ b/lib/server.js @@ -417,7 +417,7 @@ Server.prototype.attach = function (server, options) { path += '/'; function check (req) { - if ('OPTIONS' === req.method && false === options.enableOptions) { + if ('OPTIONS' === req.method && false === options.handlePreflightRequest) { return false; } return path === req.url.substr(0, path.length); @@ -432,7 +432,11 @@ Server.prototype.attach = function (server, options) { server.on('request', function (req, res) { if (check(req)) { debug('intercepting request for path "%s"', path); - self.handleRequest(req, res); + if ('OPTIONS' === req.method && 'function' === typeof options.handlePreflightRequest) { + options.handlePreflightRequest.call(server, req, res); + } else { + self.handleRequest(req, res); + } } else { for (var i = 0, l = listeners.length; i < l; i++) { listeners[i].call(server, req, res); From d78cdf92ec32752c1d42a740bc51d955e2f88908 Mon Sep 17 00:00:00 2001 From: Emilien Kenler Date: Tue, 28 Feb 2017 12:06:09 +0900 Subject: [PATCH 3/5] Add tests for the handlePreflightRequest option --- test/server.js | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/test/server.js b/test/server.js index fd0abdded..31240d927 100644 --- a/test/server.js +++ b/test/server.js @@ -2514,6 +2514,67 @@ describe('server', function () { }); }); + describe('cors', function () { + it('should handle OPTIONS requests', function (done) { + listen({handlePreflightRequest: true}, function (port) { + request.options('http://localhost:%d/engine.io/default/'.s(port)) + .set('Origin', 'http://engine.io') + .query({ transport: 'polling' }) + .end(function (res) { + expect(res.status).to.be(400); + 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'); + done(); + }); + }); + }); + + it('should not handle OPTIONS requests', function (done) { + listen({handlePreflightRequest: false}, function (port) { + request.options('http://localhost:%d/engine.io/default/'.s(port)) + .set('Origin', 'http://engine.io') + .query({ transport: 'polling' }) + .end(function (res) { + expect(res.status).to.be(501); + expect(res.body.code).to.be(undefined); + done(); + }); + }); + }); + + it('should handle OPTIONS requests with the given function', function (done) { + const handlePreflightRequest = (req, res) => { + let headers = {}; + if (req.headers.origin) { + headers['Access-Control-Allow-Credentials'] = 'true'; + headers['Access-Control-Allow-Origin'] = req.headers.origin; + } else { + headers['Access-Control-Allow-Origin'] = '*'; + } + headers['Access-Control-Allow-Methods'] = 'GET,HEAD,PUT,PATCH,POST,DELETE'; + headers['Access-Control-Allow-Headers'] = 'origin, content-type, accept'; + res.writeHead(200, headers); + res.end(); + }; + listen({handlePreflightRequest}, function (port) { + request.options('http://localhost:%d/engine.io/default/'.s(port)) + .set('Origin', 'http://engine.io') + .query({ transport: 'polling' }) + .end(function (res) { + 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-methods']).to.be('GET,HEAD,PUT,PATCH,POST,DELETE'); + expect(res.header['access-control-allow-headers']).to.be('origin, content-type, accept'); + done(); + }); + }); + }); + }); + if (!UWS_ENGINE && parseInt(process.versions.node, 10) >= 4) { describe('wsEngine option', function () { it('should allow loading of other websocket server implementation like uws', function (done) { From 3afdf8be8c4273b5e212451b9f300ff9b5e2183c Mon Sep 17 00:00:00 2001 From: Emilien Kenler Date: Wed, 1 Mar 2017 14:36:52 +0900 Subject: [PATCH 4/5] Don't use ES6 --- test/server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/server.js b/test/server.js index 31240d927..a5d40c5aa 100644 --- a/test/server.js +++ b/test/server.js @@ -2545,8 +2545,8 @@ describe('server', function () { }); it('should handle OPTIONS requests with the given function', function (done) { - const handlePreflightRequest = (req, res) => { - let headers = {}; + var handlePreflightRequest = function (req, res) { + var headers = {}; if (req.headers.origin) { headers['Access-Control-Allow-Credentials'] = 'true'; headers['Access-Control-Allow-Origin'] = req.headers.origin; From 2bd0272217e4a750951c3500a2bd2bb8ab50a962 Mon Sep 17 00:00:00 2001 From: Damien Arrachequesne Date: Sat, 11 Mar 2017 07:48:31 +0100 Subject: [PATCH 5/5] minor fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f86295b83..0069ce0b4 100644 --- a/README.md +++ b/README.md @@ -254,7 +254,7 @@ to a single process. - `path` (`String`): name of the path to capture (`/engine.io`). - `destroyUpgrade` (`Boolean`): destroy unhandled upgrade requests (`true`) - `destroyUpgradeTimeout` (`Number`): milliseconds after which unhandled requests are ended (`1000`) - - `handlePreflightRequest` (`Boolean|Function`): let engine.io handle the OPTIONS requests. You can also pass a custom function to handle the requests (`true`) + - `handlePreflightRequest` (`Boolean|Function`): whether to let engine.io handle the OPTIONS requests. You can also pass a custom function to handle the requests (`true`) - `generateId` - Generate a socket id. - Overwrite this method to generate your custom socket id.