/node_modules/express/node_modules/connect/lib/http.js

https://gitlab.com/nhanvu/cyber-duck · JavaScript · 218 lines · 98 code · 32 blank · 88 comment · 43 complexity · 2bcfc3b1b3c6548cfbd236b3c4178031 MD5 · raw file

  1. /*!
  2. * Connect - HTTPServer
  3. * Copyright(c) 2010 Sencha Inc.
  4. * Copyright(c) 2011 TJ Holowaychuk
  5. * MIT Licensed
  6. */
  7. /**
  8. * Module dependencies.
  9. */
  10. var http = require('http')
  11. , parse = require('url').parse
  12. , assert = require('assert')
  13. , utils = require('./utils');
  14. // environment
  15. var env = process.env.NODE_ENV || 'development';
  16. /**
  17. * Initialize a new `Server` with the given `middleware`.
  18. *
  19. * Examples:
  20. *
  21. * var server = connect.createServer(
  22. * connect.favicon()
  23. * , connect.logger()
  24. * , connect.static(__dirname + '/public')
  25. * );
  26. *
  27. * @params {Array} middleware
  28. * @return {Server}
  29. * @api public
  30. */
  31. var Server = exports.Server = function HTTPServer(middleware) {
  32. this.stack = [];
  33. middleware.forEach(function(fn){
  34. this.use(fn);
  35. }, this);
  36. http.Server.call(this, this.handle);
  37. };
  38. /**
  39. * Inherit from `http.Server.prototype`.
  40. */
  41. Server.prototype.__proto__ = http.Server.prototype;
  42. /**
  43. * Utilize the given middleware `handle` to the given `route`,
  44. * defaulting to _/_. This "route" is the mount-point for the
  45. * middleware, when given a value other than _/_ the middleware
  46. * is only effective when that segment is present in the request's
  47. * pathname.
  48. *
  49. * For example if we were to mount a function at _/admin_, it would
  50. * be invoked on _/admin_, and _/admin/settings_, however it would
  51. * not be invoked for _/_, or _/posts_.
  52. *
  53. * This is effectively the same as passing middleware to `connect.createServer()`,
  54. * however provides a progressive api.
  55. *
  56. * Examples:
  57. *
  58. * var server = connect.createServer();
  59. * server.use(connect.favicon());
  60. * server.use(connect.logger());
  61. * server.use(connect.static(__dirname + '/public'));
  62. *
  63. * If we wanted to prefix static files with _/public_, we could
  64. * "mount" the `static()` middleware:
  65. *
  66. * server.use('/public', connect.static(__dirname + '/public'));
  67. *
  68. * This api is chainable, meaning the following is valid:
  69. *
  70. * connect.createServer()
  71. * .use(connect.favicon())
  72. * .use(connect.logger())
  73. * .use(connect.static(__dirname + '/public'))
  74. * .listen(3000);
  75. *
  76. * @param {String|Function} route or handle
  77. * @param {Function} handle
  78. * @return {Server}
  79. * @api public
  80. */
  81. Server.prototype.use = function(route, handle){
  82. this.route = '/';
  83. // default route to '/'
  84. if ('string' != typeof route) {
  85. handle = route;
  86. route = '/';
  87. }
  88. // wrap sub-apps
  89. if ('function' == typeof handle.handle) {
  90. var server = handle;
  91. server.route = route;
  92. handle = function(req, res, next) {
  93. server.handle(req, res, next);
  94. };
  95. }
  96. // wrap vanilla http.Servers
  97. if (handle instanceof http.Server) {
  98. handle = handle.listeners('request')[0];
  99. }
  100. // normalize route to not trail with slash
  101. if ('/' == route[route.length - 1]) {
  102. route = route.substr(0, route.length - 1);
  103. }
  104. // add the middleware
  105. this.stack.push({ route: route, handle: handle });
  106. // allow chaining
  107. return this;
  108. };
  109. /**
  110. * Handle server requests, punting them down
  111. * the middleware stack.
  112. *
  113. * @api private
  114. */
  115. Server.prototype.handle = function(req, res, out) {
  116. var writeHead = res.writeHead
  117. , stack = this.stack
  118. , removed = ''
  119. , index = 0;
  120. function next(err) {
  121. var layer, path, c;
  122. req.url = removed + req.url;
  123. req.originalUrl = req.originalUrl || req.url;
  124. removed = '';
  125. layer = stack[index++];
  126. // all done
  127. if (!layer || res.headerSent) {
  128. // but wait! we have a parent
  129. if (out) return out(err);
  130. // error
  131. if (err) {
  132. var msg = 'production' == env
  133. ? 'Internal Server Error'
  134. : err.stack || err.toString();
  135. // output to stderr in a non-test env
  136. if ('test' != env) console.error(err.stack || err.toString());
  137. // unable to respond
  138. if (res.headerSent) return req.socket.destroy();
  139. res.statusCode = 500;
  140. res.setHeader('Content-Type', 'text/plain');
  141. if ('HEAD' == req.method) return res.end();
  142. res.end(msg);
  143. } else {
  144. res.statusCode = 404;
  145. res.setHeader('Content-Type', 'text/plain');
  146. if ('HEAD' == req.method) return res.end();
  147. res.end('Cannot ' + req.method + ' ' + utils.escape(req.originalUrl));
  148. }
  149. return;
  150. }
  151. try {
  152. path = parse(req.url).pathname;
  153. if (undefined == path) path = '/';
  154. // skip this layer if the route doesn't match.
  155. if (0 != path.indexOf(layer.route)) return next(err);
  156. c = path[layer.route.length];
  157. if (c && '/' != c && '.' != c) return next(err);
  158. // Call the layer handler
  159. // Trim off the part of the url that matches the route
  160. removed = layer.route;
  161. req.url = req.url.substr(removed.length);
  162. // Ensure leading slash
  163. if ('/' != req.url[0]) req.url = '/' + req.url;
  164. var arity = layer.handle.length;
  165. if (err) {
  166. if (arity === 4) {
  167. layer.handle(err, req, res, next);
  168. } else {
  169. next(err);
  170. }
  171. } else if (arity < 4) {
  172. layer.handle(req, res, next);
  173. } else {
  174. next();
  175. }
  176. } catch (e) {
  177. if (e instanceof assert.AssertionError) {
  178. console.error(e.stack + '\n');
  179. next(e);
  180. } else {
  181. next(e);
  182. }
  183. }
  184. }
  185. next();
  186. };