@@ -17,7 +17,7 @@ var http = require('http'),
17
17
util = require ( 'util' ) ,
18
18
URL = require ( 'url' ) ,
19
19
querystring = require ( 'querystring' ) ,
20
- trie = require ( './trie .js' ) ;
20
+ store = require ( './store .js' ) ;
21
21
22
22
function bound ( that , method ) {
23
23
// bind a method, to ensure `this=that` when it is called
@@ -100,10 +100,10 @@ function parse_host (req) {
100
100
function ConfigurableProxy ( options ) {
101
101
var that = this ;
102
102
this . options = options || { } ;
103
- this . trie = new trie . URLTrie ( ) ;
103
+
104
+ this . _routes = store . MemoryStore ( ) ;
104
105
this . auth_token = this . options . auth_token ;
105
106
this . includePrefix = options . includePrefix === undefined ? true : options . includePrefix ;
106
- this . routes = { } ;
107
107
this . host_routing = this . options . host_routing ;
108
108
this . error_target = options . error_target ;
109
109
if ( this . error_target && this . error_target . slice ( - 1 ) !== '/' ) {
@@ -169,7 +169,7 @@ function ConfigurableProxy (options) {
169
169
}
170
170
171
171
// proxy requests separately
172
- var proxy_callback = log_errors ( that . handle_proxy_web ) ;
172
+ var proxy_callback = log_errors ( this . handle_proxy_web ) ;
173
173
if ( this . options . ssl ) {
174
174
this . proxy_server = https . createServer ( this . options . ssl , proxy_callback ) ;
175
175
} else {
@@ -185,23 +185,33 @@ function ConfigurableProxy (options) {
185
185
186
186
util . inherits ( ConfigurableProxy , EventEmitter ) ;
187
187
188
- ConfigurableProxy . prototype . add_route = function ( path , data ) {
188
+ ConfigurableProxy . prototype . add_route = function ( path , data , cb ) {
189
189
// add a route to the routing table
190
- path = trie . trim_prefix ( path ) ;
190
+ path = this . _routes . cleanPath ( path ) ;
191
191
if ( this . host_routing && path !== '/' ) {
192
192
data . host = path . split ( '/' ) [ 1 ] ;
193
193
}
194
- this . routes [ path ] = data ;
195
- this . trie . add ( path , data ) ;
196
- this . update_last_activity ( path ) ;
194
+
195
+ var that = this ;
196
+
197
+ this . _routes . add ( path , data , function ( ) {
198
+ that . update_last_activity ( path , function ( ) {
199
+ if ( typeof ( cb ) === "function" ) {
200
+ cb ( ) ;
201
+ }
202
+ } ) ;
203
+ } ) ;
197
204
} ;
198
205
199
- ConfigurableProxy . prototype . remove_route = function ( path ) {
206
+ ConfigurableProxy . prototype . remove_route = function ( path , cb ) {
200
207
// remove a route from the routing table
201
- if ( this . routes [ path ] !== undefined ) {
202
- delete this . routes [ path ] ;
203
- this . trie . remove ( path ) ;
204
- }
208
+ var routes = this . _routes ;
209
+
210
+ routes . hasRoute ( path , function ( result ) {
211
+ if ( result ) {
212
+ routes . remove ( path , cb ) ;
213
+ }
214
+ } ) ;
205
215
} ;
206
216
207
217
ConfigurableProxy . prototype . get_routes = function ( req , res ) {
@@ -211,7 +221,7 @@ ConfigurableProxy.prototype.get_routes = function (req, res) {
211
221
var inactive_since = null ;
212
222
if ( parsed . query ) {
213
223
var query = querystring . parse ( parsed . query ) ;
214
-
224
+
215
225
if ( query . inactive_since !== undefined ) {
216
226
var timestamp = Date . parse ( query . inactive_since ) ;
217
227
if ( isFinite ( timestamp ) ) {
@@ -223,20 +233,24 @@ ConfigurableProxy.prototype.get_routes = function (req, res) {
223
233
}
224
234
}
225
235
res . writeHead ( 200 , { 'Content-Type' : 'application/json' } ) ;
226
- var routes = { } ;
227
- if ( inactive_since ) {
228
- Object . keys ( this . routes ) . map ( function ( path ) {
229
- var route = that . routes [ path ] ;
230
- if ( route . last_activity < inactive_since ) {
231
- routes [ path ] = route ;
232
- }
233
- } ) ;
234
- } else {
235
- routes = this . routes ;
236
- }
237
- res . write ( JSON . stringify ( routes ) ) ;
238
- res . end ( ) ;
239
- this . statsd . increment ( 'api.route.get' , 1 ) ;
236
+
237
+ this . _routes . getAll ( function ( routes ) {
238
+ var results = { } ;
239
+
240
+ if ( inactive_since ) {
241
+ Object . keys ( routes ) . forEach ( function ( path ) {
242
+ if ( routes [ path ] . last_activity < inactive_since ) {
243
+ results [ path ] = routes [ path ] ;
244
+ }
245
+ } ) ;
246
+ } else {
247
+ results = routes ;
248
+ }
249
+
250
+ res . write ( JSON . stringify ( results ) ) ;
251
+ res . end ( ) ;
252
+ that . statsd . increment ( 'api.route.get' , 1 ) ;
253
+ } ) ;
240
254
} ;
241
255
242
256
ConfigurableProxy . prototype . post_routes = function ( req , res , path , data ) {
@@ -250,47 +264,70 @@ ConfigurableProxy.prototype.post_routes = function (req, res, path, data) {
250
264
return ;
251
265
}
252
266
253
- this . add_route ( path , data ) ;
254
- res . writeHead ( 201 ) ;
255
- res . end ( ) ;
256
- this . statsd . increment ( 'api.route.add' , 1 ) ;
267
+ var that = this ;
268
+ this . add_route ( path , data , function ( ) {
269
+ res . writeHead ( 201 ) ;
270
+ res . end ( ) ;
271
+ that . statsd . increment ( 'api.route.add' , 1 ) ;
272
+ } ) ;
257
273
} ;
258
274
259
275
ConfigurableProxy . prototype . delete_routes = function ( req , res , path ) {
260
276
// DELETE removes an existing route
261
277
log . debug ( 'DELETE' , path ) ;
262
- if ( this . routes [ path ] === undefined ) {
263
- res . writeHead ( 404 ) ;
264
- } else {
265
- this . remove_route ( path ) ;
266
- res . writeHead ( 204 ) ;
267
- }
268
- res . end ( ) ;
269
- this . statsd . increment ( 'api.route.delete' , 1 ) ;
278
+
279
+ var that = this ;
280
+ this . _routes . hasRoute ( path , function ( result ) {
281
+ if ( result ) {
282
+ that . remove_route ( path , function ( ) {
283
+ res . writeHead ( 204 ) ;
284
+ res . end ( ) ;
285
+ that . statsd . increment ( 'api.route.delete' , 1 ) ;
286
+ } ) ;
287
+ } else {
288
+ res . writeHead ( 404 ) ;
289
+ res . end ( ) ;
290
+ that . statsd . increment ( 'api.route.delete' , 1 ) ;
291
+ }
292
+ } ) ;
270
293
} ;
271
294
272
- ConfigurableProxy . prototype . target_for_req = function ( req ) {
295
+ ConfigurableProxy . prototype . target_for_req = function ( req , cb ) {
273
296
var timer = this . statsd . createTimer ( 'find_target_for_req' ) ;
274
297
// return proxy target for a given url path
275
298
var base_path = ( this . host_routing ) ? '/' + parse_host ( req ) : '' ;
276
- var route = this . trie . get ( trie . string_to_path ( base_path + decodeURIComponent ( req . url ) ) ) ;
277
- timer . stop ( ) ;
278
- if ( route ) {
279
- return {
280
- prefix : route . prefix ,
281
- target : route . data . target ,
282
- } ;
283
- }
299
+
300
+ this . _routes . getTarget ( base_path + decodeURIComponent ( req . url ) , function ( route ) {
301
+ timer . stop ( ) ;
302
+ if ( route ) {
303
+ cb ( {
304
+ prefix : route . prefix ,
305
+ target : route . data . target
306
+ } ) ;
307
+ return ;
308
+ }
309
+
310
+ cb ( null ) ;
311
+ } ) ;
284
312
} ;
285
313
286
- ConfigurableProxy . prototype . update_last_activity = function ( prefix ) {
314
+ ConfigurableProxy . prototype . update_last_activity = function ( prefix , cb ) {
287
315
var timer = this . statsd . createTimer ( 'last_activity_updating' ) ;
288
- // note last activity in routing table
289
- if ( this . routes [ prefix ] !== undefined ) {
290
- // route may have been deleted with open connections
291
- this . routes [ prefix ] . last_activity = new Date ( ) ;
292
- }
293
- timer . stop ( ) ;
316
+ var routes = this . _routes ;
317
+
318
+ routes . hasRoute ( prefix , function ( result ) {
319
+ cb = cb || function ( ) { } ;
320
+
321
+ if ( result ) {
322
+ routes . update ( prefix , { "last_activity" : new Date ( ) } , function ( ) {
323
+ timer . stop ( ) ;
324
+ cb ( ) ;
325
+ } ) ;
326
+ } else {
327
+ timer . stop ( ) ;
328
+ cb ( ) ;
329
+ }
330
+ } ) ;
294
331
} ;
295
332
296
333
ConfigurableProxy . prototype . _handle_proxy_error_default = function ( code , kind , req , res ) {
@@ -363,48 +400,47 @@ ConfigurableProxy.prototype.handle_proxy_error = function (code, kind, req, res)
363
400
ConfigurableProxy . prototype . handle_proxy = function ( kind , req , res ) {
364
401
// proxy any request
365
402
var that = this ;
403
+ var args = Array . prototype . slice . call ( arguments , 1 ) ;
404
+
366
405
// get the proxy target
367
- var match = this . target_for_req ( req ) ;
368
- if ( ! match ) {
369
- this . handle_proxy_error ( 404 , kind , req , res ) ;
370
- return ;
371
- }
372
- this . emit ( "proxy_request" , req , res ) ;
373
- var prefix = match . prefix ;
374
- var target = match . target ;
375
- log . debug ( "PROXY" , kind . toUpperCase ( ) , req . url , "to" , target ) ;
376
- if ( ! this . includePrefix ) {
377
- req . url = req . url . slice ( prefix . length ) ;
378
- }
406
+ this . target_for_req ( req , function ( match ) {
407
+ if ( ! match ) {
408
+ that . handle_proxy_error ( 404 , kind , req , res ) ;
409
+ return ;
410
+ }
379
411
380
- // pop method off the front
381
- var args = arguments_array ( arguments ) ;
382
- args . shift ( ) ;
412
+ that . emit ( "proxy_request" , req , res ) ;
413
+ var prefix = match . prefix ;
414
+ var target = match . target ;
415
+ log . debug ( "PROXY" , kind . toUpperCase ( ) , req . url , "to" , target ) ;
416
+ if ( ! that . includePrefix ) {
417
+ req . url = req . url . slice ( prefix . length ) ;
418
+ }
383
419
384
- // add config argument
385
- args . push ( {
386
- target : target
387
- } ) ;
420
+ // add config argument
421
+ args . push ( { target : target } ) ;
388
422
389
- // add error handling
390
- args . push ( function ( e ) {
391
- log . error ( "Proxy error: " , e ) ;
392
- that . handle_proxy_error ( 503 , kind , req , res ) ;
393
- } ) ;
423
+ // add error handling
424
+ args . push ( function ( e ) {
425
+ log . error ( "Proxy error: " , e ) ;
426
+ that . handle_proxy_error ( 503 , kind , req , res ) ;
427
+ } ) ;
394
428
395
- // update last activity timestamp in routing table
396
- this . update_last_activity ( prefix ) ;
429
+ // update timestamp on any reply data as well (this includes websocket data)
430
+ req . on ( 'data' , function ( ) {
431
+ that . update_last_activity ( prefix ) ;
432
+ } ) ;
397
433
398
- // update timestamp on any reply data as well (this includes websocket data)
399
- req . on ( 'data' , function ( ) {
400
- that . update_last_activity ( prefix ) ;
401
- } ) ;
402
- res . on ( 'data' , function ( ) {
403
- that . update_last_activity ( prefix ) ;
404
- } ) ;
434
+ res . on ( 'data' , function ( ) {
435
+ that . update_last_activity ( prefix ) ;
436
+ } ) ;
405
437
406
- // dispatch the actual method
407
- this . proxy [ kind ] . apply ( this . proxy , args ) ;
438
+ // update last activity timestamp in routing table
439
+ that . update_last_activity ( prefix , function ( ) {
440
+ // dispatch the actual method
441
+ that . proxy [ kind ] . apply ( that . proxy , args ) ;
442
+ } ) ;
443
+ } ) ;
408
444
} ;
409
445
410
446
ConfigurableProxy . prototype . handle_proxy_ws = function ( req , res , head ) {
0 commit comments