diff --git a/README.md b/README.md index ed35a67..89c7de2 100644 --- a/README.md +++ b/README.md @@ -47,11 +47,14 @@ See the [demo](http://github.com/nodejitsu/node-http-proxy/blob/master/demo.js)
var http = require('http'),
httpProxy = require('http-proxy');
-
+ //
// Create your proxy server
+ //
httpProxy.createServer(9000, 'localhost').listen(8000);
+ //
// Create your target server
+ //
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write('request successfully proxied!' + '\n' + JSON.stringify(req.headers, true, 2));
@@ -63,11 +66,15 @@ See the [demo](http://github.com/nodejitsu/node-http-proxy/blob/master/demo.js)
var http = require('http'),
httpProxy = require('http-proxy');
-
- // create a proxy server with custom application logic
+
+ //
+ // Create a proxy server with custom application logic
+ //
httpProxy.createServer(function (req, res, proxy) {
+ //
// Put your custom server logic here
- proxy.proxyRequest(9000, 'localhost');
+ //
+ proxy.proxyRequest(req, res, 9000, 'localhost');
}).listen(8000);
http.createServer(function (req, res) {
@@ -81,13 +88,23 @@ See the [demo](http://github.com/nodejitsu/node-http-proxy/blob/master/demo.js)
var http = require('http'),
httpProxy = require('http-proxy');
-
- // create a proxy server with custom application logic
+
+ //
+ // Create a proxy server with custom application logic
+ //
httpProxy.createServer(function (req, res, proxy) {
+ //
+ // Buffer the request so that `data` and `end` events
+ // are not lost during async operation(s).
+ //
+ var buffer = proxy.buffer(req);
+
+ //
// Wait for two seconds then respond: this simulates
// performing async actions before proxying a request
+ //
setTimeout(function () {
- proxy.proxyRequest(9000, 'localhost');
+ proxy.proxyRequest(req, res, 9000, 'localhost', buffer);
}, 2000);
}).listen(8000);
@@ -102,15 +119,20 @@ See the [demo](http://github.com/nodejitsu/node-http-proxy/blob/master/demo.js)
var http = require('http'),
httpProxy = require('http-proxy');
+
+ //
+ // Create a new instance of HttProxy to use in your server
+ //
+ var proxy = new httpProxy.HttpProxy();
- // create a regular http server and proxy its handler
+ //
+ // Create a regular http server and proxy its handler
+ //
http.createServer(function (req, res) {
- // Create a new instance of HttProxy for this request
- // each instance is only valid for serving one request
- var proxy = new httpProxy.HttpProxy(req, res);
-
+ //
// Put your custom server logic here, then proxy
- proxy.proxyRequest(9000, 'localhost', req, res);
+ //
+ proxy.proxyRequest(req, res, 9000, 'localhost');
}).listen(8001);
http.createServer(function (req, res) {
diff --git a/bin/node-http-proxy b/bin/node-http-proxy
index 29e5c34..ad2b24c 100755
--- a/bin/node-http-proxy
+++ b/bin/node-http-proxy
@@ -9,7 +9,7 @@ var path = require('path'),
var help = [
"usage: node-http-proxy [options] ",
"",
- "All options should be set with the syntax --option=value",
+ "Starts a node-http-proxy server using the specified command-line options",
"",
"options:",
" --port PORT Port that the proxy server should run on",
@@ -20,8 +20,7 @@ var help = [
].join('\n');
if (argv.h || argv.help || Object.keys(argv).length === 2) {
- util.puts(help);
- process.exit(0);
+ return util.puts(help);
}
var location, config = {},
diff --git a/demo.js b/demo.js
index 4e5fbb2..d3c17db 100644
--- a/demo.js
+++ b/demo.js
@@ -59,9 +59,9 @@ util.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue +
// Http Proxy Server with Latency
//
httpProxy.createServer(function (req, res, proxy) {
- var paused = proxy.pause(req);
+ var buffer = proxy.buffer(req);
setTimeout(function() {
- proxy.proxyRequest(req, res, 9000, 'localhost', paused);
+ proxy.proxyRequest(req, res, 9000, 'localhost', buffer);
}, 200)
}).listen(8002);
util.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8002 '.yellow + 'with latency'.magenta.underline);
@@ -82,9 +82,9 @@ util.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue +
//
var standAloneProxy = new httpProxy.HttpProxy();
http.createServer(function (req, res) {
- var paused = standAloneProxy.pause(req);
+ var buffer = standAloneProxy.buffer(req);
setTimeout(function() {
- proxy.proxyRequest(req, res, 9000, 'localhost', paused);
+ proxy.proxyRequest(req, res, 9000, 'localhost', buffer);
}, 200);
}).listen(8004);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '8004 '.yellow + 'with proxyRequest handler'.cyan.underline + ' and latency'.magenta);
diff --git a/docs/node-http-proxy.html b/docs/node-http-proxy.html
index dd9dd97..31f1af1 100644
--- a/docs/node-http-proxy.html
+++ b/docs/node-http-proxy.html
@@ -52,7 +52,23 @@ made by all instances of HttpProxy
allowed on every outgoing request
made by all instances of HttpProxy exports.setMaxSockets = function (value) {
maxSockets = value;
-};
function createServer ([port, host, options], handler)
exports.createServer = function () {
+};
function createServer ([port, host, options, handler])
+
+@port {number} Optional Port to use on the proxy target host.
+
+@host {string} Optional Host of the proxy target.
+
+@options {Object} Optional Options for the HttpProxy instance used
+
+@handler {function} Optional Request handler for the server
+
+Returns a server that manages an instance of HttpProxy. Flexible arguments allow for:
+
+
+httpProxy.createServer(9000, 'localhost')
+- `httpProxy.createServer(9000, 'localhost', options)
+httpPRoxy.createServer(function (req, res, proxy) { ... })
+
exports.createServer = function () {
var args, callback, port, host, forward,
silent, options, proxy, server;
@@ -137,7 +153,7 @@ for managing the life-cycle of streaming reverse proxyied HTTP requests.
self.emit('routes', routes);
});
}
-};
Inherit from events.EventEmitter
util.inherits(HttpProxy, events.EventEmitter);
function pause (obj)
+}; Inherit from events.EventEmitter
util.inherits(HttpProxy, events.EventEmitter);
function buffer (obj)
@obj {Object} Object to pause events from
@@ -147,9 +163,9 @@ Consumers of HttpProxy performing async tasks
the async operation has completed, otherwise these
events will be lost.
- var pause = httpProxy.pause(req);
+ var buffer = httpProxy.buffer(req);
fs.readFile(path, function(){
- httpProxy.proxyRequest(req, res, host, port, paused);
+ httpProxy.proxyRequest(req, res, host, port, buffer);
});
@@ -157,7 +173,7 @@ the async operation has completed, otherwise these
Connect.
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
-on the HttpProxy instance.
HttpProxy.prototype.pause = function (obj) {
+on the HttpProxy instance.
HttpProxy.prototype.buffer = function (obj) {
var onData, onEnd, events = [];
obj.on('data', onData = function (data, encoding) {
@@ -195,7 +211,7 @@ if they exist.
@host {string} Optional Host of the proxy target.
-@paused {Object} Optional Result from httpProxy.pause(req)
HttpProxy.prototype.proxyRequest = function (req, res, port, host, paused) {
+@buffer {Object} Optional Result from httpProxy.buffer(req)
HttpProxy.prototype.proxyRequest = function (req, res, port, host, buffer) {
var self = this, reverseProxy, location, errState = false;
Check the proxy table for this instance to see if we need
to get the proxy location for the request supplied. We will
@@ -211,10 +227,10 @@ then respond with 404 since we do not have a valid proxy target.
-proxy.proxyRequest(req, res, port, host, paused): This will be skipped
-proxy.proxyRequest(req, res, paused): Paused will get updated appropriately
+proxy.proxyRequest(req, res, port, host, buffer): This will be skipped
+proxy.proxyRequest(req, res, buffer): Buffer will get updated appropriately
proxy.proxyRequest(req, res): No effect undefined = undefined
-
paused = port;
+
buffer = port;
port = location.port;
host = location.host;
}
@@ -242,7 +258,7 @@ specified request to the address provided in this.options.forward
path: req.url,
headers: req.headers
}, function (response) {
-
Process the reverse_proxy response when it's received.
if (response.headers.connection) {
+
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 response headers of the client response
res.writeHead(response.statusCode, response.headers);
Status code = 304
@@ -268,48 +284,50 @@ No 'data' event and no 'end'
if (!errState) {
reverseProxy.end();
}
- });
-
- if (paused && !errState) {
- paused.resume();
+ }); If we have been passed buffered data, resume it.
if (buffer && !errState) {
+ buffer.resume();
}
};
-
-HttpProxy.prototype._forwardRequest = function (req) {
+
@private function _forwardRequest (req)
+
+@req {ServerRequest} Incoming HTTP Request to proxy.
+
+Forwards the specified req to the location specified
+by this.options.forward ignoring errors and the subsequent response.
HttpProxy.prototype._forwardRequest = function (req) {
var self = this, port, host, forwardProxy;
port = this.options.forward.port;
host = this.options.forward.host;
-
Open new HTTP request to internal resource with will act as a reverse proxy pass
forwardProxy = http.request({
+
Open new HTTP request to internal resource with will act as a reverse proxy pass
forwardProxy = http.request({
host: host,
port: port,
agent: _getAgent(host, port),
method: req.method,
path: req.url,
headers: req.headers
- }, function (response) {
Ignore the response from the forward proxy since this is a 'fire-and-forget' proxy.
+ }, 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.
+ Add a listener for the connection timeout event.
Remark: Ignoring this error in the event
- forward target doesn't exist.
forwardProxy.on('error', function (err) { });
Chunk the client request body as chunks from the proxied request come in
req.on('data', function (chunk) {
+ forward target doesn't exist.
forwardProxy.on('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 () {
+ })
At the end of the client request, we are going to stop the proxied request
req.on('end', function () {
forwardProxy.end();
});
};
HttpProxy.prototype.proxyWebSocketRequest = function (port, server, host, data) {
var self = this, req = self.req, socket = self.sock, head = self.head,
- headers = new _headers(req.headers), CRLF = '\r\n';
Will generate clone of headers
+ headers = new _headers(req.headers), CRLF = '\r\n';
Will generate clone of headers
To not change original
function _headers(headers) {
var h = {};
for (var i in headers) {
h[i] = headers[i];
}
return h;
- }
WebSocket requests has method = GET
if (req.method !== 'GET' || headers.upgrade.toLowerCase() !== 'websocket') {
This request is not WebSocket request
return;
- }
Turn of all bufferings
+ }
WebSocket requests has method = GET
if (req.method !== 'GET' || headers.upgrade.toLowerCase() !== 'websocket') {
This request is not WebSocket request
return;
+ }
Turn of all bufferings
For server set KeepAlive
For client set encoding
function _socket(socket, server) {
socket.setTimeout(0);
@@ -320,20 +338,20 @@ For client set encoding
else {
socket.setEncoding('utf8');
}
- } Client socket
_socket(socket);
If host is undefined
+ }
Client socket
_socket(socket);
If host is undefined
Get it from headers
if (!host) {
host = headers.Host;
}
-
Remote host address
var remote_host = server + (port - 80 === 0 ? '' : ':' + port);
Change headers
headers.Host = remote_host;
- headers.Origin = 'http://' + remote_host;
Open request
var p = manager.getPool(port, server);
+
Remote host address
var remote_host = server + (port - 80 === 0 ? '' : ':' + port);
Change headers
headers.Host = remote_host;
+ headers.Origin = 'http://' + remote_host;
Open request
var p = manager.getPool(port, server);
- p.getClient(function(client) {
Based on 'pool/main.js'
var request = client.request('GET', req.url, headers);
+ p.getClient(function(client) {
Based on 'pool/main.js'
var request = client.request('GET', req.url, headers);
var errorListener = function (error) {
client.removeListener('error', errorListener);
-
Remove the client from the pool's available clients since it has errored
p.clients.splice(p.clients.indexOf(client), 1);
+
Remove the client from the pool's available clients since it has errored
p.clients.splice(p.clients.indexOf(client), 1);
socket.end();
- }
Not disconnect on update
client.on('upgrade', function(request, remote_socket, head) {
Prepare socket
_socket(remote_socket, true);
Emit event
onUpgrade(remote_socket);
+ }
Not disconnect on update
client.on('upgrade', function(request, remote_socket, head) {
Prepare socket
_socket(remote_socket, true);
Emit event
onUpgrade(remote_socket);
});
client.on('error', errorListener);
@@ -347,23 +365,23 @@ Get it from headers
client.busy = true;
var handshake;
- request.socket.on('data', handshake = function(data) { Handshaking
Ok, kind of harmfull part of code
+ request.socket.on('data', handshake = function(data) {
Handshaking
Ok, kind of harmfull part of code
Socket.IO is sending 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 Printable
sdata = sdata.substr(0, sdata.search(CRLF + CRLF));
Get Non-Printable
data = data.slice(Buffer.byteLength(sdata), data.length);
Replace host and origin
sdata = sdata.replace(remote_host, host)
+(Non-printable will come after double-CRLF)
var sdata = data.toString();
Get Printable
sdata = sdata.substr(0, sdata.search(CRLF + CRLF));
Get Non-Printable
data = data.slice(Buffer.byteLength(sdata), data.length);
Replace host and origin
sdata = sdata.replace(remote_host, host)
.replace(remote_host, host);
- try {
Write printable
socket.write(sdata);
Write non-printable
socket.write(data);
+ try {
Write printable
socket.write(sdata);
Write non-printable
socket.write(data);
}
catch (e) {
request.end();
socket.end();
- }
Catch socket errors
socket.on('error', function() {
+ }
Catch socket errors
socket.on('error', function() {
request.end();
- });
Remove data listener now that the 'handshake' is complete
request.socket.removeListener('data', handshake);
- });
Write upgrade-head
try {
+ });
Remove data listener now that the 'handshake' is complete
request.socket.removeListener('data', handshake);
+ });
Write upgrade-head
try {
request.write(head);
}
catch(e) {
@@ -371,9 +389,9 @@ So we split data to printable data and to non-printable
socket.end();
}
self.unwatch(socket);
- });
Request
function onUpgrade(reverse_proxy) {
+ });
Request
function onUpgrade(reverse_proxy) {
var listeners = {};
-
We're now connected to the server, so lets change server socket
reverse_proxy.on('data', listeners._r_data = function(data) {
Pass data to client
if (socket.writable) {
+
We're now connected to the server, so lets change server socket
reverse_proxy.on('data', listeners._r_data = function(data) {
Pass data to client
if (socket.writable) {
try {
socket.write(data);
}
@@ -384,19 +402,19 @@ So we split data to printable data and to non-printable
}
});
- socket.on('data', listeners._data = function(data) {
Pass data from client to server
try {
+ socket.on('data', listeners._data = function(data) {
Pass data from client to server
try {
reverse_proxy.write(data);
}
catch (e) {
reverse_proxy.end();
socket.end();
}
- });
Detach event listeners from reverse_proxy
function detach() {
+ });
Detach event listeners from reverse_proxy
function detach() {
reverse_proxy.removeListener('close', listeners._r_close);
reverse_proxy.removeListener('data', listeners._r_data);
socket.removeListener('data', listeners._data);
socket.removeListener('close', listeners._close);
- }
Hook disconnections
reverse_proxy.on('end', listeners._r_close = function() {
+ }
Hook disconnections
reverse_proxy.on('end', listeners._r_close = function() {
socket.end();
detach();
});
diff --git a/lib/node-http-proxy.js b/lib/node-http-proxy.js
index 5362ab5..1594d48 100644
--- a/lib/node-http-proxy.js
+++ b/lib/node-http-proxy.js
@@ -69,8 +69,16 @@ exports.setMaxSockets = function (value) {
};
//
-// ### function createServer ([port, host, options], handler)
-//
+// ### function createServer ([port, host, options, handler])
+// #### @port {number} **Optional** Port to use on the proxy target host.
+// #### @host {string} **Optional** Host of the proxy target.
+// #### @options {Object} **Optional** Options for the HttpProxy instance used
+// #### @handler {function} **Optional** Request handler for the server
+// Returns a server that manages an instance of HttpProxy. Flexible arguments allow for:
+//
+// * `httpProxy.createServer(9000, 'localhost')`
+// * `httpProxy.createServer(9000, 'localhost', options)
+// * `httpPRoxy.createServer(function (req, res, proxy) { ... })`
//
exports.createServer = function () {
var args, callback, port, host, forward,
@@ -172,7 +180,7 @@ var HttpProxy = exports.HttpProxy = function (options) {
util.inherits(HttpProxy, events.EventEmitter);
//
-// ### function pause (obj)
+// ### function buffer (obj)
// #### @obj {Object} Object to pause events from
// Pause `data` and `end` events on the given `obj`.
// Consumers of HttpProxy performing async tasks
@@ -180,9 +188,9 @@ util.inherits(HttpProxy, events.EventEmitter);
// the async operation has completed, otherwise these
// __events will be lost.__
//
-// var pause = httpProxy.pause(req);
+// var buffer = httpProxy.buffer(req);
// fs.readFile(path, function(){
-// httpProxy.proxyRequest(req, res, host, port, paused);
+// httpProxy.proxyRequest(req, res, host, port, buffer);
// });
//
// __Attribution:__ This approach is based heavily on
@@ -191,7 +199,7 @@ util.inherits(HttpProxy, events.EventEmitter);
// 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.pause = function (obj) {
+HttpProxy.prototype.buffer = function (obj) {
var onData, onEnd, events = [];
obj.on('data', onData = function (data, encoding) {
@@ -231,9 +239,9 @@ HttpProxy.prototype.close = function () {
// #### @res {ServerResponse} Outgoing HTTP Request to write proxied data to.
// #### @port {number} **Optional** Port to use on the proxy target host.
// #### @host {string} **Optional** Host of the proxy target.
-// #### @paused {Object} **Optional** Result from `httpProxy.pause(req)`
+// #### @buffer {Object} **Optional** Result from `httpProxy.buffer(req)`
//
-HttpProxy.prototype.proxyRequest = function (req, res, port, host, paused) {
+HttpProxy.prototype.proxyRequest = function (req, res, port, host, buffer) {
var self = this, reverseProxy, location, errState = false;
//
@@ -258,11 +266,11 @@ HttpProxy.prototype.proxyRequest = function (req, res, port, host, paused) {
// When using the ProxyTable in conjunction with an HttpProxy instance
// only the following arguments are valid:
//
- // * `proxy.proxyRequest(req, res, port, host, paused)`: This will be skipped
- // * `proxy.proxyRequest(req, res, paused)`: Paused will get updated appropriately
+ // * `proxy.proxyRequest(req, res, port, host, buffer)`: This will be skipped
+ // * `proxy.proxyRequest(req, res, buffer)`: Buffer will get updated appropriately
// * `proxy.proxyRequest(req, res)`: No effect `undefined = undefined`
//
- paused = port;
+ buffer = port;
port = location.port;
host = location.host;
}
@@ -297,7 +305,7 @@ HttpProxy.prototype.proxyRequest = function (req, res, port, host, paused) {
headers: req.headers
}, function (response) {
- // Process the reverse_proxy response when it's received.
+ // 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';
@@ -345,11 +353,18 @@ HttpProxy.prototype.proxyRequest = function (req, res, port, host, paused) {
}
});
- if (paused && !errState) {
- paused.resume();
+ // If we have been passed buffered data, resume it.
+ if (buffer && !errState) {
+ buffer.resume();
}
};
+//
+// ### @private function _forwardRequest (req)
+// #### @req {ServerRequest} Incoming HTTP Request to proxy.
+// Forwards the specified `req` to the location specified
+// by `this.options.forward` ignoring errors and the subsequent response.
+//
HttpProxy.prototype._forwardRequest = function (req) {
var self = this, port, host, forwardProxy;
diff --git a/test/helpers.js b/test/helpers.js
index 87a1e95..85782e7 100644
--- a/test/helpers.js
+++ b/test/helpers.js
@@ -100,7 +100,7 @@ TestRunner.prototype.startProxyServer = function (port, targetPort, host, callba
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 data = proxy.pause(req);
+ var data = proxy.buffer(req);
setTimeout(function () {
proxy.proxyRequest(req, res, targetPort, host, data);
@@ -133,9 +133,9 @@ TestRunner.prototype.startProxyServerWithTableAndLatency = function (port, laten
// Initialize the nodeProxy and start proxying the request
var proxyServer, that = this, proxy = new httpProxy.HttpProxy(options);
proxyServer = http.createServer(function (req, res) {
- var paused = proxy.pause(req);
+ var buffer = proxy.buffer(req);
setTimeout(function () {
- proxy.proxyRequest(req, res, paused);
+ proxy.proxyRequest(req, res, buffer);
}, latency);
});