layer.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /**
  2. * Module dependencies.
  3. */
  4. var pathRegexp = require('path-to-regexp');
  5. var debug = require('debug')('express:router:layer');
  6. /**
  7. * Module variables.
  8. */
  9. var hasOwnProperty = Object.prototype.hasOwnProperty;
  10. /**
  11. * Expose `Layer`.
  12. */
  13. module.exports = Layer;
  14. function Layer(path, options, fn) {
  15. if (!(this instanceof Layer)) {
  16. return new Layer(path, options, fn);
  17. }
  18. debug('new %s', path);
  19. options = options || {};
  20. this.handle = fn;
  21. this.name = fn.name || '<anonymous>';
  22. this.params = undefined;
  23. this.path = undefined;
  24. this.regexp = pathRegexp(path, this.keys = [], options);
  25. if (path === '/' && options.end === false) {
  26. this.regexp.fast_slash = true;
  27. }
  28. }
  29. /**
  30. * Handle the error for the layer.
  31. *
  32. * @param {Error} error
  33. * @param {Request} req
  34. * @param {Response} res
  35. * @param {function} next
  36. * @api private
  37. */
  38. Layer.prototype.handle_error = function handle_error(error, req, res, next) {
  39. var fn = this.handle;
  40. if (fn.length !== 4) {
  41. // not a standard error handler
  42. return next(error);
  43. }
  44. try {
  45. fn(error, req, res, next);
  46. } catch (err) {
  47. next(err);
  48. }
  49. };
  50. /**
  51. * Handle the request for the layer.
  52. *
  53. * @param {Request} req
  54. * @param {Response} res
  55. * @param {function} next
  56. * @api private
  57. */
  58. Layer.prototype.handle_request = function handle(req, res, next) {
  59. var fn = this.handle;
  60. if (fn.length > 3) {
  61. // not a standard request handler
  62. return next();
  63. }
  64. try {
  65. fn(req, res, next);
  66. } catch (err) {
  67. next(err);
  68. }
  69. };
  70. /**
  71. * Check if this route matches `path`, if so
  72. * populate `.params`.
  73. *
  74. * @param {String} path
  75. * @return {Boolean}
  76. * @api private
  77. */
  78. Layer.prototype.match = function match(path) {
  79. if (path == null) {
  80. // no path, nothing matches
  81. this.params = undefined;
  82. this.path = undefined;
  83. return false;
  84. }
  85. if (this.regexp.fast_slash) {
  86. // fast path non-ending match for / (everything matches)
  87. this.params = {};
  88. this.path = '';
  89. return true;
  90. }
  91. var m = this.regexp.exec(path);
  92. if (!m) {
  93. this.params = undefined;
  94. this.path = undefined;
  95. return false;
  96. }
  97. // store values
  98. this.params = {};
  99. this.path = m[0];
  100. var keys = this.keys;
  101. var params = this.params;
  102. var prop;
  103. var n = 0;
  104. var key;
  105. var val;
  106. for (var i = 1, len = m.length; i < len; ++i) {
  107. key = keys[i - 1];
  108. prop = key
  109. ? key.name
  110. : n++;
  111. val = decode_param(m[i]);
  112. if (val !== undefined || !(hasOwnProperty.call(params, prop))) {
  113. params[prop] = val;
  114. }
  115. }
  116. return true;
  117. };
  118. /**
  119. * Decode param value.
  120. *
  121. * @param {string} val
  122. * @return {string}
  123. * @api private
  124. */
  125. function decode_param(val){
  126. if (typeof val !== 'string') {
  127. return val;
  128. }
  129. try {
  130. return decodeURIComponent(val);
  131. } catch (e) {
  132. var err = new TypeError("Failed to decode param '" + val + "'");
  133. err.status = 400;
  134. throw err;
  135. }
  136. }