Skip to content

Instantly share code, notes, and snippets.

@TooTallNate
Last active October 12, 2022 06:37
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save TooTallNate/5952254 to your computer and use it in GitHub Desktop.
Save TooTallNate/5952254 to your computer and use it in GitHub Desktop.
Node.js `http.Agent` class implementations...
/**
* Module dependencies.
*/
var net = require('net');
var inherits = require('util').inherits;
var EventEmitter = require('events').EventEmitter;
/**
* Module exports.
*/
module.exports = Agent;
/**
* Base HTTP "Agent" class. Emulates the node-core `http.Agent` class, but
* implemented in a way that can be easily extended for additional functionality.
*
* This base implementation does no socket pooling, and opens
* a new connection for every HTTP request.
*
* It behaves more-or-less like `agent: false`.
*
* @api public
*/
function Agent () {
if (!(this instanceof Agent)) return new Agent();
EventEmitter.call(this);
}
inherits(Agent, EventEmitter);
/**
* Default port to connect to.
*/
Agent.prototype.defaultPort = 80;
/**
* Called by node-core's "_http_client.js" module when creating a new HTTP request
* with this Agent instance.
*
* @api public
*/
Agent.prototype.addRequest = function (req, host, port, localAddress) {
var opts;
if ('object' == typeof host) {
// >= v0.11.x API
opts = host;
} else {
// <= v0.10.x API
opts = {
host: host,
port: port,
localAddress: localAddress
};
}
// hint to use "Connection: close"
req.shouldKeepAlive = false;
// create the `net.Socket` instance
var info = {
host: opts.hostname || opts.host,
port: +opts.port || this.defaultPort,
localAddress: opts.localAddress
};
this.createConnection(info, function (err, socket) {
if (err) {
req.emit('error', err);
} else {
req.onSocket(socket);
}
});
};
/**
* Creates and returns a `net.Socket` instance to use for an HTTP request.
*
* @api public
*/
Agent.prototype.createConnection = function (opts, fn) {
var socket = net.connect(opts);
fn(null, socket);
return socket;
};
/**
* Module dependencies.
*/
var net = require('net');
var tls = require('tls');
var url = require('url');
var Agent = require('./agent');
var inherits = require('util').inherits;
/**
* 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);
Agent.call(this);
this.proxy = opts;
this.secure = this.proxy.protocol && this.proxy.protocol == 'https:';
}
inherits(HttpProxyAgent, Agent);
/**
* Called when the node-core HTTP client library is creating a new HTTP request.
*
* @api public
*/
HttpProxyAgent.prototype.addRequest = function (req, host, port, localAddress) {
var opts;
if ('object' == typeof host) {
// >= v0.11.x API
opts = host;
} else {
// <= v0.10.x API
opts = {
host: host,
port: port,
localAddress: localAddress
};
}
// change the `http.ClientRequest` instance's "path" field
// to the absolute path of the URL that will be requested
var absolute = url.format({
protocol: 'http:',
hostname: opts.hostname || opts.host,
port: opts.port,
pathname: req.path
});
req.path = absolute;
Agent.prototype.addRequest.apply(this, arguments);
};
/**
* Initiates a TCP connection to the specified HTTP proxy server.
*
* @api public
*/
HttpProxyAgent.prototype.createConnection = function (opts, fn) {
var socket;
var info = {
host: this.proxy.hostname || this.proxy.host,
port: +this.proxy.port || (this.secure ? 443 : 80)
};
if (this.secure) {
socket = tls.connect(info);
} else {
socket = net.connect(info);
}
fn(null, socket);
return socket;
};
/**
* Module dependencies.
*/
var net = require('net');
var tls = require('tls');
var url = require('url');
var Agent = require('./agent');
var inherits = require('util').inherits;
/**
* Module exports.
*/
module.exports = HttpsProxyAgent;
/**
* The `HttpsProxyAgent` implements an HTTP Agent subclass that connects to the
* specified "HTTP(s) proxy server" in order to proxy HTTPS requests.
*
* @api public
*/
function HttpsProxyAgent (opts) {
if (!(this instanceof HttpsProxyAgent)) return new HttpsProxyAgent(opts);
if ('string' == typeof opts) opts = url.parse(opts);
Agent.call(this);
this.proxy = opts;
this.secure = this.proxy.protocol && this.proxy.protocol == 'https:';
}
inherits(HttpsProxyAgent, Agent);
/**
* Default port to connect to.
*/
Agent.prototype.defaultPort = 443;
/**
* Initiates a TCP connection to the specified HTTP proxy server.
*
* @api public
*/
HttpsProxyAgent.prototype.createConnection = function (opts, fn) {
var socket;
var info = {
host: this.proxy.hostname || this.proxy.host,
port: +this.proxy.port || (this.secure ? 443 : 80)
};
if (this.secure) {
socket = tls.connect(info);
} else {
socket = net.connect(info);
}
var msg = 'CONNECT ' + opts.host + ':' + opts.port + ' HTTP/1.1\r\n' +
'Host: ' + opts.host + ':' + opts.port + '\r\n' +
'\r\n';
socket.write(msg);
socket.ondata = function (b, offset, length) {
var buf = b.slice(offset, length);
// TODO: verify that the socket is properly connected, check response...
socket.ondata = null;
// since the proxy is connecting to an SSL server, we have
// to upgrade this socket connection to an SSL connection
socket = tls.connect({
socket: socket,
servername: opts.host
});
fn(null, socket);
};
};
/**
* Usage example of the `Agent` base class.
*/
var url = require('url');
var http = require('http');
var Agent = require('./agent');
var endpoint = process.argv[2] || 'http://nodejs.org/api/';
var opts = url.parse(endpoint);
opts.agent = new Agent();
var req = http.get(opts, function (res) {
console.log('"response" event!', res.headers);
res.pipe(process.stdout);
});
/**
* Usage example of the `HttpProxyAgent` class proxying an HTTP endpoint.
*/
var url = require('url');
var http = require('http');
var HttpProxyAgent = require('./http-proxy-agent');
// HTTP proxy to connect to
var proxy = process.env.http_proxy || 'http://168.63.76.32:3128';
console.log('using proxy server %j', proxy);
proxy = url.parse(proxy);
// HTTP endpoint for the proxy to connect to
var endpoint = process.argv[2] || 'http://nodejs.org/api/';
console.log('attempting to GET %j', endpoint);
var opts = url.parse(endpoint);
// create an instance of the `HttpProxyAgent` class with the proxy server information
var agent = new HttpProxyAgent(proxy);
opts.agent = agent;
http.get(opts, function (res) {
console.log('"response" event!', res.headers);
res.pipe(process.stdout);
});
/**
* Usage example of the `HttpsProxyAgent` class proxying an
* HTTPS (SSL) endpoint over an HTTP(s) proxy.
*/
var url = require('url');
var https = require('https');
var HttpsProxyAgent = require('./https-proxy-agent');
// HTTP proxy to connect to
var proxy = process.env.http_proxy || 'http://168.63.76.32:3128';
console.log('using proxy server %j', proxy);
proxy = url.parse(proxy);
// HTTPS endpoint for the proxy to connect to
var endpoint = process.argv[2] || 'https://gist.github.com/TooTallNate/5952254/raw/07972db49b5b70a212c39dfee56ed3ab82f8179c/agent.js';
console.log('attempting to GET %j', endpoint);
var opts = url.parse(endpoint);
// create an instance of the `HttpsProxyAgent` class with the proxy server information
opts.agent = new HttpsProxyAgent(proxy);
https.get(opts, function (res) {
console.log('"response" event!', res.headers);
res.pipe(process.stdout);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment