111 lines
3.4 KiB
JavaScript
111 lines
3.4 KiB
JavaScript
|
|
||
|
/**
|
||
|
* Module dependencies.
|
||
|
*/
|
||
|
|
||
|
var net = require('net');
|
||
|
var tls = require('tls');
|
||
|
var url = require('url');
|
||
|
var extend = require('extend');
|
||
|
var Agent = require('agent-base');
|
||
|
var inherits = require('util').inherits;
|
||
|
var debug = require('debug')('http-proxy-agent');
|
||
|
|
||
|
/**
|
||
|
* Module exports.
|
||
|
*/
|
||
|
|
||
|
module.exports = HttpProxyAgent;
|
||
|
|
||
|
/**
|
||
|
* The `HttpProxyAgent` implements an HTTP Agent subclass that connects to the
|
||
|
* specified "HTTP proxy server" in order to proxy HTTP requests.
|
||
|
*
|
||
|
* @api public
|
||
|
*/
|
||
|
|
||
|
function HttpProxyAgent (opts) {
|
||
|
if (!(this instanceof HttpProxyAgent)) return new HttpProxyAgent(opts);
|
||
|
if ('string' == typeof opts) opts = url.parse(opts);
|
||
|
if (!opts) throw new Error('an HTTP(S) proxy server `host` and `port` must be specified!');
|
||
|
debug('creating new HttpProxyAgent instance: %o', opts);
|
||
|
Agent.call(this, connect);
|
||
|
|
||
|
var proxy = extend({}, opts);
|
||
|
|
||
|
// if `true`, then connect to the proxy server over TLS. defaults to `false`.
|
||
|
this.secureProxy = proxy.protocol ? /^https:?$/i.test(proxy.protocol) : false;
|
||
|
|
||
|
// prefer `hostname` over `host`, and set the `port` if needed
|
||
|
proxy.host = proxy.hostname || proxy.host;
|
||
|
proxy.port = +proxy.port || (this.secureProxy ? 443 : 80);
|
||
|
|
||
|
if (proxy.host && proxy.path) {
|
||
|
// if both a `host` and `path` are specified then it's most likely the
|
||
|
// result of a `url.parse()` call... we need to remove the `path` portion so
|
||
|
// that `net.connect()` doesn't attempt to open that as a unix socket file.
|
||
|
delete proxy.path;
|
||
|
delete proxy.pathname;
|
||
|
}
|
||
|
|
||
|
this.proxy = proxy;
|
||
|
}
|
||
|
inherits(HttpProxyAgent, Agent);
|
||
|
|
||
|
/**
|
||
|
* Called when the node-core HTTP client library is creating a new HTTP request.
|
||
|
*
|
||
|
* @api public
|
||
|
*/
|
||
|
|
||
|
function connect (req, opts, fn) {
|
||
|
var proxy = this.proxy;
|
||
|
|
||
|
// change the `http.ClientRequest` instance's "path" field
|
||
|
// to the absolute path of the URL that will be requested
|
||
|
var parsed = url.parse(req.path);
|
||
|
if (null == parsed.protocol) parsed.protocol = 'http:';
|
||
|
if (null == parsed.hostname) parsed.hostname = opts.hostname || opts.host;
|
||
|
if (null == parsed.port) parsed.port = opts.port;
|
||
|
if (parsed.port == 80) {
|
||
|
// if port is 80, then we can remove the port so that the
|
||
|
// ":80" portion is not on the produced URL
|
||
|
delete parsed.port;
|
||
|
}
|
||
|
var absolute = url.format(parsed);
|
||
|
req.path = absolute;
|
||
|
|
||
|
// inject the `Proxy-Authorization` header if necessary
|
||
|
var auth = proxy.auth;
|
||
|
if (auth) {
|
||
|
req.setHeader('Proxy-Authorization', 'Basic ' + new Buffer(auth).toString('base64'));
|
||
|
}
|
||
|
|
||
|
// create a socket connection to the proxy server
|
||
|
var socket;
|
||
|
if (this.secureProxy) {
|
||
|
socket = tls.connect(proxy);
|
||
|
} else {
|
||
|
socket = net.connect(proxy);
|
||
|
}
|
||
|
|
||
|
// at this point, the http ClientRequest's internal `_header` field might have
|
||
|
// already been set. If this is the case then we'll need to re-generate the
|
||
|
// string since we just changed the `req.path`
|
||
|
if (req._header) {
|
||
|
debug('regenerating stored HTTP header string for request');
|
||
|
req._header = null;
|
||
|
req._implicitHeader();
|
||
|
if (req.output && req.output.length > 0) {
|
||
|
debug('patching connection write() output buffer with updated header');
|
||
|
// the _header has already been queued to be written to the socket
|
||
|
var first = req.output[0];
|
||
|
var endOfHeaders = first.indexOf('\r\n\r\n') + 4;
|
||
|
req.output[0] = req._header + first.substring(endOfHeaders);
|
||
|
debug('output buffer: %o', req.output);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn(null, socket);
|
||
|
};
|