From 954ee7a225ab5806d8ee98ca4243a7b312ede636 Mon Sep 17 00:00:00 2001 From: Neil Manvar Date: Fri, 17 Nov 2017 00:52:32 -0800 Subject: [PATCH] Add support for sending events through proxy For both HTTP and HTTPS endpoints. Uses tunnel-agent for https. --- lib/transports.js | 64 +++++++++++++++++++++++++++++++++++++++++------ package.json | 1 + 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/lib/transports.js b/lib/transports.js index a606a95..4097394 100644 --- a/lib/transports.js +++ b/lib/transports.js @@ -6,8 +6,12 @@ var timeoutReq = require('timed-out'); var http = require('http'); var https = require('https'); +var tunnel = require('tunnel-agent'); -var agentOptions = {keepAlive: true, maxSockets: 100}; +var agentOptions = { + keepAlive: true, + maxSockets: 100 +}; var httpAgent = new http.Agent(agentOptions); var httpsAgent = new https.Agent(agentOptions); @@ -21,7 +25,7 @@ function HTTPTransport(options) { this.agent = httpAgent; } util.inherits(HTTPTransport, Transport); -HTTPTransport.prototype.send = function(client, message, headers, eventId, cb) { +HTTPTransport.prototype.send = function (client, message, headers, eventId, cb) { var options = { hostname: client.dsn.host, path: client.dsn.path + 'api/' + client.dsn.project_id + '/store/', @@ -31,6 +35,20 @@ HTTPTransport.prototype.send = function(client, message, headers, eventId, cb) { ca: client.ca, agent: this.agent }; + + // set path apprpriately when using http endpoint + proxy, set proxy headers appropriately when using https endpoint + proxy + if (this.options.hasOwnProperty('proxyHost')) { + if (client.dsn.protocol === 'http') { + options.path = 'http://' + client.dsn.host + ':' + client.dsn.port + client.dsn.path + 'api/' + client.dsn.project_id + '/store/'; + delete options.hostname; // only 'host' should be set when using proxy + } else { + this.options.agent.proxyOptions.headers = { + 'Content-Type': 'application/octet-stream', + host: client.dsn.host + ':' + client.dsn.port + } + } + } + for (var key in this.options) { if (this.options.hasOwnProperty(key)) { options[key] = this.options[key]; @@ -38,7 +56,10 @@ HTTPTransport.prototype.send = function(client, message, headers, eventId, cb) { } // prevent off heap memory explosion - var _name = this.agent.getName({host: client.dsn.host, port: client.dsn.port}); + var _name = this.agent.getName({ + host: client.dsn.host, + port: client.dsn.port + }); var _requests = this.agent.requests[_name]; if (_requests && Object.keys(_requests).length > client.maxReqQueueCount) { // other feedback strategy @@ -46,7 +67,7 @@ HTTPTransport.prototype.send = function(client, message, headers, eventId, cb) { return; } - var req = this.transport.request(options, function(res) { + var req = this.transport.request(options, function (res) { res.setEncoding('utf8'); if (res.statusCode >= 200 && res.statusCode < 300) { client.emit('logged', eventId); @@ -63,9 +84,8 @@ HTTPTransport.prototype.send = function(client, message, headers, eventId, cb) { client.emit('error', e); cb && cb(e); } - // force the socket to drain - var noop = function() {}; + var noop = function () {}; res.on('data', noop); res.on('end', noop); }); @@ -73,7 +93,7 @@ HTTPTransport.prototype.send = function(client, message, headers, eventId, cb) { timeoutReq(req, client.sendTimeout * 1000); var cbFired = false; - req.on('error', function(e) { + req.on('error', function (e) { client.emit('error', e); if (!cbFired) { cb && cb(e); @@ -89,10 +109,40 @@ function HTTPSTransport(options) { this.options = options || {}; this.agent = httpsAgent; } + +function HTTPProxyTransport(options) { + this.defaultPort = 80; + this.transport = http; + this.options = options || {}; + this.agent = httpAgent; + this.options.host = options.proxyHost; + this.options.port = options.proxyPort; +} + +function HTTPSProxyTransport(options) { + this.transport = https; + this.options = options || {}; + this.agent = httpsAgent; + this.options.agent = tunnel['httpsOverHttp']({ + proxy: { + host: options.proxyHost, + port: options.proxyPort, + proxyAuth: null // TODO: Add ability to specify creds/auth + }, + keepAlive: agentOptions.keepAlive, + maxSockets: agentOptions.maxSockets + }); +} + util.inherits(HTTPSTransport, HTTPTransport); +util.inherits(HTTPProxyTransport, HTTPTransport); +util.inherits(HTTPSProxyTransport, HTTPTransport); module.exports.http = new HTTPTransport(); module.exports.https = new HTTPSTransport(); module.exports.Transport = Transport; module.exports.HTTPTransport = HTTPTransport; module.exports.HTTPSTransport = HTTPSTransport; + +module.exports.HTTPProxyTransport = HTTPProxyTransport; +module.exports.HTTPSProxyTransport = HTTPSProxyTransport; diff --git a/package.json b/package.json index ebeec85..0899449 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "lsmod": "1.0.0", "stack-trace": "0.0.9", "timed-out": "4.0.1", + "tunnel-agent": "^0.6.0", "uuid": "3.0.0" }, "devDependencies": {