rc@73
|
1 /**
|
rc@73
|
2 * Module dependencies.
|
rc@73
|
3 */
|
rc@73
|
4
|
rc@73
|
5 var mixin = require('utils-merge');
|
rc@73
|
6 var escapeHtml = require('escape-html');
|
rc@73
|
7 var Router = require('./router');
|
rc@73
|
8 var methods = require('methods');
|
rc@73
|
9 var middleware = require('./middleware/init');
|
rc@73
|
10 var query = require('./middleware/query');
|
rc@73
|
11 var debug = require('debug')('express:application');
|
rc@73
|
12 var View = require('./view');
|
rc@73
|
13 var http = require('http');
|
rc@73
|
14 var compileETag = require('./utils').compileETag;
|
rc@73
|
15 var compileTrust = require('./utils').compileTrust;
|
rc@73
|
16 var deprecate = require('./utils').deprecate;
|
rc@73
|
17 var resolve = require('path').resolve;
|
rc@73
|
18
|
rc@73
|
19 /**
|
rc@73
|
20 * Application prototype.
|
rc@73
|
21 */
|
rc@73
|
22
|
rc@73
|
23 var app = exports = module.exports = {};
|
rc@73
|
24
|
rc@73
|
25 /**
|
rc@73
|
26 * Initialize the server.
|
rc@73
|
27 *
|
rc@73
|
28 * - setup default configuration
|
rc@73
|
29 * - setup default middleware
|
rc@73
|
30 * - setup route reflection methods
|
rc@73
|
31 *
|
rc@73
|
32 * @api private
|
rc@73
|
33 */
|
rc@73
|
34
|
rc@73
|
35 app.init = function(){
|
rc@73
|
36 this.cache = {};
|
rc@73
|
37 this.settings = {};
|
rc@73
|
38 this.engines = {};
|
rc@73
|
39 this.defaultConfiguration();
|
rc@73
|
40 };
|
rc@73
|
41
|
rc@73
|
42 /**
|
rc@73
|
43 * Initialize application configuration.
|
rc@73
|
44 *
|
rc@73
|
45 * @api private
|
rc@73
|
46 */
|
rc@73
|
47
|
rc@73
|
48 app.defaultConfiguration = function(){
|
rc@73
|
49 // default settings
|
rc@73
|
50 this.enable('x-powered-by');
|
rc@73
|
51 this.set('etag', 'weak');
|
rc@73
|
52 var env = process.env.NODE_ENV || 'development';
|
rc@73
|
53 this.set('env', env);
|
rc@73
|
54 this.set('subdomain offset', 2);
|
rc@73
|
55 this.set('trust proxy', false);
|
rc@73
|
56
|
rc@73
|
57 debug('booting in %s mode', env);
|
rc@73
|
58
|
rc@73
|
59 // inherit protos
|
rc@73
|
60 this.on('mount', function(parent){
|
rc@73
|
61 this.request.__proto__ = parent.request;
|
rc@73
|
62 this.response.__proto__ = parent.response;
|
rc@73
|
63 this.engines.__proto__ = parent.engines;
|
rc@73
|
64 this.settings.__proto__ = parent.settings;
|
rc@73
|
65 });
|
rc@73
|
66
|
rc@73
|
67 // setup locals
|
rc@73
|
68 this.locals = Object.create(null);
|
rc@73
|
69
|
rc@73
|
70 // top-most app is mounted at /
|
rc@73
|
71 this.mountpath = '/';
|
rc@73
|
72
|
rc@73
|
73 // default locals
|
rc@73
|
74 this.locals.settings = this.settings;
|
rc@73
|
75
|
rc@73
|
76 // default configuration
|
rc@73
|
77 this.set('view', View);
|
rc@73
|
78 this.set('views', resolve('views'));
|
rc@73
|
79 this.set('jsonp callback name', 'callback');
|
rc@73
|
80
|
rc@73
|
81 if (env === 'production') {
|
rc@73
|
82 this.enable('view cache');
|
rc@73
|
83 }
|
rc@73
|
84
|
rc@73
|
85 Object.defineProperty(this, 'router', {
|
rc@73
|
86 get: function() {
|
rc@73
|
87 throw new Error('\'app.router\' is deprecated!\nPlease see the 3.x to 4.x migration guide for details on how to update your app.');
|
rc@73
|
88 }
|
rc@73
|
89 });
|
rc@73
|
90 };
|
rc@73
|
91
|
rc@73
|
92 /**
|
rc@73
|
93 * lazily adds the base router if it has not yet been added.
|
rc@73
|
94 *
|
rc@73
|
95 * We cannot add the base router in the defaultConfiguration because
|
rc@73
|
96 * it reads app settings which might be set after that has run.
|
rc@73
|
97 *
|
rc@73
|
98 * @api private
|
rc@73
|
99 */
|
rc@73
|
100 app.lazyrouter = function() {
|
rc@73
|
101 if (!this._router) {
|
rc@73
|
102 this._router = new Router({
|
rc@73
|
103 caseSensitive: this.enabled('case sensitive routing'),
|
rc@73
|
104 strict: this.enabled('strict routing')
|
rc@73
|
105 });
|
rc@73
|
106
|
rc@73
|
107 this._router.use(query());
|
rc@73
|
108 this._router.use(middleware.init(this));
|
rc@73
|
109 }
|
rc@73
|
110 };
|
rc@73
|
111
|
rc@73
|
112 /**
|
rc@73
|
113 * Dispatch a req, res pair into the application. Starts pipeline processing.
|
rc@73
|
114 *
|
rc@73
|
115 * If no _done_ callback is provided, then default error handlers will respond
|
rc@73
|
116 * in the event of an error bubbling through the stack.
|
rc@73
|
117 *
|
rc@73
|
118 * @api private
|
rc@73
|
119 */
|
rc@73
|
120
|
rc@73
|
121 app.handle = function(req, res, done) {
|
rc@73
|
122 var env = this.get('env');
|
rc@73
|
123
|
rc@73
|
124 this._router.handle(req, res, function(err) {
|
rc@73
|
125 if (done) {
|
rc@73
|
126 return done(err);
|
rc@73
|
127 }
|
rc@73
|
128
|
rc@73
|
129 // unhandled error
|
rc@73
|
130 if (err) {
|
rc@73
|
131 // default to 500
|
rc@73
|
132 if (res.statusCode < 400) res.statusCode = 500;
|
rc@73
|
133 debug('default %s', res.statusCode);
|
rc@73
|
134
|
rc@73
|
135 // respect err.status
|
rc@73
|
136 if (err.status) res.statusCode = err.status;
|
rc@73
|
137
|
rc@73
|
138 // production gets a basic error message
|
rc@73
|
139 var msg = 'production' == env
|
rc@73
|
140 ? http.STATUS_CODES[res.statusCode]
|
rc@73
|
141 : err.stack || err.toString();
|
rc@73
|
142 msg = escapeHtml(msg);
|
rc@73
|
143
|
rc@73
|
144 // log to stderr in a non-test env
|
rc@73
|
145 if ('test' != env) console.error(err.stack || err.toString());
|
rc@73
|
146 if (res.headersSent) return req.socket.destroy();
|
rc@73
|
147 res.setHeader('Content-Type', 'text/html');
|
rc@73
|
148 res.setHeader('Content-Length', Buffer.byteLength(msg));
|
rc@73
|
149 if ('HEAD' == req.method) return res.end();
|
rc@73
|
150 res.end(msg);
|
rc@73
|
151 return;
|
rc@73
|
152 }
|
rc@73
|
153
|
rc@73
|
154 // 404
|
rc@73
|
155 debug('default 404');
|
rc@73
|
156 res.statusCode = 404;
|
rc@73
|
157 res.setHeader('Content-Type', 'text/html');
|
rc@73
|
158 if ('HEAD' == req.method) return res.end();
|
rc@73
|
159 res.end('Cannot ' + escapeHtml(req.method) + ' ' + escapeHtml(req.originalUrl) + '\n');
|
rc@73
|
160 });
|
rc@73
|
161 };
|
rc@73
|
162
|
rc@73
|
163 /**
|
rc@73
|
164 * Proxy `Router#use()` to add middleware to the app router.
|
rc@73
|
165 * See Router#use() documentation for details.
|
rc@73
|
166 *
|
rc@73
|
167 * If the _fn_ parameter is an express app, then it will be
|
rc@73
|
168 * mounted at the _route_ specified.
|
rc@73
|
169 *
|
rc@73
|
170 * @api public
|
rc@73
|
171 */
|
rc@73
|
172
|
rc@73
|
173 app.use = function(route, fn){
|
rc@73
|
174 var mount_app;
|
rc@73
|
175
|
rc@73
|
176 // default route to '/'
|
rc@73
|
177 if ('string' != typeof route) fn = route, route = '/';
|
rc@73
|
178
|
rc@73
|
179 // express app
|
rc@73
|
180 if (fn.handle && fn.set) mount_app = fn;
|
rc@73
|
181
|
rc@73
|
182 // restore .app property on req and res
|
rc@73
|
183 if (mount_app) {
|
rc@73
|
184 debug('.use app under %s', route);
|
rc@73
|
185 mount_app.mountpath = route;
|
rc@73
|
186 fn = function(req, res, next) {
|
rc@73
|
187 var orig = req.app;
|
rc@73
|
188 mount_app.handle(req, res, function(err) {
|
rc@73
|
189 req.__proto__ = orig.request;
|
rc@73
|
190 res.__proto__ = orig.response;
|
rc@73
|
191 next(err);
|
rc@73
|
192 });
|
rc@73
|
193 };
|
rc@73
|
194 }
|
rc@73
|
195
|
rc@73
|
196 this.lazyrouter();
|
rc@73
|
197 this._router.use(route, fn);
|
rc@73
|
198
|
rc@73
|
199 // mounted an app
|
rc@73
|
200 if (mount_app) {
|
rc@73
|
201 mount_app.parent = this;
|
rc@73
|
202 mount_app.emit('mount', this);
|
rc@73
|
203 }
|
rc@73
|
204
|
rc@73
|
205 return this;
|
rc@73
|
206 };
|
rc@73
|
207
|
rc@73
|
208 /**
|
rc@73
|
209 * Proxy to the app `Router#route()`
|
rc@73
|
210 * Returns a new `Route` instance for the _path_.
|
rc@73
|
211 *
|
rc@73
|
212 * Routes are isolated middleware stacks for specific paths.
|
rc@73
|
213 * See the Route api docs for details.
|
rc@73
|
214 *
|
rc@73
|
215 * @api public
|
rc@73
|
216 */
|
rc@73
|
217
|
rc@73
|
218 app.route = function(path){
|
rc@73
|
219 this.lazyrouter();
|
rc@73
|
220 return this._router.route(path);
|
rc@73
|
221 };
|
rc@73
|
222
|
rc@73
|
223 /**
|
rc@73
|
224 * Register the given template engine callback `fn`
|
rc@73
|
225 * as `ext`.
|
rc@73
|
226 *
|
rc@73
|
227 * By default will `require()` the engine based on the
|
rc@73
|
228 * file extension. For example if you try to render
|
rc@73
|
229 * a "foo.jade" file Express will invoke the following internally:
|
rc@73
|
230 *
|
rc@73
|
231 * app.engine('jade', require('jade').__express);
|
rc@73
|
232 *
|
rc@73
|
233 * For engines that do not provide `.__express` out of the box,
|
rc@73
|
234 * or if you wish to "map" a different extension to the template engine
|
rc@73
|
235 * you may use this method. For example mapping the EJS template engine to
|
rc@73
|
236 * ".html" files:
|
rc@73
|
237 *
|
rc@73
|
238 * app.engine('html', require('ejs').renderFile);
|
rc@73
|
239 *
|
rc@73
|
240 * In this case EJS provides a `.renderFile()` method with
|
rc@73
|
241 * the same signature that Express expects: `(path, options, callback)`,
|
rc@73
|
242 * though note that it aliases this method as `ejs.__express` internally
|
rc@73
|
243 * so if you're using ".ejs" extensions you dont need to do anything.
|
rc@73
|
244 *
|
rc@73
|
245 * Some template engines do not follow this convention, the
|
rc@73
|
246 * [Consolidate.js](https://github.com/visionmedia/consolidate.js)
|
rc@73
|
247 * library was created to map all of node's popular template
|
rc@73
|
248 * engines to follow this convention, thus allowing them to
|
rc@73
|
249 * work seamlessly within Express.
|
rc@73
|
250 *
|
rc@73
|
251 * @param {String} ext
|
rc@73
|
252 * @param {Function} fn
|
rc@73
|
253 * @return {app} for chaining
|
rc@73
|
254 * @api public
|
rc@73
|
255 */
|
rc@73
|
256
|
rc@73
|
257 app.engine = function(ext, fn){
|
rc@73
|
258 if ('function' != typeof fn) throw new Error('callback function required');
|
rc@73
|
259 if ('.' != ext[0]) ext = '.' + ext;
|
rc@73
|
260 this.engines[ext] = fn;
|
rc@73
|
261 return this;
|
rc@73
|
262 };
|
rc@73
|
263
|
rc@73
|
264 /**
|
rc@73
|
265 * Proxy to `Router#param()` with one added api feature. The _name_ parameter
|
rc@73
|
266 * can be an array of names.
|
rc@73
|
267 *
|
rc@73
|
268 * See the Router#param() docs for more details.
|
rc@73
|
269 *
|
rc@73
|
270 * @param {String|Array} name
|
rc@73
|
271 * @param {Function} fn
|
rc@73
|
272 * @return {app} for chaining
|
rc@73
|
273 * @api public
|
rc@73
|
274 */
|
rc@73
|
275
|
rc@73
|
276 app.param = function(name, fn){
|
rc@73
|
277 var self = this;
|
rc@73
|
278 self.lazyrouter();
|
rc@73
|
279
|
rc@73
|
280 if (Array.isArray(name)) {
|
rc@73
|
281 name.forEach(function(key) {
|
rc@73
|
282 self.param(key, fn);
|
rc@73
|
283 });
|
rc@73
|
284 return this;
|
rc@73
|
285 }
|
rc@73
|
286
|
rc@73
|
287 self._router.param(name, fn);
|
rc@73
|
288 return this;
|
rc@73
|
289 };
|
rc@73
|
290
|
rc@73
|
291 /**
|
rc@73
|
292 * Assign `setting` to `val`, or return `setting`'s value.
|
rc@73
|
293 *
|
rc@73
|
294 * app.set('foo', 'bar');
|
rc@73
|
295 * app.get('foo');
|
rc@73
|
296 * // => "bar"
|
rc@73
|
297 *
|
rc@73
|
298 * Mounted servers inherit their parent server's settings.
|
rc@73
|
299 *
|
rc@73
|
300 * @param {String} setting
|
rc@73
|
301 * @param {*} [val]
|
rc@73
|
302 * @return {Server} for chaining
|
rc@73
|
303 * @api public
|
rc@73
|
304 */
|
rc@73
|
305
|
rc@73
|
306 app.set = function(setting, val){
|
rc@73
|
307 if (arguments.length === 1) {
|
rc@73
|
308 // app.get(setting)
|
rc@73
|
309 return this.settings[setting];
|
rc@73
|
310 }
|
rc@73
|
311
|
rc@73
|
312 // set value
|
rc@73
|
313 this.settings[setting] = val;
|
rc@73
|
314
|
rc@73
|
315 // trigger matched settings
|
rc@73
|
316 switch (setting) {
|
rc@73
|
317 case 'etag':
|
rc@73
|
318 debug('compile etag %s', val);
|
rc@73
|
319 this.set('etag fn', compileETag(val));
|
rc@73
|
320 break;
|
rc@73
|
321 case 'trust proxy':
|
rc@73
|
322 debug('compile trust proxy %s', val);
|
rc@73
|
323 this.set('trust proxy fn', compileTrust(val));
|
rc@73
|
324 break;
|
rc@73
|
325 }
|
rc@73
|
326
|
rc@73
|
327 return this;
|
rc@73
|
328 };
|
rc@73
|
329
|
rc@73
|
330 /**
|
rc@73
|
331 * Return the app's absolute pathname
|
rc@73
|
332 * based on the parent(s) that have
|
rc@73
|
333 * mounted it.
|
rc@73
|
334 *
|
rc@73
|
335 * For example if the application was
|
rc@73
|
336 * mounted as "/admin", which itself
|
rc@73
|
337 * was mounted as "/blog" then the
|
rc@73
|
338 * return value would be "/blog/admin".
|
rc@73
|
339 *
|
rc@73
|
340 * @return {String}
|
rc@73
|
341 * @api private
|
rc@73
|
342 */
|
rc@73
|
343
|
rc@73
|
344 app.path = function(){
|
rc@73
|
345 return this.parent
|
rc@73
|
346 ? this.parent.path() + this.mountpath
|
rc@73
|
347 : '';
|
rc@73
|
348 };
|
rc@73
|
349
|
rc@73
|
350 /**
|
rc@73
|
351 * Check if `setting` is enabled (truthy).
|
rc@73
|
352 *
|
rc@73
|
353 * app.enabled('foo')
|
rc@73
|
354 * // => false
|
rc@73
|
355 *
|
rc@73
|
356 * app.enable('foo')
|
rc@73
|
357 * app.enabled('foo')
|
rc@73
|
358 * // => true
|
rc@73
|
359 *
|
rc@73
|
360 * @param {String} setting
|
rc@73
|
361 * @return {Boolean}
|
rc@73
|
362 * @api public
|
rc@73
|
363 */
|
rc@73
|
364
|
rc@73
|
365 app.enabled = function(setting){
|
rc@73
|
366 return !!this.set(setting);
|
rc@73
|
367 };
|
rc@73
|
368
|
rc@73
|
369 /**
|
rc@73
|
370 * Check if `setting` is disabled.
|
rc@73
|
371 *
|
rc@73
|
372 * app.disabled('foo')
|
rc@73
|
373 * // => true
|
rc@73
|
374 *
|
rc@73
|
375 * app.enable('foo')
|
rc@73
|
376 * app.disabled('foo')
|
rc@73
|
377 * // => false
|
rc@73
|
378 *
|
rc@73
|
379 * @param {String} setting
|
rc@73
|
380 * @return {Boolean}
|
rc@73
|
381 * @api public
|
rc@73
|
382 */
|
rc@73
|
383
|
rc@73
|
384 app.disabled = function(setting){
|
rc@73
|
385 return !this.set(setting);
|
rc@73
|
386 };
|
rc@73
|
387
|
rc@73
|
388 /**
|
rc@73
|
389 * Enable `setting`.
|
rc@73
|
390 *
|
rc@73
|
391 * @param {String} setting
|
rc@73
|
392 * @return {app} for chaining
|
rc@73
|
393 * @api public
|
rc@73
|
394 */
|
rc@73
|
395
|
rc@73
|
396 app.enable = function(setting){
|
rc@73
|
397 return this.set(setting, true);
|
rc@73
|
398 };
|
rc@73
|
399
|
rc@73
|
400 /**
|
rc@73
|
401 * Disable `setting`.
|
rc@73
|
402 *
|
rc@73
|
403 * @param {String} setting
|
rc@73
|
404 * @return {app} for chaining
|
rc@73
|
405 * @api public
|
rc@73
|
406 */
|
rc@73
|
407
|
rc@73
|
408 app.disable = function(setting){
|
rc@73
|
409 return this.set(setting, false);
|
rc@73
|
410 };
|
rc@73
|
411
|
rc@73
|
412 /**
|
rc@73
|
413 * Delegate `.VERB(...)` calls to `router.VERB(...)`.
|
rc@73
|
414 */
|
rc@73
|
415
|
rc@73
|
416 methods.forEach(function(method){
|
rc@73
|
417 app[method] = function(path){
|
rc@73
|
418 if ('get' == method && 1 == arguments.length) return this.set(path);
|
rc@73
|
419
|
rc@73
|
420 this.lazyrouter();
|
rc@73
|
421
|
rc@73
|
422 var route = this._router.route(path);
|
rc@73
|
423 route[method].apply(route, [].slice.call(arguments, 1));
|
rc@73
|
424 return this;
|
rc@73
|
425 };
|
rc@73
|
426 });
|
rc@73
|
427
|
rc@73
|
428 /**
|
rc@73
|
429 * Special-cased "all" method, applying the given route `path`,
|
rc@73
|
430 * middleware, and callback to _every_ HTTP method.
|
rc@73
|
431 *
|
rc@73
|
432 * @param {String} path
|
rc@73
|
433 * @param {Function} ...
|
rc@73
|
434 * @return {app} for chaining
|
rc@73
|
435 * @api public
|
rc@73
|
436 */
|
rc@73
|
437
|
rc@73
|
438 app.all = function(path){
|
rc@73
|
439 this.lazyrouter();
|
rc@73
|
440
|
rc@73
|
441 var route = this._router.route(path);
|
rc@73
|
442 var args = [].slice.call(arguments, 1);
|
rc@73
|
443 methods.forEach(function(method){
|
rc@73
|
444 route[method].apply(route, args);
|
rc@73
|
445 });
|
rc@73
|
446
|
rc@73
|
447 return this;
|
rc@73
|
448 };
|
rc@73
|
449
|
rc@73
|
450 // del -> delete alias
|
rc@73
|
451
|
rc@73
|
452 app.del = deprecate(app.delete, 'app.del: Use app.delete instead');
|
rc@73
|
453
|
rc@73
|
454 /**
|
rc@73
|
455 * Render the given view `name` name with `options`
|
rc@73
|
456 * and a callback accepting an error and the
|
rc@73
|
457 * rendered template string.
|
rc@73
|
458 *
|
rc@73
|
459 * Example:
|
rc@73
|
460 *
|
rc@73
|
461 * app.render('email', { name: 'Tobi' }, function(err, html){
|
rc@73
|
462 * // ...
|
rc@73
|
463 * })
|
rc@73
|
464 *
|
rc@73
|
465 * @param {String} name
|
rc@73
|
466 * @param {String|Function} options or fn
|
rc@73
|
467 * @param {Function} fn
|
rc@73
|
468 * @api public
|
rc@73
|
469 */
|
rc@73
|
470
|
rc@73
|
471 app.render = function(name, options, fn){
|
rc@73
|
472 var opts = {};
|
rc@73
|
473 var cache = this.cache;
|
rc@73
|
474 var engines = this.engines;
|
rc@73
|
475 var view;
|
rc@73
|
476
|
rc@73
|
477 // support callback function as second arg
|
rc@73
|
478 if ('function' == typeof options) {
|
rc@73
|
479 fn = options, options = {};
|
rc@73
|
480 }
|
rc@73
|
481
|
rc@73
|
482 // merge app.locals
|
rc@73
|
483 mixin(opts, this.locals);
|
rc@73
|
484
|
rc@73
|
485 // merge options._locals
|
rc@73
|
486 if (options._locals) mixin(opts, options._locals);
|
rc@73
|
487
|
rc@73
|
488 // merge options
|
rc@73
|
489 mixin(opts, options);
|
rc@73
|
490
|
rc@73
|
491 // set .cache unless explicitly provided
|
rc@73
|
492 opts.cache = null == opts.cache
|
rc@73
|
493 ? this.enabled('view cache')
|
rc@73
|
494 : opts.cache;
|
rc@73
|
495
|
rc@73
|
496 // primed cache
|
rc@73
|
497 if (opts.cache) view = cache[name];
|
rc@73
|
498
|
rc@73
|
499 // view
|
rc@73
|
500 if (!view) {
|
rc@73
|
501 view = new (this.get('view'))(name, {
|
rc@73
|
502 defaultEngine: this.get('view engine'),
|
rc@73
|
503 root: this.get('views'),
|
rc@73
|
504 engines: engines
|
rc@73
|
505 });
|
rc@73
|
506
|
rc@73
|
507 if (!view.path) {
|
rc@73
|
508 var err = new Error('Failed to lookup view "' + name + '" in views directory "' + view.root + '"');
|
rc@73
|
509 err.view = view;
|
rc@73
|
510 return fn(err);
|
rc@73
|
511 }
|
rc@73
|
512
|
rc@73
|
513 // prime the cache
|
rc@73
|
514 if (opts.cache) cache[name] = view;
|
rc@73
|
515 }
|
rc@73
|
516
|
rc@73
|
517 // render
|
rc@73
|
518 try {
|
rc@73
|
519 view.render(opts, fn);
|
rc@73
|
520 } catch (err) {
|
rc@73
|
521 fn(err);
|
rc@73
|
522 }
|
rc@73
|
523 };
|
rc@73
|
524
|
rc@73
|
525 /**
|
rc@73
|
526 * Listen for connections.
|
rc@73
|
527 *
|
rc@73
|
528 * A node `http.Server` is returned, with this
|
rc@73
|
529 * application (which is a `Function`) as its
|
rc@73
|
530 * callback. If you wish to create both an HTTP
|
rc@73
|
531 * and HTTPS server you may do so with the "http"
|
rc@73
|
532 * and "https" modules as shown here:
|
rc@73
|
533 *
|
rc@73
|
534 * var http = require('http')
|
rc@73
|
535 * , https = require('https')
|
rc@73
|
536 * , express = require('express')
|
rc@73
|
537 * , app = express();
|
rc@73
|
538 *
|
rc@73
|
539 * http.createServer(app).listen(80);
|
rc@73
|
540 * https.createServer({ ... }, app).listen(443);
|
rc@73
|
541 *
|
rc@73
|
542 * @return {http.Server}
|
rc@73
|
543 * @api public
|
rc@73
|
544 */
|
rc@73
|
545
|
rc@73
|
546 app.listen = function(){
|
rc@73
|
547 var server = http.createServer(this);
|
rc@73
|
548 return server.listen.apply(server, arguments);
|
rc@73
|
549 };
|