UNPKG

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