From 70cfe6ede886f0fd9e2fb0e044deea0f9a92d16f Mon Sep 17 00:00:00 2001 From: Espen Hovlandsdal Date: Wed, 17 May 2017 13:32:44 +0200 Subject: [PATCH] Fix proxying when target protocol differs from proxy protocol --- lib/eventsource.js | 6 +- test/eventsource_test.js | 115 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 115 insertions(+), 6 deletions(-) diff --git a/lib/eventsource.js b/lib/eventsource.js index fd1d48c..937ac14 100644 --- a/lib/eventsource.js +++ b/lib/eventsource.js @@ -86,8 +86,12 @@ function EventSource (url, eventSourceInitDict) { // If specify http proxy, make the request to sent to the proxy server, // and include the original url in path and Host headers - if (eventSourceInitDict && eventSourceInitDict.proxy) { + var useProxy = eventSourceInitDict && eventSourceInitDict.proxy + if (useProxy) { var proxy = parse(eventSourceInitDict.proxy) + isSecure = proxy.protocol === 'https:' + + options.protocol = isSecure ? 'https:' : 'http:' options.path = url options.headers.Host = options.host options.hostname = proxy.hostname diff --git a/test/eventsource_test.js b/test/eventsource_test.js index b6c9113..bc91833 100644 --- a/test/eventsource_test.js +++ b/test/eventsource_test.js @@ -11,6 +11,11 @@ var u = require('url') var it = mocha.it var describe = mocha.describe +var httpsServerOptions = { + key: fs.readFileSync(path.join(__dirname, 'server_certs', 'key.pem')), + cert: fs.readFileSync(path.join(__dirname, 'server_certs', 'certificate.pem')) +} + var _port = 20000 var servers = [] process.on('exit', function () { @@ -25,11 +30,7 @@ function createServer (callback) { } function createHttpsServer (callback) { - var options = { - key: fs.readFileSync(path.join(__dirname, 'server_certs', 'key.pem')), - cert: fs.readFileSync(path.join(__dirname, 'server_certs', 'certificate.pem')) - } - var server = https.createServer(options) + var server = https.createServer(httpsServerOptions) configureServer(server, 'https', _port++, callback) } @@ -72,6 +73,48 @@ function configureServer (server, protocol, port, callback) { }) } +function createProxy (target, protocol, callback) { + var proxyPort = _port++ + var targetProtocol = target.indexOf('https') === 0 ? 'https' : 'http' + var requester = targetProtocol === 'https' ? https : http + var serve = protocol === 'https' ? https : http + + var proxied = [] + var server = serve.createServer(serve === https ? httpsServerOptions : undefined) + + server.on('request', function (req, res) { + var options = u.parse(target) + options.headers = req.headers + options.rejectUnauthorized = false + + var upstreamReq = requester.request(options, function (upstreamRes) { + upstreamRes.pipe(res) + }) + + proxied.push(upstreamReq) + upstreamReq.end() + }) + + servers.push(server) + + var oldClose = server.close + server.close = function (closeCb) { + proxied.forEach(function (res) { + res.abort() + }) + + oldClose.call(server, function () { + servers.splice(servers.indexOf(server), 1) + closeCb() + }) + } + + server.listen(proxyPort, function onOpen (err) { + server.url = protocol + '://localhost:' + proxyPort + callback(err, server) + }) +} + function writeEvents (chunks) { return function (req, res) { res.writeHead(200, {'Content-Type': 'text/event-stream'}) @@ -1019,3 +1062,65 @@ describe('Events', function () { }) }) }) + +describe('Proxying', function () { + it('proxies http->http requests', function (done) { + createServer(function (err, server) { + if (err) return done(err) + + server.on('request', writeEvents(['data: World\n\n'])) + + createProxy(server.url, 'http', function (err, proxy) { + if (err) return done(err) + + var es = new EventSource(server.url, {proxy: proxy.url}) + es.onmessage = function (m) { + assert.equal(m.data, 'World') + proxy.close(function () { + server.close(done) + }) + } + }) + }) + }) + + it('proxies http->https requests', function (done) { + createHttpsServer(function (err, server) { + if (err) return done(err) + + server.on('request', writeEvents(['data: World\n\n'])) + + createProxy(server.url, 'http', function (err, proxy) { + if (err) return done(err) + + var es = new EventSource(server.url, {proxy: proxy.url}) + es.onmessage = function (m) { + assert.equal(m.data, 'World') + proxy.close(function () { + server.close(done) + }) + } + }) + }) + }) + + it('proxies https->http requests', function (done) { + createHttpsServer(function (err, server) { + if (err) return done(err) + + server.on('request', writeEvents(['data: World\n\n'])) + + createProxy(server.url, 'https', function (err, proxy) { + if (err) return done(err) + + var es = new EventSource(server.url, {proxy: proxy.url, rejectUnauthorized: false}) + es.onmessage = function (m) { + assert.equal(m.data, 'World') + proxy.close(function () { + server.close(done) + }) + } + }) + }) + }) +})