Skip to content

Commit 66afb2a

Browse files
committed
[api] Revert to old 0.1.x codebase for bug testing and performance comparison
1 parent 69c162d commit 66afb2a

File tree

6 files changed

+226
-143
lines changed

6 files changed

+226
-143
lines changed

LICENSE

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
node-http-proxy
33

4-
Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, & Marak Squires
4+
Copyright (c) 2010 Charlie Robbins & Marak Squires http://github.com/nodejitsu/node-http-proxy
55

66
Permission is hereby granted, free of charge, to any person obtaining
77
a copy of this software and associated documentation files (the

README.md

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

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

@@ -52,9 +52,9 @@ see the [demo](http://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, proxyRequest) {
55+
httpProxy.createServer(function (req, res, proxy) {
5656
// Put your custom server logic here
57-
proxyRequest(9000, 'localhost');
57+
proxy.proxyRequest(9000, 'localhost', req, res);
5858
}).listen(8000);
5959

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

6666
</pre>
6767

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

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:
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);
7180

72-
<pre>
73-
httpProxy.createServer(function (req, res, proxyRequest) {
74-
setTimeout(function () {
75-
proxyRequest(port, server);
76-
}, latency);
77-
}).listen(8081);
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+
7887
</pre>
7988

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

8291
If you have a suggestion for a feature currently not supported, feel free to open a [support issue](http://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.
8392

84-
<br/>
93+
<br/><hr/>
8594
### License
8695

8796
(The MIT License)
8897

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

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

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

demo.js

+16-5
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,28 @@ 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, proxyRequest){
48+
httpProxy.createServer(function (req, res, proxy){
4949
setTimeout(function(){
50-
proxyRequest(9000, 'localhost', req, res);
51-
}, 2000)
50+
proxy.proxyRequest(9000, 'localhost', req, res);
51+
}, 200)
5252
}).listen(8001);
5353
sys.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8001 '.yellow + 'with latency'.magenta.underline );
5454

55-
/****** regular http server ******/
55+
/****** http server with proxyRequest handler and latency******/
5656
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+
66+
/****** regular http server ******/
67+
/*http.createServer(function (req, res){
5768
res.writeHead(200, {'Content-Type': 'text/plain'});
5869
res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
5970
res.end();
6071
}).listen(9000);
61-
sys.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow);
72+
sys.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow);*/

lib/node-http-proxy.js

+162-82
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
2-
node-http-proxy.js: http proxy for node.js with pooling and event buffering
2+
node-http-proxy.js: http proxy for node.js
33
4-
Copyright (c) 2010 Mikeal Rogers, Charlie Robbins
4+
Copyright (c) 2010 Charlie Robbins & Marak Squires http://github.com/nodejitsu/node-http-proxy
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,11 +24,11 @@
2424
2525
*/
2626

27-
var sys = require('sys'),
28-
http = require('http'),
29-
pool = require('pool'),
30-
url = require('url'),
31-
events = require('events'),
27+
var sys = require('sys'),
28+
http = require('http'),
29+
eyes = require('eyes'),
30+
events = require('events'),
31+
pool = require('pool'),
3232
min = 0,
3333
max = 100;
3434

@@ -38,25 +38,9 @@ manager.setMinClients(min);
3838
manager.setMaxClients(max);
3939

4040
exports.createServer = function () {
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];
46-
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-
}
53-
else {
54-
port = port ? port : uri.port ? uri.port : 80;
55-
host = host ? host : uri.hostname;
56-
callback(port, host);
57-
}
58-
});
59-
return proxy;
41+
// Initialize the nodeProxy to start proxying requests
42+
var proxy = new (exports.HttpProxy);
43+
return proxy.createServer.apply(proxy, arguments);
6044
};
6145

6246
exports.setMin = function (value) {
@@ -67,73 +51,169 @@ exports.setMin = function (value) {
6751
exports.setMax = function (value) {
6852
max = value;
6953
manager.setMaxClients(max);
70-
}
54+
};
7155

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 };
56+
exports.HttpProxy = function () {
57+
this.emitter = new(events.EventEmitter);
58+
this.events = {};
59+
this.listeners = {};
60+
this.collisions = {};
61+
};
62+
63+
exports.HttpProxy.prototype = {
64+
toArray: function (obj){
65+
var len = obj.length,
66+
arr = new Array(len);
67+
for (var i = 0; i < len; ++i) {
68+
arr[i] = obj[i];
69+
}
70+
return arr;
71+
},
72+
73+
createServer: function () {
74+
var self = this,
75+
server,
76+
port,
77+
callback;
7778

78-
req.on('data', b);
79-
req.on('end', e);
79+
if (typeof(arguments[0]) === "function") {
80+
callback = arguments[0];
81+
}
82+
else {
83+
port = arguments[0];
84+
server = arguments[1];
85+
}
8086

81-
server.emit('route', req, res, function (port, hostname) {
82-
var p = manager.getPool(port, hostname);
87+
var proxyServer = http.createServer(function (req, res){
88+
self.watch(req, res);
8389

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'});
90+
// If we were passed a callback to process the request
91+
// or response in some way, then call it.
92+
if(callback) {
93+
callback(req, res, self);
94+
}
95+
else {
96+
self.proxyRequest(port, server, req, res);
97+
}
98+
});
99+
100+
return proxyServer;
101+
},
102+
103+
watch: function (req, res) {
104+
var self = this;
105+
106+
// Create a unique id for this request so
107+
// we can reference it later.
108+
var id = new Date().getTime().toString();
109+
110+
// If we get a request in the same tick, we need to
111+
// append to the id so it stays unique.
112+
if(typeof this.collisions[id] === 'undefined') {
113+
this.collisions[id] = 0;
114+
}
115+
else {
116+
this.collisions[id]++;
117+
id += this.collisions[id];
118+
}
119+
120+
req.id = id;
121+
this.events[req.id] = [];
122+
123+
this.listeners[req.id] = {
124+
onData: function () {
125+
self.events[req.id].push(['data'].concat(self.toArray(arguments)));
126+
},
127+
onEnd: function () {
128+
self.events[req.id].push(['end'].concat(self.toArray(arguments)));
129+
}
130+
};
88131

132+
req.addListener('data', this.listeners[req.id].onData);
133+
req.addListener('end', this.listeners[req.id].onEnd);
134+
135+
},
136+
137+
unwatch: function (req, res) {
138+
req.removeListener('data', this.listeners[req.id].onData);
139+
req.removeListener('end', this.listeners[req.id].onEnd);
140+
141+
// Rebroadcast any events that have been buffered
142+
while(this.events[req.id].length > 0) {
143+
var args = this.events[req.id].shift();
144+
req.emit.apply(req, args);
145+
}
146+
147+
// Remove the data from the event and listeners hashes
148+
delete this.listeners[req.id];
149+
delete this.events[req.id];
150+
151+
// If this request id is a base time, delete it
152+
if (typeof this.collisions[req.id] !== 'undefined') {
153+
delete this.collisions[req.id];
154+
}
155+
},
156+
157+
proxyRequest: function (port, server, req, res) {
158+
// Remark: nodeProxy.body exists solely for testability
159+
this.body = '';
160+
var self = this;
161+
162+
// Open new HTTP request to internal resource with will act as a reverse proxy pass
163+
var p = manager.getPool(port, server);
164+
eyes.inspect(req.headers);
165+
// Make request to internal server, passing along the method and headers
166+
p.request(req.method, req.url, req.headers, function (reverse_proxy) {
167+
// Add a listener for the connection timeout event
168+
reverse_proxy.connection.addListener('error', function (err) {
169+
res.writeHead(200, {'Content-Type': 'text/plain'});
170+
171+
if(req.method !== 'HEAD') {
172+
res.write('An error has occurred: ' + sys.puts(JSON.stringify(err)));
173+
}
174+
175+
res.end();
176+
});
177+
178+
179+
// Add a listener for the reverse_proxy response event
180+
reverse_proxy.addListener('response', function (response) {
181+
if (response.headers.connection) {
182+
if (req.headers.connection) response.headers.connection = req.headers.connection;
183+
else response.headers.connection = 'close';
184+
}
185+
186+
// Set the response headers of the client response
187+
res.writeHead(response.statusCode, response.headers);
188+
189+
// Add event handler for the proxied response in chunks
190+
response.addListener('data', function (chunk) {
89191
if(req.method !== 'HEAD') {
90-
res.write('An error has occurred: ' + sys.puts(JSON.stringify(err)));
192+
res.write(chunk, 'binary');
193+
self.body += chunk;
91194
}
195+
});
196+
197+
// Add event listener for end of proxied response
198+
response.addListener('end', function () {
199+
// Remark: Emit the end event for testability
200+
self.emitter.emit('end', null, self.body);
92201

93202
res.end();
94203
});
204+
});
95205

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();
111-
}
206+
// Chunk the client request body as chunks from the proxied request come in
207+
req.addListener('data', function (chunk) {
208+
reverse_proxy.write(chunk, 'binary');
209+
})
112210

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-
});
211+
// At the end of the client request, we are going to stop the proxied request
212+
req.addListener('end', function () {
213+
reverse_proxy.end();
135214
});
215+
216+
self.unwatch(req, res);
136217
});
137-
})
138-
return server;
139-
};
218+
}
219+
};

0 commit comments

Comments
 (0)