rc@73: /*! rc@73: * method-override rc@73: * Copyright(c) 2010 Sencha Inc. rc@73: * Copyright(c) 2011 TJ Holowaychuk rc@73: * Copyright(c) 2014 Jonathan Ong rc@73: * Copyright(c) 2014 Douglas Christopher Wilson rc@73: * MIT Licensed rc@73: */ rc@73: rc@73: /** rc@73: * Module dependencies. rc@73: */ rc@73: rc@73: var methods = require('methods'); rc@73: var parseurl = require('parseurl'); rc@73: var querystring = require('querystring'); rc@73: var vary = require('vary'); rc@73: rc@73: /** rc@73: * Method Override: rc@73: * rc@73: * Provides faux HTTP method support. rc@73: * rc@73: * Pass an optional `getter` to use when checking for rc@73: * a method override. rc@73: * rc@73: * A string is converted to a getter that will look for rc@73: * the method in `req.body[getter]` and a function will be rc@73: * called with `req` and expects the method to be returned. rc@73: * If the string starts with `X-` then it will look in rc@73: * `req.headers[getter]` instead. rc@73: * rc@73: * The original method is available via `req.originalMethod`. rc@73: * rc@73: * @param {string|function} [getter=X-HTTP-Method-Override] rc@73: * @param {object} [options] rc@73: * @return {function} rc@73: * @api public rc@73: */ rc@73: rc@73: module.exports = function methodOverride(getter, options){ rc@73: options = options || {} rc@73: rc@73: // get the getter fn rc@73: var get = typeof getter === 'function' rc@73: ? getter rc@73: : createGetter(getter || 'X-HTTP-Method-Override') rc@73: rc@73: // get allowed request methods to examine rc@73: var methods = options.methods === undefined rc@73: ? ['POST'] rc@73: : options.methods rc@73: rc@73: return function methodOverride(req, res, next) { rc@73: var method rc@73: var val rc@73: rc@73: req.originalMethod = req.originalMethod || req.method rc@73: rc@73: // validate request is on allowed method rc@73: if (methods && methods.indexOf(req.originalMethod) === -1) { rc@73: return next() rc@73: } rc@73: rc@73: val = get(req, res) rc@73: method = Array.isArray(val) rc@73: ? val[0] rc@73: : val rc@73: rc@73: // replace rc@73: if (method !== undefined && supports(method)) { rc@73: req.method = method.toUpperCase() rc@73: } rc@73: rc@73: next() rc@73: } rc@73: } rc@73: rc@73: /** rc@73: * Create a getter for the given string. rc@73: */ rc@73: rc@73: function createGetter(str) { rc@73: if (str.substr(0, 2).toUpperCase() === 'X-') { rc@73: // header getter rc@73: return createHeaderGetter(str) rc@73: } rc@73: rc@73: return createQueryGetter(str) rc@73: } rc@73: rc@73: /** rc@73: * Create a getter for the given query key name. rc@73: */ rc@73: rc@73: function createQueryGetter(key) { rc@73: return function(req, res) { rc@73: var url = parseurl(req) rc@73: var query = querystring.parse(url.query || '') rc@73: return query[key] rc@73: } rc@73: } rc@73: rc@73: /** rc@73: * Create a getter for the given header name. rc@73: */ rc@73: rc@73: function createHeaderGetter(str) { rc@73: var header = str.toLowerCase() rc@73: rc@73: return function(req, res) { rc@73: // set appropriate Vary header rc@73: vary(res, str) rc@73: rc@73: // multiple headers get joined with comma by node.js core rc@73: return (req.headers[header] || '').split(/ *, */) rc@73: } rc@73: } rc@73: rc@73: /** rc@73: * Check if node supports `method`. rc@73: */ rc@73: rc@73: function supports(method) { rc@73: return method rc@73: && typeof method === 'string' rc@73: && methods.indexOf(method.toLowerCase()) !== -1 rc@73: }