26
26
27
27
var util = require ( 'util' ) ,
28
28
http = require ( 'http' ) ,
29
+ https = require ( 'https' ) ,
29
30
events = require ( 'events' ) ,
30
31
ProxyTable = require ( './proxy-table' ) . ProxyTable ,
31
32
maxSockets = 100 ;
@@ -36,21 +37,46 @@ var util = require('util'),
36
37
exports . version = [ 0 , 4 , 2 ] ;
37
38
38
39
//
39
- // ### function _getAgent (host, port)
40
+ // ### function _getAgent (host, port, secure )
40
41
// #### @host {string} Host of the agent to get
41
42
// #### @port {number} Port of the agent to get
43
+ // #### @secure {boolean} Value indicating whether or not to use HTTPS
42
44
// Retreives an agent from the `http` module
43
45
// and sets the `maxSockets` property appropriately.
44
46
//
45
- function _getAgent ( host , port ) {
46
- //
47
- // TODO (indexzero): Make this configurable for http / https
48
- //
49
- var agent = http . getAgent ( host , port ) ;
47
+ function _getAgent ( host , port , secure ) {
48
+ var agent = ! secure ? http . getAgent ( host , port ) : https . getAgent ( {
49
+ host : host ,
50
+ port : port
51
+ } ) ;
52
+
50
53
agent . maxSockets = maxSockets ;
51
54
return agent ;
52
55
}
53
56
57
+ //
58
+ // ### function _getProtocol (outgoing, https)
59
+ // #### @outgoing {Object} Outgoing request options
60
+ // #### @secure {Object|boolean} Settings for `https`
61
+ // Returns the appropriate protocol based on the settings in
62
+ // `secure`. If the protocol is `https` this function will update
63
+ // the options in `outgoing` as appropriate by adding `ca`, `key`,
64
+ // and `cert` if they exist in `secure`.
65
+ //
66
+ function _getProtocol ( outgoing , secure ) {
67
+ var protocol = secure ? https : http ;
68
+
69
+ if ( typeof secure === 'object' ) {
70
+ [ 'ca' , 'cert' , 'key' ] . forEach ( function ( prop ) {
71
+ if ( secure [ prop ] ) {
72
+ outgoing [ prop ] = secure [ prop ] ;
73
+ }
74
+ } )
75
+ }
76
+
77
+ return protocol ;
78
+ }
79
+
54
80
//
55
81
// ### function getMaxSockets ()
56
82
// Returns the maximum number of sockets
@@ -104,20 +130,34 @@ exports.createServer = function () {
104
130
105
131
proxy = new HttpProxy ( options ) ;
106
132
server = http . createServer ( function ( req , res ) {
107
- proxy . emit ( 'request' , req , res , req . headers . host , req . url ) ;
108
-
109
- // If we were passed a callback to process the request
110
- // or response in some way, then call it.
111
133
if ( callback ) {
134
+ //
135
+ // If we were passed a callback to process the request
136
+ // or response in some way, then call it.
137
+ //
112
138
callback ( req , res , proxy ) ;
113
139
}
114
140
else if ( port && host ) {
115
- proxy . proxyRequest ( req , res , port , host ) ;
141
+ //
142
+ // If we have a target host and port for the request
143
+ // then proxy to the specified location.
144
+ //
145
+ proxy . proxyRequest ( req , res , {
146
+ port : port ,
147
+ host : host
148
+ } ) ;
116
149
}
117
150
else if ( proxy . proxyTable ) {
151
+ //
152
+ // If the proxy is configured with a ProxyTable
153
+ // instance then use that before failing.
154
+ //
118
155
proxy . proxyRequest ( req , res ) ;
119
156
}
120
157
else {
158
+ //
159
+ // Otherwise this server is improperly configured.
160
+ //
121
161
throw new Error ( 'Cannot proxy without port, host, or router.' )
122
162
}
123
163
} ) ;
@@ -136,10 +176,19 @@ exports.createServer = function () {
136
176
server . on ( 'upgrade' , function ( req , socket , head ) {
137
177
// Tunnel websocket requests too
138
178
139
- proxy . proxyWebSocketRequest ( req , socket , head , port , host ) ;
179
+ proxy . proxyWebSocketRequest ( req , socket , head , {
180
+ port : port ,
181
+ host : host
182
+ } ) ;
140
183
} ) ;
141
184
}
142
-
185
+
186
+ //
187
+ // Set the proxy on the server so it is available
188
+ // to the consumer of the server
189
+ //
190
+ server . proxy = proxy ;
191
+
143
192
return server ;
144
193
} ;
145
194
@@ -165,11 +214,12 @@ exports.createServer = function () {
165
214
var HttpProxy = exports . HttpProxy = function ( options ) {
166
215
events . EventEmitter . call ( this ) ;
167
216
168
- options = options || { } ;
169
- this . options = options ;
217
+ var self = this ;
218
+ options = options || { } ;
219
+ this . forward = options . forward ;
220
+ this . https = options . https ;
170
221
171
222
if ( options . router ) {
172
- var self = this ;
173
223
this . proxyTable = new ProxyTable ( options . router , options . silent , options . hostnameOnly ) ;
174
224
this . proxyTable . on ( 'routes' , function ( routes ) {
175
225
self . emit ( 'routes' , routes ) ;
@@ -196,7 +246,7 @@ util.inherits(HttpProxy, events.EventEmitter);
196
246
//
197
247
// __Attribution:__ This approach is based heavily on
198
248
// [Connect](https://github.com/senchalabs/connect/blob/master/lib/utils.js#L157).
199
- // However, this is not a big leap from the implementation in node-http-proxy < 0.4.0.
249
+ // However, this is not a big leap from the implementation in node-http-proxy < 0.4.0.
200
250
// This simply chooses to manage the scope of the events on a new Object literal as opposed to
201
251
// [on the HttpProxy instance](https://github.com/nodejitsu/node-http-proxy/blob/v0.3.1/lib/node-http-proxy.js#L154).
202
252
//
@@ -238,20 +288,25 @@ HttpProxy.prototype.close = function () {
238
288
// ### function proxyRequest (req, res, [port, host, paused])
239
289
// #### @req {ServerRequest} Incoming HTTP Request to proxy.
240
290
// #### @res {ServerResponse} Outgoing HTTP Request to write proxied data to.
241
- // #### @port {number} **Optional** Port to use on the proxy target host.
242
- // #### @host {string} **Optional** Host of the proxy target.
243
- // #### @buffer {Object} **Optional** Result from `httpProxy.buffer(req)`
291
+ // #### @options {Object} Options for the outgoing proxy request.
292
+ // options.port {number} Port to use on the proxy target host.
293
+ // options.host {string} Host of the proxy target.
294
+ // options.buffer {Object} Result from `httpProxy.buffer(req)`
295
+ // options.https {Object|boolean} Settings for https.
244
296
//
245
- HttpProxy . prototype . proxyRequest = function ( req , res , port , host , buffer ) {
246
- var self = this , reverseProxy , location , errState = false , opts ;
297
+ HttpProxy . prototype . proxyRequest = function ( req , res , options ) {
298
+ var self = this , errState = false , location , outgoing , protocol , reverseProxy ;
299
+
300
+ // Create an empty options hash if none is passed.
301
+ options = options || { } ;
247
302
248
303
//
249
304
// Check the proxy table for this instance to see if we need
250
305
// to get the proxy location for the request supplied. We will
251
306
// always ignore the proxyTable if an explicit `port` and `host`
252
307
// arguments are supplied to `proxyRequest`.
253
308
//
254
- if ( this . proxyTable && ! host ) {
309
+ if ( this . proxyTable && ! options . host ) {
255
310
location = this . proxyTable . getProxyLocation ( req ) ;
256
311
257
312
//
@@ -267,13 +322,12 @@ HttpProxy.prototype.proxyRequest = function (req, res, port, host, buffer) {
267
322
// When using the ProxyTable in conjunction with an HttpProxy instance
268
323
// only the following arguments are valid:
269
324
//
270
- // * `proxy.proxyRequest(req, res, port, host, buffer )`: This will be skipped
271
- // * `proxy.proxyRequest(req, res, buffer)`: Buffer will get updated appropriately
272
- // * `proxy.proxyRequest(req, res)`: No effect `undefined = undefined`
325
+ // * `proxy.proxyRequest(req, res, { host: 'localhost' } )`: This will be skipped
326
+ // * `proxy.proxyRequest(req, res, { buffer: buffer } )`: Buffer will get updated appropriately
327
+ // * `proxy.proxyRequest(req, res)`: Options will be assigned appropriately.
273
328
//
274
- buffer = port ;
275
- port = location . port ;
276
- host = location . host ;
329
+ options . port = location . port ;
330
+ options . host = location . host ;
277
331
}
278
332
279
333
//
@@ -284,14 +338,14 @@ HttpProxy.prototype.proxyRequest = function (req, res, port, host, buffer) {
284
338
//
285
339
// Emit the `start` event indicating that we have begun the proxy operation.
286
340
//
287
- this . emit ( 'start' , req , res , host , port ) ;
341
+ this . emit ( 'start' , req , res , options ) ;
288
342
289
343
//
290
344
// If forwarding is enabled for this instance, foward proxy the
291
- // specified request to the address provided in `this.options. forward`
345
+ // specified request to the address provided in `this.forward`
292
346
//
293
- if ( this . options . forward ) {
294
- this . emit ( 'forward' , req , res , this . options . forward . host , this . options . forward . port ) ;
347
+ if ( this . forward ) {
348
+ this . emit ( 'forward' , req , res , this . forward ) ;
295
349
this . _forwardRequest ( req ) ;
296
350
}
297
351
@@ -312,21 +366,23 @@ HttpProxy.prototype.proxyRequest = function (req, res, port, host, buffer) {
312
366
res . end ( ) ;
313
367
}
314
368
315
- var opts = {
316
- host : host ,
317
- port : port ,
318
- agent : _getAgent ( host , port ) ,
369
+ outgoing = {
370
+ host : options . host ,
371
+ port : options . port ,
372
+ agent : _getAgent ( options . host , options . port , options . https || this . https ) ,
319
373
method : req . method ,
320
374
path : req . url ,
321
375
headers : req . headers
322
376
} ;
323
377
324
378
// Force the `connection` header to be 'close' until
325
379
// node.js core re-implements 'keep-alive'.
326
- opts . headers [ 'connection' ] = 'close' ;
380
+ outgoing . headers [ 'connection' ] = 'close' ;
381
+
382
+ protocol = _getProtocol ( outgoing , options . https || this . https ) ;
327
383
328
384
// Open new HTTP request to internal resource with will act as a reverse proxy pass
329
- reverseProxy = http . request ( opts , function ( response ) {
385
+ reverseProxy = protocol . request ( outgoing , function ( response ) {
330
386
331
387
// Process the `reverseProxy` `response` when it's received.
332
388
if ( response . headers . connection ) {
@@ -388,38 +444,40 @@ HttpProxy.prototype.proxyRequest = function (req, res, port, host, buffer) {
388
444
} ) ;
389
445
390
446
// If we have been passed buffered data, resume it.
391
- if ( buffer && ! errState ) {
392
- buffer . resume ( ) ;
447
+ if ( options . buffer && ! errState ) {
448
+ options . buffer . resume ( ) ;
393
449
}
394
450
} ;
395
451
396
452
//
397
453
// ### @private function _forwardRequest (req)
398
454
// #### @req {ServerRequest} Incoming HTTP Request to proxy.
399
455
// Forwards the specified `req` to the location specified
400
- // by `this.options. forward` ignoring errors and the subsequent response.
456
+ // by `this.forward` ignoring errors and the subsequent response.
401
457
//
402
458
HttpProxy . prototype . _forwardRequest = function ( req ) {
403
- var self = this , port , host , forwardProxy , opts ;
459
+ var self = this , port , host , outgoing , protocol , forwardProxy ;
404
460
405
- port = this . options . forward . port ;
406
- host = this . options . forward . host ;
461
+ port = this . forward . port ;
462
+ host = this . forward . host ;
407
463
408
- opts = {
464
+ outgoing = {
409
465
host : host ,
410
466
port : port ,
411
- agent : _getAgent ( host , port ) ,
467
+ agent : _getAgent ( host , port , this . forward . https ) ,
412
468
method : req . method ,
413
469
path : req . url ,
414
470
headers : req . headers
415
471
} ;
416
472
417
473
// Force the `connection` header to be 'close' until
418
474
// node.js core re-implements 'keep-alive'.
419
- opts . headers [ 'connection' ] = 'close' ;
475
+ outgoing . headers [ 'connection' ] = 'close' ;
476
+
477
+ protocol = _getProtocol ( outgoing , this . forward . https ) ;
420
478
421
479
// Open new HTTP request to internal resource with will act as a reverse proxy pass
422
- forwardProxy = http . request ( opts , function ( response ) {
480
+ forwardProxy = protocol . request ( outgoing , function ( response ) {
423
481
//
424
482
// Ignore the response from the forward proxy since this is a 'fire-and-forget' proxy.
425
483
// Remark (indexzero): We will eventually emit a 'forward' event here for performance tuning.
@@ -444,8 +502,8 @@ HttpProxy.prototype._forwardRequest = function (req) {
444
502
} ) ;
445
503
} ;
446
504
447
- HttpProxy . prototype . proxyWebSocketRequest = function ( req , socket , head , port , host , buffer ) {
448
- var self = this , CRLF = '\r\n' ;
505
+ HttpProxy . prototype . proxyWebSocketRequest = function ( req , socket , head , options ) {
506
+ var self = this , outgoing , errState = false , CRLF = '\r\n' ;
449
507
450
508
// WebSocket requests has method = GET
451
509
if ( req . method !== 'GET' || req . headers . upgrade . toLowerCase ( ) !== 'websocket' ) {
@@ -519,24 +577,24 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, port, h
519
577
_socket ( socket ) ;
520
578
521
579
// Remote host address
522
- var remoteHost = host + ( port - 80 === 0 ? '' : ':' + port ) ,
523
- agent = _getAgent ( host , port ) ;
580
+ var agent = _getAgent ( options . host , options . port ) ,
581
+ remoteHost = options . host + ( options . port - 80 === 0 ? '' : ':' + options . port ) ;
524
582
525
583
// Change headers
526
- req . headers . host = remoteHost ;
527
- req . headers . origin = 'http://' + host ;
584
+ req . headers . host = remoteHost ;
585
+ req . headers . origin = 'http://' + options . host ;
528
586
529
- var opts = {
530
- host : host ,
531
- port : port ,
587
+ outgoing = {
588
+ host : options . host ,
589
+ port : options . port ,
532
590
agent : agent ,
533
591
method : 'GET' ,
534
592
path : req . url ,
535
593
headers : req . headers
536
- }
594
+ } ;
537
595
538
596
// Make the outgoing WebSocket request
539
- var request = http . request ( opts , function ( ) { } ) ;
597
+ var request = http . request ( outgoing , function ( ) { } ) ;
540
598
541
599
// Not disconnect on update
542
600
agent . on ( 'upgrade' , function ( request , remoteSocket , head ) {
@@ -567,8 +625,8 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, port, h
567
625
data = data . slice ( Buffer . byteLength ( sdata ) , data . length ) ;
568
626
569
627
// Replace host and origin
570
- sdata = sdata . replace ( remoteHost , host )
571
- . replace ( remoteHost , host ) ;
628
+ sdata = sdata . replace ( remoteHost , options . host )
629
+ . replace ( remoteHost , options . host ) ;
572
630
573
631
try {
574
632
// Write printable
@@ -602,7 +660,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, port, h
602
660
}
603
661
604
662
// If we have been passed buffered data, resume it.
605
- if ( buffer && ! errState ) {
606
- buffer . resume ( ) ;
663
+ if ( options . buffer && ! errState ) {
664
+ options . buffer . resume ( ) ;
607
665
}
608
666
} ;
0 commit comments