fyrejet
Version:
Web Framework for node.js that strives to provide (almost) perfect compatibility with Express, while providing better performance, where you need it.
205 lines (168 loc) • 4.3 kB
JavaScript
const Buffer = require('safe-buffer').Buffer
const contentDisposition = require('content-disposition')
const contentType = require('content-type')
const deprecate = require('depd')('fyrejet')
const flatten = require('array-flatten')
const mime = require('send').mime
const etag = require('etag')
const proxyaddr = require('proxy-addr')
const qs = require('qs')
const querystring = require('querystring')
const etagWeak = createETagGenerator({ weak: true })
const etagStrong = createETagGenerator({ weak: false })
function forEachObject (obj, cb) {
const keys = Object.keys(obj)
const length = keys.length
for (let i = 0; i < length; i++) {
cb(obj[keys[i]], keys[i])
}
}
function merge (a, b) {
a = Object.assign(a, b)
return a
};
function isAbsolute (path) {
if (path[0] === '/') return true
if (path[1] === ':' && (path[2] === '\\' || path[2] === '/')) return true // Windows device path
if (path.substring(0, 2) === '\\\\') return true // Microsoft Azure absolute path
};
function normalizeType (type) {
return ~type.indexOf('/')
? acceptParams(type)
: { value: mime.lookup(type), params: {} }
};
function normalizeTypes (types) {
const ret = []
for (let i = 0; i < types.length; ++i) {
ret.push(normalizeType(types[i]))
}
return ret
};
function acceptParams (str, index) {
const parts = str.split(/ *; */)
const ret = { value: parts[0], quality: 1, params: {}, originalIndex: index }
for (let i = 1; i < parts.length; ++i) {
const pms = parts[i].split(/ *= */)
if (pms[0] === 'q') {
ret.quality = parseFloat(pms[1])
} else {
ret.params[pms[0]] = pms[1]
}
}
return ret
}
function compileETag (val) {
let fn
if (typeof val === 'function') {
return val
}
switch (val) {
case true:
fn = etagWeak
break
case false:
fn = null
break
case 'strong':
fn = etagStrong
break
case 'weak':
fn = etagWeak
break
default:
throw new TypeError('unknown value for etag function: ' + val)
}
return fn
}
function compileQueryParser (val) {
let fn
if (typeof val === 'function') {
return val
}
switch (val) {
case true:
fn = querystring.parse
break
case false:
fn = newObject
break
case 'extended':
fn = parseExtendedQueryString
break
case 'simple':
fn = querystring.parse
break
default:
throw new TypeError('unknown value for query parser function: ' + val)
}
return fn
}
function compileTrust (val) {
if (typeof val === 'function') return val
if (val === true) {
// Support plain true/false
return function () { return true }
}
if (typeof val === 'number') {
// Support trusting hop count
return function (a, i) { return i < val }
}
if (typeof val === 'string') {
// Support comma-separated values
val = val.split(/ *, */)
}
return proxyaddr.compile(val || [])
}
function setCharset (type, charset) {
if (!type || !charset) {
return type
}
// parse type
const parsed = contentType.parse(type)
// set charset
parsed.parameters.charset = charset
// format type
return contentType.format(parsed)
};
function createETagGenerator (options) {
return function generateETag (body, encoding) {
const buf = !Buffer.isBuffer(body) ? Buffer.from(body, encoding) : body
return etag(buf, options)
}
}
function parseExtendedQueryString (str) {
return qs.parse(str, {
allowPrototypes: true
})
}
function newObject () {
return {}
}
function logerror (err) {
/* istanbul ignore next */
if (this.get('env') !== 'test') console.error(err.stack || err.toString())
}
const toString = (str) => {
return str + ''
}
const toLowerCase = (str) => {
return toString(str).toLowerCase()
}
module.exports = {
forEachObject,
merge,
etag: etagStrong,
wetag: etagWeak,
isAbsolute,
flatten: deprecate.function(flatten, 'utils.flatten: use array-flatten npm module instead'),
normalizeType,
normalizeTypes,
contentDisposition: deprecate.function(contentDisposition, 'utils.contentDisposition: use content-disposition npm module instead'),
compileETag,
compileQueryParser,
compileTrust,
setCharset,
logerror,
toString,
toLowerCase
}