fastify
Advanced tools
Comparing version 4.27.0 to 5.0.0-aplha.1
@@ -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
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
2446602
336
58779
46
1
414
6
+ Addedfast-uri@2.4.0(transitive)
Updated@fastify/error@^3.4.1
Updatedfast-json-stringify@^5.14.1
Updatedfind-my-way@^8.1.0
Updatedlight-my-request@^5.13.0
Updatedrfdc@^1.3.1
Updatedsemver@^7.6.0
Updatedtoad-cache@^3.7.0