nodemailer
Version:
Easy as cake e-mail sending from your Node.js applications
129 lines (107 loc) • 3.88 kB
JavaScript
;
/**
* Minimal HTTP/S proxy client
*/
var net = require('net');
var tls = require('tls');
var urllib = require('url');
module.exports = proxyConnect;
/**
* Establishes proxied connection to destinationPort
*
* proxyConnect("http://localhost:3128/", 80, "google.com", function(err, socket){
* socket.write("GET / HTTP/1.0\r\n\r\n");
* });
*
* @param {String} proxyUrl proxy configuration, etg "http://proxy.host:3128/"
* @param {Number} destinationPort Port to open in destination host
* @param {String} destinationHost Destination hostname
* @param {Function} callback Callback to run with the rocket object once connection is established
*/
function proxyConnect(proxyUrl, destinationPort, destinationHost, callback) {
var proxy = urllib.parse(proxyUrl);
// create a socket connection to the proxy server
var options;
var connect;
var socket;
options = {
host: proxy.hostname,
port: Number(proxy.port) ? Number(proxy.port) : (proxy.protocol === 'https:' ? 443 : 80)
};
if (proxy.protocol === 'https:') {
// we can use untrusted proxies as long as we verify actual SMTP certificates
options.rejectUnauthorized = false;
connect = tls.connect.bind(tls);
} else {
connect = net.connect.bind(net);
}
// Error harness for initial connection. Once connection is established, the responsibility
// to handle errors is passed to whoever uses this socket
var finished = false;
var tempSocketErr = function (err) {
if (finished) {
return;
}
finished = true;
try {
socket.destroy();
} catch (E) {
// ignore
}
callback(err);
};
socket = connect(options, function () {
if (finished) {
return;
}
var reqHeaders = {
Host: destinationHost + ':' + destinationPort,
Connection: 'close'
};
if (proxy.auth) {
reqHeaders['Proxy-Authorization'] = 'Basic ' + new Buffer(proxy.auth).toString('base64');
}
socket.write(
// HTTP method
'CONNECT ' + destinationHost + ':' + destinationPort + ' HTTP/1.1\r\n' +
// HTTP request headers
Object.keys(reqHeaders).map(function (key) {
return key + ': ' + reqHeaders[key];
}).join('\r\n') +
// End request
'\r\n\r\n');
var headers = '';
var onSocketData = function (chunk) {
var match;
var remainder;
if (finished) {
return;
}
headers += chunk.toString('binary');
if ((match = headers.match(/\r\n\r\n/))) {
socket.removeListener('data', onSocketData);
remainder = headers.substr(match.index + match[0].length);
headers = headers.substr(0, match.index);
if (remainder) {
socket.unshift(new Buffer(remainder, 'binary'));
}
// proxy connection is now established
finished = true;
socket.removeListener('error', tempSocketErr);
// check response code
match = headers.match(/^HTTP\/\d+\.\d+ (\d+)/i);
if (!match || (match[1] || '').charAt(0) !== '2') {
try {
socket.destroy();
} catch (E) {
// ignore
}
return callback(new Error('Invalid response from proxy' + (match && ': ' + match[1] || '')));
}
return callback(null, socket);
}
};
socket.on('data', onSocketData);
});
socket.once('error', tempSocketErr);
}