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