Socket
Socket
Sign inDemoInstall

http-proxy

Package Overview
Dependencies
Maintainers
3
Versions
85
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

http-proxy - npm Package Compare versions

Comparing version 0.6.1 to 0.7.0

examples/helpers/store.js

18

examples/package.json
{
"name": "http-proxy-examples"
, "description": "packages required to run the examples"
, "version": "0.0.0"
, "dependencies": {
"connect": "1.6"
, "connect-gzip": "0.1"
, "connect-jsonp": "0.0.5"
, "connect-restreamer": "1"
, "proxy-by-url": "0.0.0"
"name": "http-proxy-examples",
"description": "packages required to run the examples",
"version": "0.0.0",
"dependencies": {
"connect": "1.6",
"connect-gzip": "0.1",
"connect-jsonp": "0.0.5",
"connect-restreamer": "1",
"proxy-by-url": ">= 0.0.1"
}
}

@@ -31,141 +31,17 @@ /*

events = require('events'),
ProxyTable = require('./proxy-table').ProxyTable,
maxSockets = 100;
//
// ### Version 0.5.7 // 5/19/2011
// Expose version information through `pkginfo`.
//
exports.version = [0, 5, 7];
require('pkginfo')(module, 'version');
//
// Track our own list of agents internal to `node-http-proxy`
// ### Export the relevant objects exposed by `node-http-proxy`
//
var _agents = {};
var HttpProxy = exports.HttpProxy = require('./node-http-proxy/http-proxy').HttpProxy,
ProxyTable = exports.ProxyTable = require('./node-http-proxy/proxy-table').ProxyTable,
RoutingProxy = exports.RoutingProxy = require('./node-http-proxy/routing-proxy').RoutingProxy;
//
// ### function _getAgent (host, port, secure)
// #### @host {string} Host of the agent to get
// #### @port {number} Port of the agent to get
// #### @secure {boolean} Value indicating whether or not to use HTTPS
// Retreives an agent from the `http` or `https` module
// and sets the `maxSockets` property appropriately.
//
function _getAgent (host, port, secure) {
var Agent, id = [host, port].join(':');
if (!port) {
port = secure ? 443 : 80;
}
if (!_agents[id]) {
Agent = secure ? https.Agent : http.Agent;
_agents[id] = new Agent({
host: host,
port: port
});
_agents[id].maxSockets = maxSockets;
}
return _agents[id];
}
//
// ### function _getProtocol (secure, outgoing)
// #### @secure {Object|boolean} Settings for `https`
// #### @outgoing {Object} Outgoing request options
// Returns the appropriate protocol based on the settings in
// `secure`. If the protocol is `https` this function will update
// the options in `outgoing` as appropriate by adding `ca`, `key`,
// and `cert` if they exist in `secure`.
//
function _getProtocol (secure, outgoing) {
var protocol = secure ? https : http;
if (typeof secure === 'object') {
outgoing = outgoing || {};
['ca', 'cert', 'key'].forEach(function (prop) {
if (secure[prop]) {
outgoing[prop] = secure[prop];
}
})
}
return protocol;
}
//
// ### function getMaxSockets ()
// Returns the maximum number of sockets
// allowed on __every__ outgoing request
// made by __all__ instances of `HttpProxy`
//
exports.getMaxSockets = function () {
return maxSockets;
};
//
// ### function setMaxSockets ()
// Sets the maximum number of sockets
// allowed on __every__ outgoing request
// made by __all__ instances of `HttpProxy`
//
exports.setMaxSockets = function (value) {
maxSockets = value;
};
//
// stack
// adapted from https://github.com/creationix/stack
//
function stack (middlewares, proxy) {
var handle;
middlewares.reverse().forEach(function (layer) {
var child = handle;
var next = function (err) {
if (err) {
throw err;
//return error(req, res, err);
}
child(req, res);
}
next.__proto__ = proxy;
handle = function (req, res) {
layer(req, res, next);
};
});
return handle;
}
//
// stack
// adapted from https://github.com/creationix/stack
//
function stack (middlewares, proxy) {
var handle;
middlewares.reverse().forEach(function (layer) {
var child = handle;
handle = function (req, res) {
var next = function (err) {
if (err) {
throw err;
//
// TODO: figure out where to send errors.
// return error(req, res, err);
//
}
child(req, res);
}
next.__proto__ = proxy;
layer(req, res, next);
};
});
return handle;
}
//
// ### function createServer ([port, host, options, handler])

@@ -184,67 +60,119 @@ // #### @port {number} **Optional** Port to use on the proxy target host.

var args = Array.prototype.slice.call(arguments),
callback, forward,
port, host,
proxy, server,
handlers = [],
options = {},
middleware = [],
silent;
message,
handler,
server,
proxy,
host,
port;
//
// Liberally parse arguments of the form:
//
// httpProxy.createServer('localhost', 9000, callback);
// httpProxy.createServer({ host: 'localhost', port: 9000 }, callback);
// **NEED MORE HERE!!!**
//
args.forEach(function (arg) {
switch (typeof arg) {
case 'string': host = arg; break;
case 'number': port = arg; break;
case 'function': middleware.push(handler = callback = arg); break;
case 'object': options = arg; break;
case 'string': host = arg; break;
case 'number': port = arg; break;
case 'object': options = arg || {}; break;
case 'function': handlers.push(arg); break;
};
});
var proxy = new HttpProxy(options);
if (port && host) {
//
// Helper function to create intelligent error message(s)
// for the very liberal arguments parsing performed by
// `require('http-proxy').createServer()`.
//
function validArguments() {
var conditions = {
'port and host': function () {
return port && host;
},
'options.target or options.router': function () {
return options && (options.router ||
(options.target && options.target.host && options.target.port));
},
'or proxy handlers': function () {
return handlers && handlers.length;
}
}
var missing = Object.keys(conditions).filter(function (name) {
return !conditions[name]();
});
if (missing.length === 3) {
message = 'Cannot proxy without ' + missing.join(', ');
return false;
}
return true;
}
if (!validArguments()) {
//
// If we have a target host and port for the request
// then proxy to the specified location.
// If `host`, `port` and `options` are all not passed (with valid
// options) then this server is improperly configured.
//
handler = function (req, res) {
proxy.proxyRequest(req, res, {
port: port,
host: host
});
}
throw new Error(message);
return;
}
if (middleware.length) {
middleware.push(handler);
}
}
else if (proxy.proxyTable) {
//
// Hoist up any explicit `host` or `port` arguments
// that have been passed in to the options we will
// pass to the `httpProxy.HttpProxy` constructor.
//
options.target = options.target || {};
options.target.port = options.target.port || port;
options.target.host = options.target.host || host;
if (options.target && options.target.host && options.target.port) {
//
// If the proxy is configured with a ProxyTable
// instance then use that before failing.
// If an explicit `host` and `port` combination has been passed
// to `.createServer()` then instantiate a hot-path optimized
// `HttpProxy` object and add the "proxy" middleware layer.
//
handler = function (req, res) {
proxy = new HttpProxy(options);
handlers.push(function (req, res) {
proxy.proxyRequest(req, res);
}
if (middleware.length) {
middleware.push(handler);
}
});
}
if (middleware.length > 1) {
handler = callback = stack(middleware, proxy);
}
else if (middleware.length) {
//do not use middleware code if it's not needed.
var h = middleware[0];
handler = callback = function (req,res) { h(req,res,proxy) };
}
if (!handler) {
else {
//
// Otherwise this server is improperly configured.
// If no explicit `host` or `port` combination has been passed then
// we have to assume that this is a "go-anywhere" Proxy (i.e. a `RoutingProxy`).
//
throw new Error('Cannot proxy without port, host, or router.')
proxy = new RoutingProxy(options);
if (options.router) {
//
// If a routing table has been supplied than we assume
// the user intends us to add the "proxy" middleware layer
// for them
//
handlers.push(function (req, res) {
proxy.proxyRequest(req, res);
});
proxy.on('routes', function (routes) {
server.emit('routes', routes);
});
}
}
server = options.https
//
// Create the `http[s].Server` instance which will use
// an instance of `httpProxy.HttpProxy`.
//
handler = handlers.length > 1
? exports.stack(handlers, proxy)
: function (req, res) { handlers[0](req, res, proxy) };
server = options.https
? https.createServer(options.https, handler)

@@ -257,15 +185,10 @@ : http.createServer(handler);

proxy.on('routes', function (routes) {
server.emit('routes', routes);
});
if (!callback) {
// WebSocket support: if callback is empty tunnel
// websocket request automatically
if (handlers.length <= 1) {
//
// If an explicit callback has not been supplied then
// automagically proxy the request using the `HttpProxy`
// instance we have created.
//
server.on('upgrade', function (req, socket, head) {
// Tunnel websocket requests too
proxy.proxyWebSocketRequest(req, socket, head, {
port: port,
host: host
});
proxy.proxyWebSocketRequest(req, socket, head);
});

@@ -279,3 +202,2 @@ }

server.proxy = proxy;
return server;

@@ -285,55 +207,2 @@ };

//
// ### function HttpProxy (options)
// #### @options {Object} Options for this instance.
// Constructor function for new instances of HttpProxy responsible
// for managing the life-cycle of streaming reverse proxyied HTTP requests.
//
// Example options:
//
// {
// router: {
// 'foo.com': 'localhost:8080',
// 'bar.com': 'localhost:8081'
// },
// forward: {
// host: 'localhost',
// port: 9001
// }
// }
//
var HttpProxy = exports.HttpProxy = function (options) {
events.EventEmitter.call(this);
var self = this;
options = options || {};
//
// Setup basic proxying options
//
this.https = options.https;
this.forward = options.forward;
this.target = options.target || {};
//
// Setup additional options for WebSocket proxying. When forcing
// the WebSocket handshake to change the `sec-websocket-location`
// and `sec-websocket-origin` headers `options.source` **MUST**
// be provided or the operation will fail with an `origin mismatch`
// by definition.
//
this.source = options.source || { host: 'localhost', port: 8000 };
this.changeOrigin = options.changeOrigin || false;
if (options.router) {
this.proxyTable = new ProxyTable(options.router, options.silent, options.hostnameOnly);
this.proxyTable.on('routes', function (routes) {
self.emit('routes', routes);
});
}
};
// Inherit from events.EventEmitter
util.inherits(HttpProxy, events.EventEmitter);
//
// ### function buffer (obj)

@@ -355,7 +224,9 @@ // #### @obj {Object} Object to pause events from

// However, this is not a big leap from the implementation in node-http-proxy < 0.4.0.
// This simply chooses to manage the scope of the events on a new Object literal as opposed to
// This simply chooses to manage the scope of the events on a new Object literal as opposed to
// [on the HttpProxy instance](https://github.com/nodejitsu/node-http-proxy/blob/v0.3.1/lib/node-http-proxy.js#L154).
//
HttpProxy.prototype.buffer = function (obj) {
var onData, onEnd, events = [];
exports.buffer = function (obj) {
var events = [],
onData,
onEnd;

@@ -375,2 +246,10 @@ obj.on('data', onData = function (data, encoding) {

},
destroy: function () {
this.end();
this.resume = function () {
console.error("Cannot resume buffer after destroying it.");
};
onData = onEnd = events = obj = null;
},
resume: function () {

@@ -386,557 +265,138 @@ this.end();

//
// ### function close ()
// Frees the resources associated with this instance,
// if they exist.
// ### function getMaxSockets ()
// Returns the maximum number of sockets
// allowed on __every__ outgoing request
// made by __all__ instances of `HttpProxy`
//
HttpProxy.prototype.close = function () {
if (this.proxyTable) {
this.proxyTable.close();
}
exports.getMaxSockets = function () {
return maxSockets;
};
//
// ### function proxyRequest (req, res, [port, host, paused])
// #### @req {ServerRequest} Incoming HTTP Request to proxy.
// #### @res {ServerResponse} Outgoing HTTP Request to write proxied data to.
// #### @options {Object} Options for the outgoing proxy request.
// ### function setMaxSockets ()
// Sets the maximum number of sockets
// allowed on __every__ outgoing request
// made by __all__ instances of `HttpProxy`
//
// options.port {number} Port to use on the proxy target host.
// options.host {string} Host of the proxy target.
// options.buffer {Object} Result from `httpProxy.buffer(req)`
// options.https {Object|boolean} Settings for https.
// options.enableXForwarded {boolean} Don't clobber x-forwarded headers to allow layered proxies.
exports.setMaxSockets = function (value) {
maxSockets = value;
};
//
HttpProxy.prototype.proxyRequest = function (req, res, options) {
var self = this, errState = false, location, outgoing, protocol, reverseProxy;
// ### function stack (middlewares, proxy)
// #### @middlewares {Array} Array of functions to stack.
// #### @proxy {HttpProxy|RoutingProxy} Proxy instance to
// Iteratively build up a single handler to the `http.Server`
// `request` event (i.e. `function (req, res)`) by wrapping
// each middleware `layer` into a `child` middleware which
// is in invoked by the parent (i.e. predecessor in the Array).
//
// adapted from https://github.com/creationix/stack
//
exports.stack = function stack (middlewares, proxy) {
var handle;
middlewares.reverse().forEach(function (layer) {
var child = handle;
handle = function (req, res) {
var next = function (err) {
if (err) {
if (res._headerSent) {
res.destroy();
}
else {
res.statusCode = 500;
res.setHeader('Content-Type', 'text/plain');
res.end('Internal Server Error');
}
console.error('Error in middleware(s): %s', err.stack);
return;
}
if (child) {
child(req, res);
}
};
//
// Create an empty options hash if none is passed.
// If default options have been passed to the constructor
// of this instance, use them by default.
//
options = options || {};
options.host = options.host || this.target.host;
options.port = options.port || this.target.port;
options.enableXForwarded =
(undefined === options.enableXForwarded ? true : options.enableXForwarded);
//
// Check the proxy table for this instance to see if we need
// to get the proxy location for the request supplied. We will
// always ignore the proxyTable if an explicit `port` and `host`
// arguments are supplied to `proxyRequest`.
//
if (this.proxyTable && !options.host) {
location = this.proxyTable.getProxyLocation(req);
//
// If no location is returned from the ProxyTable instance
// then respond with `404` since we do not have a valid proxy target.
//
if (!location) {
res.writeHead(404);
return res.end();
}
//
// When using the ProxyTable in conjunction with an HttpProxy instance
// only the following arguments are valid:
//
// * `proxy.proxyRequest(req, res, { host: 'localhost' })`: This will be skipped
// * `proxy.proxyRequest(req, res, { buffer: buffer })`: Buffer will get updated appropriately
// * `proxy.proxyRequest(req, res)`: Options will be assigned appropriately.
//
options.port = location.port;
options.host = location.host;
}
//
// Add common proxy headers to the request so that they can
// be availible to the proxy target server:
//
// * `x-forwarded-for`: IP Address of the original request
// * `x-forwarded-proto`: Protocol of the original request
// * `x-forwarded-port`: Port of the original request.
//
if (options.enableXForwarded === true) {
req.headers['x-forwarded-for'] = req.connection.remoteAddress || req.connection.socket.remoteAddress;
req.headers['x-forwarded-port'] = req.connection.remotePort || req.connection.socket.remotePort;
req.headers['x-forwarded-proto'] = res.connection.pair ? 'https' : 'http';
}
//
// Emit the `start` event indicating that we have begun the proxy operation.
//
this.emit('start', req, res, options);
//
// If forwarding is enabled for this instance, foward proxy the
// specified request to the address provided in `this.forward`
//
if (this.forward) {
this.emit('forward', req, res, this.forward);
this._forwardRequest(req);
}
//
// #### function proxyError (err)
// #### @err {Error} Error contacting the proxy target
// Short-circuits `res` in the event of any error when
// contacting the proxy target at `host` / `port`.
//
function proxyError(err) {
errState = true;
//
// Emit an `error` event, allowing the application to use custom
// error handling. The error handler should end the response.
//
if (self.emit('proxyError', err, req, res)) {
return;
}
res.writeHead(500, { 'Content-Type': 'text/plain' });
if (req.method !== 'HEAD') {
//
// This NODE_ENV=production behavior is mimics Express and
// Connect.
// Set the prototype of the `next` function to the instance
// of the `proxy` so that in can be used interchangably from
// a `connect` style callback and a true `HttpProxy` object.
//
if (process.env.NODE_ENV === 'production') {
res.write('Internal Server Error');
}
else {
res.write('An error has occurred: ' + JSON.stringify(err));
}
}
res.end();
}
outgoing = {
host: options.host,
port: options.port,
agent: _getAgent(options.host, options.port, options.https || this.target.https),
method: req.method,
path: req.url,
headers: req.headers
};
protocol = _getProtocol(options.https || this.target.https, outgoing);
// Open new HTTP request to internal resource with will act as a reverse proxy pass
reverseProxy = protocol.request(outgoing, function (response) {
// Process the `reverseProxy` `response` when it's received.
if (response.headers.connection) {
if (req.headers.connection) response.headers.connection = req.headers.connection;
else response.headers.connection = 'close';
}
// Set the headers of the client response
res.writeHead(response.statusCode, response.headers);
// `response.statusCode === 304`: No 'data' event and no 'end'
if (response.statusCode === 304) {
return res.end();
}
// For each data `chunk` received from the `reverseProxy`
// `response` write it to the outgoing `res`.
response.on('data', function (chunk) {
if (req.method !== 'HEAD') {
res.write(chunk);
}
});
// When the `reverseProxy` `response` ends, end the
// corresponding outgoing `res` unless we have entered
// an error state. In which case, assume `res.end()` has
// already been called and the 'error' event listener
// removed.
response.on('end', function () {
if (!errState) {
reverseProxy.removeListener('error', proxyError);
res.end();
// Emit the `end` event now that we have completed proxying
self.emit('end', req, res);
}
});
// e.g. `function (req, res, next)` vs. `function (req, res, proxy)`
//
next.__proto__ = proxy;
layer(req, res, next);
};
});
// Handle 'error' events from the `reverseProxy`.
reverseProxy.once('error', proxyError);
// For each data `chunk` received from the incoming
// `req` write it to the `reverseProxy` request.
req.on('data', function (chunk) {
if (!errState) {
reverseProxy.write(chunk);
}
});
//
// When the incoming `req` ends, end the corresponding `reverseProxy`
// request unless we have entered an error state.
//
req.on('end', function () {
if (!errState) {
reverseProxy.end();
}
});
// If we have been passed buffered data, resume it.
if (options.buffer && !errState) {
options.buffer.resume();
}
return handle;
};
//
// ### @private function _forwardRequest (req)
// #### @req {ServerRequest} Incoming HTTP Request to proxy.
// Forwards the specified `req` to the location specified
// by `this.forward` ignoring errors and the subsequent response.
// ### function _getAgent (host, port, secure)
// #### @options {Object} Options to use when creating the agent.
//
HttpProxy.prototype._forwardRequest = function (req) {
var self = this, port, host, outgoing, protocol, forwardProxy;
port = this.forward.port;
host = this.forward.host;
outgoing = {
host: host,
port: port,
agent: _getAgent(host, port, this.forward.https),
method: req.method,
path: req.url,
headers: req.headers
};
// Force the `connection` header to be 'close' until
// node.js core re-implements 'keep-alive'.
outgoing.headers['connection'] = 'close';
protocol = _getProtocol(this.forward.https, outgoing);
// Open new HTTP request to internal resource with will act as a reverse proxy pass
forwardProxy = protocol.request(outgoing, function (response) {
//
// Ignore the response from the forward proxy since this is a 'fire-and-forget' proxy.
// Remark (indexzero): We will eventually emit a 'forward' event here for performance tuning.
//
});
// Add a listener for the connection timeout event.
//
// Remark: Ignoring this error in the event
// forward target doesn't exist.
//
forwardProxy.once('error', function (err) { });
// Chunk the client request body as chunks from the proxied request come in
req.on('data', function (chunk) {
forwardProxy.write(chunk);
})
// At the end of the client request, we are going to stop the proxied request
req.on('end', function () {
forwardProxy.end();
});
};
// {
// host: 'localhost',
// port: 9000,
// https: true,
// maxSockets: 100
// }
//
// ### function proxyWebSocketRequest (req, socket, head, options)
// #### @req {ServerRequest} Websocket request to proxy.
// #### @socket {net.Socket} Socket for the underlying HTTP request
// #### @head {string} Headers for the Websocket request.
// #### @options {Object} Options to use when proxying this request.
// Createsan agent from the `http` or `https` module
// and sets the `maxSockets` property appropriately.
//
// options.port {number} Port to use on the proxy target host.
// options.host {string} Host of the proxy target.
// options.buffer {Object} Result from `httpProxy.buffer(req)`
// options.https {Object|boolean} Settings for https.
//
HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options) {
var self = this,
listeners = {},
errState = false,
CRLF = '\r\n',
outgoing;
options = options || {};
options.host = options.host || this.target.host;
options.port = options.port || this.target.port;
if (this.proxyTable && !options.host) {
location = this.proxyTable.getProxyLocation(req);
if (!location) {
return socket.destroy();
}
options.port = location.port;
options.host = location.host;
exports._getAgent = function _getAgent (options) {
if (!options || !options.host) {
throw new Error('`options.host` is required to create an Agent.');
}
//
// WebSocket requests must have the `GET` method and
// the `upgrade:websocket` header
//
if (req.method !== 'GET' || req.headers.upgrade.toLowerCase() !== 'websocket') {
//
// This request is not WebSocket request
//
return;
if (!options.port) {
options.port = options.https ? 443 : 80;
}
//
// Helper function for setting appropriate socket values:
// 1. Turn of all bufferings
// 2. For server set KeepAlive
// 3. For client set encoding
//
function _socket(socket, keepAlive) {
socket.setTimeout(0);
socket.setNoDelay(true);
if (keepAlive) {
if (socket.setKeepAlive) {
socket.setKeepAlive(true, 0);
}
else if (socket.pair.cleartext.socket.setKeepAlive) {
socket.pair.cleartext.socket.setKeepAlive(true, 0);
}
}
else {
socket.setEncoding('utf8');
}
}
var Agent = options.https ? https.Agent : http.Agent,
agent;
//
// On `upgrade` from the Agent socket, listen to
// the appropriate events.
//
function onUpgrade (reverseProxy, proxySocket) {
if (!reverseProxy) {
proxySocket.end();
socket.end();
return;
}
agent = new Agent({
host: options.host,
port: options.port
});
//
// Any incoming data on this WebSocket to the proxy target
// will be written to the `reverseProxy` socket.
//
proxySocket.on('data', listeners.onIncoming = function (data) {
if (reverseProxy.incoming.socket.writable) {
try {
self.emit('websocket:outgoing', req, socket, head, data);
reverseProxy.incoming.socket.write(data);
}
catch (e) {
reverseProxy.incoming.socket.end();
proxySocket.end();
}
}
});
agent.maxSockets = options.maxSockets || maxSockets;
//
// Any outgoing data on this Websocket from the proxy target
// will be written to the `proxySocket` socket.
//
reverseProxy.incoming.socket.on('data', listeners.onOutgoing = function(data) {
try {
self.emit('websocket:incoming', reverseProxy, reverseProxy.incoming, head, data);
proxySocket.write(data);
}
catch (e) {
proxySocket.end();
socket.end();
}
});
return agent;
}
//
// Helper function to detach all event listeners
// from `reverseProxy` and `proxySocket`.
//
function detach() {
proxySocket.removeListener('end', listeners.onIncomingClose);
proxySocket.removeListener('data', listeners.onIncoming);
reverseProxy.incoming.socket.removeListener('end', listeners.onOutgoingClose);
reverseProxy.incoming.socket.removeListener('data', listeners.onOutgoing);
}
//
// ### function _getProtocol (options)
// #### @options {Object} Options for the proxy target.
// Returns the appropriate node.js core protocol module (i.e. `http` or `https`)
// based on the `options` supplied.
//
exports._getProtocol = function _getProtocol (options) {
return options.https ? https : http;
};
//
// If the incoming `proxySocket` socket closes, then
// detach all event listeners.
//
proxySocket.on('end', listeners.onIncomingClose = function() {
reverseProxy.incoming.socket.end();
detach();
// Emit the `end` event now that we have completed proxying
self.emit('websocket:end', req, socket, head);
});
//
// If the `reverseProxy` socket closes, then detach all
// event listeners.
//
reverseProxy.incoming.socket.on('end', listeners.onOutgoingClose = function() {
proxySocket.end();
detach();
});
};
// Setup the incoming client socket.
_socket(socket);
function getPort (port) {
port = port || 80;
return port - 80 === 0 ? '' : ':' + port
}
//
// Get the protocol, and host for this request and create an instance
// of `http.Agent` or `https.Agent` from the pool managed by `node-http-proxy`.
//
var protocolName = options.https || this.target.https ? 'https' : 'http',
portUri = getPort(this.source.port),
remoteHost = options.host + portUri,
agent = _getAgent(options.host, options.port, options.https || this.target.https);
// Change headers (if requested).
if (this.changeOrigin) {
req.headers.host = remoteHost;
req.headers.origin = protocolName + '://' + remoteHost;
}
//
// Make the outgoing WebSocket request
//
outgoing = {
host: options.host,
port: options.port,
method: 'GET',
path: req.url,
headers: req.headers,
};
//
// ### function _getBase (options)
// #### @options {Object} Options for the proxy target.
// Returns the relevate base object to create on outgoing proxy request.
// If `options.https` are supplied, this function respond with an object
// containing the relevant `ca`, `key`, and `cert` properties.
//
exports._getBase = function _getBase (options) {
var result = function () {};
var reverseProxy = agent.appendMessage(outgoing);
//
// On any errors from the `reverseProxy` emit the
// `webSocketProxyError` and close the appropriate
// connections.
//
function proxyError (err) {
reverseProxy.end();
if (self.emit('webSocketProxyError', req, socket, head)) {
return;
}
socket.end();
}
//
// Here we set the incoming `req`, `socket` and `head` data to the outgoing
// request so that we can reuse this data later on in the closure scope
// available to the `upgrade` event. This bookkeeping is not tracked anywhere
// in nodejs core and is **very** specific to proxying WebSockets.
//
reverseProxy.agent = agent;
reverseProxy.incoming = {
request: req,
socket: socket,
head: head
};
//
// If the agent for this particular `host` and `port` combination
// is not already listening for the `upgrade` event, then do so once.
// This will force us not to disconnect.
//
// In addition, it's important to note the closure scope here. Since
// there is no mapping of the
//
if (!agent._events || agent._events['upgrade'].length === 0) {
agent.on('upgrade', function (_, remoteSocket, head) {
//
// Prepare the socket for the reverseProxy request and begin to
// stream data between the two sockets. Here it is important to
// note that `remoteSocket._httpMessage === reverseProxy`.
//
_socket(remoteSocket, true);
onUpgrade(remoteSocket._httpMessage, remoteSocket);
});
}
//
// If the reverseProxy connection has an underlying socket,
// then execute the WebSocket handshake.
//
if (typeof reverseProxy.socket !== 'undefined') {
reverseProxy.socket.on('data', function handshake (data) {
//
// Ok, kind of harmfull part of code. Socket.IO sends a hash
// at the end of handshake if protocol === 76, but we need
// to replace 'host' and 'origin' in response so we split
// data to printable data and to non-printable. (Non-printable
// will come after double-CRLF).
//
var sdata = data.toString();
// Get the Printable data
sdata = sdata.substr(0, sdata.search(CRLF + CRLF));
// Get the Non-Printable data
data = data.slice(Buffer.byteLength(sdata), data.length);
if (self.https && !self.target.https) {
//
// If the proxy server is running HTTPS but the client is running
// HTTP then replace `ws` with `wss` in the data sent back to the client.
//
sdata = sdata.replace('ws:', 'wss:');
if (options.https && typeof options.https === 'object') {
['ca', 'cert', 'key'].forEach(function (key) {
if (options.https[key]) {
result.prototype[key] = options.https[key];
}
try {
//
// Write the printable and non-printable data to the socket
// from the original incoming request.
//
self.emit('websocket:handshake', req, socket, head, sdata, data);
socket.write(sdata);
socket.write(data);
}
catch (ex) {
proxyError(ex)
}
// Catch socket errors
socket.on('error', proxyError);
// Remove data listener now that the 'handshake' is complete
reverseProxy.socket.removeListener('data', handshake);
});
}
reverseProxy.on('error', proxyError);
try {
//
// Attempt to write the upgrade-head to the reverseProxy request.
//
reverseProxy.write(head);
}
catch (ex) {
proxyError(ex);
}
//
// If we have been passed buffered data, resume it.
//
if (options.buffer && !errState) {
options.buffer.resume();
}
return result;
};
{
"name": "http-proxy",
"version": "0.7.0",
"description": "A full-featured http reverse proxy for node.js",
"version": "0.6.1",
"author": "Charlie Robbins <charlie.robbins@gmail.com>",

@@ -9,3 +9,4 @@ "contributors": [

{ "name": "Marak Squires", "email": "marak.squires@gmail.com" },
{ "name": "Fedor Indutny", "email": "fedor.indutny@gmail.com" }
{ "name": "Fedor Indutny", "email": "fedor.indutny@gmail.com" },
{ "name": "Dominic Tarr", "email": "dominic@nodejitsu.com" }
],

@@ -19,3 +20,4 @@ "repository": {

"colors": "0.x.x",
"optimist": "0.2.x"
"optimist": "0.2.x",
"pkginfo": "0.2.x"
},

@@ -29,4 +31,8 @@ "devDependencies": {

"bin": { "node-http-proxy": "./bin/node-http-proxy" },
"scripts": { "test": "vows test/*-test.js --spec && vows test/*-test.js --spec --https" },
"scripts": {
"test": "npm run-script test-http && npm run-script test-https",
"test-http": "vows --spec && vows --spec --target=secure",
"test-https": "vows --spec --source=secure && vows --spec --source=secure --target=secure"
},
"engines": { "node": "0.4.x || 0.5.x" }
}

@@ -1,2 +0,2 @@

# node-http-proxy - v0.5.9
# node-http-proxy

@@ -117,3 +117,3 @@ <img src="http://i.imgur.com/8fTt9.png" />

//
var buffer = proxy.buffer(req);
var buffer = httpProxy.buffer(req);

@@ -361,2 +361,9 @@ //

### Configuring your Socket limits
By default, `node-http-proxy` will set a 100 socket limit for all `host:port` proxy targets. If you wish to change this you can two it in two ways:
1. By passing the `maxSockets` option to `httpProxy.createServer()`
2. By calling `httpProxy.setMaxSockets(n)`, where `n` is the number of sockets you with to use.
## Using node-http-proxy from the command line

@@ -363,0 +370,0 @@ When you install this package with npm, a node-http-proxy binary will become available to you. Using this binary is easy with some simple options:

@@ -8,24 +8,13 @@ /*

var fs = require('fs'),
var assert = require('assert'),
fs = require('fs'),
http = require('http'),
https = require('https'),
path = require('path'),
argv = require('optimist').argv,
request = require('request'),
vows = require('vows'),
assert = require('assert'),
request = require('request'),
websocket = require('./../vendor/websocket'),
httpProxy = require('./../lib/node-http-proxy');
websocket = require('../vendor/websocket'),
httpProxy = require('../lib/node-http-proxy');
function merge (target) {
var objs = Array.prototype.slice.call(arguments, 1);
objs.forEach(function(o) {
Object.keys(o).forEach(function (attr) {
if (! o.__lookupGetter__(attr)) {
target[attr] = o[attr];
}
});
});
return target;
}
var loadHttps = exports.loadHttps = function () {

@@ -38,17 +27,31 @@ return {

var TestRunner = exports.TestRunner = function (protocol, target) {
this.options = {};
this.options.target = {};
this.protocol = protocol;
this.target = target;
this.testServers = [];
var parseProtocol = exports.parseProtocol = function () {
function setupProtocol (secure) {
return {
secure: secure,
protocols: {
http: secure ? 'https' : 'http',
ws: secure ? 'wss' : 'ws'
}
}
}
return {
source: setupProtocol(argv.source === 'secure'),
target: setupProtocol(argv.target === 'secure')
};
}
if (protocol === 'https') {
this.options.https = loadHttps();
var TestRunner = exports.TestRunner = function (options) {
options = options || {};
this.source = options.source || {};
this.target = options.target || {};
this.testServers = [];
if (this.source.secure) {
this.source.https = loadHttps();
}
if (target === 'https') {
this.options.target = {
https: loadHttps()
};
if (this.target.secure) {
this.target.https = loadHttps();
}

@@ -64,5 +67,8 @@ };

topic: function () {
var that = this, options = {
var that = this,
options;
options = {
method: 'GET',
uri: self.protocol + '://localhost:' + proxyPort,
uri: self.source.protocols.http + '://localhost:' + proxyPort,
headers: {

@@ -72,2 +78,3 @@ host: host

};

@@ -98,3 +105,3 @@ function startTest () {

var assertion = "should receive " + statusCode + " responseCode",
protocol = this.protocol;
protocol = this.source.protocols.http;

@@ -132,3 +139,2 @@ var test = {

//
TestRunner.prototype.webSocketTest = function (options) {

@@ -170,3 +176,2 @@ var self = this;

//
TestRunner.prototype.webSocketTestWithTable = function (options) {

@@ -182,5 +187,5 @@ var self = this;

self.startProxyServerWithTable(
options.ports.proxy,
{router: options.router},
self.startProxyServerWithTable(
options.ports.proxy,
{ router: options.router },
function (err, proxy) {

@@ -210,4 +215,3 @@ if (options.onServer) { options.onServer(proxy) }

var that = this,
options = that.options,
proxyServer = httpProxy.createServer(targetPort, host, options);
proxyServer = httpProxy.createServer(host, targetPort, this.getOptions());

@@ -224,14 +228,15 @@ proxyServer.listen(port, function () {

TestRunner.prototype.startLatentProxyServer = function (port, targetPort, host, latency, callback) {
//
// Initialize the nodeProxy and start proxying the request
var that = this, proxyServer = httpProxy.createServer(function (req, res, proxy) {
var buffer = proxy.buffer(req);
//
var that = this,
proxyServer;
proxyServer = httpProxy.createServer(host, targetPort, function (req, res, proxy) {
var buffer = httpProxy.buffer(req);
setTimeout(function () {
proxy.proxyRequest(req, res, {
port: targetPort,
host: host,
buffer: buffer
});
proxy.proxyRequest(req, res, buffer);
}, latency);
}, this.options);
}, this.getOptions());

@@ -248,3 +253,5 @@ proxyServer.listen(port, function () {

TestRunner.prototype.startProxyServerWithTable = function (port, options, callback) {
var that = this, proxyServer = httpProxy.createServer(merge({}, options, this.options));
var that = this,
proxyServer = httpProxy.createServer(merge({}, options, this.getOptions()));
proxyServer.listen(port, function () {

@@ -262,9 +269,11 @@ that.testServers.push(proxyServer);

TestRunner.prototype.startProxyServerWithTableAndLatency = function (port, latency, options, callback) {
//
// Initialize the nodeProxy and start proxying the request
var proxyServer,
that = this,
proxy = new httpProxy.HttpProxy(merge({}, options, that.options));
//
var that = this,
proxy = new httpProxy.RoutingProxy(merge({}, options, this.getOptions())),
proxyServer;
var handler = function (req, res) {
var buffer = proxy.buffer(req);
var buffer = httpProxy.buffer(req);
setTimeout(function () {

@@ -277,5 +286,5 @@ proxy.proxyRequest(req, res, {

proxyServer = that.options.https
? https.createServer(that.options.https, handler, that.options)
: http.createServer(handler, that.options);
proxyServer = this.source.https
? https.createServer(this.source.https, handler)
: http.createServer(handler);

@@ -294,3 +303,5 @@ proxyServer.listen(port, function () {

TestRunner.prototype.startProxyServerWithForwarding = function (port, targetPort, host, options, callback) {
var that = this, proxyServer = httpProxy.createServer(targetPort, host, merge({}, options, this.options));
var that = this,
proxyServer = httpProxy.createServer(targetPort, host, merge({}, options, this.getOptions()));
proxyServer.listen(port, function () {

@@ -306,3 +317,7 @@ that.testServers.push(proxyServer);

TestRunner.prototype.startTargetServer = function (port, output, callback) {
var that = this, targetServer, handler = function (req, res) {
var that = this,
targetServer,
handler;
handler = function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });

@@ -312,5 +327,5 @@ res.write(output);

};
targetServer = this.options.target.https
? https.createServer(this.options.target.https, handler)
targetServer = this.target.https
? https.createServer(this.target.https, handler)
: http.createServer(handler);

@@ -334,1 +349,40 @@

};
//
// Creates a new instance of the options to
// pass to `httpProxy.createServer()`
//
TestRunner.prototype.getOptions = function () {
return {
https: clone(this.source.https),
target: {
https: clone(this.target.https)
}
};
};
//
// ### @private function clone (object)
// #### @object {Object} Object to clone
// Shallow clones the specified object.
//
function clone (object) {
if (!object) { return null }
return Object.keys(object).reduce(function (obj, k) {
obj[k] = object[k];
return obj;
}, {});
}
function merge (target) {
var objs = Array.prototype.slice.call(arguments, 1);
objs.forEach(function(o) {
Object.keys(o).forEach(function (attr) {
if (! o.__lookupGetter__(attr)) {
target[attr] = o[attr];
}
});
});
return target;
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc