arnaucube
arnaucube/thoughtsPublic Self-hosted repository
thoughts/node_modules/express/lib/utils.js
node_modules/express/lib/utils.jsRaw
  1/*!
  2 * express
  3 * Copyright(c) 2009-2013 TJ Holowaychuk
  4 * Copyright(c) 2014-2015 Douglas Christopher Wilson
  5 * MIT Licensed
  6 */
  7
  8'use strict';
  9
 10/**
 11 * Module dependencies.
 12 * @api private
 13 */
 14
 15var contentDisposition = require('content-disposition');
 16var contentType = require('content-type');
 17var deprecate = require('depd')('express');
 18var flatten = require('array-flatten');
 19var mime = require('send').mime;
 20var basename = require('path').basename;
 21var etag = require('etag');
 22var proxyaddr = require('proxy-addr');
 23var qs = require('qs');
 24var querystring = require('querystring');
 25
 26/**
 27 * Return strong ETag for `body`.
 28 *
 29 * @param {String|Buffer} body
 30 * @param {String} [encoding]
 31 * @return {String}
 32 * @api private
 33 */
 34
 35exports.etag = function (body, encoding) {
 36  var buf = !Buffer.isBuffer(body)
 37    ? new Buffer(body, encoding)
 38    : body;
 39
 40  return etag(buf, {weak: false});
 41};
 42
 43/**
 44 * Return weak ETag for `body`.
 45 *
 46 * @param {String|Buffer} body
 47 * @param {String} [encoding]
 48 * @return {String}
 49 * @api private
 50 */
 51
 52exports.wetag = function wetag(body, encoding){
 53  var buf = !Buffer.isBuffer(body)
 54    ? new Buffer(body, encoding)
 55    : body;
 56
 57  return etag(buf, {weak: true});
 58};
 59
 60/**
 61 * Check if `path` looks absolute.
 62 *
 63 * @param {String} path
 64 * @return {Boolean}
 65 * @api private
 66 */
 67
 68exports.isAbsolute = function(path){
 69  if ('/' === path[0]) return true;
 70  if (':' === path[1] && ('\\' === path[2] || '/' === path[2])) return true; // Windows device path
 71  if ('\\\\' === path.substring(0, 2)) return true; // Microsoft Azure absolute path
 72};
 73
 74/**
 75 * Flatten the given `arr`.
 76 *
 77 * @param {Array} arr
 78 * @return {Array}
 79 * @api private
 80 */
 81
 82exports.flatten = deprecate.function(flatten,
 83  'utils.flatten: use array-flatten npm module instead');
 84
 85/**
 86 * Normalize the given `type`, for example "html" becomes "text/html".
 87 *
 88 * @param {String} type
 89 * @return {Object}
 90 * @api private
 91 */
 92
 93exports.normalizeType = function(type){
 94  return ~type.indexOf('/')
 95    ? acceptParams(type)
 96    : { value: mime.lookup(type), params: {} };
 97};
 98
 99/**
100 * Normalize `types`, for example "html" becomes "text/html".
101 *
102 * @param {Array} types
103 * @return {Array}
104 * @api private
105 */
106
107exports.normalizeTypes = function(types){
108  var ret = [];
109
110  for (var i = 0; i < types.length; ++i) {
111    ret.push(exports.normalizeType(types[i]));
112  }
113
114  return ret;
115};
116
117/**
118 * Generate Content-Disposition header appropriate for the filename.
119 * non-ascii filenames are urlencoded and a filename* parameter is added
120 *
121 * @param {String} filename
122 * @return {String}
123 * @api private
124 */
125
126exports.contentDisposition = deprecate.function(contentDisposition,
127  'utils.contentDisposition: use content-disposition npm module instead');
128
129/**
130 * Parse accept params `str` returning an
131 * object with `.value`, `.quality` and `.params`.
132 * also includes `.originalIndex` for stable sorting
133 *
134 * @param {String} str
135 * @return {Object}
136 * @api private
137 */
138
139function acceptParams(str, index) {
140  var parts = str.split(/ *; */);
141  var ret = { value: parts[0], quality: 1, params: {}, originalIndex: index };
142
143  for (var i = 1; i < parts.length; ++i) {
144    var pms = parts[i].split(/ *= */);
145    if ('q' === pms[0]) {
146      ret.quality = parseFloat(pms[1]);
147    } else {
148      ret.params[pms[0]] = pms[1];
149    }
150  }
151
152  return ret;
153}
154
155/**
156 * Compile "etag" value to function.
157 *
158 * @param  {Boolean|String|Function} val
159 * @return {Function}
160 * @api private
161 */
162
163exports.compileETag = function(val) {
164  var fn;
165
166  if (typeof val === 'function') {
167    return val;
168  }
169
170  switch (val) {
171    case true:
172      fn = exports.wetag;
173      break;
174    case false:
175      break;
176    case 'strong':
177      fn = exports.etag;
178      break;
179    case 'weak':
180      fn = exports.wetag;
181      break;
182    default:
183      throw new TypeError('unknown value for etag function: ' + val);
184  }
185
186  return fn;
187}
188
189/**
190 * Compile "query parser" value to function.
191 *
192 * @param  {String|Function} val
193 * @return {Function}
194 * @api private
195 */
196
197exports.compileQueryParser = function compileQueryParser(val) {
198  var fn;
199
200  if (typeof val === 'function') {
201    return val;
202  }
203
204  switch (val) {
205    case true:
206      fn = querystring.parse;
207      break;
208    case false:
209      fn = newObject;
210      break;
211    case 'extended':
212      fn = parseExtendedQueryString;
213      break;
214    case 'simple':
215      fn = querystring.parse;
216      break;
217    default:
218      throw new TypeError('unknown value for query parser function: ' + val);
219  }
220
221  return fn;
222}
223
224/**
225 * Compile "proxy trust" value to function.
226 *
227 * @param  {Boolean|String|Number|Array|Function} val
228 * @return {Function}
229 * @api private
230 */
231
232exports.compileTrust = function(val) {
233  if (typeof val === 'function') return val;
234
235  if (val === true) {
236    // Support plain true/false
237    return function(){ return true };
238  }
239
240  if (typeof val === 'number') {
241    // Support trusting hop count
242    return function(a, i){ return i < val };
243  }
244
245  if (typeof val === 'string') {
246    // Support comma-separated values
247    val = val.split(/ *, */);
248  }
249
250  return proxyaddr.compile(val || []);
251}
252
253/**
254 * Set the charset in a given Content-Type string.
255 *
256 * @param {String} type
257 * @param {String} charset
258 * @return {String}
259 * @api private
260 */
261
262exports.setCharset = function setCharset(type, charset) {
263  if (!type || !charset) {
264    return type;
265  }
266
267  // parse type
268  var parsed = contentType.parse(type);
269
270  // set charset
271  parsed.parameters.charset = charset;
272
273  // format type
274  return contentType.format(parsed);
275};
276
277/**
278 * Parse an extended query string with qs.
279 *
280 * @return {Object}
281 * @private
282 */
283
284function parseExtendedQueryString(str) {
285  return qs.parse(str, {
286    allowPrototypes: true
287  });
288}
289
290/**
291 * Return new empty object.
292 *
293 * @return {Object}
294 * @api private
295 */
296
297function newObject() {
298  return {};
299}