Socket
Socket
Sign inDemoInstall

fastify

Package Overview
Dependencies
60
Maintainers
4
Versions
282
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 4.27.0 to 5.0.0-aplha.1

docs/Guides/Migration-Guide-V5.md

6

build/build-validation.js

@@ -41,7 +41,7 @@ 'use strict'

pluginTimeout: 10000,
requestIdHeader: 'request-id',
requestIdHeader: false,
requestIdLogLabel: 'reqId',
http2SessionTimeout: 72000, // 72 seconds
exposeHeadRoutes: true,
useSemicolonDelimiter: true
useSemicolonDelimiter: false
}

@@ -102,3 +102,3 @@

pluginTimeout: { type: 'integer', default: defaultInitOptions.pluginTimeout },
requestIdHeader: { anyOf: [{ enum: [false] }, { type: 'string' }], default: defaultInitOptions.requestIdHeader },
requestIdHeader: { anyOf: [{ type: 'boolean' }, { type: 'string' }], default: defaultInitOptions.requestIdHeader },
requestIdLogLabel: { type: 'string', default: defaultInitOptions.requestIdLogLabel },

@@ -105,0 +105,0 @@ http2SessionTimeout: { type: 'integer', default: defaultInitOptions.http2SessionTimeout },

@@ -106,3 +106,3 @@ <h1 align="center">Fastify</h1>

server.decorate('magicKey', null)
server.decorate('magicKey')

@@ -307,3 +307,3 @@ server.listen({ port: '1234' }, () => {

// Set up the placeholder for the magicKey
fastify.decorate('magicKey', null)
fastify.decorate('magicKey')

@@ -411,3 +411,3 @@ // Our magic -- important to make sure errors are handled. Beware of async

```js
fastify.decorate('magicKey', null)
fastify.decorate('magicKey')
```

@@ -414,0 +414,0 @@

@@ -32,2 +32,9 @@ <h1 align="center">Fastify</h1>

> ## ⚠ Security Notice
> When using with RegExp to detect `Content-Type`, you should beware of
> how to properly detect the `Content-Type`. For example, if you need
> `application/*`, you should use `/^application\/([\w-]+);?/` to match the
> [essence MIME type](https://mimesniff.spec.whatwg.org/#mime-type-miscellaneous)
> only.
### Usage

@@ -56,3 +63,3 @@ ```js

// Handle all content types that matches RegExp
fastify.addContentTypeParser(/^image\/.*/, function (request, payload, done) {
fastify.addContentTypeParser(/^image\/([\w-]+);?/, function (request, payload, done) {
imageParser(payload, function (err, body) {

@@ -59,0 +66,0 @@ done(err, body)

@@ -196,3 +196,3 @@ <h1 align="center">Fastify</h1>

async function myPlugin (app) {
app.decorateRequest('foo', null)
app.decorateRequest('foo')
app.addHook('onRequest', async (req, reply) => {

@@ -240,3 +240,3 @@ req.foo = { bar: 42 }

async function myPlugin (app) {
app.decorateRequest('foo', null)
app.decorateRequest('foo')
app.addHook('onRequest', async (req, reply) => {

@@ -243,0 +243,0 @@ req.foo = { bar: 42 }

@@ -47,2 +47,5 @@ <h1 align="center">Fastify</h1>

- [FST_ERR_LOG_INVALID_LOGGER](#fst_err_log_invalid_logger)
- [FST_ERR_LOG_INVALID_LOGGER_INSTANCE](#fst_err_log_invalid_logger_instance)
- [FST_ERR_LOG_INVALID_LOGGER_CONFIG](#fst_err_log_invalid_logger_config)
- [FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED](#fst_err_log_logger_and_logger_instance_provided)
- [FST_ERR_REP_INVALID_PAYLOAD_TYPE](#fst_err_rep_invalid_payload_type)

@@ -74,3 +77,2 @@ - [FST_ERR_REP_RESPONSE_BODY_CONSUMED](#fst_err_rep_response_body_consumed)

- [FST_ERR_ASYNC_CONSTRAINT](#fst_err_async_constraint)
- [FST_ERR_DEFAULT_ROUTE_INVALID_TYPE](#fst_err_default_route_invalid_type)
- [FST_ERR_INVALID_URL](#fst_err_invalid_url)

@@ -95,2 +97,3 @@ - [FST_ERR_ROUTE_OPTIONS_NOT_OBJ](#fst_err_route_options_not_obj)

- [FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE](#fst_err_plugin_not_present_in_instance)
- [FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER](#fst_err_plugin_invalid_async_handler)
- [FST_ERR_VALIDATION](#fst_err_validation)

@@ -319,2 +322,5 @@ - [FST_ERR_LISTEN_OPTIONS_INVALID](#fst_err_listen_options_invalid)

| <a id="fst_err_log_invalid_logger">FST_ERR_LOG_INVALID_LOGGER</a> | The logger should have all these methods: `'info'`, `'error'`, `'debug'`, `'fatal'`, `'warn'`, `'trace'`, `'child'`. | Use a logger with all the required methods. | [#4520](https://github.com/fastify/fastify/pull/4520) |
| <a id="fst_err_log_invalid_logger_instance">FST_ERR_LOG_INVALID_LOGGER_INSTANCE</a> | The `loggerInstance` only accepts a logger instance, not a configuration object. | To pass a configuration object, use `'logger'` instead. | [#5020](https://github.com/fastify/fastify/pull/5020) |
| <a id="fst_err_log_invalid_logger_config">FST_ERR_LOG_INVALID_LOGGER_CONFIG</a> | The logger option only accepts a configuration object, not a logger instance. | To pass an instance, use `'loggerInstance'` instead. | [#5020](https://github.com/fastify/fastify/pull/5020) |
| <a id="fst_err_log_logger_and_logger_instance_provided">FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED</a> | You cannot provide both `'logger'` and `'loggerInstance'`. | Please provide only one option. | [#5020](https://github.com/fastify/fastify/pull/5020) |
| <a id="fst_err_rep_invalid_payload_type">FST_ERR_REP_INVALID_PAYLOAD_TYPE</a> | Reply payload can be either a `string` or a `Buffer`. | Use a `string` or a `Buffer` for the payload. | [#1168](https://github.com/fastify/fastify/pull/1168) |

@@ -346,3 +352,2 @@ | <a id="fst_err_rep_response_body_consumed">FST_ERR_REP_RESPONSE_BODY_CONSUMED</a> | Using `Response` as reply payload, but the body is being consumed. | Make sure you don't consume the `Response.body` | [#5286](https://github.com/fastify/fastify/pull/5286) |

| <a id="fst_err_async_constraint">FST_ERR_ASYNC_CONSTRAINT</a> | The router received an error when using asynchronous constraints. | - | [#4323](https://github.com/fastify/fastify/pull/4323) |
| <a id="fst_err_default_route_invalid_type">FST_ERR_DEFAULT_ROUTE_INVALID_TYPE</a> | The `defaultRoute` type should be a function. | Use a function for the `defaultRoute`. | [#2733](https://github.com/fastify/fastify/pull/2733) |
| <a id="fst_err_invalid_url">FST_ERR_INVALID_URL</a> | URL must be a string. | Use a string for the URL. | [#3653](https://github.com/fastify/fastify/pull/3653) |

@@ -367,2 +372,3 @@ | <a id="fst_err_route_options_not_obj">FST_ERR_ROUTE_OPTIONS_NOT_OBJ</a> | Options for the route must be an object. | Use an object for the route options. | [#4554](https://github.com/fastify/fastify/pull/4554) |

| <a id="fst_err_plugin_not_present_in_instance">FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE</a> | The decorator is not present in the instance. | - | [#4554](https://github.com/fastify/fastify/pull/4554) |
| <a id="fst_err_plugin_invalid_async_handler">FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER</a> | The plugin being registered mixes async and callback styles. | - | [#5141](https://github.com/fastify/fastify/pull/5141) |
| <a id="fst_err_validation">FST_ERR_VALIDATION</a> | The Request failed the payload validation. | Check the request payload. | [#4824](https://github.com/fastify/fastify/pull/4824) |

@@ -369,0 +375,0 @@ | <a id="fst_err_listen_options_invalid">FST_ERR_LISTEN_OPTIONS_INVALID</a> | Invalid listen options. | Check the listen options. | [#4886](https://github.com/fastify/fastify/pull/4886) |

@@ -101,6 +101,6 @@ <h1 align="center">Fastify</h1>

By default, Fastify adds an ID to every request for easier tracking. If the
"request-id" header is present its value is used, otherwise a new incremental ID
is generated. See Fastify Factory
[`requestIdHeader`](./Server.md#factory-request-id-header) and Fastify Factory
[`genReqId`](./Server.md#genreqid) for customization options.
requestIdHeader-option is set and the corresponding header is present than
its value is used, otherwise a new incremental ID is generated. See Fastify
Factory [`requestIdHeader`](./Server.md#factory-request-id-header) and Fastify
Factory [`genReqId`](./Server.md#genreqid) for customization options.

@@ -247,3 +247,3 @@ The default logger is configured with a set of standard serializers that

headers: request.headers,
hostname: request.hostname,
host: request.host,
remoteAddress: request.ip,

@@ -250,0 +250,0 @@ remotePort: request.socket.remotePort

@@ -23,6 +23,8 @@ <h1 align="center">Fastify</h1>

[`trustProxy`](./Server.md#factory-trust-proxy) option is enabled)
- `hostname` - the host of the incoming request (derived from `X-Forwarded-Host`
- `host` - the host of the incoming request (derived from `X-Forwarded-Host`
header when the [`trustProxy`](./Server.md#factory-trust-proxy) option is
enabled). For HTTP/2 compatibility it returns `:authority` if no host header
exists.
- `hostname` - the host of the incoming request without the port
- `port` - the port that the server is listening on
- `protocol` - the protocol of the incoming request (`https` or `http`)

@@ -108,3 +110,5 @@ - `method` - the method of the incoming request

console.log(request.ips)
console.log(request.host)
console.log(request.hostname)
console.log(request.port)
console.log(request.protocol)

@@ -111,0 +115,0 @@ console.log(request.url)

@@ -193,2 +193,20 @@ <h1 align="center">Fastify</h1>

`fastify.propfind(path, [options], handler)`
`fastify.proppatch(path, [options], handler)`
`fastify.mkcol(path, [options], handler)`
`fastify.copy(path, [options], handler)`
`fastify.move(path, [options], handler)`
`fastify.lock(path, [options], handler)`
`fastify.unlock(path, [options], handler)`
`fastify.trace(path, [options], handler)`
`fastify.search(path, [options], handler)`
Example:

@@ -582,3 +600,3 @@ ```js

headers: req.headers,
hostname: req.hostname,
host: req.host,
remoteAddress: req.ip,

@@ -814,23 +832,1 @@ remotePort: req.socket.remotePort

> ```
### ⚠ HTTP version check
Fastify will check the HTTP version of every request, based on configuration
options ([http2](./Server.md#http2), [https](./Server.md#https), and
[serverFactory](./Server.md#serverfactory)), to determine if it matches one or
all of the > following versions: `2.0`, `1.1`, and `1.0`. If Fastify receives a
different HTTP version in the request it will return a `505 HTTP Version Not
Supported` error.
| | 2.0 | 1.1 | 1.0 | skip |
|:------------------------:|:---:|:---:|:---:|:----:|
| http2 | ✓ | | | |
| http2 + https | ✓ | | | |
| http2 + https.allowHTTP1 | ✓ | ✓ | ✓ | |
| https | | ✓ | ✓ | |
| http | | ✓ | ✓ | |
| serverFactory | | | | ✓ |
Note: The internal HTTP version check will be removed in the future when Node
implements [this feature](https://github.com/nodejs/node/issues/43115).

@@ -17,6 +17,4 @@

- [FSTDEP010](#FSTDEP010)
- [FSTDEP011](#FSTDEP011)
- [FSTDEP012](#FSTDEP012)
- [FSTDEP013](#FSTDEP013)
- [FSTDEP014](#FSTDEP014)
- [FSTDEP015](#FSTDEP015)

@@ -84,6 +82,4 @@ - [FSTDEP016](#FSTDEP016)

| <a id="FSTDEP010">FSTDEP010</a> | Modifying the `reply.sent` property is deprecated. | Use the `reply.hijack()` method. | [#3140](https://github.com/fastify/fastify/pull/3140) |
| <a id="FSTDEP011">FSTDEP011</a> | Variadic listen method is deprecated. | Use `.listen(optionsObject)`. | [#3712](https://github.com/fastify/fastify/pull/3712) |
| <a id="FSTDEP012">FSTDEP012</a> | You are trying to access the deprecated `request.context` property. | Use `request.routeOptions.config` or `request.routeOptions.schema`. | [#4216](https://github.com/fastify/fastify/pull/4216) [#5084](https://github.com/fastify/fastify/pull/5084) |
| <a id="FSTDEP013">FSTDEP013</a> | Direct return of "trailers" function is deprecated. | Use "callback" or "async-await" for return value. | [#4380](https://github.com/fastify/fastify/pull/4380) |
| <a id="FSTDEP014">FSTDEP014</a> | You are trying to set/access the default route. This property is deprecated. | Use `setNotFoundHandler` if you want to custom a 404 handler or the wildcard (`*`) to match all routes. | [#4480](https://github.com/fastify/fastify/pull/4480) |
| <a id="FSTDEP015">FSTDEP015</a> | You are accessing the deprecated `request.routeSchema` property. | Use `request.routeOptions.schema`. | [#4470](https://github.com/fastify/fastify/pull/4470) |

@@ -90,0 +86,0 @@ | <a id="FSTDEP016">FSTDEP016</a> | You are accessing the deprecated `request.routeConfig` property. | Use `request.routeOptions.config`. | [#4470](https://github.com/fastify/fastify/pull/4470) |

@@ -105,3 +105,4 @@ import * as http from 'http'

onConstructorPoisoning?: ConstructorAction,
logger?: boolean | FastifyLoggerOptions<RawServer> & PinoLoggerOptions | Logger,
logger?: boolean | FastifyLoggerOptions<RawServer> & PinoLoggerOptions,
loggerInstance?: Logger
serializerOpts?: FJSOptions | Record<string, unknown>,

@@ -108,0 +109,0 @@ serverFactory?: FastifyServerFactory<RawServer>,

'use strict'
const VERSION = '4.27.0'
const VERSION = '5.0.0-aplha.1'

@@ -35,3 +35,3 @@ const Avvio = require('avvio')

const { createServer, compileValidateHTTPVersion } = require('./lib/server')
const { createServer } = require('./lib/server')
const Reply = require('./lib/reply')

@@ -115,3 +115,3 @@ const Request = require('./lib/request')

const requestIdHeader = (options.requestIdHeader === false) ? false : (options.requestIdHeader || defaultInitOptions.requestIdHeader).toLowerCase()
const requestIdHeader = typeof options.requestIdHeader === 'string' && options.requestIdHeader.length !== 0 ? options.requestIdHeader.toLowerCase() : (options.requestIdHeader === true && 'request-id')
const genReqId = reqIdGenFactory(requestIdHeader, options.genReqId)

@@ -257,4 +257,2 @@ const requestIdLogLabel = options.requestIdLogLabel || 'reqId'

routing: httpHandler,
getDefaultRoute: router.getDefaultRoute.bind(router),
setDefaultRoute: router.setDefaultRoute.bind(router),
// routes shorthand methods

@@ -282,2 +280,35 @@ delete: function _delete (url, options, handler) {

},
propfind: function _propfind (url, options, handler) {
return router.prepareRoute.call(this, { method: 'PROPFIND', url, options, handler })
},
proppatch: function _proppatch (url, options, handler) {
return router.prepareRoute.call(this, { method: 'PROPPATCH', url, options, handler })
},
mkcalendar: function _mkcalendar (url, options, handler) {
return router.prepareRoute.call(this, { method: 'MKCALENDAR', url, options, handler })
},
mkcol: function _mkcol (url, options, handler) {
return router.prepareRoute.call(this, { method: 'MKCOL', url, options, handler })
},
copy: function _copy (url, options, handler) {
return router.prepareRoute.call(this, { method: 'COPY', url, options, handler })
},
move: function _move (url, options, handler) {
return router.prepareRoute.call(this, { method: 'MOVE', url, options, handler })
},
lock: function _lock (url, options, handler) {
return router.prepareRoute.call(this, { method: 'LOCK', url, options, handler })
},
unlock: function _unlock (url, options, handler) {
return router.prepareRoute.call(this, { method: 'UNLOCK', url, options, handler })
},
trace: function _trace (url, options, handler) {
return router.prepareRoute.call(this, { method: 'TRACE', url, options, handler })
},
report: function _mkcalendar (url, options, handler) {
return router.prepareRoute.call(this, { method: 'REPORT', url, options, handler })
},
search: function _search (url, options, handler) {
return router.prepareRoute.call(this, { method: 'SEARCH', url, options, handler })
},
all: function _all (url, options, handler) {

@@ -510,3 +541,2 @@ return router.prepareRoute.call(this, { method: supportedMethods, url, options, handler })

throwIfAlreadyStarted,
validateHTTPVersion: compileValidateHTTPVersion(options),
keepAliveConnections

@@ -513,0 +543,0 @@ })

@@ -6,3 +6,3 @@ // This file is autogenerated by build/build-validation.js, do not edit

module.exports.default = validate10;
const schema11 = {"type":"object","additionalProperties":false,"properties":{"connectionTimeout":{"type":"integer","default":0},"keepAliveTimeout":{"type":"integer","default":72000},"forceCloseConnections":{"oneOf":[{"type":"string","pattern":"idle"},{"type":"boolean"}]},"maxRequestsPerSocket":{"type":"integer","default":0,"nullable":true},"requestTimeout":{"type":"integer","default":0},"bodyLimit":{"type":"integer","default":1048576},"caseSensitive":{"type":"boolean","default":true},"allowUnsafeRegex":{"type":"boolean","default":false},"http2":{"type":"boolean"},"https":{"if":{"not":{"oneOf":[{"type":"boolean"},{"type":"null"},{"type":"object","additionalProperties":false,"required":["allowHTTP1"],"properties":{"allowHTTP1":{"type":"boolean"}}}]}},"then":{"setDefaultValue":true}},"ignoreTrailingSlash":{"type":"boolean","default":false},"ignoreDuplicateSlashes":{"type":"boolean","default":false},"disableRequestLogging":{"type":"boolean","default":false},"jsonShorthand":{"type":"boolean","default":true},"maxParamLength":{"type":"integer","default":100},"onProtoPoisoning":{"type":"string","default":"error"},"onConstructorPoisoning":{"type":"string","default":"error"},"pluginTimeout":{"type":"integer","default":10000},"requestIdHeader":{"anyOf":[{"enum":[false]},{"type":"string"}],"default":"request-id"},"requestIdLogLabel":{"type":"string","default":"reqId"},"http2SessionTimeout":{"type":"integer","default":72000},"exposeHeadRoutes":{"type":"boolean","default":true},"useSemicolonDelimiter":{"type":"boolean","default":true},"versioning":{"type":"object","additionalProperties":true,"required":["storage","deriveVersion"],"properties":{"storage":{},"deriveVersion":{}}},"constraints":{"type":"object","additionalProperties":{"type":"object","required":["name","storage","validate","deriveConstraint"],"additionalProperties":true,"properties":{"name":{"type":"string"},"storage":{},"validate":{},"deriveConstraint":{}}}}}};
const schema11 = {"type":"object","additionalProperties":false,"properties":{"connectionTimeout":{"type":"integer","default":0},"keepAliveTimeout":{"type":"integer","default":72000},"forceCloseConnections":{"oneOf":[{"type":"string","pattern":"idle"},{"type":"boolean"}]},"maxRequestsPerSocket":{"type":"integer","default":0,"nullable":true},"requestTimeout":{"type":"integer","default":0},"bodyLimit":{"type":"integer","default":1048576},"caseSensitive":{"type":"boolean","default":true},"allowUnsafeRegex":{"type":"boolean","default":false},"http2":{"type":"boolean"},"https":{"if":{"not":{"oneOf":[{"type":"boolean"},{"type":"null"},{"type":"object","additionalProperties":false,"required":["allowHTTP1"],"properties":{"allowHTTP1":{"type":"boolean"}}}]}},"then":{"setDefaultValue":true}},"ignoreTrailingSlash":{"type":"boolean","default":false},"ignoreDuplicateSlashes":{"type":"boolean","default":false},"disableRequestLogging":{"type":"boolean","default":false},"jsonShorthand":{"type":"boolean","default":true},"maxParamLength":{"type":"integer","default":100},"onProtoPoisoning":{"type":"string","default":"error"},"onConstructorPoisoning":{"type":"string","default":"error"},"pluginTimeout":{"type":"integer","default":10000},"requestIdHeader":{"anyOf":[{"type":"boolean"},{"type":"string"}],"default":false},"requestIdLogLabel":{"type":"string","default":"reqId"},"http2SessionTimeout":{"type":"integer","default":72000},"exposeHeadRoutes":{"type":"boolean","default":true},"useSemicolonDelimiter":{"type":"boolean","default":false},"versioning":{"type":"object","additionalProperties":true,"required":["storage","deriveVersion"],"properties":{"storage":{},"deriveVersion":{}}},"constraints":{"type":"object","additionalProperties":{"type":"object","required":["name","storage","validate","deriveConstraint"],"additionalProperties":true,"properties":{"name":{"type":"string"},"storage":{},"validate":{},"deriveConstraint":{}}}}}};
const func2 = Object.prototype.hasOwnProperty;

@@ -62,3 +62,3 @@ const pattern0 = new RegExp("idle", "u");

if(data.requestIdHeader === undefined){
data.requestIdHeader = "request-id";
data.requestIdHeader = false;
}

@@ -75,3 +75,3 @@ if(data.requestIdLogLabel === undefined){

if(data.useSemicolonDelimiter === undefined){
data.useSemicolonDelimiter = true;
data.useSemicolonDelimiter = false;
}

@@ -849,4 +849,13 @@ const _errs1 = errors;

const _errs59 = errors;
if(!(data19 === false)){
const err12 = {instancePath:instancePath+"/requestIdHeader",schemaPath:"#/properties/requestIdHeader/anyOf/0/enum",keyword:"enum",params:{allowedValues: schema11.properties.requestIdHeader.anyOf[0].enum},message:"must be equal to one of the allowed values"};
if(typeof data19 !== "boolean"){
let coerced21 = undefined;
if(!(coerced21 !== undefined)){
if(data19 === "false" || data19 === 0 || data19 === null){
coerced21 = false;
}
else if(data19 === "true" || data19 === 1){
coerced21 = true;
}
else {
const err12 = {instancePath:instancePath+"/requestIdHeader",schemaPath:"#/properties/requestIdHeader/anyOf/0/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"};
if(vErrors === null){

@@ -860,15 +869,23 @@ vErrors = [err12];

}
}
if(coerced21 !== undefined){
data19 = coerced21;
if(data !== undefined){
data["requestIdHeader"] = coerced21;
}
}
}
var _valid3 = _errs59 === errors;
valid6 = valid6 || _valid3;
if(!valid6){
const _errs60 = errors;
const _errs61 = errors;
if(typeof data19 !== "string"){
let dataType21 = typeof data19;
let coerced21 = undefined;
if(!(coerced21 !== undefined)){
if(dataType21 == "number" || dataType21 == "boolean"){
coerced21 = "" + data19;
let dataType22 = typeof data19;
let coerced22 = undefined;
if(!(coerced22 !== undefined)){
if(dataType22 == "number" || dataType22 == "boolean"){
coerced22 = "" + data19;
}
else if(data19 === null){
coerced21 = "";
coerced22 = "";
}

@@ -886,10 +903,10 @@ else {

}
if(coerced21 !== undefined){
data19 = coerced21;
if(coerced22 !== undefined){
data19 = coerced22;
if(data !== undefined){
data["requestIdHeader"] = coerced21;
data["requestIdHeader"] = coerced22;
}
}
}
var _valid3 = _errs60 === errors;
var _valid3 = _errs61 === errors;
valid6 = valid6 || _valid3;

@@ -923,12 +940,12 @@ }

let data20 = data.requestIdLogLabel;
const _errs62 = errors;
const _errs63 = errors;
if(typeof data20 !== "string"){
let dataType22 = typeof data20;
let coerced22 = undefined;
if(!(coerced22 !== undefined)){
if(dataType22 == "number" || dataType22 == "boolean"){
coerced22 = "" + data20;
let dataType23 = typeof data20;
let coerced23 = undefined;
if(!(coerced23 !== undefined)){
if(dataType23 == "number" || dataType23 == "boolean"){
coerced23 = "" + data20;
}
else if(data20 === null){
coerced22 = "";
coerced23 = "";
}

@@ -940,20 +957,20 @@ else {

}
if(coerced22 !== undefined){
data20 = coerced22;
if(coerced23 !== undefined){
data20 = coerced23;
if(data !== undefined){
data["requestIdLogLabel"] = coerced22;
data["requestIdLogLabel"] = coerced23;
}
}
}
var valid0 = _errs62 === errors;
var valid0 = _errs63 === errors;
if(valid0){
let data21 = data.http2SessionTimeout;
const _errs64 = errors;
const _errs65 = errors;
if(!(((typeof data21 == "number") && (!(data21 % 1) && !isNaN(data21))) && (isFinite(data21)))){
let dataType23 = typeof data21;
let coerced23 = undefined;
if(!(coerced23 !== undefined)){
if(dataType23 === "boolean" || data21 === null
|| (dataType23 === "string" && data21 && data21 == +data21 && !(data21 % 1))){
coerced23 = +data21;
let dataType24 = typeof data21;
let coerced24 = undefined;
if(!(coerced24 !== undefined)){
if(dataType24 === "boolean" || data21 === null
|| (dataType24 === "string" && data21 && data21 == +data21 && !(data21 % 1))){
coerced24 = +data21;
}

@@ -965,21 +982,21 @@ else {

}
if(coerced23 !== undefined){
data21 = coerced23;
if(coerced24 !== undefined){
data21 = coerced24;
if(data !== undefined){
data["http2SessionTimeout"] = coerced23;
data["http2SessionTimeout"] = coerced24;
}
}
}
var valid0 = _errs64 === errors;
var valid0 = _errs65 === errors;
if(valid0){
let data22 = data.exposeHeadRoutes;
const _errs66 = errors;
const _errs67 = errors;
if(typeof data22 !== "boolean"){
let coerced24 = undefined;
if(!(coerced24 !== undefined)){
let coerced25 = undefined;
if(!(coerced25 !== undefined)){
if(data22 === "false" || data22 === 0 || data22 === null){
coerced24 = false;
coerced25 = false;
}
else if(data22 === "true" || data22 === 1){
coerced24 = true;
coerced25 = true;
}

@@ -991,21 +1008,21 @@ else {

}
if(coerced24 !== undefined){
data22 = coerced24;
if(coerced25 !== undefined){
data22 = coerced25;
if(data !== undefined){
data["exposeHeadRoutes"] = coerced24;
data["exposeHeadRoutes"] = coerced25;
}
}
}
var valid0 = _errs66 === errors;
var valid0 = _errs67 === errors;
if(valid0){
let data23 = data.useSemicolonDelimiter;
const _errs68 = errors;
const _errs69 = errors;
if(typeof data23 !== "boolean"){
let coerced25 = undefined;
if(!(coerced25 !== undefined)){
let coerced26 = undefined;
if(!(coerced26 !== undefined)){
if(data23 === "false" || data23 === 0 || data23 === null){
coerced25 = false;
coerced26 = false;
}
else if(data23 === "true" || data23 === 1){
coerced25 = true;
coerced26 = true;
}

@@ -1017,15 +1034,15 @@ else {

}
if(coerced25 !== undefined){
data23 = coerced25;
if(coerced26 !== undefined){
data23 = coerced26;
if(data !== undefined){
data["useSemicolonDelimiter"] = coerced25;
data["useSemicolonDelimiter"] = coerced26;
}
}
}
var valid0 = _errs68 === errors;
var valid0 = _errs69 === errors;
if(valid0){
if(data.versioning !== undefined){
let data24 = data.versioning;
const _errs70 = errors;
if(errors === _errs70){
const _errs71 = errors;
if(errors === _errs71){
if(data24 && typeof data24 == "object" && !Array.isArray(data24)){

@@ -1043,3 +1060,3 @@ let missing1;

}
var valid0 = _errs70 === errors;
var valid0 = _errs71 === errors;
}

@@ -1052,9 +1069,9 @@ else {

let data25 = data.constraints;
const _errs73 = errors;
if(errors === _errs73){
const _errs74 = errors;
if(errors === _errs74){
if(data25 && typeof data25 == "object" && !Array.isArray(data25)){
for(const key2 in data25){
let data26 = data25[key2];
const _errs76 = errors;
if(errors === _errs76){
const _errs77 = errors;
if(errors === _errs77){
if(data26 && typeof data26 == "object" && !Array.isArray(data26)){

@@ -1070,10 +1087,10 @@ let missing2;

if(typeof data27 !== "string"){
let dataType26 = typeof data27;
let coerced26 = undefined;
if(!(coerced26 !== undefined)){
if(dataType26 == "number" || dataType26 == "boolean"){
coerced26 = "" + data27;
let dataType27 = typeof data27;
let coerced27 = undefined;
if(!(coerced27 !== undefined)){
if(dataType27 == "number" || dataType27 == "boolean"){
coerced27 = "" + data27;
}
else if(data27 === null){
coerced26 = "";
coerced27 = "";
}

@@ -1085,6 +1102,6 @@ else {

}
if(coerced26 !== undefined){
data27 = coerced26;
if(coerced27 !== undefined){
data27 = coerced27;
if(data26 !== undefined){
data26["name"] = coerced26;
data26["name"] = coerced27;
}

@@ -1101,3 +1118,3 @@ }

}
var valid7 = _errs76 === errors;
var valid7 = _errs77 === errors;
if(!valid7){

@@ -1113,3 +1130,3 @@ break;

}
var valid0 = _errs73 === errors;
var valid0 = _errs74 === errors;
}

@@ -1155,2 +1172,2 @@ else {

module.exports.defaultInitOptions = {"connectionTimeout":0,"keepAliveTimeout":72000,"maxRequestsPerSocket":0,"requestTimeout":0,"bodyLimit":1048576,"caseSensitive":true,"allowUnsafeRegex":false,"disableRequestLogging":false,"jsonShorthand":true,"ignoreTrailingSlash":false,"ignoreDuplicateSlashes":false,"maxParamLength":100,"onProtoPoisoning":"error","onConstructorPoisoning":"error","pluginTimeout":10000,"requestIdHeader":"request-id","requestIdLogLabel":"reqId","http2SessionTimeout":72000,"exposeHeadRoutes":true,"useSemicolonDelimiter":true}
module.exports.defaultInitOptions = {"connectionTimeout":0,"keepAliveTimeout":72000,"maxRequestsPerSocket":0,"requestTimeout":0,"bodyLimit":1048576,"caseSensitive":true,"allowUnsafeRegex":false,"disableRequestLogging":false,"jsonShorthand":true,"ignoreTrailingSlash":false,"ignoreDuplicateSlashes":false,"maxParamLength":100,"onProtoPoisoning":"error","onConstructorPoisoning":"error","pluginTimeout":10000,"requestIdHeader":false,"requestIdLogLabel":"reqId","http2SessionTimeout":72000,"exposeHeadRoutes":true,"useSemicolonDelimiter":false}

@@ -5,3 +5,2 @@ 'use strict'

const { FifoMap: Fifo } = require('toad-cache')
const { safeParse: safeParseContentType, defaultContentType } = require('fast-content-type-parse')
const secureJson = require('secure-json-parse')

@@ -31,2 +30,3 @@ const {

} = require('./errors')
const { FSTSEC001 } = require('./warnings')

@@ -39,3 +39,3 @@ function ContentTypeParser (bodyLimit, onProtoPoisoning, onConstructorPoisoning) {

this.customParsers.set('text/plain', new Parser(true, false, bodyLimit, defaultPlainTextParser))
this.parserList = [new ParserListItem('application/json'), new ParserListItem('text/plain')]
this.parserList = ['application/json', 'text/plain']
this.parserRegExpList = []

@@ -48,6 +48,13 @@ this.cache = new Fifo(100)

if (!contentTypeIsString && !(contentType instanceof RegExp)) throw new FST_ERR_CTP_INVALID_TYPE()
if (contentTypeIsString && contentType.length === 0) throw new FST_ERR_CTP_EMPTY_TYPE()
if (typeof parserFn !== 'function') throw new FST_ERR_CTP_INVALID_HANDLER()
if (contentTypeIsString) {
contentType = contentType.trim().toLowerCase()
if (contentType.length === 0) throw new FST_ERR_CTP_EMPTY_TYPE()
} else if (!(contentType instanceof RegExp)) {
throw new FST_ERR_CTP_INVALID_TYPE()
}
if (typeof parserFn !== 'function') {
throw new FST_ERR_CTP_INVALID_HANDLER()
}
if (this.existingParser(contentType)) {

@@ -70,12 +77,13 @@ throw new FST_ERR_CTP_ALREADY_PRESENT(contentType)

if (contentTypeIsString && contentType === '*') {
if (contentType === '*') {
this.customParsers.set('', parser)
} else {
if (contentTypeIsString) {
this.parserList.unshift(new ParserListItem(contentType))
this.parserList.unshift(contentType)
this.customParsers.set(contentType, parser)
} else {
contentType.isEssence = contentType.source.indexOf(';') === -1
validateRegExp(contentType)
this.parserRegExpList.unshift(contentType)
this.customParsers.set(contentType.toString(), parser)
}
this.customParsers.set(contentType.toString(), parser)
}

@@ -85,3 +93,10 @@ }

ContentTypeParser.prototype.hasParser = function (contentType) {
return this.customParsers.has(typeof contentType === 'string' ? contentType : contentType.toString())
if (typeof contentType === 'string') {
contentType = contentType.trim().toLowerCase()
} else {
if (!(contentType instanceof RegExp)) throw new FST_ERR_CTP_INVALID_TYPE()
contentType = contentType.toString()
}
return this.customParsers.has(contentType)
}

@@ -101,23 +116,16 @@

ContentTypeParser.prototype.getParser = function (contentType) {
if (this.hasParser(contentType)) {
return this.customParsers.get(contentType)
}
let parser = this.customParsers.get(contentType)
if (parser !== undefined) return parser
const parser = this.cache.get(contentType)
parser = this.cache.get(contentType)
if (parser !== undefined) return parser
const parsed = safeParseContentType(contentType)
// dummyContentType always the same object
// we can use === for the comparison and return early
if (parsed === defaultContentType) {
return this.customParsers.get('')
}
// eslint-disable-next-line no-var
for (var i = 0; i !== this.parserList.length; ++i) {
const parserListItem = this.parserList[i]
if (compareContentType(parsed, parserListItem)) {
const parser = this.customParsers.get(parserListItem.name)
// we set request content-type in cache to reduce parsing of MIME type
if (
contentType.slice(0, parserListItem.length) === parserListItem &&
(contentType.length === parserListItem.length || contentType.charCodeAt(parserListItem.length) === 59 /* `;` */ || contentType.charCodeAt(parserListItem.length) === 32 /* ` ` */)
) {
parser = this.customParsers.get(parserListItem)
this.cache.set(contentType, parser)

@@ -131,5 +139,4 @@ return parser

const parserRegExp = this.parserRegExpList[j]
if (compareRegExpContentType(contentType, parsed.type, parserRegExp)) {
const parser = this.customParsers.get(parserRegExp.toString())
// we set request content-type in cache to reduce parsing of MIME type
if (parserRegExp.test(contentType)) {
parser = this.customParsers.get(parserRegExp.toString())
this.cache.set(contentType, parser)

@@ -151,10 +158,16 @@ return parser

ContentTypeParser.prototype.remove = function (contentType) {
if (!(typeof contentType === 'string' || contentType instanceof RegExp)) throw new FST_ERR_CTP_INVALID_TYPE()
let parsers
const removed = this.customParsers.delete(contentType.toString())
if (typeof contentType === 'string') {
contentType = contentType.trim().toLowerCase()
parsers = this.parserList
} else {
if (!(contentType instanceof RegExp)) throw new FST_ERR_CTP_INVALID_TYPE()
contentType = contentType.toString()
parsers = this.parserRegExpList
}
const parsers = typeof contentType === 'string' ? this.parserList : this.parserRegExpList
const removed = this.customParsers.delete(contentType)
const idx = parsers.findIndex(ct => ct.toString() === contentType)
const idx = parsers.findIndex(ct => ct.toString() === contentType.toString())
if (idx > -1) {

@@ -194,3 +207,3 @@ parsers.splice(idx, 1)

if (result && typeof result.then === 'function') {
if (typeof result?.then === 'function') {
result.then(body => done(null, body), done)

@@ -218,5 +231,3 @@ }

const limit = options.limit === null ? parser.bodyLimit : options.limit
const contentLength = request.headers['content-length'] === undefined
? NaN
: Number(request.headers['content-length'])
const contentLength = Number(request.headers['content-length'])

@@ -387,56 +398,11 @@ if (contentLength > limit) {

function compareContentType (contentType, parserListItem) {
if (parserListItem.isEssence) {
// we do essence check
return contentType.type.indexOf(parserListItem) !== -1
} else {
// when the content-type includes parameters
// we do a full-text search
// reject essence content-type before checking parameters
if (contentType.type.indexOf(parserListItem.type) === -1) return false
for (const key of parserListItem.parameterKeys) {
// reject when missing parameters
if (!(key in contentType.parameters)) return false
// reject when parameters do not match
if (contentType.parameters[key] !== parserListItem.parameters[key]) return false
}
return true
function validateRegExp (regexp) {
// RegExp should either start with ^ or include ;?
// It can ensure the user is properly detect the essence
// MIME types.
if (regexp.source[0] !== '^' && regexp.source.includes(';?') === false) {
FSTSEC001(regexp.source)
}
}
function compareRegExpContentType (contentType, essenceMIMEType, regexp) {
if (regexp.isEssence) {
// we do essence check
return regexp.test(essenceMIMEType)
} else {
// when the content-type includes parameters
// we do a full-text match
return regexp.test(contentType)
}
}
function ParserListItem (contentType) {
this.name = contentType
// we pre-calculate all the needed information
// before content-type comparison
const parsed = safeParseContentType(contentType)
this.isEssence = contentType.indexOf(';') === -1
// we should not allow empty string for parser list item
// because it would become a match-all handler
if (this.isEssence === false && parsed.type === '') {
// handle semicolon or empty string
const tmp = contentType.split(';', 1)[0]
this.type = tmp === '' ? contentType : tmp
} else {
this.type = parsed.type
}
this.parameters = parsed.parameters
this.parameterKeys = Object.keys(parsed.parameters)
}
// used in ContentTypeParser.remove
ParserListItem.prototype.toString = function () {
return this.name
}
module.exports = ContentTypeParser

@@ -443,0 +409,0 @@ module.exports.helpers = {

@@ -212,2 +212,23 @@ 'use strict'

FST_ERR_LOG_INVALID_LOGGER_INSTANCE: createError(
'FST_ERR_LOG_INVALID_LOGGER_INSTANCE',
'loggerInstance only accepts a logger instance.',
500,
TypeError
),
FST_ERR_LOG_INVALID_LOGGER_CONFIG: createError(
'FST_ERR_LOG_INVALID_LOGGER_CONFIG',
'logger options only accepts a configuration object.',
500,
TypeError
),
FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED: createError(
'FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED',
'You cannot provide both logger and loggerInstance. Please provide only one.',
500,
TypeError
),
/**

@@ -343,8 +364,2 @@ * reply

),
FST_ERR_DEFAULT_ROUTE_INVALID_TYPE: createError(
'FST_ERR_DEFAULT_ROUTE_INVALID_TYPE',
'The defaultRoute type should be a function',
500,
TypeError
),
FST_ERR_INVALID_URL: createError(

@@ -434,2 +449,8 @@ 'FST_ERR_INVALID_URL',

),
FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER: createError(
'FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER',
'The %s plugin being registered mixes async and callback styles. Async plugin should not mix async and callback style.',
500,
TypeError
),

@@ -436,0 +457,0 @@ /**

'use strict'
const { bodylessMethods, bodyMethods } = require('./httpMethods')
const { validate: validateSchema } = require('./validation')

@@ -23,3 +24,3 @@ const { preValidationHookRunner, preHandlerHookRunner } = require('./hooks')

if (method === 'GET' || method === 'HEAD') {
if (bodylessMethods.has(method)) {
handler(request, reply)

@@ -29,11 +30,13 @@ return

const contentType = headers['content-type']
if (bodyMethods.has(method)) {
const contentType = headers['content-type']
const contentLength = headers['content-length']
const transferEncoding = headers['transfer-encoding']
if (method === 'POST' || method === 'PUT' || method === 'PATCH' || method === 'TRACE' || method === 'SEARCH' ||
method === 'PROPFIND' || method === 'PROPPATCH' || method === 'LOCK' || method === 'REPORT' || method === 'MKCALENDAR') {
if (contentType === undefined) {
if (
headers['transfer-encoding'] === undefined &&
(headers['content-length'] === '0' || headers['content-length'] === undefined)
) { // Request has no body to parse
(contentLength === undefined || contentLength === '0') &&
transferEncoding === undefined
) {
// Request has no body to parse
handler(request, reply)

@@ -44,2 +47,7 @@ } else {

} else {
if (contentLength === undefined && transferEncoding === undefined && method === 'OPTIONS') {
// OPTIONS can have a Content-Type header without a body
handler(request, reply)
return
}
context.contentTypeParser.run(contentType, handler, request, reply)

@@ -50,17 +58,2 @@ }

if (method === 'OPTIONS' || method === 'DELETE') {
if (
contentType !== undefined &&
(
headers['transfer-encoding'] !== undefined ||
headers['content-length'] !== undefined
)
) {
context.contentTypeParser.run(contentType, handler, request, reply)
} else {
handler(request, reply)
}
return
}
// Return 404 instead of 405 see https://github.com/fastify/fastify/pull/862 for discussion

@@ -67,0 +60,0 @@ handler(request, reply)

'use strict'
const bodylessMethods = new Set([
// Standard
'GET',
'HEAD',
'TRACE',
// WebDAV
'UNLOCK'
])
const bodyMethods = new Set([
// Standard
'DELETE',
'OPTIONS',
'PATCH',
'PUT',
'POST',
// WebDAV
'COPY',
'LOCK',
'MOVE',
'MKCOL',
'PROPFIND',
'PROPPATCH',
'REPORT',
'SEARCH',
'MKCALENDAR'
])
module.exports = {
bodylessMethods,
bodyMethods,
supportedMethods: [
'DELETE',
'GET',
'HEAD',
'PATCH',
'POST',
'PUT',
'OPTIONS',
'PROPFIND',
'PROPPATCH',
'MKCOL',
'COPY',
'MOVE',
'LOCK',
'UNLOCK',
'TRACE',
'SEARCH',
'REPORT',
'MKCALENDAR'
...bodylessMethods,
...bodyMethods
]
}

@@ -14,3 +14,6 @@ 'use strict'

FST_ERR_LOG_INVALID_DESTINATION,
FST_ERR_LOG_INVALID_LOGGER
FST_ERR_LOG_INVALID_LOGGER,
FST_ERR_LOG_INVALID_LOGGER_INSTANCE,
FST_ERR_LOG_INVALID_LOGGER_CONFIG,
FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED
} = require('./errors')

@@ -55,3 +58,3 @@

version: req.headers && req.headers['accept-version'],
hostname: req.hostname,
host: req.host,
remoteAddress: req.ip,

@@ -75,3 +78,4 @@ remotePort: req.socket ? req.socket.remotePort : undefined

function createLogger (options) {
if (!options.logger) {
// if no logger is provided, then create a default logger
if (!options.loggerInstance && !options.logger) {
const logger = nullLogger

@@ -82,6 +86,11 @@ logger.child = () => logger

if (validateLogger(options.logger)) {
if (options.logger && options.loggerInstance) {
throw new FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED()
}
// check if the logger instance has all required properties
if (validateLogger(options.loggerInstance)) {
const logger = createPinoLogger({
logger: options.logger,
serializers: Object.assign({}, serializers, options.logger.serializers)
logger: options.loggerInstance,
serializers: Object.assign({}, serializers, options.loggerInstance.serializers)
})

@@ -91,2 +100,11 @@ return { logger, hasLogger: true }

// if a logger instance is passed to logger, throw an exception
if (validateLogger(options.logger)) {
throw FST_ERR_LOG_INVALID_LOGGER_CONFIG()
}
if (options.loggerInstance) {
throw FST_ERR_LOG_INVALID_LOGGER_INSTANCE()
}
const localLoggerOptions = {}

@@ -93,0 +111,0 @@ if (Object.prototype.toString.call(options.logger) === '[object Object]') {

@@ -12,5 +12,5 @@ 'use strict'

FST_ERR_PLUGIN_VERSION_MISMATCH,
FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE
FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE,
FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER
} = require('./errors')
const { FSTWRN002 } = require('./warnings.js')

@@ -142,3 +142,3 @@ function getMeta (fn) {

if (fn.constructor.name === 'AsyncFunction' && fn.length === 3) {
FSTWRN002(pluginName || 'anonymous')
throw new FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER(pluginName)
}

@@ -145,0 +145,0 @@ }

@@ -126,3 +126,3 @@ 'use strict'

},
hostname: {
host: {
get () {

@@ -261,3 +261,3 @@ if (this.ip !== undefined && this.headers['x-forwarded-host']) {

},
hostname: {
host: {
get () {

@@ -267,2 +267,23 @@ return this.raw.headers.host || this.raw.headers[':authority']

},
hostname: {
get () {
return (this.host).split(':')[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 portFromHeader = parseInt((this.headers.host || this.headers[':authority']).split(':').slice(-1)[0])
if (!isNaN(portFromHeader)) {
return portFromHeader
}
// fall back to null
return null
}
},
protocol: {

@@ -305,9 +326,9 @@ get () {

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
)
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
)

@@ -349,4 +370,4 @@ const validateFn = validatorCompiler({

if (validate == null && (schema == null ||
typeof schema !== 'object' ||
Array.isArray(schema))
typeof schema !== 'object' ||
Array.isArray(schema))
) {

@@ -353,0 +374,0 @@ throw new FST_ERR_REQ_INVALID_VALIDATION_INVOCATION(httpPart)

@@ -12,4 +12,3 @@ 'use strict'

FSTDEP007,
FSTDEP008,
FSTDEP014
FSTDEP008
} = require('./warnings')

@@ -25,3 +24,2 @@

FST_ERR_SCH_SERIALIZATION_BUILD,
FST_ERR_DEFAULT_ROUTE_INVALID_TYPE,
FST_ERR_DUPLICATED_ROUTE,

@@ -77,3 +75,2 @@ FST_ERR_INVALID_URL,

let globalExposeHeadRoutes
let validateHTTPVersion
let keepAliveConnections

@@ -95,3 +92,2 @@

throwIfAlreadyStarted = fastifyArgs.throwIfAlreadyStarted
validateHTTPVersion = fastifyArgs.validateHTTPVersion

@@ -109,14 +105,2 @@ globalExposeHeadRoutes = options.exposeHeadRoutes

prepareRoute,
getDefaultRoute: function () {
FSTDEP014()
return router.defaultRoute
},
setDefaultRoute: function (defaultRoute) {
FSTDEP014()
if (typeof defaultRoute !== 'function') {
throw new FST_ERR_DEFAULT_ROUTE_INVALID_TYPE()
}
router.defaultRoute = defaultRoute
},
routeHandler,

@@ -176,3 +160,7 @@ closeRoutes: () => { closing = true },

function hasRoute ({ options }) {
return findRoute(options) !== null
return router.hasRoute(
options.method,
options.url || '',
options.constraints
)
}

@@ -465,15 +453,2 @@

// TODO: The check here should be removed once https://github.com/nodejs/node/issues/43115 resolve in core.
if (!validateHTTPVersion(req.httpVersion)) {
childLogger.info({ res: { statusCode: 505 } }, 'request aborted - invalid HTTP version')
const message = '{"error":"HTTP Version Not Supported","message":"HTTP Version Not Supported","statusCode":505}'
const headers = {
'Content-Type': 'application/json',
'Content-Length': message.length
}
res.writeHead(505, headers)
res.end(message)
return
}
if (closing === true) {

@@ -480,0 +455,0 @@ /* istanbul ignore next mac, windows */

@@ -7,3 +7,2 @@ 'use strict'

const { FSTDEP011 } = require('./warnings')
const { kState, kOptions, kServerBindings } = require('./symbols')

@@ -19,3 +18,2 @@ const { onListenHookRunner } = require('./hooks')

module.exports.createServer = createServer
module.exports.compileValidateHTTPVersion = compileValidateHTTPVersion

@@ -30,23 +28,7 @@ function defaultResolveServerListeningText (address) {

// `this` is the Fastify object
function listen (listenOptions, ...args) {
let cb = args.slice(-1).pop()
// When the variadic signature deprecation is complete, the function
// declaration should become:
// function listen (listenOptions = { port: 0, host: 'localhost' }, cb = undefined)
// Upon doing so, the `normalizeListenArgs` function is no longer needed,
// and all of this preamble to feed it correctly also no longer needed.
const firstArgType = Object.prototype.toString.call(arguments[0])
if (arguments.length === 0) {
listenOptions = normalizeListenArgs([])
} else if (arguments.length > 0 && (firstArgType !== '[object Object]' && firstArgType !== '[object Function]')) {
FSTDEP011()
listenOptions = normalizeListenArgs(Array.from(arguments))
cb = listenOptions.cb
} else if (args.length > 1) {
// `.listen(obj, a, ..., n, callback )`
FSTDEP011()
// Deal with `.listen(port, host, backlog, [cb])`
const hostPath = listenOptions.path ? [listenOptions.path] : [listenOptions.port ?? 0, listenOptions.host ?? 'localhost']
Object.assign(listenOptions, normalizeListenArgs([...hostPath, ...args]))
} else {
function listen (
listenOptions = { port: 0, host: 'localhost' },
cb = undefined
) {
if (typeof cb === 'function') {
listenOptions.cb = cb

@@ -284,52 +266,2 @@ }

/**
* Creates a function that, based upon initial configuration, will
* verify that every incoming request conforms to allowed
* HTTP versions for the Fastify instance, e.g. a Fastify HTTP/1.1
* server will not serve HTTP/2 requests upon the result of the
* verification function.
*
* @param {object} options fastify option
* @param {function} [options.serverFactory] If present, the
* validator function will skip all checks.
* @param {boolean} [options.http2 = false] If true, the validator
* function will allow HTTP/2 requests.
* @param {object} [options.https = null] https server options
* @param {boolean} [options.https.allowHTTP1] If true and use
* with options.http2 the validator function will allow HTTP/1
* request to http2 server.
*
* @returns {function} HTTP version validator function.
*/
function compileValidateHTTPVersion (options) {
let bypass = false
// key-value map to store valid http version
const map = new Map()
if (options.serverFactory) {
// When serverFactory is passed, we cannot identify how to check http version reliably
// So, we should skip the http version check
bypass = true
}
if (options.http2) {
// HTTP2 must serve HTTP/2.0
map.set('2.0', true)
if (options.https && options.https.allowHTTP1 === true) {
// HTTP2 with HTTPS.allowHTTP1 allow fallback to HTTP/1.1 and HTTP/1.0
map.set('1.1', true)
map.set('1.0', true)
}
} else {
// HTTP must server HTTP/1.1 and HTTP/1.0
map.set('1.1', true)
map.set('1.0', true)
}
// The compiled function here placed in one of the hottest path inside fastify
// the implementation here must be as performant as possible
return function validateHTTPVersion (httpVersion) {
// `bypass` skip the check when custom server factory provided
// `httpVersion in obj` check for the valid http version we should support
return bypass || map.has(httpVersion)
}
}
function getServerInstance (options, httpHandler) {

@@ -372,35 +304,2 @@ let server = null

function normalizeListenArgs (args) {
if (args.length === 0) {
return { port: 0, host: 'localhost' }
}
const cb = typeof args[args.length - 1] === 'function' ? args.pop() : undefined
const options = { cb }
const firstArg = args[0]
const argsLength = args.length
const lastArg = args[argsLength - 1]
if (typeof firstArg === 'string' && isNaN(firstArg)) {
/* Deal with listen (pipe[, backlog]) */
options.path = firstArg
options.backlog = argsLength > 1 ? lastArg : undefined
} else {
/* Deal with listen ([port[, host[, backlog]]]) */
options.port = argsLength >= 1 && Number.isInteger(firstArg) ? firstArg : normalizePort(firstArg)
// This will listen to what localhost is.
// It can be 127.0.0.1 or ::1, depending on the operating system.
// Fixes https://github.com/fastify/fastify/issues/1022.
options.host = argsLength >= 2 && args[1] ? args[1] : 'localhost'
options.backlog = argsLength >= 3 ? args[2] : undefined
}
return options
}
function normalizePort (firstArg) {
const port = Number(firstArg)
return port >= 0 && !Number.isNaN(port) && Number.isInteger(port) ? port : 0
}
function logServerAddress (server, listenTextResolver) {

@@ -407,0 +306,0 @@ let address = server.address()

@@ -5,2 +5,21 @@ 'use strict'

/**
* Deprecation codes:
* - FSTDEP005
* - FSTDEP006
* - FSTDEP007
* - FSTDEP008
* - FSTDEP009
* - FSTDEP010
* - FSTDEP012
* - FSTDEP013
* - FSTDEP015
* - FSTDEP016
* - FSTDEP017
* - FSTDEP018
* - FSTDEP019
* - FSTWRN001
* - FSTSEC001
*/
const FSTDEP005 = createDeprecation({

@@ -36,7 +55,2 @@ code: 'FSTDEP005',

const FSTDEP011 = createDeprecation({
code: 'FSTDEP011',
message: 'Variadic listen method is deprecated. Please use ".listen(optionsObject)" instead. The variadic signature will be removed in `fastify@5`.'
})
const FSTDEP012 = createDeprecation({

@@ -52,7 +66,2 @@ code: 'FSTDEP012',

const FSTDEP014 = createDeprecation({
code: 'FSTDEP014',
message: 'You are trying to set/access the default route. This property is deprecated. Please, use setNotFoundHandler if you want to custom a 404 handler or the wildcard (*) to match all routes.'
})
const FSTDEP015 = createDeprecation({

@@ -95,6 +104,6 @@ code: 'FSTDEP015',

const FSTWRN002 = createWarning({
name: 'FastifyWarning',
code: 'FSTWRN002',
message: 'The %s plugin being registered mixes async and callback styles, which will result in an error in `fastify@5`',
const FSTSEC001 = createWarning({
name: 'FastifySecurity',
code: 'FSTSEC001',
message: 'You are using /%s/ Content-Type which may be vulnerable to CORS attack. Please make sure your RegExp start with "^" or include ";?" to proper detection of the essence MIME type.',
unlimited: true

@@ -110,6 +119,4 @@ })

FSTDEP010,
FSTDEP011,
FSTDEP012,
FSTDEP013,
FSTDEP014,
FSTDEP015,

@@ -122,3 +129,3 @@ FSTDEP016,

FSTWRN001,
FSTWRN002
FSTSEC001
}
{
"name": "fastify",
"version": "4.27.0",
"version": "5.0.0-aplha.1",
"description": "Fast and low overhead web framework, for Node.js",

@@ -156,34 +156,35 @@ "main": "fastify.js",

"devDependencies": {
"@fastify/pre-commit": "^2.0.2",
"@sinclair/typebox": "^0.31.17",
"@sinonjs/fake-timers": "^11.1.0",
"@types/node": "^20.8.4",
"@typescript-eslint/eslint-plugin": "^6.7.5",
"@typescript-eslint/parser": "^6.7.5",
"@eslint/js": "^9.1.1",
"@fastify/pre-commit": "^2.1.0",
"@sinclair/typebox": "^0.32.22",
"@sinonjs/fake-timers": "^11.2.2",
"@types/node": "^20.12.7",
"@typescript-eslint/eslint-plugin": "^7.7.0",
"@typescript-eslint/parser": "^7.7.0",
"ajv": "^8.12.0",
"ajv-errors": "^3.0.0",
"ajv-formats": "^2.1.1",
"ajv-formats": "^3.0.1",
"ajv-i18n": "^4.2.0",
"ajv-merge-patch": "^5.0.1",
"autocannon": "^7.14.0",
"autocannon": "^7.15.0",
"branch-comparer": "^1.1.0",
"c8": "^8.0.1",
"c8": "^9.1.0",
"concurrently": "^8.2.2",
"cross-env": "^7.0.3",
"eslint": "^8.51.0",
"eslint": "^8.57.0",
"eslint-config-standard": "^17.1.0",
"eslint-import-resolver-node": "^0.3.9",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-n": "^16.2.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-n": "^16.6.2",
"eslint-plugin-promise": "^6.1.1",
"fast-json-body": "^1.1.0",
"fastify-plugin": "^4.5.1",
"fluent-json-schema": "^4.1.2",
"fluent-json-schema": "^4.2.1",
"form-data": "^4.0.0",
"h2url": "^0.2.0",
"http-errors": "^2.0.0",
"joi": "^17.11.0",
"json-schema-to-ts": "^2.9.2",
"joi": "^17.12.3",
"json-schema-to-ts": "^3.0.1",
"JSONStream": "^1.3.5",
"markdownlint-cli2": "^0.10.0",
"markdownlint-cli2": "^0.13.0",
"node-forge": "^1.3.1",

@@ -197,11 +198,11 @@ "proxyquire": "^2.1.3",

"tap": "^16.3.9",
"tsd": "^0.29.0",
"typescript": "^5.2.2",
"undici": "^5.26.0",
"tsd": "^0.31.0",
"typescript": "^5.4.5",
"undici": "^6.13.0",
"vary": "^1.1.2",
"yup": "^1.3.2"
"yup": "^1.4.0"
},
"dependencies": {
"@fastify/ajv-compiler": "^3.5.0",
"@fastify/error": "^3.4.0",
"@fastify/error": "^3.4.1",
"@fastify/fast-json-stringify-compiler": "^4.3.0",

@@ -211,12 +212,12 @@ "abstract-logging": "^2.0.1",

"fast-content-type-parse": "^1.1.0",
"fast-json-stringify": "^5.8.0",
"find-my-way": "^8.0.0",
"light-my-request": "^5.11.0",
"fast-json-stringify": "^5.14.1",
"find-my-way": "^8.1.0",
"light-my-request": "^5.13.0",
"pino": "^9.0.0",
"process-warning": "^3.0.0",
"proxy-addr": "^2.0.7",
"rfdc": "^1.3.0",
"rfdc": "^1.3.1",
"secure-json-parse": "^2.7.0",
"semver": "^7.5.4",
"toad-cache": "^3.3.0"
"semver": "^7.6.0",
"toad-cache": "^3.7.0"
},

@@ -223,0 +224,0 @@ "standard": {

@@ -49,7 +49,5 @@ <div align="center"> <a href="https://fastify.dev/">

The `main` branch refers to the Fastify `v4` release. Check out the
[`v3.x` branch](https://github.com/fastify/fastify/tree/3.x) for `v3`.
The `main` branch refers to the Fastify `v5` release, which is not released/LTS yet.
Check out the [`4.x` branch](https://github.com/fastify/fastify/tree/4.x) for `v4`.
### Table of Contents

@@ -56,0 +54,0 @@

@@ -27,4 +27,24 @@ 'use strict'

const optsWithHostnameAndPort = {
schema: {
response: {
'2xx': {
type: 'object',
properties: {
hello: {
type: 'string'
},
hostname: {
type: 'string'
},
port: {
type: 'string'
}
}
}
}
}
}
test('async await', t => {
t.plan(11)
t.plan(13)
const fastify = Fastify()

@@ -50,2 +70,12 @@ try {

try {
fastify.get('/await/hostname_port', optsWithHostnameAndPort, async function awaitMyFunc (req, reply) {
await sleep(200)
return { hello: 'world', hostname: req.hostname, port: req.port }
})
t.pass()
} catch (e) {
t.fail()
}
fastify.listen({ port: 0 }, err => {

@@ -74,2 +104,16 @@ t.error(err)

})
t.test('test for hostname and port in request', t => {
t.plan(4)
sget({
method: 'GET',
url: 'http://localhost:' + fastify.server.address().port + '/await/hostname_port'
}, (err, response, body) => {
t.error(err)
t.equal(response.statusCode, 200)
const parsedBody = JSON.parse(body)
t.equal(parsedBody.hostname, 'localhost')
t.equal(parseInt(parsedBody.port), fastify.server.address().port)
})
})
})

@@ -141,3 +185,3 @@ })

const fastify = Fastify({
logger
loggerInstance: logger
})

@@ -144,0 +188,0 @@

@@ -15,3 +15,3 @@ 'use strict'

test('should know about internal parsers', t => {
t.plan(4)
t.plan(5)

@@ -23,2 +23,3 @@ const fastify = Fastify()

t.ok(fastify.hasContentTypeParser('text/plain'))
t.ok(fastify.hasContentTypeParser(' text/plain '))
t.notOk(fastify.hasContentTypeParser('application/jsoff'))

@@ -28,4 +29,4 @@ })

test('should work with string and RegExp', t => {
t.plan(7)
test('should only work with string and RegExp', t => {
t.plan(8)

@@ -44,2 +45,3 @@ const fastify = Fastify()

t.notOk(fastify.hasContentTypeParser('*'))
t.throws(() => fastify.hasContentTypeParser(123), FST_ERR_CTP_INVALID_TYPE)
})

@@ -52,3 +54,3 @@

test('should return matching parser', t => {
t.plan(3)
t.plan(6)

@@ -64,5 +66,8 @@ const fastify = Fastify()

t.equal(fastify[keys.kContentTypeParser].getParser('text/html').fn, third)
t.equal(fastify[keys.kContentTypeParser].getParser('text/html; charset=utf-8').fn, third)
t.equal(fastify[keys.kContentTypeParser].getParser('text/html ; charset=utf-8').fn, third)
t.equal(fastify[keys.kContentTypeParser].getParser('text/htmlINVALID')?.fn, undefined)
})
test('should return matching parser with caching', t => {
test('should return matching parser with caching /1', t => {
t.plan(6)

@@ -82,2 +87,17 @@

test('should return matching parser with caching /2', t => {
t.plan(6)
const fastify = Fastify()
fastify.addContentTypeParser(/^text\/html(;\s*charset=[^;]+)?$/, first)
t.equal(fastify[keys.kContentTypeParser].getParser('text/html').fn, first)
t.equal(fastify[keys.kContentTypeParser].cache.size, 1)
t.equal(fastify[keys.kContentTypeParser].getParser('text/html;charset=utf-8').fn, first)
t.equal(fastify[keys.kContentTypeParser].cache.size, 2)
t.equal(fastify[keys.kContentTypeParser].getParser('text/html;charset=utf-8').fn, first)
t.equal(fastify[keys.kContentTypeParser].cache.size, 2)
})
test('should prefer content type parser with string value', t => {

@@ -209,2 +229,32 @@ t.plan(2)

test('should lowercase contentTypeParser name', async t => {
t.plan(1)
const fastify = Fastify()
fastify.addContentTypeParser('text/html', function (req, done) {
done()
})
try {
fastify.addContentTypeParser('TEXT/html', function (req, done) {
done()
})
} catch (err) {
t.same(err.message, FST_ERR_CTP_ALREADY_PRESENT('text/html').message)
}
})
test('should trim contentTypeParser name', async t => {
t.plan(1)
const fastify = Fastify()
fastify.addContentTypeParser('text/html', function (req, done) {
done()
})
try {
fastify.addContentTypeParser(' text/html', function (req, done) {
done()
})
} catch (err) {
t.same(err.message, FST_ERR_CTP_ALREADY_PRESENT('text/html').message)
}
})
t.end()

@@ -267,3 +317,3 @@ })

test('should remove default parser', t => {
t.plan(3)
t.plan(6)

@@ -276,2 +326,5 @@ const fastify = Fastify()

t.notOk(contentTypeParser.parserList.find(parser => parser === 'application/json'))
t.ok(contentTypeParser.remove(' text/plain '))
t.notOk(contentTypeParser.customParsers['text/plain'])
t.notOk(contentTypeParser.parserList.find(parser => parser === 'text/plain'))
})

@@ -434,28 +487,21 @@

test('Safeguard against content-type spoofing - regexp', async t => {
t.plan(1)
test('Warning against improper content-type - regexp', t => {
t.plan(2)
const fastify = Fastify()
process.on('warning', onWarning)
function onWarning (warning) {
t.equal(warning.name, 'FastifySecurity')
t.equal(warning.code, 'FSTSEC001')
}
t.teardown(() => process.removeListener('warning', onWarning))
fastify.removeAllContentTypeParsers()
fastify.addContentTypeParser(/text\/plain/, function (request, body, done) {
t.pass('should be called')
done(null, body)
})
fastify.addContentTypeParser(/application\/json/, function (request, body, done) {
t.fail('shouldn\'t be called')
done(null, body)
})
fastify.post('/', async () => {
return 'ok'
})
await fastify.inject({
method: 'POST',
path: '/',
headers: {
'content-type': 'text/plain; content-type="application/json"'
},
body: ''
})
})

@@ -491,30 +537,2 @@

test('content-type match parameters - string 2', async t => {
t.plan(1)
const fastify = Fastify()
fastify.removeAllContentTypeParsers()
fastify.addContentTypeParser('application/json; charset=utf8; foo=bar', function (request, body, done) {
t.pass('should be called')
done(null, body)
})
fastify.addContentTypeParser('text/plain; charset=utf8; foo=bar', function (request, body, done) {
t.fail('shouldn\'t be called')
done(null, body)
})
fastify.post('/', async () => {
return 'ok'
})
await fastify.inject({
method: 'POST',
path: '/',
headers: {
'content-type': 'application/json; foo=bar; charset=utf8'
},
body: ''
})
})
test('content-type match parameters - regexp', async t => {

@@ -665,68 +683,2 @@ t.plan(1)

test('allow partial content-type - essence check', async t => {
t.plan(1)
const fastify = Fastify()
fastify.removeAllContentTypeParsers()
fastify.addContentTypeParser('json', function (request, body, done) {
t.pass('should be called')
done(null, body)
})
fastify.post('/', async () => {
return 'ok'
})
await fastify.inject({
method: 'POST',
path: '/',
headers: {
'content-type': 'application/json; foo=bar; charset=utf8'
},
body: ''
})
await fastify.inject({
method: 'POST',
path: '/',
headers: {
'content-type': 'image/jpeg'
},
body: ''
})
})
test('allow partial content-type - not essence check', async t => {
t.plan(1)
const fastify = Fastify()
fastify.removeAllContentTypeParsers()
fastify.addContentTypeParser('json;', function (request, body, done) {
t.pass('should be called')
done(null, body)
})
fastify.post('/', async () => {
return 'ok'
})
await fastify.inject({
method: 'POST',
path: '/',
headers: {
'content-type': 'application/json; foo=bar; charset=utf8'
},
body: ''
})
await fastify.inject({
method: 'POST',
path: '/',
headers: {
'content-type': 'image/jpeg'
},
body: ''
})
})
test('edge case content-type - ;', async t => {

@@ -733,0 +685,0 @@ t.plan(1)

@@ -66,3 +66,3 @@ 'use strict'

test('Should get the body as string', t => {
test('Should get the body as string /1', t => {
t.plan(6)

@@ -106,2 +106,41 @@ const fastify = Fastify()

test('Should get the body as string /2', t => {
t.plan(6)
const fastify = Fastify()
fastify.post('/', (req, reply) => {
reply.send(req.body)
})
fastify.addContentTypeParser('text/plain/test', { parseAs: 'string' }, function (req, body, done) {
t.ok('called')
t.ok(typeof body === 'string')
try {
const plainText = body
done(null, plainText)
} catch (err) {
err.statusCode = 400
done(err, undefined)
}
})
fastify.listen({ port: 0 }, err => {
t.error(err)
sget({
method: 'POST',
url: getServerUrl(fastify),
body: 'hello world',
headers: {
'Content-Type': ' text/plain/test '
}
}, (err, response, body) => {
t.error(err)
t.equal(response.statusCode, 200)
t.equal(body.toString(), 'hello world')
fastify.close()
})
})
})
test('Should get the body as buffer', t => {

@@ -108,0 +147,0 @@ t.plan(6)

@@ -303,4 +303,24 @@ 'use strict'

test('shorthand - delete with application/json Content-Type header and null body', t => {
t.plan(4)
const fastify = require('..')()
fastify.delete('/', {}, (req, reply) => {
t.equal(req.body, null)
reply.send(req.body)
})
fastify.inject({
method: 'DELETE',
url: '/',
headers: { 'Content-Type': 'application/json' },
body: 'null'
}, (err, response) => {
t.error(err)
t.equal(response.statusCode, 200)
t.same(response.payload.toString(), 'null')
})
})
// https://github.com/fastify/fastify/issues/936
test('shorthand - delete with application/json Content-Type header and without body', t => {
// Skip this test because this is an invalid request
test('shorthand - delete with application/json Content-Type header and without body', { skip: 'https://github.com/fastify/fastify/pull/5419' }, t => {
t.plan(4)

@@ -307,0 +327,0 @@ const fastify = require('..')()

@@ -52,2 +52,18 @@ 'use strict'

test('findRoute should return null when when url is not passed', t => {
t.plan(1)
const fastify = Fastify()
fastify.get('/artists/:artistId', {
schema: {
params: { artistId: { type: 'integer' } }
},
handler: (req, reply) => reply.send(typeof req.params.artistId)
})
t.equal(fastify.findRoute({
method: 'POST'
}), null)
})
test('findRoute should return null when route cannot be found due to a different path', t => {

@@ -54,0 +70,0 @@ t.plan(1)

@@ -77,2 +77,11 @@ 'use strict'

test('Should handle properly requestIdHeader option', t => {
t.plan(4)
t.equal(Fastify({ requestIdHeader: '' }).initialConfig.requestIdHeader, false)
t.equal(Fastify({ requestIdHeader: false }).initialConfig.requestIdHeader, false)
t.equal(Fastify({ requestIdHeader: true }).initialConfig.requestIdHeader, 'request-id')
t.equal(Fastify({ requestIdHeader: 'x-request-id' }).initialConfig.requestIdHeader, 'x-request-id')
})
test('Should accept option to set genReqId with setGenReqId option', t => {

@@ -79,0 +88,0 @@ t.plan(9)

@@ -206,2 +206,14 @@ 'use strict'

test('shorthand - get, set port', t => {
t.plan(1)
try {
fastify.get('/port', headersSchema, function (req, reply) {
reply.code(200).send({ port: req.port })
})
t.pass()
} catch (e) {
t.fail()
}
})
fastify.listen({ port: 0 }, err => {

@@ -384,2 +396,18 @@ t.error(err)

})
test('shorthand - request get headers - test fall back port', t => {
t.plan(3)
sget({
method: 'GET',
headers: {
host: 'example.com'
},
json: true,
url: 'http://localhost:' + fastify.server.address().port + '/port'
}, (err, response, body) => {
t.error(err)
t.equal(response.statusCode, 200)
t.equal(body.port, null)
})
})
})

@@ -74,5 +74,5 @@ 'use strict'

method: 'GET',
url: '/example/12345.png'
url: '/example/:file(^\\d+).png'
}), true)
})
})

@@ -219,7 +219,3 @@ 'use strict'

t.error(err)
if (upMethod === 'OPTIONS') {
t.equal(response.statusCode, 200)
} else {
t.equal(response.statusCode, 415)
}
t.equal(response.statusCode, 415)
})

@@ -226,0 +222,0 @@ })

@@ -15,3 +15,3 @@ 'use strict'

test('A route supports host constraints under http2 protocol and secure connection', (t) => {
t.plan(5)
t.plan(6)

@@ -49,2 +49,10 @@ let fastify

})
fastify.route({
method: 'GET',
url: '/hostname_port',
constraints: { host: constrain },
handler: function (req, reply) {
reply.code(200).send({ ...beta, hostname: req.hostname })
}
})

@@ -92,3 +100,16 @@ fastify.listen({ port: 0 }, err => {

})
t.test('https get request - constrain - verify hostname and port from request', async (t) => {
t.plan(1)
const url = `https://localhost:${fastify.server.address().port}/hostname_port`
const res = await h2url.concat({
url,
headers: {
':authority': constrain
}
})
const body = JSON.parse(res.body)
t.equal(body.hostname, constrain)
})
})
})

@@ -23,6 +23,10 @@ 'use strict'

fastify.get('/hostname', function (req, reply) {
reply.code(200).send(req.hostname)
fastify.get('/host', function (req, reply) {
reply.code(200).send(req.host)
})
fastify.get('/hostname_port', function (req, reply) {
reply.code(200).send({ hostname: req.hostname, port: req.port })
})
fastify.listen({ port: 0 }, err => {

@@ -44,12 +48,23 @@ t.error(err)

test('http hostname', async (t) => {
test('http host', async (t) => {
t.plan(1)
const hostname = `localhost:${fastify.server.address().port}`
const host = `localhost:${fastify.server.address().port}`
const url = `http://${hostname}/hostname`
const url = `http://${host}/host`
const res = await h2url.concat({ url })
t.equal(res.body, hostname)
t.equal(res.body, host)
})
test('http hostname and port', async (t) => {
t.plan(2)
const host = `localhost:${fastify.server.address().port}`
const url = `http://${host}/hostname_port`
const res = await h2url.concat({ url })
t.equal(JSON.parse(res.body).hostname, host.split(':')[0])
t.equal(JSON.parse(res.body).port, parseInt(host.split(':')[1]))
})
})

@@ -13,3 +13,3 @@ 'use strict'

test('secure', (t) => {
t.plan(4)
t.plan(5)

@@ -36,2 +36,5 @@ let fastify

})
fastify.get('/hostname_port', function (req, reply) {
reply.code(200).send({ hostname: req.hostname, port: req.port })
})

@@ -60,3 +63,11 @@ fastify.listen({ port: 0 }, err => {

})
t.test('https get request - test hostname and port', async (t) => {
t.plan(2)
const url = `https://localhost:${fastify.server.address().port}/hostname_port`
const parsedbody = JSON.parse((await h2url.concat({ url })).body)
t.equal(parsedbody.hostname, 'localhost')
t.equal(parsedbody.port, fastify.server.address().port)
})
})
})

@@ -77,1 +77,58 @@ 'use strict'

})
test('https - headers', (t) => {
t.plan(4)
let fastify
try {
fastify = Fastify({
https: {
key: global.context.key,
cert: global.context.cert
}
})
t.pass('Key/cert successfully loaded')
} catch (e) {
t.fail('Key/cert loading failed', e)
}
fastify.get('/', function (req, reply) {
reply.code(200).send({ hello: 'world', hostname: req.hostname, port: req.port })
})
t.teardown(async () => { await fastify.close() })
fastify.listen({ port: 0 }, err => {
t.error(err)
t.test('https get request', t => {
t.plan(4)
sget({
method: 'GET',
url: 'https://localhost:' + fastify.server.address().port,
rejectUnauthorized: false
}, (err, response, body) => {
t.error(err)
t.equal(response.statusCode, 200)
const parsedBody = JSON.parse(body)
t.equal(parsedBody.hostname, 'localhost')
t.equal(parsedBody.port, fastify.server.address().port)
})
})
t.test('https get request - test port fall back', t => {
t.plan(3)
sget({
method: 'GET',
headers: {
host: 'example.com'
},
url: 'https://localhost:' + fastify.server.address().port,
rejectUnauthorized: false
}, (err, response, body) => {
t.error(err)
t.equal(response.statusCode, 200)
const parsedBody = JSON.parse(body)
t.equal(parsedBody.port, null)
})
})
})
})

@@ -8,3 +8,3 @@ 'use strict'

test('should expose 80 errors', t => {
test('should expose 83 errors', t => {
t.plan(1)

@@ -18,7 +18,7 @@ const exportedKeys = Object.keys(errors)

}
t.equal(counter, 80)
t.equal(counter, 83)
})
test('ensure name and codes of Errors are identical', t => {
t.plan(80)
t.plan(83)
const exportedKeys = Object.keys(errors)

@@ -332,2 +332,32 @@ for (const key of exportedKeys) {

test('FST_ERR_LOG_INVALID_LOGGER_INSTANCE', t => {
t.plan(5)
const error = new errors.FST_ERR_LOG_INVALID_LOGGER_INSTANCE()
t.equal(error.name, 'FastifyError')
t.equal(error.code, 'FST_ERR_LOG_INVALID_LOGGER_INSTANCE')
t.equal(error.message, 'loggerInstance only accepts a logger instance.')
t.equal(error.statusCode, 500)
t.ok(error instanceof TypeError)
})
test('FST_ERR_LOG_INVALID_LOGGER_CONFIG', t => {
t.plan(5)
const error = new errors.FST_ERR_LOG_INVALID_LOGGER_CONFIG()
t.equal(error.name, 'FastifyError')
t.equal(error.code, 'FST_ERR_LOG_INVALID_LOGGER_CONFIG')
t.equal(error.message, 'logger options only accepts a configuration object.')
t.equal(error.statusCode, 500)
t.ok(error instanceof TypeError)
})
test('FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED', t => {
t.plan(5)
const error = new errors.FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED()
t.equal(error.name, 'FastifyError')
t.equal(error.code, 'FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED')
t.equal(error.message, 'You cannot provide both logger and loggerInstance. Please provide only one.')
t.equal(error.statusCode, 500)
t.ok(error instanceof TypeError)
})
test('FST_ERR_REP_INVALID_PAYLOAD_TYPE', t => {

@@ -593,12 +623,2 @@ t.plan(5)

test('FST_ERR_DEFAULT_ROUTE_INVALID_TYPE', t => {
t.plan(5)
const error = new errors.FST_ERR_DEFAULT_ROUTE_INVALID_TYPE()
t.equal(error.name, 'FastifyError')
t.equal(error.code, 'FST_ERR_DEFAULT_ROUTE_INVALID_TYPE')
t.equal(error.message, 'The defaultRoute type should be a function')
t.equal(error.statusCode, 500)
t.ok(error instanceof TypeError)
})
test('FST_ERR_INVALID_URL', t => {

@@ -764,2 +784,12 @@ t.plan(5)

test('FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER', t => {
t.plan(5)
const error = new errors.FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER('easter-egg')
t.equal(error.name, 'FastifyError')
t.equal(error.code, 'FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER')
t.equal(error.message, 'The easter-egg plugin being registered mixes async and callback styles. Async plugin should not mix async and callback style.')
t.equal(error.statusCode, 500)
t.ok(error instanceof TypeError)
})
test('FST_ERR_PLUGIN_CALLBACK_NOT_FN', t => {

@@ -846,3 +876,3 @@ t.plan(5)

test('Ensure that all errors are in Errors.md TOC', t => {
t.plan(80)
t.plan(83)
const errorsMd = readFileSync(resolve(__dirname, '../../docs/Reference/Errors.md'), 'utf8')

@@ -859,3 +889,3 @@

test('Ensure that non-existing errors are not in Errors.md TOC', t => {
t.plan(80)
t.plan(83)
const errorsMd = readFileSync(resolve(__dirname, '../../docs/Reference/Errors.md'), 'utf8')

@@ -873,3 +903,3 @@

test('Ensure that all errors are in Errors.md documented', t => {
t.plan(80)
t.plan(83)
const errorsMd = readFileSync(resolve(__dirname, '../../docs/Reference/Errors.md'), 'utf8')

@@ -886,3 +916,3 @@

test('Ensure that non-existing errors are not in Errors.md documented', t => {
t.plan(80)
t.plan(83)
const errorsMd = readFileSync(resolve(__dirname, '../../docs/Reference/Errors.md'), 'utf8')

@@ -889,0 +919,0 @@

@@ -48,7 +48,7 @@ 'use strict'

pluginTimeout: 10000,
requestIdHeader: 'request-id',
requestIdHeader: false,
requestIdLogLabel: 'reqId',
http2SessionTimeout: 72000,
exposeHeadRoutes: true,
useSemicolonDelimiter: true
useSemicolonDelimiter: false
}

@@ -109,3 +109,3 @@

},
logger: pino({ level: 'info' }),
loggerInstance: pino({ level: 'info' }),
constraints: {

@@ -290,7 +290,7 @@ version: versionStrategy

pluginTimeout: 10000,
requestIdHeader: 'request-id',
requestIdHeader: false,
requestIdLogLabel: 'reqId',
http2SessionTimeout: 72000,
exposeHeadRoutes: true,
useSemicolonDelimiter: true
useSemicolonDelimiter: false
})

@@ -297,0 +297,0 @@ } catch (error) {

@@ -49,3 +49,3 @@ 'use strict'

test('The logger should reuse request id header for req.id', t => {
test('The logger should not reuse request id header for req.id', t => {
const fastify = Fastify()

@@ -69,2 +69,31 @@ fastify.get('/', (req, reply) => {

const payload = JSON.parse(res.payload)
t.ok(payload.id !== 'request-id-1', 'the request id from the header should not be returned with default configuration')
t.ok(payload.id === 'req-1') // first request id when using the default configuration
fastify.close()
t.end()
})
})
})
test('The logger should reuse request id header for req.id if requestIdHeader is set', t => {
const fastify = Fastify({
requestIdHeader: 'request-id'
})
fastify.get('/', (req, reply) => {
t.ok(req.id)
reply.send({ id: req.id })
})
fastify.listen({ port: 0 }, err => {
t.error(err)
fastify.inject({
method: 'GET',
url: 'http://localhost:' + fastify.server.address().port,
headers: {
'Request-Id': 'request-id-1'
}
}, (err, res) => {
t.error(err)
const payload = JSON.parse(res.payload)
t.ok(payload.id === 'request-id-1', 'the request id from the header should be returned')

@@ -132,3 +161,3 @@ fastify.close()

version: undefined,
hostname: undefined,
host: undefined,
remoteAddress: undefined,

@@ -135,0 +164,0 @@ remotePort: undefined

@@ -63,3 +63,3 @@ 'use strict'

t.equal(request.ips, undefined)
t.equal(request.hostname, 'hostname')
t.equal(request.host, 'hostname')
t.equal(request.body, undefined)

@@ -146,3 +146,3 @@ t.equal(request.method, 'GET')

test('Regular request - hostname from authority', t => {
t.plan(2)
t.plan(3)
const headers = {

@@ -160,7 +160,8 @@ ':authority': 'authority'

t.type(request, Request)
t.equal(request.hostname, 'authority')
t.equal(request.host, 'authority')
t.equal(request.port, null)
})
test('Regular request - host header has precedence over authority', t => {
t.plan(2)
t.plan(3)
const headers = {

@@ -178,3 +179,4 @@ host: 'hostname',

t.type(request, Request)
t.equal(request.hostname, 'hostname')
t.equal(request.host, 'hostname')
t.equal(request.port, null)
})

@@ -229,3 +231,3 @@

t.same(request.ips, ['ip', '1.1.1.1', '2.2.2.2'])
t.equal(request.hostname, 'example.com')
t.equal(request.host, 'example.com')
t.equal(request.body, undefined)

@@ -280,3 +282,3 @@ t.equal(request.method, 'GET')

t.type(request, TpRequest)
t.equal(request.hostname, 'hostname')
t.equal(request.host, 'hostname')
})

@@ -300,3 +302,3 @@

t.type(request, TpRequest)
t.equal(request.hostname, 'authority')
t.equal(request.host, 'authority')
})

@@ -321,3 +323,3 @@

t.type(request, TpRequest)
t.equal(request.hostname, 'example.com')
t.equal(request.host, 'example.com')
})

@@ -341,3 +343,3 @@

t.type(request, TpRequest)
t.equal(request.hostname, 'example.com')
t.equal(request.host, 'example.com')
t.equal(request.protocol, 'https')

@@ -385,3 +387,3 @@ })

t.equal(request.ips, undefined)
t.equal(request.hostname, 'hostname')
t.equal(request.host, 'hostname')
t.same(request.body, null)

@@ -388,0 +390,0 @@ t.equal(request.method, 'GET')

@@ -35,5 +35,5 @@ 'use strict'

const logger = require('pino')(stream)
const loggerInstance = require('pino')(stream)
const fastify = Fastify({ logger })
const fastify = Fastify({ loggerInstance })
t.teardown(fastify.close.bind(fastify))

@@ -207,3 +207,3 @@

const logger = {
const loggerInstance = {
fatal: (msg) => { t.equal(msg, 'fatal') },

@@ -215,6 +215,6 @@ error: (msg) => { t.equal(msg, 'error') },

trace: (msg) => { t.equal(msg, 'trace') },
child: () => logger
child: () => loggerInstance
}
const fastify = Fastify({ logger })
const fastify = Fastify({ loggerInstance })
t.teardown(fastify.close.bind(fastify))

@@ -229,3 +229,3 @@

const child = fastify.log.child()
t.equal(child, logger)
t.equal(child, loggerInstance)
})

@@ -253,3 +253,3 @@

const stream = split(JSON.parse)
const logger = require('pino')({
const loggerInstance = require('pino')({
level: 'info',

@@ -266,3 +266,3 @@ serializers: {

const fastify = Fastify({
logger
loggerInstance
})

@@ -269,0 +269,0 @@ t.teardown(fastify.close.bind(fastify))

@@ -32,6 +32,6 @@ 'use strict'

const logger = pino({ level: 'trace' }, stream)
const loggerInstance = pino({ level: 'trace' }, stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -233,6 +233,6 @@ t.teardown(fastify.close.bind(fastify))

const stream = split(JSON.parse)
const logger = pino(stream)
const loggerInstance = pino(stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -239,0 +239,0 @@ t.teardown(fastify.close.bind(fastify))

@@ -15,3 +15,3 @@ 'use strict'

t.plan(12)
t.plan(16)

@@ -52,6 +52,6 @@ t.test('logger can be silenced', (t) => {

const logger = pino({ level: 'error' }, stream)
const loggerInstance = pino({ level: 'error' }, stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -99,6 +99,6 @@ t.teardown(fastify.close.bind(fastify))

const logger = pino({ level: 'error' }, stream)
const loggerInstance = pino({ level: 'error' }, stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -136,6 +136,6 @@ t.teardown(fastify.close.bind(fastify))

const logger = pino({ level: 'error' }, stream)
const loggerInstance = pino({ level: 'error' }, stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -200,5 +200,5 @@ t.teardown(fastify.close.bind(fastify))

const logger = pino({ level: 'info' }, stream)
const loggerInstance = pino({ level: 'info' }, stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -260,5 +260,5 @@ t.teardown(fastify.close.bind(fastify))

const logger = pino({ level: 'info' }, stream)
const loggerInstance = pino({ level: 'info' }, stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -299,5 +299,5 @@ t.teardown(fastify.close.bind(fastify))

const logger = pino({ level: 'info' }, stream)
const loggerInstance = pino({ level: 'info' }, stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -343,6 +343,6 @@ t.teardown(fastify.close.bind(fastify))

const logger = pino({ level: 'info' }, stream)
const loggerInstance = pino({ level: 'info' }, stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -380,6 +380,6 @@ t.teardown(fastify.close.bind(fastify))

const logger = pino({ level: 'warn' }, stream)
const loggerInstance = pino({ level: 'warn' }, stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -416,6 +416,6 @@ t.teardown(fastify.close.bind(fastify))

const logger = pino({ level: 'warn' }, stream)
const loggerInstance = pino({ level: 'warn' }, stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -457,6 +457,6 @@ t.teardown(fastify.close.bind(fastify))

const logger = pino({ level: 'error' }, stream)
const loggerInstance = pino({ level: 'error' }, stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -511,2 +511,83 @@ t.teardown(fastify.close.bind(fastify))

})
t.test('Should throw an error if logger instance is passed to `logger`', async (t) => {
t.plan(2)
const stream = split(JSON.parse)
const logger = require('pino')(stream)
try {
Fastify({ logger })
} catch (err) {
t.ok(err)
t.equal(err.code, 'FST_ERR_LOG_INVALID_LOGGER_CONFIG')
}
})
t.test('Should throw an error if options are passed to `loggerInstance`', async (t) => {
t.plan(2)
try {
Fastify({ loggerInstance: { level: 'log' } })
} catch (err) {
t.ok(err)
t.equal(err.code, 'FST_ERR_LOG_INVALID_LOGGER_INSTANCE')
}
})
t.test('If both `loggerInstance` and `logger` are provided, an error should be thrown', async (t) => {
t.plan(2)
const loggerInstanceStream = split(JSON.parse)
const loggerInstance = pino({ level: 'error' }, loggerInstanceStream)
const loggerStream = split(JSON.parse)
try {
Fastify({
logger: {
stream: loggerStream,
level: 'info'
},
loggerInstance
})
} catch (err) {
t.ok(err)
t.equal(err.code, 'FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED')
}
})
t.test('`logger` should take pino configuration and create a pino logger', async (t) => {
const lines = ['hello', 'world']
t.plan(2 * lines.length + 2)
const loggerStream = split(JSON.parse)
const fastify = Fastify({
logger: {
stream: loggerStream,
level: 'error'
}
})
t.teardown(fastify.close.bind(fastify))
fastify.get('/hello', (req, reply) => {
req.log.error('hello')
reply.code(404).send()
})
fastify.get('/world', (req, reply) => {
req.log.error('world')
reply.code(201).send()
})
await fastify.ready()
{
const response = await fastify.inject({ method: 'GET', url: '/hello' })
t.equal(response.statusCode, 404)
}
{
const response = await fastify.inject({ method: 'GET', url: '/world' })
t.equal(response.statusCode, 201)
}
for await (const [line] of on(loggerStream, 'data')) {
t.equal(line.level, 50)
t.equal(line.msg, lines.shift())
if (lines.length === 0) break
}
})
})

@@ -27,5 +27,5 @@ 'use strict'

const logger = pino({ level: 'info' }, stream)
const loggerInstance = pino({ level: 'info' }, stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -74,3 +74,3 @@ t.teardown(fastify.close.bind(fastify))

const logger = pino({
const loggerInstance = pino({
level: 'info',

@@ -83,3 +83,3 @@ serializers: {

const fastify = Fastify({
logger
loggerInstance
})

@@ -121,3 +121,3 @@ t.teardown(fastify.close.bind(fastify))

const logger = pino({
const loggerInstance = pino({
level: 'info',

@@ -129,3 +129,3 @@ serializers: {

const fastify = Fastify({ logger })
const fastify = Fastify({ loggerInstance })
t.teardown(fastify.close.bind(fastify))

@@ -132,0 +132,0 @@

@@ -10,2 +10,3 @@ 'use strict'

const fakeTimer = require('@sinonjs/fake-timers')
const { FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER } = require('../lib/errors')

@@ -419,22 +420,25 @@ test('pluginTimeout', t => {

test('registering plugins with mixed style should return a warning', async t => {
t.plan(12)
test('registering anonymous plugin with mixed style should throw', async t => {
t.plan(2)
const pluginNames = ['error-plugin', 'anonymous', 'anotherPlugin', 'anotherPluginNamed']
const fastify = Fastify()
const oldWarnings = process.listeners('warning')
process.removeAllListeners('warning')
process.on('warning', onWarning)
function onWarning (warning) {
t.match(warning.message, new RegExp(`.*${pluginNames.shift()} plugin being registered mixes async and callback styles.*`))
t.equal(warning.name, 'FastifyWarning')
t.equal(warning.code, 'FSTWRN002')
const anonymousPlugin = async (app, opts, done) => {
done()
}
t.teardown(() => {
process.removeListener('warning', onWarning)
for (const warning of oldWarnings) {
process.on('warning', warning)
}
})
fastify.register(anonymousPlugin)
try {
await fastify.ready()
t.fail('should throw')
} catch (error) {
t.type(error, FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER)
t.equal(error.message, 'The anonymousPlugin plugin being registered mixes async and callback styles. Async plugin should not mix async and callback style.')
}
})
test('registering named plugin with mixed style should throw', async t => {
t.plan(2)
const fastify = Fastify()

@@ -446,21 +450,13 @@

}
const namedPlugin = fp(errorPlugin, { name: pluginName })
async function anotherPlugin (app, opts, done) {
done()
}
fastify.register(namedPlugin)
const anotherPluginNamed = async function (app, opts, done) {
done()
try {
await fastify.ready()
t.fail('should throw')
} catch (error) {
t.type(error, FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER)
t.equal(error.message, 'The error-plugin plugin being registered mixes async and callback styles. Async plugin should not mix async and callback style.')
}
fastify.register(namedPlugin)
fastify.register(async (app, opts, done) => {
done()
})
fastify.register(anotherPlugin)
fastify.register(anotherPluginNamed)
await fastify.ready()
})

@@ -6,2 +6,3 @@ 'use strict'

const Fastify = require('..')
const sget = require('simple-get').concat
const semver = require('semver')

@@ -76,2 +77,17 @@ const undici = require('undici')

test('Test for hostname and port', t => {
const app = Fastify()
t.teardown(app.close.bind(app))
app.get('/host', (req, res) => {
const host = 'localhost:8000'
t.equal(req.host, host)
t.equal(req.hostname, req.host.split(':')[0])
t.equal(req.port, Number(req.host.split(':')[1]))
res.send('ok')
})
app.listen({ port: 8000 }, () => {
sget('http://localhost:8000/host', () => { t.end() })
})
})
test('abort signal', { skip: semver.lt(process.version, '16.0.0') }, t => {

@@ -78,0 +94,0 @@ t.test('listen should not start server', t => {

@@ -71,3 +71,3 @@ 'use strict'

const fastify = Fastify({ logger: spyLogger })
const fastify = Fastify({ loggerInstance: spyLogger })
fastify.get('/', function (req, reply) {

@@ -74,0 +74,0 @@ reply.send({ hello: 'world' })

@@ -91,3 +91,3 @@ 'use strict'

const fastify = Fastify({
logger: spyLogger
loggerInstance: spyLogger
})

@@ -140,3 +140,3 @@

const fastify = Fastify({
logger: spyLogger
loggerInstance: spyLogger
})

@@ -143,0 +143,0 @@

@@ -29,5 +29,7 @@ 'use strict'

}
if (options.hostname) {
t.ok(req.hostname, 'hostname is defined')
t.equal(req.hostname, options.hostname, 'gets hostname from x-forwarded-host')
if (options.host) {
t.ok(req.host, 'host is defined')
t.equal(req.host, options.host, 'gets host from x-forwarded-host')
t.ok(req.hostname)
t.equal(req.hostname, options.host, 'gets hostname from x-forwarded-host')
}

@@ -41,2 +43,6 @@ if (options.ips) {

}
if (options.port) {
t.ok(req.port, 'port is defined')
t.equal(req.port, options.port, 'port is taken from x-forwarded-for or host')
}
}

@@ -50,3 +56,3 @@

test('trust proxy, not add properties to node req', (t) => {
t.plan(8)
t.plan(14)
const app = fastify({

@@ -56,9 +62,9 @@ trustProxy: true

app.get('/trustproxy', function (req, reply) {
testRequestValues(t, req, { ip: '1.1.1.1', hostname: 'example.com' })
reply.code(200).send({ ip: req.ip, hostname: req.hostname })
testRequestValues(t, req, { ip: '1.1.1.1', host: 'example.com', port: app.server.address().port })
reply.code(200).send({ ip: req.ip, host: req.host })
})
app.get('/trustproxychain', function (req, reply) {
testRequestValues(t, req, { ip: '2.2.2.2', ips: [localhost, '1.1.1.1', '2.2.2.2'] })
reply.code(200).send({ ip: req.ip, hostname: req.hostname })
testRequestValues(t, req, { ip: '2.2.2.2', ips: [localhost, '1.1.1.1', '2.2.2.2'], port: app.server.address().port })
reply.code(200).send({ ip: req.ip, host: req.host })
})

@@ -77,3 +83,3 @@

test('trust proxy chain', (t) => {
t.plan(3)
t.plan(9)
const app = fastify({

@@ -84,4 +90,4 @@ trustProxy: [localhost, '192.168.1.1']

app.get('/trustproxychain', function (req, reply) {
testRequestValues(t, req, { ip: '1.1.1.1' })
reply.code(200).send({ ip: req.ip, hostname: req.hostname })
testRequestValues(t, req, { ip: '1.1.1.1', host: 'example.com', port: app.server.address().port })
reply.code(200).send({ ip: req.ip, host: req.host })
})

@@ -99,3 +105,3 @@

test('trust proxy function', (t) => {
t.plan(3)
t.plan(9)
const app = fastify({

@@ -105,4 +111,4 @@ trustProxy: (address) => address === localhost

app.get('/trustproxyfunc', function (req, reply) {
testRequestValues(t, req, { ip: '1.1.1.1' })
reply.code(200).send({ ip: req.ip, hostname: req.hostname })
testRequestValues(t, req, { ip: '1.1.1.1', host: 'example.com', port: app.server.address().port })
reply.code(200).send({ ip: req.ip, host: req.host })
})

@@ -120,3 +126,3 @@

test('trust proxy number', (t) => {
t.plan(4)
t.plan(10)
const app = fastify({

@@ -126,4 +132,4 @@ trustProxy: 1

app.get('/trustproxynumber', function (req, reply) {
testRequestValues(t, req, { ip: '1.1.1.1', ips: [localhost, '1.1.1.1'] })
reply.code(200).send({ ip: req.ip, hostname: req.hostname })
testRequestValues(t, req, { ip: '1.1.1.1', ips: [localhost, '1.1.1.1'], host: 'example.com', port: app.server.address().port })
reply.code(200).send({ ip: req.ip, host: req.host })
})

@@ -141,3 +147,3 @@

test('trust proxy IP addresses', (t) => {
t.plan(4)
t.plan(10)
const app = fastify({

@@ -147,4 +153,4 @@ trustProxy: `${localhost}, 2.2.2.2`

app.get('/trustproxyipaddrs', function (req, reply) {
testRequestValues(t, req, { ip: '1.1.1.1', ips: [localhost, '1.1.1.1'] })
reply.code(200).send({ ip: req.ip, hostname: req.hostname })
testRequestValues(t, req, { ip: '1.1.1.1', ips: [localhost, '1.1.1.1'], host: 'example.com', port: app.server.address().port })
reply.code(200).send({ ip: req.ip, host: req.host })
})

@@ -162,3 +168,3 @@

test('trust proxy protocol', (t) => {
t.plan(13)
t.plan(31)
const app = fastify({

@@ -168,12 +174,12 @@ trustProxy: true

app.get('/trustproxyprotocol', function (req, reply) {
testRequestValues(t, req, { ip: '1.1.1.1', protocol: 'lorem' })
reply.code(200).send({ ip: req.ip, hostname: req.hostname })
testRequestValues(t, req, { ip: '1.1.1.1', protocol: 'lorem', host: 'example.com', port: app.server.address().port })
reply.code(200).send({ ip: req.ip, host: req.host })
})
app.get('/trustproxynoprotocol', function (req, reply) {
testRequestValues(t, req, { ip: '1.1.1.1', protocol: 'http' })
reply.code(200).send({ ip: req.ip, hostname: req.hostname })
testRequestValues(t, req, { ip: '1.1.1.1', protocol: 'http', host: 'example.com', port: app.server.address().port })
reply.code(200).send({ ip: req.ip, host: req.host })
})
app.get('/trustproxyprotocols', function (req, reply) {
testRequestValues(t, req, { ip: '1.1.1.1', protocol: 'dolor' })
reply.code(200).send({ ip: req.ip, hostname: req.hostname })
testRequestValues(t, req, { ip: '1.1.1.1', protocol: 'dolor', host: 'example.com', port: app.server.address().port })
reply.code(200).send({ ip: req.ip, host: req.host })
})

@@ -180,0 +186,0 @@

@@ -62,4 +62,2 @@ import { expectAssignable } from 'tsd'

expectAssignable<FastifyErrorConstructor>(errorCodes.FST_ERR_ASYNC_CONSTRAINT)
expectAssignable<FastifyErrorConstructor>(errorCodes.FST_ERR_DEFAULT_ROUTE_INVALID_TYPE)
expectAssignable<FastifyErrorConstructor>(errorCodes.FST_ERR_INVALID_URL)
expectAssignable<FastifyErrorConstructor>(errorCodes.FST_ERR_ROUTE_OPTIONS_NOT_OBJ)

@@ -66,0 +64,0 @@ expectAssignable<FastifyErrorConstructor>(errorCodes.FST_ERR_ROUTE_DUPLICATED_HANDLER)

@@ -95,3 +95,3 @@ import fastify, {

version: '1.0.0',
hostname: 'localhost',
host: 'localhost',
remoteAddress: '127.0.0.1',

@@ -98,0 +98,0 @@ remotePort: 3000

@@ -197,44 +197,2 @@ import { expectAssignable, expectDeprecated, expectError, expectNotDeprecated, expectType } from 'tsd'

// test listen method callback
expectAssignable<void>(server.listen(3000, '', 0, (err, address) => {
expectType<Error | null>(err)
}))
expectAssignable<void>(server.listen('3000', '', 0, (err, address) => {
expectType<Error | null>(err)
}))
expectAssignable<void>(server.listen(3000, '', (err, address) => {
expectType<Error | null>(err)
}))
expectAssignable<void>(server.listen('3000', '', (err, address) => {
expectType<Error | null>(err)
}))
expectAssignable<void>(server.listen(3000, (err, address) => {
expectType<Error | null>(err)
}))
expectAssignable<void>(server.listen('3000', (err, address) => {
expectType<Error | null>(err)
}))
// test listen method callback types
expectAssignable<void>(server.listen('3000', (err, address) => {
expectAssignable<Error|null>(err)
expectAssignable<string>(address)
}))
// test listen method promise
expectAssignable<PromiseLike<string>>(server.listen(3000))
expectAssignable<PromiseLike<string>>(server.listen('3000'))
expectAssignable<PromiseLike<string>>(server.listen(3000, '', 0))
expectAssignable<PromiseLike<string>>(server.listen('3000', '', 0))
expectAssignable<PromiseLike<string>>(server.listen(3000, ''))
expectAssignable<PromiseLike<string>>(server.listen('3000', ''))
// Test variadic listen signatures Typescript deprecation
expectDeprecated(server.listen(3000))
expectDeprecated(server.listen('3000'))
expectDeprecated(server.listen(3000, '', 0))
expectDeprecated(server.listen('3000', '', 0))
expectDeprecated(server.listen(3000, ''))
expectDeprecated(server.listen('3000', ''))
// test listen opts objects

@@ -457,3 +415,3 @@ expectAssignable<PromiseLike<string>>(server.listen())

server.decorate('typedTestProperty', null, ['foo'])
server.decorate('typedTestProperty', null)
expectError(server.decorate('typedTestProperty', null))
expectError(server.decorate('typedTestProperty', 'foo'))

@@ -498,3 +456,3 @@ expectError(server.decorate('typedTestProperty', {

server.decorateRequest('typedTestRequestProperty', null, ['foo'])
server.decorateRequest('typedTestRequestProperty', null)
expectError(server.decorateRequest('typedTestRequestProperty', null))
expectError(server.decorateRequest('typedTestRequestProperty', 'foo'))

@@ -539,3 +497,3 @@ expectError(server.decorateRequest('typedTestRequestProperty', {

server.decorateReply('typedTestReplyProperty', null, ['foo'])
server.decorateReply('typedTestReplyProperty', null)
expectError(server.decorateReply('typedTestReplyProperty', null))
expectError(server.decorateReply('typedTestReplyProperty', 'foo'))

@@ -577,7 +535,3 @@ expectError(server.decorateReply('typedTestReplyProperty', {

expectType<boolean>(server.hasPlugin(''))
expectAssignable<DefaultRoute<RawRequestDefaultExpression, RawReplyDefaultExpression>>(server.getDefaultRoute())
expectType<FastifySchemaCompiler<any> | undefined>(server.validatorCompiler)
expectType<FastifySerializerCompiler<any> | undefined>(server.serializerCompiler)

@@ -124,4 +124,4 @@ import { expectAssignable, expectDeprecated, expectError, expectNotAssignable, expectType } from 'tsd'

const serverWithAutoInferredPino = fastify({
logger: P({
const serverWithLoggerInstance = fastify({
loggerInstance: P({
level: 'info',

@@ -132,4 +132,42 @@ redact: ['x-userinfo']

expectType<P.Logger>(serverWithAutoInferredPino.log)
expectType<P.Logger>(serverWithLoggerInstance.log)
const serverWithPinoConfig = fastify({
logger: {
level: 'info',
serializers: {
req (IncomingMessage) {
expectType<FastifyRequest>(IncomingMessage)
return {
method: 'method',
url: 'url',
version: 'version',
host: 'hostname',
remoteAddress: 'remoteAddress',
remotePort: 80,
other: ''
}
},
res (ServerResponse) {
expectType<ResSerializerReply<Server, FastifyReply>>(ServerResponse)
expectAssignable<Partial<FastifyReply> & Pick<FastifyReply, 'statusCode'>>(ServerResponse)
expectNotAssignable<FastifyReply>(ServerResponse)
return {
statusCode: 'statusCode'
}
},
err (FastifyError) {
return {
other: '',
type: 'type',
message: 'msg',
stack: 'stack'
}
}
}
}
})
expectType<FastifyBaseLogger>(serverWithPinoConfig.log)
const serverAutoInferredFileOption = fastify({

@@ -170,3 +208,3 @@ logger: {

version: 'version',
hostname: 'hostname',
host: 'hostname',
remoteAddress: 'remoteAddress',

@@ -173,0 +211,0 @@ remotePort: 80,

@@ -118,3 +118,3 @@ import { expectAssignable, expectError, expectType } from 'tsd'

const serverWithTypeProviderAndLogger = fastify({
logger: customLogger
loggerInstance: customLogger
}).withTypeProvider<TestTypeProvider>()

@@ -121,0 +121,0 @@ type ServerWithTypeProviderAndLogger = FastifyInstance<Server, IncomingMessage, ServerResponse, typeof customLogger, TestTypeProvider>

@@ -72,2 +72,4 @@ import { expectAssignable, expectType } from 'tsd'

expectType<string>(request.hostname)
expectType<string>(request.host)
expectType<number>(request.port)
expectType<string>(request.ip)

@@ -157,3 +159,3 @@ expectType<string[] | undefined>(request.ips)

const serverWithCustomLogger = fastify({ logger: customLogger })
const serverWithCustomLogger = fastify({ loggerInstance: customLogger })
expectType<

@@ -160,0 +162,0 @@ FastifyInstance<RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, CustomLoggerInterface>

@@ -39,5 +39,9 @@ import { FastifyError } from '@fastify/error'

type LowerCaseHTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete' | 'options';
type LowerCaseHTTPMethods = 'delete' | 'get' | 'head' | 'patch' | 'post' | 'put' |
'options' | 'propfind' | 'proppatch' | 'mkcol' | 'copy' | 'move' | 'lock' |
'unlock' | 'trace' | 'search'
['GET', 'POST', 'PUT', 'PATCH', 'HEAD', 'DELETE', 'OPTIONS'].forEach(method => {
;['DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT', 'OPTIONS', 'PROPFIND',
'PROPPATCH', 'MKCOL', 'COPY', 'MOVE', 'LOCK', 'UNLOCK', 'TRACE', 'SEARCH'
].forEach(method => {
// route method

@@ -44,0 +48,0 @@ expectType<FastifyInstance>(fastify().route({

@@ -122,4 +122,4 @@ 'use strict'

handler: (req, reply) => {
reply.send({ hello: 'world', hostname: req.hostname, port: req.port })
t.equal(req.originalUrl, '/this-would-404-without-url-rewrite')
reply.send({ hello: 'world' })
}

@@ -136,3 +136,4 @@ })

t.error(err)
t.same(JSON.parse(body), { hello: 'world' })
const parsedBody = JSON.parse(body)
t.same(parsedBody, { hello: 'world', hostname: 'localhost', port: fastify.server.address().port })
t.equal(response.statusCode, 200)

@@ -139,0 +140,0 @@ })

@@ -8,3 +8,3 @@ 'use strict'

test('use semicolon delimiter default true', t => {
test('use semicolon delimiter default false', t => {
t.plan(4)

@@ -16,3 +16,3 @@

fastify.get('/1234', (req, reply) => {
fastify.get('/1234;foo=bar', (req, reply) => {
reply.send(req.query)

@@ -24,3 +24,2 @@ })

console.log('http://localhost:' + fastify.server.address().port + '/1234;foo=bar')
sget({

@@ -32,5 +31,3 @@ method: 'GET',

t.equal(response.statusCode, 200)
t.same(JSON.parse(body), {
foo: 'bar'
})
t.same(JSON.parse(body), {})
})

@@ -37,0 +34,0 @@ })

@@ -457,3 +457,3 @@ 'use strict'

http.get({
hostname: fastify.server.address().hostname,
host: fastify.server.address().hostname,
port: fastify.server.address().port,

@@ -460,0 +460,0 @@ path: '/',

@@ -12,3 +12,3 @@ import { FastifyError } from '@fastify/error'

import { FastifyRequest } from './request'
import { DefaultRoute, RouteGenericInterface, RouteHandlerMethod, RouteOptions, RouteShorthandMethod } from './route'
import { RouteGenericInterface, RouteHandlerMethod, RouteOptions, RouteShorthandMethod } from './route'
import {

@@ -113,4 +113,2 @@ FastifySchema,

(property: string | symbol, value: null): Return;
(property: string | symbol, value: null|undefined, dependencies: string[]): Return;

@@ -174,23 +172,2 @@ }

/**
* @deprecated Variadic listen method is deprecated. Please use `.listen(optionsObject, callback)` instead. The variadic signature will be removed in `fastify@5`
* @see https://github.com/fastify/fastify/pull/3712
*/
listen(port: number | string, address: string, backlog: number, callback: (err: Error|null, address: string) => void): void;
/**
* @deprecated Variadic listen method is deprecated. Please use `.listen(optionsObject, callback)` instead. The variadic signature will be removed in `fastify@5`
* @see https://github.com/fastify/fastify/pull/3712
*/
listen(port: number | string, address: string, callback: (err: Error|null, address: string) => void): void;
/**
* @deprecated Variadic listen method is deprecated. Please use `.listen(optionsObject, callback)` instead. The variadic signature will be removed in `fastify@5`
* @see https://github.com/fastify/fastify/pull/3712
*/
listen(port: number | string, callback: (err: Error|null, address: string) => void): void;
/**
* @deprecated Variadic listen method is deprecated. Please use `.listen(optionsObject)` instead. The variadic signature will be removed in `fastify@5`
* @see https://github.com/fastify/fastify/pull/3712
*/
listen(port: number | string, address?: string, backlog?: number): Promise<string>;
ready(): FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider> & PromiseLike<undefined>;

@@ -202,4 +179,2 @@ ready(readyListener: (err: Error | null) => void): FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider>;

routing(req: RawRequest, res: RawReply): void;
getDefaultRoute(): DefaultRoute<RawRequest, RawReply>;
setDefaultRoute(defaultRoute: DefaultRoute<RawRequest, RawReply>): void;

@@ -212,9 +187,18 @@ route<

delete: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
get: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
head: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
patch: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
post: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
put: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
delete: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
options: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
patch: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
propfind: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
proppatch: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
mkcol: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
copy: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
move: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
lock: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
unlock: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
trace: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
search: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
all: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;

@@ -221,0 +205,0 @@

@@ -61,3 +61,3 @@ import { FastifyError } from '@fastify/error'

version?: string;
hostname?: string;
host?: string;
remoteAddress?: string;

@@ -64,0 +64,0 @@ remotePort?: number;

@@ -78,2 +78,4 @@ import { ErrorObject } from '@fastify/ajv-compiler'

readonly ips?: string[];
readonly host: string;
readonly port: number;
readonly hostname: string;

@@ -80,0 +82,0 @@ readonly url: string;

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc