index.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. /*!
  2. * method-override
  3. * Copyright(c) 2010 Sencha Inc.
  4. * Copyright(c) 2011 TJ Holowaychuk
  5. * Copyright(c) 2014 Jonathan Ong
  6. * Copyright(c) 2014 Douglas Christopher Wilson
  7. * MIT Licensed
  8. */
  9. /**
  10. * Module dependencies.
  11. */
  12. var debug = require('debug')('method-override')
  13. var methods = require('methods');
  14. var parseurl = require('parseurl');
  15. var querystring = require('querystring');
  16. var vary = require('vary');
  17. /**
  18. * Method Override:
  19. *
  20. * Provides faux HTTP method support.
  21. *
  22. * Pass an optional `getter` to use when checking for
  23. * a method override.
  24. *
  25. * A string is converted to a getter that will look for
  26. * the method in `req.body[getter]` and a function will be
  27. * called with `req` and expects the method to be returned.
  28. * If the string starts with `X-` then it will look in
  29. * `req.headers[getter]` instead.
  30. *
  31. * The original method is available via `req.originalMethod`.
  32. *
  33. * @param {string|function} [getter=X-HTTP-Method-Override]
  34. * @param {object} [options]
  35. * @return {function}
  36. * @api public
  37. */
  38. module.exports = function methodOverride(getter, options){
  39. options = options || {}
  40. // get the getter fn
  41. var get = typeof getter === 'function'
  42. ? getter
  43. : createGetter(getter || 'X-HTTP-Method-Override')
  44. // get allowed request methods to examine
  45. var methods = options.methods === undefined
  46. ? ['POST']
  47. : options.methods
  48. return function methodOverride(req, res, next) {
  49. var method
  50. var val
  51. req.originalMethod = req.originalMethod || req.method
  52. // validate request is an allowed method
  53. if (methods && methods.indexOf(req.originalMethod) === -1) {
  54. return next()
  55. }
  56. val = get(req, res)
  57. method = Array.isArray(val)
  58. ? val[0]
  59. : val
  60. // replace
  61. if (method !== undefined && supports(method)) {
  62. req.method = method.toUpperCase()
  63. debug('override %s as %s', req.originalMethod, req.method)
  64. }
  65. next()
  66. }
  67. }
  68. /**
  69. * Create a getter for the given string.
  70. */
  71. function createGetter(str) {
  72. if (str.substr(0, 2).toUpperCase() === 'X-') {
  73. // header getter
  74. return createHeaderGetter(str)
  75. }
  76. return createQueryGetter(str)
  77. }
  78. /**
  79. * Create a getter for the given query key name.
  80. */
  81. function createQueryGetter(key) {
  82. return function(req, res) {
  83. var url = parseurl(req)
  84. var query = querystring.parse(url.query || '')
  85. return query[key]
  86. }
  87. }
  88. /**
  89. * Create a getter for the given header name.
  90. */
  91. function createHeaderGetter(str) {
  92. var header = str.toLowerCase()
  93. return function(req, res) {
  94. // set appropriate Vary header
  95. vary(res, str)
  96. // multiple headers get joined with comma by node.js core
  97. return (req.headers[header] || '').split(/ *, */)
  98. }
  99. }
  100. /**
  101. * Check if node supports `method`.
  102. */
  103. function supports(method) {
  104. return method
  105. && typeof method === 'string'
  106. && methods.indexOf(method.toLowerCase()) !== -1
  107. }