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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2446602
336
58779
46
1
1
414
6
+ Addedfast-uri@3.0.1(transitive)
- Removedfast-uri@3.0.2(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