Skip to content
This repository was archived by the owner on Oct 23, 2023. It is now read-only.

Commit 6c5c58b

Browse files
committed
Use tunnel-agent for proxying https request
1 parent 2e9c8e5 commit 6c5c58b

File tree

2 files changed

+80
-101
lines changed

2 files changed

+80
-101
lines changed

lib/transports.js

Lines changed: 79 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ var timeoutReq = require('timed-out');
66

77
var http = require('http');
88
var https = require('https');
9-
var Tls = require('tls');
9+
var tunnel = require('tunnel-agent');
1010

1111
var agentOptions = {keepAlive: true, maxSockets: 100};
1212
var httpAgent = new http.Agent(agentOptions);
@@ -16,128 +16,106 @@ function Transport() {}
1616
util.inherits(Transport, events.EventEmitter);
1717

1818
function HTTPTransport(options) {
19-
this.defaultPort = 80;
20-
this.transport = http;
21-
this.options = options || {};
22-
this.agent = httpAgent;
19+
this.defaultPort = 80;
20+
this.transport = http;
21+
this.options = options || {};
22+
this.agent = httpAgent;
2323
}
2424
util.inherits(HTTPTransport, Transport);
2525
HTTPTransport.prototype.send = function(client, message, headers, eventId, cb) {
2626

27-
var options = {
28-
hostname: client.dsn.host,
29-
path: client.dsn.path + 'api/' + client.dsn.project_id + '/store/',
30-
headers: headers,
31-
method: 'POST',
32-
port: client.dsn.port || this.defaultPort,
33-
ca: client.ca,
34-
agent: this.agent
35-
};
36-
37-
// set path apprpriately when using proxy
38-
if (this.options.hasOwnProperty('host')) {
39-
if (client.dsn.protocol === 'http') {
40-
options.path = 'http://' + client.dsn.host + ':' + client.dsn.port + client.dsn.path + 'api/' + client.dsn.project_id + '/store/'
41-
} else {
42-
options.path = client.dsn.host + ':' + client.dsn.port;
43-
}
44-
delete options.hostname; // only 'host' should be set when using proxy
45-
}
46-
47-
for (var key in this.options) {
48-
if (this.options.hasOwnProperty(key)) {
49-
options[key] = this.options[key];
27+
var options = {
28+
hostname: client.dsn.host,
29+
path: client.dsn.path + 'api/' + client.dsn.project_id + '/store/',
30+
headers: headers,
31+
method: 'POST',
32+
port: client.dsn.port || this.defaultPort,
33+
ca: client.ca,
34+
agent: this.agent
35+
};
36+
37+
// set path apprpriately when using http endpoint + proxy, set proxy headers appropriately when using https endpoint + proxy
38+
if (this.options.hasOwnProperty('proxyHost')) {
39+
if (client.dsn.protocol === 'http') {
40+
options.path = 'http://' + client.dsn.host + ':' + client.dsn.port + client.dsn.path + 'api/' + client.dsn.project_id + '/store/';
41+
delete options.hostname; // only 'host' should be set when using proxy
42+
} else {
43+
this.options.agent.proxyOptions.headers = {
44+
'Content-Type': 'application/octet-stream',
45+
host: client.dsn.host + ':' + client.dsn.port
46+
}
47+
}
5048
}
51-
}
52-
53-
// prevent off heap memory explosion
54-
var _name = this.agent.getName({host: client.dsn.host, port: client.dsn.port});
55-
var _requests = this.agent.requests[_name];
56-
if (_requests && Object.keys(_requests).length > client.maxReqQueueCount) {
57-
// other feedback strategy
58-
client.emit('error', new Error('client req queue is full..'));
59-
return;
60-
}
61-
62-
var req = this.transport.request(options, function(res) {
63-
res.setEncoding('utf8');
64-
if (res.statusCode >= 200 && res.statusCode < 300) {
65-
client.emit('logged', eventId);
66-
cb && cb(null, eventId);
67-
} else {
68-
var reason = res.headers['x-sentry-error'];
69-
var e = new Error('HTTP Error (' + res.statusCode + '): ' + reason);
70-
e.response = res;
71-
e.statusCode = res.statusCode;
72-
e.reason = reason;
73-
e.sendMessage = message;
74-
e.requestHeaders = headers;
75-
e.eventId = eventId;
76-
client.emit('error', e);
77-
cb && cb(e);
78-
}
79-
80-
// force the socket to drain
81-
var noop = function() {};
82-
res.on('data', noop);
83-
res.on('end', noop);
84-
});
8549

86-
timeoutReq(req, client.sendTimeout * 1000);
87-
88-
var cbFired = false;
89-
req.on('error', function(e) {
90-
client.emit('error', e);
91-
if (!cbFired) {
92-
cb && cb(e);
93-
cbFired = true;
50+
for (var key in this.options) {
51+
if (this.options.hasOwnProperty(key)) {
52+
options[key] = this.options[key];
53+
}
9454
}
95-
});
96-
97-
// TLS connection for proxying to HTTPS endpoint
98-
/* req.on('connect', function (res, socket, head) {
99-
var cts = Tls.connect({
100-
host: client.dsn.host,
101-
socket: socket
102-
}, function () {
103-
cts.write('GET /welcome HTTP/1.1rnHost: sentry.iornrn');
104-
});
105-
106-
cts.on('data', function (data) {
107-
// console.log(data.toString());
108-
});
109-
});
110-
req.end(); */
111-
112-
req.end(message);
55+
56+
var req = this.transport.request(options, function(res) {
57+
res.setEncoding('utf8');
58+
if (res.statusCode >= 200 && res.statusCode < 300) {
59+
client.emit('logged', eventId);
60+
cb && cb(null, eventId);
61+
} else {
62+
var reason = res.headers['x-sentry-error'];
63+
var e = new Error('HTTP Error (' + res.statusCode + '): ' + reason);
64+
e.response = res;
65+
e.statusCode = res.statusCode;
66+
e.reason = reason;
67+
e.sendMessage = message;
68+
e.requestHeaders = headers;
69+
e.eventId = eventId;
70+
client.emit('error', e);
71+
cb && cb(e);
72+
}
73+
// force the socket to drain
74+
var noop = function() {};
75+
res.on('data', noop);
76+
res.on('end', noop);
77+
});
78+
79+
timeoutReq(req, client.sendTimeout * 1000);
80+
81+
var cbFired = false;
82+
req.on('error', function(e) {
83+
client.emit('error', e);
84+
if (!cbFired) {
85+
cb && cb(e);
86+
cbFired = true;
87+
}
88+
});
89+
90+
req.end(message);
11391
};
11492

11593
function HTTPSTransport(options) {
116-
this.defaultPort = 443;
117-
this.transport = https;
118-
this.options = options || {};
119-
this.agent = httpsAgent;
94+
this.defaultPort = 443;
95+
this.transport = https;
96+
this.options = options || {};
12097
}
12198

12299
function HTTPProxyTransport(options) {
123100
// this.defaultPort = 80;
124101
this.transport = http;
125102
this.options = options || {};
126-
127-
// set host and port for proxy
128103
this.options.host = options.proxyHost;
129104
this.options.port = options.proxyPort;
130105
}
131106

132107
function HTTPSProxyTransport(options) {
133-
// Not working yet ):
134-
this.defaultPort = 443;
135-
this.transport = http;
108+
this.transport = https;
136109
this.options = options || {};
137-
138-
this.options.host = options.proxyHost;
139-
this.options.port = options.proxyPort;
140-
this.options.method = 'CONNECT';
110+
this.options.agent = tunnel['httpsOverHttp']({
111+
proxy: {
112+
host: options.proxyHost,
113+
port: options.proxyPort,
114+
proxyAuth: null // TODO: Add ability to specify creds/auth
115+
},
116+
keepAlive: agentOptions.keepAlive,
117+
maxSockets: agentOptions.maxSockets
118+
});
141119
}
142120

143121
util.inherits(HTTPSTransport, HTTPTransport);

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"lsmod": "1.0.0",
3535
"stack-trace": "0.0.9",
3636
"timed-out": "4.0.1",
37+
"tunnel-agent": "^0.6.0",
3738
"uuid": "3.0.0"
3839
},
3940
"devDependencies": {

0 commit comments

Comments
 (0)