UNPKG

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