fyrejet
Version:
Web Framework for node.js that strives to provide (almost) perfect compatibility with Express, while providing better performance, where you need it.
232 lines (183 loc) • 5.86 kB
JavaScript
'use strict'
/*
* Fyrejet
* Copyright(c) 2021 Nicholas Schamberg
* MIT Licensed
*/
const accepts = require('accepts')
const deprecate = require('depd')('fyrejet')
const { isIP } = require('net')
const typeis = require('type-is')
const fresh = require('fresh')
const parseRange = require('range-parser')
const proxyaddr = require('proxy-addr')
module.exports = {
build,
req: build(Object.create({}))
}
function build (req) {
req.activateExpress = function () {
// stub function to break as few apps as possible
return this
}
req.get = req.header = function header (name) {
if (typeof name !== 'string') {
if (!name) {
throw new TypeError('name argument is required to req.get')
}
throw new TypeError('name must be a string to req.get')
}
const lc = name.toLowerCase()
switch (lc) {
case 'referer':
case 'referrer':
return this.headers.referrer || this.headers.referer
default:
return this.headers[lc]
}
}
req.accepts = function reqAccepts (...args) {
const accept = accepts(this)
return accept.types.apply(accept, args)
}
req.acceptsEncodings = function (...args) {
const accept = accepts(this)
return accept.encodings.apply(accept, args)
}
req.acceptsCharsets = function (...args) {
const accept = accepts(this)
return accept.charsets.apply(accept, args)
}
req.acceptsLanguages = function (...args) {
const accept = accepts(this)
return accept.languages.apply(accept, args)
}
req.range = function range (size, options) {
const range = this.headers.range
if (!range) return
return parseRange(size, range, options)
}
req.param = function param (name, defaultValue) {
const params = this.params || {}
const body = this.body || {}
const query = this.query || {}
const args = !defaultValue ? 'name' : 'name, default'
deprecate(
'req.param(' + args + '): Use req.params, req.body, or req.query instead'
)
if (params[name] != null && params.hasOwnProperty(name)) { return params[name] }
if (body[name] != null) return body[name]
if (query[name] != null) return query[name]
return defaultValue
}
req.is = function is (types) {
let arr = types
// support flattened arguments
if (!Array.isArray(types)) {
arr = new Array(arguments.length)
for (let i = 0, j = arr.length; i < j; i++) {
arr[i] = arguments[i]
}
}
return typeis(this, arr)
}
req.protocol = function protocol () {
const proto = this.connection.encrypted ? 'https' : 'http'
const trust = this.app.__settings.get('trust proxy fn')
if (!trust(this.connection.remoteAddress, 0)) {
return proto
}
// Note: X-Forwarded-Proto is normally only ever a
// single value, but this is to be safe.
const header = this.headers['x-forwarded-proto'] || proto
const index = header.indexOf(',')
return index !== -1 ? header.substring(0, index).trim() : header.trim()
}
req.secure = function secure () {
return this.protocol() === 'https'
}
req.ip = function ip () {
const trust = this.app.__settings.get('trust proxy fn')
return proxyaddr(this, trust)
}
req.ips = function ips () {
const trust = this.app.__settings.get('trust proxy fn')
const addrs = proxyaddr.all(this, trust)
// reverse the order (to farthest -> closest)
// and remove socket address
addrs.reverse().pop()
return addrs
}
req.subdomains = function subdomains () {
const hostname = this.hostname()
if (!hostname) return []
const offset = this.app.__settings.get('subdomain offset')
const subdomains = !isIP(hostname)
? hostname.split('.').reverse()
: [hostname]
return subdomains.slice(offset)
}
req.setUrl = function setUrl (url) {
this.url = url
this.rData_internal.urlPrev = url
return this
}
req.setMethod = function setMethod (method) {
this.method = method
this.rData_internal.methodPrev = method
return this
}
req.hostname = function hostname () {
const trust = this.app.__settings.get('trust proxy fn')
let host = this.headers['x-forwarded-host']
if (!host || !trust(this.connection.remoteAddress, 0)) {
host = this.headers.host
} else if (host.indexOf(',') !== -1) {
// Note: X-Forwarded-Host is normally only ever a
// single value, but this is to be safe.
host = host.substring(0, host.indexOf(',')).trimRight()
}
if (!host) return
// IPv6 literal support
const offset = host[0] === '[' ? host.indexOf(']') + 1 : 0
const index = host.indexOf(':', offset)
return index !== -1 ? host.substring(0, index) : host
}
req.fresh = function reqFresh () {
const method = this.method
// GET or HEAD for weak freshness validation only
if (method !== 'GET' && method !== 'HEAD') return false
// 2xx or 304 as per rfc2616 14.26
if (
(this.res.statusCode >= 200 && this.res.statusCode < 300) ||
this.res.statusCode === 304
) {
return fresh(this.headers, {
etag: this.res.getHeader('ETag'),
'last-modified': this.res.getHeader('Last-Modified')
})
}
return false
}
req.baseUrl = function baseUrl () {
const baseUrl = this.originalUrl.replace(this.currentUrl(), '')
return baseUrl
}
req.currentUrl = function currentUrl () {
const route = this.route
if (route.middleware) {
let url = this.url.replace(route.pattern, '')
url = url || '/'
return url
}
return this.url
}
req.stale = function stale () {
return !this.fresh()
}
req.xhr = function xhr () {
const val = this.headers['x-requested-with'] || ''
return val.toLowerCase() === 'xmlhttprequest'
}
return req
}