You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

176 lines
3.1 KiB

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