github.com/solo-io/unik@v0.0.0-20190717152701-a58d3e8e33b7/docs/examples/example-nodejs-fileserver/node_modules/express/lib/utils.js (about) 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 15 var contentDisposition = require('content-disposition'); 16 var contentType = require('content-type'); 17 var deprecate = require('depd')('express'); 18 var flatten = require('array-flatten'); 19 var mime = require('send').mime; 20 var basename = require('path').basename; 21 var etag = require('etag'); 22 var proxyaddr = require('proxy-addr'); 23 var qs = require('qs'); 24 var 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 35 exports.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 52 exports.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 68 exports.isAbsolute = function(path){ 69 if ('/' == path[0]) return true; 70 if (':' == path[1] && '\\' == path[2]) return true; 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 82 exports.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 93 exports.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 107 exports.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 126 exports.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 139 function 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 163 exports.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 197 exports.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 232 exports.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 262 exports.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 284 function parseExtendedQueryString(str) { 285 return qs.parse(str, { 286 allowDots: false, 287 allowPrototypes: true 288 }); 289 } 290 291 /** 292 * Return new empty object. 293 * 294 * @return {Object} 295 * @api private 296 */ 297 298 function newObject() { 299 return {}; 300 }