27
27
var sys = require ( 'sys' ) ,
28
28
http = require ( 'http' ) ,
29
29
eyes = require ( 'eyes' ) ,
30
+ pool = require ( 'pool' ) ,
30
31
events = require ( 'events' ) ,
31
32
pool = require ( 'pool' ) ,
32
33
min = 0 ,
@@ -38,9 +39,26 @@ manager.setMinClients(min);
38
39
manager . setMaxClients ( max ) ;
39
40
40
41
exports . createServer = function ( ) {
41
- // Initialize the nodeProxy to start proxying requests
42
- var proxy = new ( exports . HttpProxy ) ;
43
- return proxy . createServer . apply ( proxy , arguments ) ;
42
+ var args , callback , port , host ;
43
+ args = Array . prototype . slice . call ( arguments ) ;
44
+ callback = typeof args [ args . length - 1 ] === 'function' && args . pop ( ) ;
45
+ if ( args [ 0 ] ) port = args [ 0 ] ;
46
+ if ( args [ 1 ] ) host = args [ 1 ] ;
47
+
48
+ var server = http . createServer ( function ( req , res ) {
49
+ var proxy = new HttpProxy ( req , res ) ;
50
+
51
+ // If we were passed a callback to process the request
52
+ // or response in some way, then call it.
53
+ if ( callback ) {
54
+ callback ( req , res , proxy ) ;
55
+ }
56
+ else {
57
+ proxy . proxyRequest ( port , server ) ;
58
+ }
59
+ } ) ;
60
+
61
+ return server ;
44
62
} ;
45
63
46
64
exports . setMin = function ( value ) {
@@ -53,14 +71,15 @@ exports.setMax = function (value) {
53
71
manager . setMaxClients ( max ) ;
54
72
} ;
55
73
56
- exports . HttpProxy = function ( ) {
74
+ var HttpProxy = function ( req , res ) {
57
75
this . emitter = new ( events . EventEmitter ) ;
58
76
this . events = { } ;
59
- this . listeners = { } ;
60
- this . collisions = { } ;
77
+ this . req = req ;
78
+ this . res = res ;
79
+ this . watch ( req ) ;
61
80
} ;
62
81
63
- exports . HttpProxy . prototype = {
82
+ HttpProxy . prototype = {
64
83
toArray : function ( obj ) {
65
84
var len = obj . length ,
66
85
arr = new Array ( len ) ;
@@ -70,119 +89,60 @@ exports.HttpProxy.prototype = {
70
89
return arr ;
71
90
} ,
72
91
73
- createServer : function ( ) {
74
- var self = this ,
75
- server ,
76
- port ,
77
- callback ;
78
-
79
- if ( typeof ( arguments [ 0 ] ) === "function" ) {
80
- callback = arguments [ 0 ] ;
81
- }
82
- else {
83
- port = arguments [ 0 ] ;
84
- server = arguments [ 1 ] ;
85
- }
86
-
87
- var proxyServer = http . createServer ( function ( req , res ) {
88
- self . watch ( req , res ) ;
89
-
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 ) {
92
+ watch : function ( req ) {
93
+ this . events = [ ] ;
104
94
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
- }
95
+
96
+ this . onData = function ( ) {
97
+ self . events . push ( [ 'data' ] . concat ( self . toArray ( arguments ) ) ) ;
98
+ } ;
99
+ this . onEnd = function ( ) {
100
+ self . events . push ( [ 'end' ] . concat ( self . toArray ( arguments ) ) ) ;
130
101
} ;
131
102
132
- req . addListener ( 'data' , this . listeners [ req . id ] . onData ) ;
133
- req . addListener ( 'end' , this . listeners [ req . id ] . onEnd ) ;
134
-
103
+ req . addListener ( 'data' , this . onData ) ;
104
+ req . addListener ( 'end' , this . onEnd ) ;
135
105
} ,
136
106
137
- unwatch : function ( req , res ) {
138
- req . removeListener ( 'data' , this . listeners [ req . id ] . onData ) ;
139
- req . removeListener ( 'end' , this . listeners [ req . id ] . onEnd ) ;
107
+ unwatch : function ( req ) {
108
+ req . removeListener ( 'data' , this . onData ) ;
109
+ req . removeListener ( 'end' , this . onEnd ) ;
140
110
141
111
// 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 ] ;
112
+ for ( var i = 0 , len = this . events . length ; i < len ; ++ i ) {
113
+ req . emit . apply ( req , this . events [ i ] ) ;
154
114
}
155
115
} ,
156
116
157
- proxyRequest : function ( port , server , req , res ) {
117
+ proxyRequest : function ( port , server ) {
158
118
// Remark: nodeProxy.body exists solely for testability
159
- this . body = '' ;
160
- var self = this ;
119
+ var self = this , req = this . req , res = this . res ;
120
+ self . body = '' ;
161
121
162
122
// 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
123
+ var p = manager . getPool ( port , server ) ;
124
+
166
125
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 ) {
126
+ // Create an error handler so we can use it temporarily
127
+ var error = function ( err ) {
169
128
res . writeHead ( 200 , { 'Content-Type' : 'text/plain' } ) ;
170
129
171
130
if ( req . method !== 'HEAD' ) {
172
131
res . write ( 'An error has occurred: ' + sys . puts ( JSON . stringify ( err ) ) ) ;
173
132
}
174
133
175
134
res . end ( ) ;
176
- } ) ;
177
-
135
+ } ;
136
+ // Add a listener for the connection timeout event
137
+ reverse_proxy . connection . addListener ( 'error' , error ) ;
178
138
179
139
// Add a listener for the reverse_proxy response event
180
140
reverse_proxy . addListener ( 'response' , function ( response ) {
181
141
if ( response . headers . connection ) {
182
142
if ( req . headers . connection ) response . headers . connection = req . headers . connection ;
183
143
else response . headers . connection = 'close' ;
184
144
}
185
-
145
+
186
146
// Set the response headers of the client response
187
147
res . writeHead ( response . statusCode , response . headers ) ;
188
148
@@ -211,9 +171,65 @@ exports.HttpProxy.prototype = {
211
171
// At the end of the client request, we are going to stop the proxied request
212
172
req . addListener ( 'end' , function ( ) {
213
173
reverse_proxy . end ( ) ;
174
+ reverse_proxy . connection . removeListener ( 'error' , error ) ;
214
175
} ) ;
215
176
216
- self . unwatch ( req , res ) ;
177
+ self . unwatch ( req ) ;
217
178
} ) ;
218
179
}
219
180
} ;
181
+
182
+ exports . HttpProxy = HttpProxy ;
183
+
184
+ /*// Create an error handler so we can use it temporarily
185
+ var error = function (err) {
186
+ res.writeHead(200, {'Content-Type': 'text/plain'});
187
+
188
+ if(req.method !== 'HEAD') {
189
+ res.write('An error has occurred: ' + sys.puts(JSON.stringify(err)));
190
+ }
191
+
192
+ res.end();
193
+ };
194
+ // Add a listener for the connection timeout event
195
+ reverse_proxy.connection.addListener('error', error);
196
+
197
+ // Add a listener for the reverse_proxy response event
198
+ reverse_proxy.addListener('response', function (response) {
199
+ if (response.headers.connection) {
200
+ if (req.headers.connection) response.headers.connection = req.headers.connection;
201
+ else response.headers.connection = 'close';
202
+ }
203
+
204
+ // Set the response headers of the client response
205
+ res.writeHead(response.statusCode, response.headers);
206
+
207
+ // Add event handler for the proxied response in chunks
208
+ response.addListener('data', function (chunk) {
209
+ if(req.method !== 'HEAD') {
210
+ res.write(chunk, 'binary');
211
+ self.body += chunk;
212
+ }
213
+ });
214
+
215
+ // Add event listener for end of proxied response
216
+ response.addListener('end', function () {
217
+ // Remark: Emit the end event for testability
218
+ self.emitter.emit('end', null, self.body);
219
+
220
+ res.end();
221
+ });
222
+ });
223
+
224
+ // Chunk the client request body as chunks from the proxied request come in
225
+ req.addListener('data', function (chunk) {
226
+ reverse_proxy.write(chunk, 'binary');
227
+ })
228
+
229
+ // At the end of the client request, we are going to stop the proxied request
230
+ req.addListener('end', function () {
231
+ reverse_proxy.end();
232
+ //reverse_proxy.connection.removeListener('error', error);
233
+ });
234
+
235
+ self.unwatch(req);*/
0 commit comments