Skip to content

Commit fd61828

Browse files
committed
[api dist] Merge of branch 0.2.0
2 parents 6661753 + eb39018 commit fd61828

File tree

4 files changed

+155
-216
lines changed

4 files changed

+155
-216
lines changed

README.md

+14-23
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# node-http-proxy - v0.1.5
1+
# node-http-proxy - v0.2.0
22

33
<img src = "http://i.imgur.com/dSSUX.png"/>
44

@@ -52,9 +52,9 @@ see the [demo](https://github.com./nodejitsu/node-http-proxy/blob/master/demo.js)
5252
httpProxy = require('http-proxy');
5353

5454
// create a proxy server with custom application logic
55-
httpProxy.createServer(function (req, res, proxy) {
55+
httpProxy.createServer(function (req, res, proxyRequest) {
5656
// Put your custom server logic here
57-
proxy.proxyRequest(9000, 'localhost', req, res);
57+
proxyRequest(9000, 'localhost');
5858
}).listen(8000);
5959

6060
http.createServer(function (req, res){
@@ -65,37 +65,28 @@ see the [demo](https://github.com./nodejitsu/node-http-proxy/blob/master/demo.js)
6565

6666
</pre>
6767

68-
### How to proxy requests with a regular http server
69-
<pre>
70-
var http = require('http'),
71-
httpProxy = require('http-proxy');
68+
### How to proxy requests with latent operations (IO, etc.)
7269

73-
// create a regular http server and proxy its handler
74-
http.createServer(function (req, res){
75-
var proxy = new httpProxy.HttpProxy;
76-
proxy.watch(req, res);
77-
// Put your custom server logic here
78-
proxy.proxyRequest(9000, 'localhost', req, res);
79-
}).listen(8001);
70+
node-http-proxy supports event buffering, that means if an event (like 'data', or 'end') is raised by the incoming request before you have a chance to perform your custom server logic, those events will be captured and re-raised when you later proxy the request. Here's a simple example:
8071

81-
http.createServer(function (req, res){
82-
res.writeHead(200, {'Content-Type': 'text/plain'});
83-
res.write('request successfully proxied: ' + req.url +'\n' + JSON.stringify(req.headers, true, 2));
84-
res.end();
85-
}).listen(9000);
86-
72+
<pre>
73+
httpProxy.createServer(function (req, res, proxyRequest) {
74+
setTimeout(function () {
75+
proxyRequest(port, server);
76+
}, latency);
77+
}).listen(8081);
8778
</pre>
8879

8980
### Why doesn't node-http-proxy have more advanced features like x, y, or z?
9081

9182
If you have a suggestion for a feature currently not supported, feel free to open a [support issue](https://github.com./nodejitsu/node-http-proxy/issues). node-http-proxy is designed to just proxy http requests from one server to another, but we will be soon releasing many other complimentary projects that can be used in conjunction with node-http-proxy.
9283

93-
<br/><hr/>
84+
<br/>
9485
### License
9586

9687
(The MIT License)
9788

98-
Copyright (c) 2010 Charlie Robbins & Marak Squires https://github.com./nodejitsu/
89+
Copyright (c) 2010 Mikeal Rogers, Charlie Robbins & Marak Squires
9990

10091
Permission is hereby granted, free of charge, to any person obtaining
10192
a copy of this software and associated documentation files (the
@@ -116,4 +107,4 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
116107
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
117108
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
118109

119-
[0]:http://nodejitsu.com "nodejitsu.com"
110+
[0]:http://nodejitsu.com "nodejitsu.com"

demo.js

+4-15
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
var sys = require('sys'),
2828
colors = require('colors')
2929
http = require('http'),
30-
httpProxy = require('http-proxy');
30+
httpProxy = require('./lib/node-http-proxy');
3131

3232
// ascii art from https://github.com./marak/asciimo
3333
var welcome = '\
@@ -45,24 +45,13 @@ httpProxy.createServer(9000, 'localhost').listen(8000);
4545
sys.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow);
4646

4747
/****** http proxy server with latency******/
48-
httpProxy.createServer(function (req, res, proxy){
48+
httpProxy.createServer(function (req, res, proxyRequest){
4949
setTimeout(function(){
50-
proxy.proxyRequest(9000, 'localhost', req, res);
51-
}, 200)
50+
proxyRequest(9000, 'localhost', req, res);
51+
}, 2000)
5252
}).listen(8001);
5353
sys.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8001 '.yellow + 'with latency'.magenta.underline );
5454

55-
/****** http server with proxyRequest handler and latency******/
56-
http.createServer(function (req, res){
57-
var proxy = new httpProxy.HttpProxy;
58-
proxy.watch(req, res);
59-
60-
setTimeout(function(){
61-
proxy.proxyRequest(9000, 'localhost', req, res);
62-
}, 200);
63-
}).listen(8002);
64-
sys.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '8002 '.yellow + 'with proxyRequest handler'.cyan.underline + ' and latency'.magenta);
65-
6655
/****** regular http server ******/
6756
http.createServer(function (req, res){
6857
res.writeHead(200, {'Content-Type': 'text/plain'});

lib/node-http-proxy.js

+102-158
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
2-
node-http-proxy.js: http proxy for node.js
2+
node-http-proxy.js: http proxy for node.js with pooling and event buffering
33
4-
Copyright (c) 2010 Charlie Robbins & Marak Squires https://github.com./nodejitsu/node-http-proxy
4+
Copyright (c) 2010 Mikeal Rogers, Charlie Robbins
55
66
Permission is hereby granted, free of charge, to any person obtaining
77
a copy of this software and associated documentation files (the
@@ -24,172 +24,116 @@
2424
2525
*/
2626

27-
var sys = require('sys'),
28-
http = require('http'),
29-
events = require('events');
30-
31-
exports.HttpProxy = function () {
32-
this.emitter = new(events.EventEmitter);
33-
this.events = {};
34-
this.listeners = {};
35-
this.collisions = {};
36-
};
27+
var sys = require('sys'),
28+
http = require('http'),
29+
pool = require('pool'),
30+
url = require('url'),
31+
events = require('events'),
32+
min = 0,
33+
max = 100;
34+
35+
// Setup the PoolManager
36+
var manager = pool.createPoolManager();
37+
manager.setMinClients(min);
38+
manager.setMaxClients(max);
3739

3840
exports.createServer = function () {
39-
// Initialize the nodeProxy to start proxying requests
40-
var proxy = new (exports.HttpProxy);
41-
return proxy.createServer.apply(proxy, arguments);
42-
};
43-
44-
exports.HttpProxy.prototype = {
45-
toArray: function (obj){
46-
var len = obj.length,
47-
arr = new Array(len);
48-
for (var i = 0; i < len; ++i) {
49-
arr[i] = obj[i];
50-
}
51-
return arr;
52-
},
41+
var args, action, port, host;
42+
args = Array.prototype.slice.call(arguments);
43+
action = typeof args[args.length - 1] === 'function' && args.pop();
44+
if (args[0]) port = args[0];
45+
if (args[1]) host = args[1];
5346

54-
createServer: function () {
55-
var self = this,
56-
server,
57-
port,
58-
callback;
59-
60-
if (typeof(arguments[0]) === "function") {
61-
callback = arguments[0];
62-
}
47+
var proxy = createProxy();
48+
proxy.on('route', function (req, res, callback) {
49+
var uri = url.parse(req.url);
50+
if (action) {
51+
action(req, res, callback);
52+
}
6353
else {
64-
port = arguments[0];
65-
server = arguments[1];
54+
port = port ? port : uri.port ? uri.port : 80;
55+
host = host ? host : uri.hostname;
56+
callback(port, host);
6657
}
67-
68-
var proxyServer = http.createServer(function (req, res){
69-
self.watch(req, res);
70-
71-
// If we were passed a callback to process the request
72-
// or response in some way, then call it.
73-
if(callback) {
74-
callback(req, res, self);
75-
}
76-
else {
77-
self.proxyRequest(port, server, req, res);
78-
}
79-
});
80-
81-
return proxyServer;
82-
},
83-
84-
watch: function (req, res) {
85-
var self = this;
86-
87-
// Create a unique id for this request so
88-
// we can reference it later.
89-
var id = new Date().getTime().toString();
90-
91-
// If we get a request in the same tick, we need to
92-
// append to the id so it stays unique.
93-
if(typeof this.collisions[id] === 'undefined') {
94-
this.collisions[id] = 0;
95-
}
96-
else {
97-
this.collisions[id]++;
98-
id += this.collisions[id];
99-
}
100-
101-
req.id = id;
102-
this.events[req.id] = [];
103-
104-
this.listeners[req.id] = {
105-
onData: function () {
106-
self.events[req.id].push(['data'].concat(self.toArray(arguments)));
107-
},
108-
onEnd: function () {
109-
self.events[req.id].push(['end'].concat(self.toArray(arguments)));
110-
}
111-
};
112-
113-
req.addListener('data', this.listeners[req.id].onData);
114-
req.addListener('end', this.listeners[req.id].onEnd);
115-
116-
},
117-
118-
unwatch: function (req, res) {
119-
req.removeListener('data', this.listeners[req.id].onData);
120-
req.removeListener('end', this.listeners[req.id].onEnd);
121-
122-
// Rebroadcast any events that have been buffered
123-
while(this.events[req.id].length > 0) {
124-
var args = this.events[req.id].shift();
125-
req.emit.apply(req, args);
126-
}
127-
128-
// Remove the data from the event and listeners hashes
129-
delete this.listeners[req.id];
130-
delete this.events[req.id];
131-
132-
// If this request id is a base time, delete it
133-
if (typeof this.collisions[req.id] !== 'undefined') {
134-
delete this.collisions[req.id];
135-
}
136-
},
137-
138-
proxyRequest: function (port, server, req, res) {
139-
// Remark: nodeProxy.body exists solely for testability
140-
this.body = '';
141-
var self = this;
142-
143-
// Open new HTTP request to internal resource with will act as a reverse proxy pass
144-
var c = http.createClient(port, server);
145-
146-
// Make request to internal server, passing along the method and headers
147-
var reverse_proxy = c.request(req.method, req.url, req.headers);
148-
149-
// Add a listener for the connection timeout event
150-
reverse_proxy.connection.addListener('error', function (err) {
151-
res.writeHead(200, {'Content-Type': 'text/plain'});
152-
153-
if(req.method !== 'HEAD') {
154-
res.write('An error has occurred: ' + sys.puts(JSON.stringify(err)));
155-
}
58+
});
59+
return proxy;
60+
};
15661

157-
res.end();
158-
});
62+
exports.setMin = function (value) {
63+
min = value;
64+
manager.setMinClients(min);
65+
};
15966

67+
exports.setMax = function (value) {
68+
max = value;
69+
manager.setMaxClients(max);
70+
}
16071

161-
// Add a listener for the reverse_proxy response event
162-
reverse_proxy.addListener('response', function (response) {
163-
// Set the response headers of the client response
164-
res.writeHead(response.statusCode, response.headers);
72+
var createProxy = function () {
73+
var server = http.createServer(function (req, res) {
74+
var buffers = [],
75+
b = function (chunk) { buffers.push(chunk) },
76+
e = function () { e = false };
77+
78+
req.on('data', b);
79+
req.on('end', e);
80+
81+
server.emit('route', req, res, function (port, hostname) {
82+
var p = manager.getPool(port, hostname);
16583

166-
// Add event handler for the proxied response in chunks
167-
response.addListener('data', function (chunk) {
168-
if(req.method !== 'HEAD') {
169-
res.write(chunk, 'binary');
170-
self.body += chunk;
84+
p.request(req.method, req.url, req.headers, function (reverse_proxy) {
85+
var data = '';
86+
reverse_proxy.on('error', function (err) {
87+
res.writeHead(500, {'Content-Type': 'text/plain'});
88+
89+
if(req.method !== 'HEAD') {
90+
res.write('An error has occurred: ' + sys.puts(JSON.stringify(err)));
91+
}
92+
93+
res.end();
94+
});
95+
96+
buffers.forEach(function (c) {
97+
data += c;
98+
reverse_proxy.write(c);
99+
});
100+
101+
buffers = null;
102+
req.removeListener('data', b);
103+
sys.pump(req, reverse_proxy);
104+
105+
if (e) {
106+
req.removeListener('end', e);
107+
req.addListener('end', function () { reverse_proxy.end() });
108+
}
109+
else {
110+
reverse_proxy.end();
171111
}
172-
});
173112

174-
// Add event listener for end of proxied response
175-
response.addListener('end', function () {
176-
// Remark: Emit the end event for testability
177-
self.emitter.emit('end', null, self.body);
178-
179-
res.end();
113+
// Add a listener for the reverse_proxy response event
114+
reverse_proxy.addListener('response', function (response) {
115+
if (response.headers.connection) {
116+
if (req.headers.connection) response.headers.connection = req.headers.connection;
117+
else response.headers.connection = 'close';
118+
}
119+
120+
// These two listeners are for testability and observation
121+
// of what's passed back from the target server
122+
response.addListener('data', function (chunk) {
123+
data += chunk;
124+
});
125+
126+
response.addListener('end', function() {
127+
server.emit('proxy', null, data);
128+
});
129+
130+
// Set the response headers of the client response
131+
res.writeHead(response.statusCode, response.headers);
132+
133+
sys.pump(response, res);
134+
});
180135
});
181136
});
182-
183-
// Chunk the client request body as chunks from the proxied request come in
184-
req.addListener('data', function (chunk) {
185-
reverse_proxy.write(chunk, 'binary');
186-
})
187-
188-
// At the end of the client request, we are going to stop the proxied request
189-
req.addListener('end', function () {
190-
reverse_proxy.end();
191-
});
192-
193-
this.unwatch(req, res);
194-
}
195-
};
137+
})
138+
return server;
139+
};

0 commit comments

Comments
 (0)