fatsify核心功能示例测试!!!
This commit is contained in:
369
node_modules/fastify/lib/request.js
generated
vendored
Normal file
369
node_modules/fastify/lib/request.js
generated
vendored
Normal file
@@ -0,0 +1,369 @@
|
||||
'use strict'
|
||||
|
||||
const proxyAddr = require('@fastify/proxy-addr')
|
||||
const {
|
||||
kHasBeenDecorated,
|
||||
kSchemaBody,
|
||||
kSchemaHeaders,
|
||||
kSchemaParams,
|
||||
kSchemaQuerystring,
|
||||
kSchemaController,
|
||||
kOptions,
|
||||
kRequestCacheValidateFns,
|
||||
kRouteContext,
|
||||
kRequestOriginalUrl
|
||||
} = require('./symbols')
|
||||
const { FST_ERR_REQ_INVALID_VALIDATION_INVOCATION, FST_ERR_DEC_UNDECLARED } = require('./errors')
|
||||
const decorators = require('./decorate')
|
||||
|
||||
const HTTP_PART_SYMBOL_MAP = {
|
||||
body: kSchemaBody,
|
||||
headers: kSchemaHeaders,
|
||||
params: kSchemaParams,
|
||||
querystring: kSchemaQuerystring,
|
||||
query: kSchemaQuerystring
|
||||
}
|
||||
|
||||
function Request (id, params, req, query, log, context) {
|
||||
this.id = id
|
||||
this[kRouteContext] = context
|
||||
this.params = params
|
||||
this.raw = req
|
||||
this.query = query
|
||||
this.log = log
|
||||
this.body = undefined
|
||||
}
|
||||
Request.props = []
|
||||
|
||||
function getTrustProxyFn (tp) {
|
||||
if (typeof tp === 'function') {
|
||||
return tp
|
||||
}
|
||||
if (tp === true) {
|
||||
// Support trusting everything
|
||||
return null
|
||||
}
|
||||
if (typeof tp === 'number') {
|
||||
// Support trusting hop count
|
||||
return function (a, i) { return i < tp }
|
||||
}
|
||||
if (typeof tp === 'string') {
|
||||
// Support comma-separated tps
|
||||
const values = tp.split(',').map(it => it.trim())
|
||||
return proxyAddr.compile(values)
|
||||
}
|
||||
return proxyAddr.compile(tp)
|
||||
}
|
||||
|
||||
function buildRequest (R, trustProxy) {
|
||||
if (trustProxy) {
|
||||
return buildRequestWithTrustProxy(R, trustProxy)
|
||||
}
|
||||
|
||||
return buildRegularRequest(R)
|
||||
}
|
||||
|
||||
function buildRegularRequest (R) {
|
||||
const props = R.props.slice()
|
||||
function _Request (id, params, req, query, log, context) {
|
||||
this.id = id
|
||||
this[kRouteContext] = context
|
||||
this.params = params
|
||||
this.raw = req
|
||||
this.query = query
|
||||
this.log = log
|
||||
this.body = undefined
|
||||
|
||||
let prop
|
||||
for (let i = 0; i < props.length; i++) {
|
||||
prop = props[i]
|
||||
this[prop.key] = prop.value
|
||||
}
|
||||
}
|
||||
Object.setPrototypeOf(_Request.prototype, R.prototype)
|
||||
Object.setPrototypeOf(_Request, R)
|
||||
_Request.props = props
|
||||
_Request.parent = R
|
||||
|
||||
return _Request
|
||||
}
|
||||
|
||||
function getLastEntryInMultiHeaderValue (headerValue) {
|
||||
// we use the last one if the header is set more than once
|
||||
const lastIndex = headerValue.lastIndexOf(',')
|
||||
return lastIndex === -1 ? headerValue.trim() : headerValue.slice(lastIndex + 1).trim()
|
||||
}
|
||||
|
||||
function buildRequestWithTrustProxy (R, trustProxy) {
|
||||
const _Request = buildRegularRequest(R)
|
||||
const proxyFn = getTrustProxyFn(trustProxy)
|
||||
|
||||
// This is a more optimized version of decoration
|
||||
_Request[kHasBeenDecorated] = true
|
||||
|
||||
Object.defineProperties(_Request.prototype, {
|
||||
ip: {
|
||||
get () {
|
||||
const addrs = proxyAddr.all(this.raw, proxyFn)
|
||||
return addrs[addrs.length - 1]
|
||||
}
|
||||
},
|
||||
ips: {
|
||||
get () {
|
||||
return proxyAddr.all(this.raw, proxyFn)
|
||||
}
|
||||
},
|
||||
host: {
|
||||
get () {
|
||||
if (this.ip !== undefined && this.headers['x-forwarded-host']) {
|
||||
return getLastEntryInMultiHeaderValue(this.headers['x-forwarded-host'])
|
||||
}
|
||||
/**
|
||||
* The last fallback supports the following cases:
|
||||
* 1. http.requireHostHeader === false
|
||||
* 2. HTTP/1.0 without a Host Header
|
||||
* 3. Headers schema that may remove the Host Header
|
||||
*/
|
||||
return this.headers.host ?? this.headers[':authority'] ?? ''
|
||||
}
|
||||
},
|
||||
protocol: {
|
||||
get () {
|
||||
if (this.headers['x-forwarded-proto']) {
|
||||
return getLastEntryInMultiHeaderValue(this.headers['x-forwarded-proto'])
|
||||
}
|
||||
if (this.socket) {
|
||||
return this.socket.encrypted ? 'https' : 'http'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return _Request
|
||||
}
|
||||
|
||||
function assertsRequestDecoration (request, name) {
|
||||
if (!decorators.hasKey(request, name) && !decorators.exist(request, name)) {
|
||||
throw new FST_ERR_DEC_UNDECLARED(name, 'request')
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperties(Request.prototype, {
|
||||
server: {
|
||||
get () {
|
||||
return this[kRouteContext].server
|
||||
}
|
||||
},
|
||||
url: {
|
||||
get () {
|
||||
return this.raw.url
|
||||
}
|
||||
},
|
||||
originalUrl: {
|
||||
get () {
|
||||
/* istanbul ignore else */
|
||||
if (!this[kRequestOriginalUrl]) {
|
||||
this[kRequestOriginalUrl] = this.raw.originalUrl || this.raw.url
|
||||
}
|
||||
return this[kRequestOriginalUrl]
|
||||
}
|
||||
},
|
||||
method: {
|
||||
get () {
|
||||
return this.raw.method
|
||||
}
|
||||
},
|
||||
routeOptions: {
|
||||
get () {
|
||||
const context = this[kRouteContext]
|
||||
const routeLimit = context._parserOptions.limit
|
||||
const serverLimit = context.server.initialConfig.bodyLimit
|
||||
const version = context.server.hasConstraintStrategy('version') ? this.raw.headers['accept-version'] : undefined
|
||||
const options = {
|
||||
method: context.config?.method,
|
||||
url: context.config?.url,
|
||||
bodyLimit: (routeLimit || serverLimit),
|
||||
attachValidation: context.attachValidation,
|
||||
logLevel: context.logLevel,
|
||||
exposeHeadRoute: context.exposeHeadRoute,
|
||||
prefixTrailingSlash: context.prefixTrailingSlash,
|
||||
handler: context.handler,
|
||||
config: context.config,
|
||||
schema: context.schema,
|
||||
version
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
},
|
||||
is404: {
|
||||
get () {
|
||||
return this[kRouteContext].config?.url === undefined
|
||||
}
|
||||
},
|
||||
socket: {
|
||||
get () {
|
||||
return this.raw.socket
|
||||
}
|
||||
},
|
||||
ip: {
|
||||
get () {
|
||||
if (this.socket) {
|
||||
return this.socket.remoteAddress
|
||||
}
|
||||
}
|
||||
},
|
||||
host: {
|
||||
get () {
|
||||
/**
|
||||
* The last fallback supports the following cases:
|
||||
* 1. http.requireHostHeader === false
|
||||
* 2. HTTP/1.0 without a Host Header
|
||||
* 3. Headers schema that may remove the Host Header
|
||||
*/
|
||||
return this.raw.headers.host ?? this.raw.headers[':authority'] ?? ''
|
||||
}
|
||||
},
|
||||
hostname: {
|
||||
get () {
|
||||
return this.host.split(':', 1)[0]
|
||||
}
|
||||
},
|
||||
port: {
|
||||
get () {
|
||||
// first try taking port from host
|
||||
const portFromHost = parseInt(this.host.split(':').slice(-1)[0])
|
||||
if (!isNaN(portFromHost)) {
|
||||
return portFromHost
|
||||
}
|
||||
// now fall back to port from host/:authority header
|
||||
const host = (this.headers.host ?? this.headers[':authority'] ?? '')
|
||||
const portFromHeader = parseInt(host.split(':').slice(-1)[0])
|
||||
if (!isNaN(portFromHeader)) {
|
||||
return portFromHeader
|
||||
}
|
||||
// fall back to null
|
||||
return null
|
||||
}
|
||||
},
|
||||
protocol: {
|
||||
get () {
|
||||
if (this.socket) {
|
||||
return this.socket.encrypted ? 'https' : 'http'
|
||||
}
|
||||
}
|
||||
},
|
||||
headers: {
|
||||
get () {
|
||||
if (this.additionalHeaders) {
|
||||
return Object.assign({}, this.raw.headers, this.additionalHeaders)
|
||||
}
|
||||
return this.raw.headers
|
||||
},
|
||||
set (headers) {
|
||||
this.additionalHeaders = headers
|
||||
}
|
||||
},
|
||||
getValidationFunction: {
|
||||
value: function (httpPartOrSchema) {
|
||||
if (typeof httpPartOrSchema === 'string') {
|
||||
const symbol = HTTP_PART_SYMBOL_MAP[httpPartOrSchema]
|
||||
return this[kRouteContext][symbol]
|
||||
} else if (typeof httpPartOrSchema === 'object') {
|
||||
return this[kRouteContext][kRequestCacheValidateFns]?.get(httpPartOrSchema)
|
||||
}
|
||||
}
|
||||
},
|
||||
compileValidationSchema: {
|
||||
value: function (schema, httpPart = null) {
|
||||
const { method, url } = this
|
||||
|
||||
if (this[kRouteContext][kRequestCacheValidateFns]?.has(schema)) {
|
||||
return this[kRouteContext][kRequestCacheValidateFns].get(schema)
|
||||
}
|
||||
|
||||
const validatorCompiler = this[kRouteContext].validatorCompiler ||
|
||||
this.server[kSchemaController].validatorCompiler ||
|
||||
(
|
||||
// We compile the schemas if no custom validatorCompiler is provided
|
||||
// nor set
|
||||
this.server[kSchemaController].setupValidator(this.server[kOptions]) ||
|
||||
this.server[kSchemaController].validatorCompiler
|
||||
)
|
||||
|
||||
const validateFn = validatorCompiler({
|
||||
schema,
|
||||
method,
|
||||
url,
|
||||
httpPart
|
||||
})
|
||||
|
||||
// We create a WeakMap to compile the schema only once
|
||||
// Its done lazily to avoid add overhead by creating the WeakMap
|
||||
// if it is not used
|
||||
// TODO: Explore a central cache for all the schemas shared across
|
||||
// encapsulated contexts
|
||||
if (this[kRouteContext][kRequestCacheValidateFns] == null) {
|
||||
this[kRouteContext][kRequestCacheValidateFns] = new WeakMap()
|
||||
}
|
||||
|
||||
this[kRouteContext][kRequestCacheValidateFns].set(schema, validateFn)
|
||||
|
||||
return validateFn
|
||||
}
|
||||
},
|
||||
validateInput: {
|
||||
value: function (input, schema, httpPart) {
|
||||
httpPart = typeof schema === 'string' ? schema : httpPart
|
||||
|
||||
const symbol = (httpPart != null && typeof httpPart === 'string') && HTTP_PART_SYMBOL_MAP[httpPart]
|
||||
let validate
|
||||
|
||||
if (symbol) {
|
||||
// Validate using the HTTP Request Part schema
|
||||
validate = this[kRouteContext][symbol]
|
||||
}
|
||||
|
||||
// We cannot compile if the schema is missed
|
||||
if (validate == null && (schema == null ||
|
||||
typeof schema !== 'object' ||
|
||||
Array.isArray(schema))
|
||||
) {
|
||||
throw new FST_ERR_REQ_INVALID_VALIDATION_INVOCATION(httpPart)
|
||||
}
|
||||
|
||||
if (validate == null) {
|
||||
if (this[kRouteContext][kRequestCacheValidateFns]?.has(schema)) {
|
||||
validate = this[kRouteContext][kRequestCacheValidateFns].get(schema)
|
||||
} else {
|
||||
// We proceed to compile if there's no validate function yet
|
||||
validate = this.compileValidationSchema(schema, httpPart)
|
||||
}
|
||||
}
|
||||
|
||||
return validate(input)
|
||||
}
|
||||
},
|
||||
getDecorator: {
|
||||
value: function (name) {
|
||||
assertsRequestDecoration(this, name)
|
||||
|
||||
const decorator = this[name]
|
||||
if (typeof decorator === 'function') {
|
||||
return decorator.bind(this)
|
||||
}
|
||||
|
||||
return decorator
|
||||
}
|
||||
},
|
||||
setDecorator: {
|
||||
value: function (name, value) {
|
||||
assertsRequestDecoration(this, name)
|
||||
|
||||
this[name] = value
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = Request
|
||||
module.exports.buildRequest = buildRequest
|
||||
Reference in New Issue
Block a user