2626
2727var util = require ( 'util' ) ,
2828 http = require ( 'http' ) ,
29+ https = require ( 'https' ) ,
2930 events = require ( 'events' ) ,
3031 ProxyTable = require ( './proxy-table' ) . ProxyTable ,
3132 maxSockets = 100 ;
@@ -36,21 +37,46 @@ var util = require('util'),
3637exports . version = [ 0 , 4 , 2 ] ;
3738
3839//
39- // ### function _getAgent (host, port)
40+ // ### function _getAgent (host, port, secure )
4041// #### @host {string} Host of the agent to get
4142// #### @port {number} Port of the agent to get
43+ // #### @secure {boolean} Value indicating whether or not to use HTTPS
4244// Retreives an agent from the `http` module
4345// and sets the `maxSockets` property appropriately.
4446//
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+
5053 agent . maxSockets = maxSockets ;
5154 return agent ;
5255}
5356
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+
5480//
5581// ### function getMaxSockets ()
5682// Returns the maximum number of sockets
@@ -104,20 +130,34 @@ exports.createServer = function () {
104130
105131 proxy = new HttpProxy ( options ) ;
106132 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.
111133 if ( callback ) {
134+ //
135+ // If we were passed a callback to process the request
136+ // or response in some way, then call it.
137+ //
112138 callback ( req , res , proxy ) ;
113139 }
114140 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+ } ) ;
116149 }
117150 else if ( proxy . proxyTable ) {
151+ //
152+ // If the proxy is configured with a ProxyTable
153+ // instance then use that before failing.
154+ //
118155 proxy . proxyRequest ( req , res ) ;
119156 }
120157 else {
158+ //
159+ // Otherwise this server is improperly configured.
160+ //
121161 throw new Error ( 'Cannot proxy without port, host, or router.' )
122162 }
123163 } ) ;
@@ -136,10 +176,19 @@ exports.createServer = function () {
136176 server . on ( 'upgrade' , function ( req , socket , head ) {
137177 // Tunnel websocket requests too
138178
139- proxy . proxyWebSocketRequest ( req , socket , head , port , host ) ;
179+ proxy . proxyWebSocketRequest ( req , socket , head , {
180+ port : port ,
181+ host : host
182+ } ) ;
140183 } ) ;
141184 }
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+
143192 return server ;
144193} ;
145194
@@ -165,11 +214,12 @@ exports.createServer = function () {
165214var HttpProxy = exports . HttpProxy = function ( options ) {
166215 events . EventEmitter . call ( this ) ;
167216
168- options = options || { } ;
169- this . options = options ;
217+ var self = this ;
218+ options = options || { } ;
219+ this . forward = options . forward ;
220+ this . https = options . https ;
170221
171222 if ( options . router ) {
172- var self = this ;
173223 this . proxyTable = new ProxyTable ( options . router , options . silent , options . hostnameOnly ) ;
174224 this . proxyTable . on ( 'routes' , function ( routes ) {
175225 self . emit ( 'routes' , routes ) ;
@@ -196,7 +246,7 @@ util.inherits(HttpProxy, events.EventEmitter);
196246//
197247// __Attribution:__ This approach is based heavily on
198248// [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.
200250// This simply chooses to manage the scope of the events on a new Object literal as opposed to
201251// [on the HttpProxy instance](https://github.com/nodejitsu/node-http-proxy/blob/v0.3.1/lib/node-http-proxy.js#L154).
202252//
@@ -238,20 +288,25 @@ HttpProxy.prototype.close = function () {
238288// ### function proxyRequest (req, res, [port, host, paused])
239289// #### @req {ServerRequest} Incoming HTTP Request to proxy.
240290// #### @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.
244296//
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 || { } ;
247302
248303 //
249304 // Check the proxy table for this instance to see if we need
250305 // to get the proxy location for the request supplied. We will
251306 // always ignore the proxyTable if an explicit `port` and `host`
252307 // arguments are supplied to `proxyRequest`.
253308 //
254- if ( this . proxyTable && ! host ) {
309+ if ( this . proxyTable && ! options . host ) {
255310 location = this . proxyTable . getProxyLocation ( req ) ;
256311
257312 //
@@ -267,13 +322,12 @@ HttpProxy.prototype.proxyRequest = function (req, res, port, host, buffer) {
267322 // When using the ProxyTable in conjunction with an HttpProxy instance
268323 // only the following arguments are valid:
269324 //
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.
273328 //
274- buffer = port ;
275- port = location . port ;
276- host = location . host ;
329+ options . port = location . port ;
330+ options . host = location . host ;
277331 }
278332
279333 //
@@ -284,14 +338,14 @@ HttpProxy.prototype.proxyRequest = function (req, res, port, host, buffer) {
284338 //
285339 // Emit the `start` event indicating that we have begun the proxy operation.
286340 //
287- this . emit ( 'start' , req , res , host , port ) ;
341+ this . emit ( 'start' , req , res , options ) ;
288342
289343 //
290344 // 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`
292346 //
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 ) ;
295349 this . _forwardRequest ( req ) ;
296350 }
297351
@@ -312,21 +366,23 @@ HttpProxy.prototype.proxyRequest = function (req, res, port, host, buffer) {
312366 res . end ( ) ;
313367 }
314368
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 ) ,
319373 method : req . method ,
320374 path : req . url ,
321375 headers : req . headers
322376 } ;
323377
324378 // Force the `connection` header to be 'close' until
325379 // 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 ) ;
327383
328384 // 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 ) {
330386
331387 // Process the `reverseProxy` `response` when it's received.
332388 if ( response . headers . connection ) {
@@ -388,38 +444,40 @@ HttpProxy.prototype.proxyRequest = function (req, res, port, host, buffer) {
388444 } ) ;
389445
390446 // 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 ( ) ;
393449 }
394450} ;
395451
396452//
397453// ### @private function _forwardRequest (req)
398454// #### @req {ServerRequest} Incoming HTTP Request to proxy.
399455// 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.
401457//
402458HttpProxy . prototype . _forwardRequest = function ( req ) {
403- var self = this , port , host , forwardProxy , opts ;
459+ var self = this , port , host , outgoing , protocol , forwardProxy ;
404460
405- port = this . options . forward . port ;
406- host = this . options . forward . host ;
461+ port = this . forward . port ;
462+ host = this . forward . host ;
407463
408- opts = {
464+ outgoing = {
409465 host : host ,
410466 port : port ,
411- agent : _getAgent ( host , port ) ,
467+ agent : _getAgent ( host , port , this . forward . https ) ,
412468 method : req . method ,
413469 path : req . url ,
414470 headers : req . headers
415471 } ;
416472
417473 // Force the `connection` header to be 'close' until
418474 // 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 ) ;
420478
421479 // 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 ) {
423481 //
424482 // Ignore the response from the forward proxy since this is a 'fire-and-forget' proxy.
425483 // Remark (indexzero): We will eventually emit a 'forward' event here for performance tuning.
@@ -444,8 +502,8 @@ HttpProxy.prototype._forwardRequest = function (req) {
444502 } ) ;
445503} ;
446504
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' ;
449507
450508 // WebSocket requests has method = GET
451509 if ( req . method !== 'GET' || req . headers . upgrade . toLowerCase ( ) !== 'websocket' ) {
@@ -519,24 +577,24 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, port, h
519577 _socket ( socket ) ;
520578
521579 // 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 ) ;
524582
525583 // 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 ;
528586
529- var opts = {
530- host : host ,
531- port : port ,
587+ outgoing = {
588+ host : options . host ,
589+ port : options . port ,
532590 agent : agent ,
533591 method : 'GET' ,
534592 path : req . url ,
535593 headers : req . headers
536- }
594+ } ;
537595
538596 // Make the outgoing WebSocket request
539- var request = http . request ( opts , function ( ) { } ) ;
597+ var request = http . request ( outgoing , function ( ) { } ) ;
540598
541599 // Not disconnect on update
542600 agent . on ( 'upgrade' , function ( request , remoteSocket , head ) {
@@ -567,8 +625,8 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, port, h
567625 data = data . slice ( Buffer . byteLength ( sdata ) , data . length ) ;
568626
569627 // 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 ) ;
572630
573631 try {
574632 // Write printable
@@ -602,7 +660,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, port, h
602660 }
603661
604662 // 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 ( ) ;
607665 }
608666} ;
0 commit comments