@@ -56,12 +56,14 @@ var HttpProxy = exports.HttpProxy = require('./node-http-proxy/http-proxy'
56
56
//
57
57
exports . createServer = function ( ) {
58
58
var args = Array . prototype . slice . call ( arguments ) ,
59
+ handlers = [ ] ,
59
60
options = { } ,
60
- host , port ,
61
- server , proxy ,
62
- callback ,
61
+ message ,
63
62
handler ,
64
- silent ;
63
+ server ,
64
+ proxy ,
65
+ host ,
66
+ port ;
65
67
66
68
//
67
69
// Liberally parse arguments of the form:
@@ -75,18 +77,50 @@ exports.createServer = function () {
75
77
case 'string' : host = arg ; break ;
76
78
case 'number' : port = arg ; break ;
77
79
case 'object' : options = arg || { } ; break ;
78
- case 'function' : callback = arg ; break ;
80
+ case 'function' : handlers . push ( arg ) ; break ;
79
81
} ;
80
82
} ) ;
81
83
82
- if ( ! host && ! port && ! options ) {
84
+ //
85
+ // Helper function to create intelligent error message(s)
86
+ // for the very liberal arguments parsing performed by
87
+ // `require('http-proxy').createServer()`.
88
+ //
89
+ function validArguments ( ) {
90
+ var conditions = {
91
+ 'port and host' : function ( ) {
92
+ return port && host ;
93
+ } ,
94
+ 'options.target or options.router' : function ( ) {
95
+ return options && ( options . router ||
96
+ ( options . target && options . target . host && options . target . port ) ) ;
97
+ } ,
98
+ 'or proxy handlers' : function ( ) {
99
+ return handlers && handlers . length ;
100
+ }
101
+ }
102
+
103
+ var missing = Object . keys ( conditions ) . filter ( function ( name ) {
104
+ return ! conditions [ name ] ( ) ;
105
+ } ) ;
106
+
107
+ if ( missing . length === 3 ) {
108
+ message = 'Cannot proxy without ' + missing . join ( ', ' ) ;
109
+ return false ;
110
+ }
111
+
112
+ return true ;
113
+ }
114
+
115
+ if ( ! validArguments ( ) ) {
83
116
//
84
- // If `host`, `port` and `options` are all not passed, then
85
- // this server is improperly configured.
117
+ // If `host`, `port` and `options` are all not passed (with valid
118
+ // options) then this server is improperly configured.
86
119
//
87
- throw new Error ( 'Cannot proxy without port, host, or router.' )
120
+ throw new Error ( message ) ;
121
+ return ;
88
122
}
89
-
123
+
90
124
//
91
125
// Hoist up any explicit `host` or `port` arguments
92
126
// that have been passed in to the options we will
@@ -96,28 +130,57 @@ exports.createServer = function () {
96
130
options . target . port = options . target . port || port ;
97
131
options . target . host = options . target . host || host ;
98
132
133
+ if ( options . target && options . target . host && options . target . port ) {
134
+ //
135
+ // If an explicit `host` and `port` combination has been passed
136
+ // to `.createServer()` then instantiate a hot-path optimized
137
+ // `HttpProxy` object and add the "proxy" middleware layer.
138
+ //
139
+ proxy = new HttpProxy ( options ) ;
140
+ handlers . push ( function ( req , res ) {
141
+ proxy . proxyRequest ( req , res ) ;
142
+ } ) ;
143
+ }
144
+ else {
145
+ //
146
+ // If no explicit `host` or `port` combination has been passed then
147
+ // we have to assume that this is a "go-anywhere" Proxy (i.e. a `RoutingProxy`).
148
+ //
149
+ proxy = new RoutingProxy ( options ) ;
150
+
151
+ if ( options . router ) {
152
+ //
153
+ // If a routing table has been supplied than we assume
154
+ // the user intends us to add the "proxy" middleware layer
155
+ // for them
156
+ //
157
+ handlers . push ( function ( req , res ) {
158
+ proxy . proxyRequest ( req , res ) ;
159
+ } ) ;
160
+
161
+ proxy . on ( 'routes' , function ( routes ) {
162
+ server . emit ( 'routes' , routes ) ;
163
+ } ) ;
164
+ }
165
+ }
166
+
99
167
//
100
168
// Create the `http[s].Server` instance which will use
101
169
// an instance of `httpProxy.HttpProxy`.
102
170
//
103
- proxy = new HttpProxy ( options ) ;
104
- handler = callback
105
- ? function ( req , res ) { callback ( req , res , proxy ) }
106
- : function ( req , res ) { proxy . proxyRequest ( req , res ) } ;
171
+ handler = handlers . length > 1
172
+ ? exports . stack ( handlers , proxy )
173
+ : function ( req , res ) { handlers [ 0 ] ( req , res , proxy ) } ;
107
174
108
175
server = options . https
109
176
? https . createServer ( options . https , handler )
110
177
: http . createServer ( handler ) ;
111
178
112
- //server.on('close', function () {
113
- // proxy.close();
114
- //});
115
-
116
- proxy . on ( 'routes' , function ( routes ) {
117
- server . emit ( 'routes' , routes ) ;
179
+ server . on ( 'close' , function ( ) {
180
+ proxy . close ( ) ;
118
181
} ) ;
119
182
120
- if ( ! callback ) {
183
+ if ( handlers . length <= 1 ) {
121
184
//
122
185
// If an explicit callback has not been supplied then
123
186
// automagically proxy the request using the `HttpProxy`
@@ -213,6 +276,13 @@ exports.setMaxSockets = function (value) {
213
276
214
277
//
215
278
// ### function stack (middlewares, proxy)
279
+ // #### @middlewares {Array} Array of functions to stack.
280
+ // #### @proxy {HttpProxy|RoutingProxy} Proxy instance to
281
+ // Iteratively build up a single handler to the `http.Server`
282
+ // `request` event (i.e. `function (req, res)`) by wrapping
283
+ // each middleware `layer` into a `child` middleware which
284
+ // is in invoked by the parent (i.e. predecessor in the Array).
285
+ //
216
286
// adapted from https://github.com/creationix/stack
217
287
//
218
288
exports . stack = function stack ( middlewares , proxy ) {
@@ -235,9 +305,18 @@ exports.stack = function stack (middlewares, proxy) {
235
305
return ;
236
306
}
237
307
238
- child ( req , res ) ;
239
- }
308
+ if ( child ) {
309
+ child ( req , res ) ;
310
+ }
311
+ } ;
240
312
313
+ //
314
+ // Set the prototype of the `next` function to the instance
315
+ // of the `proxy` so that in can be used interchangably from
316
+ // a `connect` style callback and a true `HttpProxy` object.
317
+ //
318
+ // e.g. `function (req, res, next)` vs. `function (req, res, proxy)`
319
+ //
241
320
next . __proto__ = proxy ;
242
321
layer ( req , res , next ) ;
243
322
} ;
0 commit comments