Comparing version 3.28.0 to 3.29.4
@@ -11,9 +11,9 @@ <h1 align="center">Fastify</h1> | ||
- [`fastify-accepts`](https://github.com/fastify/fastify-accepts) to have | ||
- [`@fastify/accepts`](https://github.com/fastify/fastify-accepts) to have | ||
[accepts](https://www.npmjs.com/package/accepts) in your request object. | ||
- [`fastify-accepts-serializer`](https://github.com/fastify/fastify-accepts-serializer) | ||
- [`@fastify/accepts-serializer`](https://github.com/fastify/fastify-accepts-serializer) | ||
to serialize to output according to `Accept` header. | ||
- [`fastify-auth`](https://github.com/fastify/fastify-auth) Run multiple auth | ||
- [`@fastify/auth`](https://github.com/fastify/fastify-auth) Run multiple auth | ||
functions in Fastify. | ||
- [`fastify-autoload`](https://github.com/fastify/fastify-autoload) Require all | ||
- [`@fastify/autoload`](https://github.com/fastify/fastify-autoload) Require all | ||
plugins in a directory. | ||
@@ -23,17 +23,17 @@ - [`fastify-awilix`](https://github.com/fastify/fastify-awilix) Dependency | ||
[awilix](https://github.com/jeffijoe/awilix). | ||
- [`fastify-bankai`](https://github.com/fastify/fastify-bankai) | ||
- [`@fastify/bankai`](https://github.com/fastify/fastify-bankai) | ||
[Bankai](https://github.com/yoshuawuyts/bankai) assets compiler for Fastify. | ||
- [`fastify-basic-auth`](https://github.com/fastify/fastify-basic-auth) Basic | ||
- [`@fastify/basic-auth`](https://github.com/fastify/fastify-basic-auth) Basic | ||
auth plugin for Fastify. | ||
- [`fastify-bearer-auth`](https://github.com/fastify/fastify-bearer-auth) Bearer | ||
- [`@fastify/bearer-auth`](https://github.com/fastify/fastify-bearer-auth) Bearer | ||
auth plugin for Fastify. | ||
- [`fastify-caching`](https://github.com/fastify/fastify-caching) General | ||
- [`@fastify/caching`](https://github.com/fastify/fastify-caching) General | ||
server-side cache and ETag support. | ||
- [`fastify-circuit-breaker`](https://github.com/fastify/fastify-circuit-breaker) | ||
- [`@fastify/circuit-breaker`](https://github.com/fastify/fastify-circuit-breaker) | ||
A low overhead circuit breaker for your routes. | ||
- [`fastify-compress`](https://github.com/fastify/fastify-compress) Fastify | ||
- [`@fastify/compress`](https://github.com/fastify/fastify-compress) Fastify | ||
compression utils. | ||
- [`fastify-cookie`](https://github.com/fastify/fastify-cookie) Parse and set | ||
- [`@fastify/cookie`](https://github.com/fastify/fastify-cookie) Parse and set | ||
cookie headers. | ||
- [`fastify-cors`](https://github.com/fastify/fastify-cors) Enables the use of | ||
- [`@fastify/cors`](https://github.com/fastify/fastify-cors) Enables the use of | ||
CORS in a Fastify application. | ||
@@ -43,39 +43,39 @@ - [`fastify-csrf`](https://github.com/fastify/fastify-csrf) A plugin for adding | ||
Fastify. | ||
- [`fastify-diagnostics-channel`](https://github.com/fastify/fastify-diagnostics-channel) | ||
- [`@fastify/diagnostics-channel`](https://github.com/fastify/fastify-diagnostics-channel) | ||
Plugin to deal with `diagnostics_channel` on Fastify | ||
- [`fastify-elasticsearch`](https://github.com/fastify/fastify-elasticsearch) | ||
- [`@fastify/elasticsearch`](https://github.com/fastify/fastify-elasticsearch) | ||
Plugin to share the same ES client. | ||
- [`fastify-env`](https://github.com/fastify/fastify-env) Load and check | ||
- [`@fastify/env`](https://github.com/fastify/fastify-env) Load and check | ||
configuration. | ||
- [`fastify-etag`](https://github.com/fastify/fastify-etag) Automatically | ||
- [`@fastify/etag`](https://github.com/fastify/fastify-etag) Automatically | ||
generate ETags for HTTP responses. | ||
- [`fastify-flash`](https://github.com/fastify/fastify-flash) Set and get flash | ||
- [`@fastify/flash`](https://github.com/fastify/fastify-flash) Set and get flash | ||
messages using the session. | ||
- [`fastify-formbody`](https://github.com/fastify/fastify-formbody) Plugin to | ||
- [`@fastify/formbody`](https://github.com/fastify/fastify-formbody) Plugin to | ||
parse x-www-form-urlencoded bodies. | ||
- [`fastify-funky`](https://github.com/fastify/fastify-funky) Makes functional | ||
- [`@fastify/funky`](https://github.com/fastify/fastify-funky) Makes functional | ||
programming in Fastify more convenient. Adds support for Fastify routes | ||
returning functional structures, such as Either, Task or plain parameterless | ||
function. | ||
- [`fastify-helmet`](https://github.com/fastify/fastify-helmet) Important | ||
- [`@fastify/helmet`](https://github.com/fastify/fastify-helmet) Important | ||
security headers for Fastify. | ||
- [`fastify-http-proxy`](https://github.com/fastify/fastify-http-proxy) Proxy | ||
- [`@fastify/http-proxy`](https://github.com/fastify/fastify-http-proxy) Proxy | ||
your HTTP requests to another server, with hooks. | ||
- [`fastify-jwt`](https://github.com/fastify/fastify-jwt) JWT utils for Fastify, | ||
- [`@fastify/jwt`](https://github.com/fastify/fastify-jwt) JWT utils for Fastify, | ||
internally uses [fast-jwt](https://github.com/nearform/fast-jwt). | ||
- [`fastify-leveldb`](https://github.com/fastify/fastify-leveldb) Plugin to | ||
- [`@fastify/leveldb`](https://github.com/fastify/fastify-leveldb) Plugin to | ||
share a common LevelDB connection across Fastify. | ||
- [`fastify-mongodb`](https://github.com/fastify/fastify-mongodb) Fastify | ||
- [`@fastify/mongodb`](https://github.com/fastify/fastify-mongodb) Fastify | ||
MongoDB connection plugin, with which you can share the same MongoDB | ||
connection pool across every part of your server. | ||
- [`fastify-multipart`](https://github.com/fastify/fastify-multipart) Multipart | ||
- [`@fastify/multipart`](https://github.com/fastify/fastify-multipart) Multipart | ||
support for Fastify. | ||
- [`fastify-oauth2`](https://github.com/fastify/fastify-oauth2) Wrap around | ||
- [`@fastify/oauth2`](https://github.com/fastify/fastify-oauth2) Wrap around | ||
[`simple-oauth2`](https://github.com/lelylan/simple-oauth2). | ||
- [`fastify-postgres`](https://github.com/fastify/fastify-postgres) Fastify | ||
- [`@fastify/postgres`](https://github.com/fastify/fastify-postgres) Fastify | ||
PostgreSQL connection plugin, with this you can share the same PostgreSQL | ||
connection pool in every part of your server. | ||
- [`fastify-rate-limit`](https://github.com/fastify/fastify-rate-limit) A low | ||
- [`@fastify/rate-limit`](https://github.com/fastify/fastify-rate-limit) A low | ||
overhead rate limiter for your routes. | ||
- [`fastify-request-context`](https://github.com/fastify/fastify-request-context) | ||
- [`@fastify/request-context`](https://github.com/fastify/fastify-request-context) | ||
Request-scoped storage, based on | ||
@@ -85,13 +85,13 @@ [AsyncLocalStorage](https://nodejs.org/api/async_hooks.html#async_hooks_class_asynclocalstorage) | ||
providing functionality similar to thread-local storages. | ||
- [`fastify-response-validation`](https://github.com/fastify/fastify-response-validation) | ||
- [`@fastify/response-validation`](https://github.com/fastify/fastify-response-validation) | ||
A simple plugin that enables response validation for Fastify. | ||
- [`fastify-nextjs`](https://github.com/fastify/fastify-nextjs) React | ||
- [`@fastify/nextjs`](https://github.com/fastify/fastify-nextjs) React | ||
server-side rendering support for Fastify with | ||
[Next](https://github.com/zeit/next.js/). | ||
- [`fastify-redis`](https://github.com/fastify/fastify-redis) Fastify Redis | ||
- [`@fastify/redis`](https://github.com/fastify/fastify-redis) Fastify Redis | ||
connection plugin, with which you can share the same Redis connection across | ||
every part of your server. | ||
- [`fastify-reply-from`](https://github.com/fastify/fastify-reply-from) Plugin | ||
- [`@fastify/reply-from`](https://github.com/fastify/fastify-reply-from) Plugin | ||
to forward the current HTTP request to another server. | ||
- [`fastify-routes`](https://github.com/fastify/fastify-routes) Plugin that | ||
- [`@fastify/routes`](https://github.com/fastify/fastify-routes) Plugin that | ||
provides a `Map` of routes. | ||
@@ -101,3 +101,3 @@ - [`fastify-schedule`](https://github.com/fastify/fastify-schedule) Plugin for | ||
[toad-scheduler](https://github.com/kibertoad/toad-scheduler). | ||
- [`fastify-sensible`](https://github.com/fastify/fastify-sensible) Defaults for | ||
- [`@fastify/sensible`](https://github.com/fastify/fastify-sensible) Defaults for | ||
Fastify that everyone can agree on. It adds some useful decorators such as | ||
@@ -107,10 +107,10 @@ HTTP errors and assertions, but also more request and reply methods. | ||
Fastify. | ||
- [`fastify-static`](https://github.com/fastify/fastify-static) Plugin for | ||
- [`@fastify/static`](https://github.com/fastify/fastify-static) Plugin for | ||
serving static files as fast as possible. | ||
- [`fastify-swagger`](https://github.com/fastify/fastify-swagger) Plugin for | ||
- [`@fastify/swagger`](https://github.com/fastify/fastify-swagger) Plugin for | ||
serving Swagger/OpenAPI documentation for Fastify, supporting dynamic | ||
generation. | ||
- [`fastify-websocket`](https://github.com/fastify/fastify-websocket) WebSocket | ||
- [`@fastify/websocket`](https://github.com/fastify/fastify-websocket) WebSocket | ||
support for Fastify. Built upon [ws](https://github.com/websockets/ws). | ||
- [`fastify-url-data`](https://github.com/fastify/fastify-url-data) Decorate the | ||
- [`@fastify/url-data`](https://github.com/fastify/fastify-url-data) Decorate the | ||
`Request` object with a method to access raw URL components. | ||
@@ -117,0 +117,0 @@ - [`middie`](https://github.com/fastify/middie) Middleware engine for Fastify. |
@@ -198,6 +198,6 @@ <h1 align="center">Fastify</h1> | ||
First, install `fastify-plugin` and `fastify-mongodb`: | ||
First, install `fastify-plugin` and `@fastify/mongodb`: | ||
``` | ||
npm i --save fastify-plugin fastify-mongodb | ||
npm i --save fastify-plugin @fastify/mongodb | ||
``` | ||
@@ -250,3 +250,3 @@ | ||
import fastifyPlugin from 'fastify-plugin' | ||
import fastifyMongo from 'fastify-mongodb' | ||
import fastifyMongo from '@fastify/mongodb' | ||
@@ -270,3 +270,3 @@ async function dbConnector (fastify, options) { | ||
async function dbConnector (fastify, options) { | ||
fastify.register(require('fastify-mongodb'), { | ||
fastify.register(require('@fastify/mongodb'), { | ||
url: 'mongodb://localhost:27017/test_database' | ||
@@ -273,0 +273,0 @@ }) |
@@ -17,3 +17,3 @@ # V3 Migration Guide | ||
If you use Express middleware in your application, please install and register | ||
the [`fastify-express`](https://github.com/fastify/fastify-express) or | ||
the [`@fastify/express`](https://github.com/fastify/fastify-express) or | ||
[`middie`](https://github.com/fastify/middie) plugin before doing so. | ||
@@ -32,3 +32,3 @@ | ||
// Using the Express `cors` middleware in Fastify v3. | ||
await fastify.register(require('fastify-express')); | ||
await fastify.register(require('@fastify/express')); | ||
fastify.use(require('cors')()); | ||
@@ -35,0 +35,0 @@ ``` |
@@ -448,6 +448,6 @@ <h1 align="center">Fastify</h1> | ||
error objects across your codebase and plugins with the | ||
[`fastify-error`](https://github.com/fastify/fastify-error) module. | ||
[`@fastify/error`](https://github.com/fastify/fastify-error) module. | ||
```js | ||
const createError = require('fastify-error') | ||
const createError = require('@fastify/error') | ||
const CustomError = createError('ERROR_CODE', 'message') | ||
@@ -481,8 +481,8 @@ console.log(new CustomError()) | ||
rendering (*ejs, pug, handlebars, marko*) plugin support for Fastify. | ||
- [`fastify-mongodb`](https://github.com/fastify/fastify-mongodb) Fastify | ||
- [`@fastify/mongodb`](https://github.com/fastify/fastify-mongodb) Fastify | ||
MongoDB connection plugin, with this you can share the same MongoDB connection | ||
pool in every part of your server. | ||
- [`fastify-multipart`](https://github.com/fastify/fastify-multipart) Multipart | ||
- [`@fastify/multipart`](https://github.com/fastify/fastify-multipart) Multipart | ||
support for Fastify | ||
- [`fastify-helmet`](https://github.com/fastify/fastify-helmet) Important | ||
- [`@fastify/helmet`](https://github.com/fastify/fastify-helmet) Important | ||
security headers for Fastify | ||
@@ -489,0 +489,0 @@ |
@@ -36,5 +36,5 @@ <h1 align="center">Fastify</h1> | ||
at: | ||
- [`fastify-caching`](https://github.com/fastify/fastify-caching) | ||
- [`fastify-compress`](https://github.com/fastify/fastify-compress) | ||
- [`fastify-cookie`](https://github.com/fastify/fastify-cookie) | ||
- [`@fastify/caching`](https://github.com/fastify/fastify-caching) | ||
- [`@fastify/compress`](https://github.com/fastify/fastify-compress) | ||
- [`@fastify/cookie`](https://github.com/fastify/fastify-cookie) | ||
- [`point-of-view`](https://github.com/fastify/point-of-view) | ||
@@ -97,8 +97,8 @@ - [`under-pressure`](https://github.com/fastify/under-pressure) | ||
rendering (*ejs, pug, handlebars, marko*) plugin support for Fastify. | ||
- [`fastify-mongodb`](https://github.com/fastify/fastify-mongodb) Fastify | ||
- [`@fastify/mongodb`](https://github.com/fastify/fastify-mongodb) Fastify | ||
MongoDB connection plugin, with this you can share the same MongoDB connection | ||
pool in every part of your server. | ||
- [`fastify-multipart`](https://github.com/fastify/fastify-multipart) Multipart | ||
- [`@fastify/multipart`](https://github.com/fastify/fastify-multipart) Multipart | ||
support for Fastify. | ||
- [`fastify-helmet`](https://github.com/fastify/fastify-helmet) Important | ||
- [`@fastify/helmet`](https://github.com/fastify/fastify-helmet) Important | ||
security headers for Fastify. |
@@ -36,3 +36,3 @@ <h1 align="center">Fastify</h1> | ||
access to the same context as the second route. Using | ||
[fastify-bearer-auth][bearer] to provide the authentication, the code for this | ||
[@fastify/bearer-auth][bearer] to provide the authentication, the code for this | ||
example is as follows: | ||
@@ -48,3 +48,3 @@ | ||
fastify.register(async function authenticatedContext (childServer) { | ||
childServer.register(require('fastify-bearer-auth'), { keys: ['abc123'] }) | ||
childServer.register(require('@fastify/bearer-auth'), { keys: ['abc123'] }) | ||
@@ -108,3 +108,3 @@ childServer.route({ | ||
the _root context_. | ||
2. Only the `authenticatedContext` has access to the `fastify-bearer-auth` | ||
2. Only the `authenticatedContext` has access to the `@fastify/bearer-auth` | ||
plugin. | ||
@@ -111,0 +111,0 @@ 3. Both the `publicContext` and `grandchildContext` have access to the `foo` |
@@ -354,3 +354,3 @@ <h1 align="center">Fastify</h1> | ||
fastify.addHook('preHandler', async (request, reply) => { | ||
// the fastify-static plugin will send a file asynchronously, | ||
// the @fastify/static plugin will send a file asynchronously, | ||
// so we should return reply | ||
@@ -357,0 +357,0 @@ reply.sendFile('myfile') |
@@ -7,3 +7,3 @@ <h1 align="center">Fastify</h1> | ||
requires an external plugin such as | ||
[`fastify-express`](https://github.com/fastify/fastify-express) or | ||
[`@fastify/express`](https://github.com/fastify/fastify-express) or | ||
[`middie`](https://github.com/fastify/middie). | ||
@@ -13,7 +13,7 @@ | ||
An example of registering the | ||
[`fastify-express`](https://github.com/fastify/fastify-express) plugin to `use` | ||
[`@fastify/express`](https://github.com/fastify/fastify-express) plugin to `use` | ||
Express middleware: | ||
```js | ||
await fastify.register(require('fastify-express')) | ||
await fastify.register(require('@fastify/express')) | ||
fastify.use(require('cors')()) | ||
@@ -75,7 +75,7 @@ fastify.use(require('dns-prefetch-control')()) | ||
Fastify offers some alternatives to the most commonly used middleware, such as | ||
[`fastify-helmet`](https://github.com/fastify/fastify-helmet) in case of | ||
[`@fastify/helmet`](https://github.com/fastify/fastify-helmet) in case of | ||
[`helmet`](https://github.com/helmetjs/helmet), | ||
[`fastify-cors`](https://github.com/fastify/fastify-cors) for | ||
[`@fastify/cors`](https://github.com/fastify/fastify-cors) for | ||
[`cors`](https://github.com/expressjs/cors), and | ||
[`fastify-static`](https://github.com/fastify/fastify-static) for | ||
[`@fastify/static`](https://github.com/fastify/fastify-static) for | ||
[`serve-static`](https://github.com/expressjs/serve-static). |
@@ -486,3 +486,3 @@ <h1 align="center">Fastify</h1> | ||
[`http-errors`](https://npm.im/http-errors) module or | ||
[`fastify-sensible`](https://github.com/fastify/fastify-sensible) plugin to | ||
[`@fastify/sensible`](https://github.com/fastify/fastify-sensible) plugin to | ||
generate errors: | ||
@@ -489,0 +489,0 @@ |
@@ -607,3 +607,3 @@ <h1 align="center">Fastify</h1> | ||
out | ||
[fastify-swagger](https://github.com/fastify/fastify-swagger/blob/master/index.d.ts). | ||
[@fastify/swagger](https://github.com/fastify/fastify-swagger/blob/master/index.d.ts). | ||
@@ -610,0 +610,0 @@ With those files completed, the plugin is now ready to be consumed by any |
@@ -12,3 +12,3 @@ import * as http from 'http' | ||
import { Options as AjvOptions } from '@fastify/ajv-compiler' | ||
import { FastifyError } from 'fastify-error' | ||
import { FastifyError } from '@fastify/error' | ||
import { FastifyReply } from './types/reply' | ||
@@ -167,3 +167,3 @@ import { FastifySchemaValidationError } from './types/schema' | ||
declare module 'fastify-error' { | ||
declare module '@fastify/error' { | ||
interface FastifyError { | ||
@@ -193,3 +193,3 @@ validation?: ValidationResult[]; | ||
export { FastifyBodyParser, FastifyContentTypeParser, AddContentTypeParser, hasContentTypeParser, getDefaultJsonParser, ProtoAction, ConstructorAction } from './types/content-type-parser' | ||
export { FastifyError } from 'fastify-error' | ||
export { FastifyError } from '@fastify/error' | ||
export { FastifySchema, FastifySchemaCompiler } from './types/schema' | ||
@@ -196,0 +196,0 @@ export { HTTPMethods, RawServerBase, RawRequestDefaultExpression, RawReplyDefaultExpression, RawServerDefault, ContextConfigDefault, RequestBodyDefault, RequestQuerystringDefault, RequestParamsDefault, RequestHeadersDefault } from './types/utils' |
'use strict' | ||
const VERSION = '3.28.0' | ||
const VERSION = '3.29.4' | ||
@@ -587,3 +587,3 @@ const Avvio = require('avvio') | ||
// If the socket is not writable, there is no reason to try to send data. | ||
if (socket.writable && socket.bytesWritten === 0) { | ||
if (socket.writable) { | ||
socket.write(`HTTP/1.1 400 Bad Request\r\nContent-Length: ${body.length}\r\nContent-Type: application/json\r\n\r\n${body}`) | ||
@@ -590,0 +590,0 @@ } |
@@ -9,2 +9,3 @@ 'use strict' | ||
lru = typeof lru === 'function' ? lru : lru.default | ||
const { parse: parseContentType } = require('content-type') | ||
@@ -36,6 +37,7 @@ const secureJson = require('secure-json-parse') | ||
this[kDefaultJsonParse] = getDefaultJsonParser(onProtoPoisoning, onConstructorPoisoning) | ||
this.customParsers = {} | ||
this.customParsers['application/json'] = new Parser(true, false, bodyLimit, this[kDefaultJsonParse]) | ||
this.customParsers['text/plain'] = new Parser(true, false, bodyLimit, defaultPlainTextParser) | ||
this.parserList = ['application/json', 'text/plain'] | ||
// using a map instead of a plain object to avoid prototype hijack attacks | ||
this.customParsers = new Map() | ||
this.customParsers.set('application/json', new Parser(true, false, bodyLimit, this[kDefaultJsonParse])) | ||
this.customParsers.set('text/plain', new Parser(true, false, bodyLimit, defaultPlainTextParser)) | ||
this.parserList = [new ParserListItem('application/json'), new ParserListItem('text/plain')] | ||
this.parserRegExpList = [] | ||
@@ -70,10 +72,10 @@ this.cache = lru(100) | ||
if (contentTypeIsString && contentType === '*') { | ||
this.customParsers[''] = parser | ||
this.customParsers.set('', parser) | ||
} else { | ||
if (contentTypeIsString) { | ||
this.parserList.unshift(contentType) | ||
this.parserList.unshift(new ParserListItem(contentType)) | ||
} else { | ||
this.parserRegExpList.unshift(contentType) | ||
} | ||
this.customParsers[contentType] = parser | ||
this.customParsers.set(contentType.toString(), parser) | ||
} | ||
@@ -83,22 +85,40 @@ } | ||
ContentTypeParser.prototype.hasParser = function (contentType) { | ||
return contentType in this.customParsers | ||
return this.customParsers.has(typeof contentType === 'string' ? contentType : contentType.toString()) | ||
} | ||
ContentTypeParser.prototype.existingParser = function (contentType) { | ||
if (contentType === 'application/json') { | ||
return this.customParsers['application/json'] && this.customParsers['application/json'].fn !== this[kDefaultJsonParse] | ||
if (contentType === 'application/json' && this.customParsers.has(contentType)) { | ||
return this.customParsers.get(contentType).fn !== this[kDefaultJsonParse] | ||
} | ||
if (contentType === 'text/plain') { | ||
return this.customParsers['text/plain'] && this.customParsers['text/plain'].fn !== defaultPlainTextParser | ||
if (contentType === 'text/plain' && this.customParsers.has(contentType)) { | ||
return this.customParsers.get(contentType).fn !== defaultPlainTextParser | ||
} | ||
return contentType in this.customParsers | ||
return this.hasParser(contentType) | ||
} | ||
ContentTypeParser.prototype.getParser = function (contentType) { | ||
if (this.hasParser(contentType)) { | ||
return this.customParsers.get(contentType) | ||
} | ||
const parser = this.cache.get(contentType) | ||
// TODO not covered by tests, this is a security backport | ||
/* istanbul ignore next */ | ||
if (parser !== undefined) return parser | ||
const parsed = safeParseContentType(contentType) | ||
// dummyContentType always the same object | ||
// we can use === for the comparsion and return early | ||
if (parsed === dummyContentType) { | ||
return this.customParsers.get('') | ||
} | ||
// eslint-disable-next-line no-var | ||
for (var i = 0; i !== this.parserList.length; ++i) { | ||
const parserName = this.parserList[i] | ||
if (contentType.indexOf(parserName) > -1) { | ||
const parser = this.customParsers[parserName] | ||
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 | ||
this.cache.set(contentType, parser) | ||
@@ -112,4 +132,5 @@ return parser | ||
const parserRegExp = this.parserRegExpList[j] | ||
if (parserRegExp.test(contentType)) { | ||
const parser = this.customParsers[parserRegExp] | ||
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 | ||
this.cache.set(contentType, parser) | ||
@@ -120,7 +141,7 @@ return parser | ||
return this.customParsers[''] | ||
return this.customParsers.get('') | ||
} | ||
ContentTypeParser.prototype.removeAll = function () { | ||
this.customParsers = {} | ||
this.customParsers = new Map() | ||
this.parserRegExpList = [] | ||
@@ -134,3 +155,3 @@ this.parserList = [] | ||
delete this.customParsers[contentType] | ||
this.customParsers.delete(contentType.toString()) | ||
@@ -300,3 +321,3 @@ const parsers = typeof contentType === 'string' ? this.parserList : this.parserRegExpList | ||
contentTypeParser[kDefaultJsonParse] = c[kDefaultJsonParse] | ||
Object.assign(contentTypeParser.customParsers, c.customParsers) | ||
contentTypeParser.customParsers = new Map(c.customParsers.entries()) | ||
contentTypeParser.parserList = c.parserList.slice() | ||
@@ -354,2 +375,59 @@ return contentTypeParser | ||
// dummy here to prevent repeated object creation | ||
const dummyContentType = { type: '', parameters: Object.create(null) } | ||
function safeParseContentType (contentType) { | ||
try { | ||
return parseContentType(contentType) | ||
} catch (err) { | ||
return dummyContentType | ||
} | ||
} | ||
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 compareRegExpContentType (contentType, essenceMIMEType, regexp) { | ||
if (regexp.source.indexOf(';') === -1) { | ||
// 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 comparsion | ||
const parsed = safeParseContentType(contentType) | ||
this.type = parsed.type | ||
this.parameters = parsed.parameters | ||
this.parameterKeys = Object.keys(parsed.parameters) | ||
this.isEssence = contentType.indexOf(';') === -1 | ||
} | ||
// used in ContentTypeParser.remove | ||
ParserListItem.prototype.toString = function () { | ||
return this.name | ||
} | ||
module.exports = ContentTypeParser | ||
@@ -356,0 +434,0 @@ module.exports.helpers = { |
'use strict' | ||
const createError = require('fastify-error') | ||
const createError = require('@fastify/error') | ||
const codes = { | ||
@@ -5,0 +5,0 @@ /** |
@@ -548,3 +548,3 @@ 'use strict' | ||
if (err != null) { | ||
if (res.headersSent) { | ||
if (res.headersSent || reply.request.raw.aborted === true) { | ||
if (!errorLogged) { | ||
@@ -551,0 +551,0 @@ errorLogged = true |
{ | ||
"name": "fastify", | ||
"version": "3.28.0", | ||
"version": "3.29.4", | ||
"description": "Fast and low overhead web framework, for Node.js", | ||
@@ -130,5 +130,4 @@ "main": "fastify.js", | ||
"@types/pino": "^6.0.1", | ||
"@typescript-eslint/eslint-plugin": "^5.0.0", | ||
"@typescript-eslint/parser": "^5.0.0", | ||
"JSONStream": "^1.3.5", | ||
"@typescript-eslint/eslint-plugin": "^5.21.0", | ||
"@typescript-eslint/parser": "^5.21.0", | ||
"ajv": "^6.0.0", | ||
@@ -144,7 +143,7 @@ "ajv-errors": "^1.0.1", | ||
"dns-prefetch-control": "^0.3.0", | ||
"eslint": "^8.0.1", | ||
"eslint": "^8.14.0", | ||
"eslint-config-standard": "^17.0.0-1", | ||
"eslint-import-resolver-node": "^0.3.2", | ||
"eslint-plugin-import": "^2.25.4", | ||
"eslint-plugin-n": "^14.0.0", | ||
"eslint-import-resolver-node": "^0.3.6", | ||
"eslint-plugin-import": "^2.26.0", | ||
"eslint-plugin-n": "^15.2.0", | ||
"eslint-plugin-promise": "^6.0.0", | ||
@@ -162,2 +161,3 @@ "fast-json-body": "^1.1.0", | ||
"ienoopen": "^1.1.0", | ||
"JSONStream": "^1.3.5", | ||
"license-checker": "^25.0.1", | ||
@@ -172,3 +172,3 @@ "pem": "^1.14.4", | ||
"split2": "^4.1.0", | ||
"standard": "^17.0.0-2", | ||
"standard": "^17.0.0", | ||
"tap": "^15.1.1", | ||
@@ -185,7 +185,6 @@ "tap-mocha-reporter": "^5.0.1", | ||
"@fastify/ajv-compiler": "^1.0.0", | ||
"@fastify/error": "^2.0.0", | ||
"abstract-logging": "^2.0.0", | ||
"avvio": "^7.1.2", | ||
"fast-json-stringify": "^2.5.2", | ||
"fastify-error": "^0.3.0", | ||
"process-warning": "^1.0.0", | ||
"find-my-way": "^4.5.0", | ||
@@ -195,2 +194,4 @@ "flatstr": "^1.0.12", | ||
"pino": "^6.13.0", | ||
"process-warning": "^1.0.0", | ||
"content-type": "^1.0.4", | ||
"proxy-addr": "^2.0.7", | ||
@@ -197,0 +198,0 @@ "rfdc": "^1.1.4", |
@@ -184,3 +184,3 @@ 'use strict' | ||
contentTypeParser.add('*', {}, first) | ||
t.equal(contentTypeParser.customParsers[''].fn, first) | ||
t.equal(contentTypeParser.customParsers.get('').fn, first) | ||
}) | ||
@@ -243,3 +243,3 @@ | ||
t.same(Object.keys(contentTypeParser.customParsers).length, 2) | ||
t.same(contentTypeParser.customParsers.size, 2) | ||
}) | ||
@@ -267,1 +267,281 @@ | ||
}) | ||
test('Safeguard against malicious content-type / 1', async t => { | ||
const badNames = Object.getOwnPropertyNames({}.__proto__) // eslint-disable-line | ||
t.plan(badNames.length) | ||
const fastify = Fastify() | ||
fastify.post('/', async () => { | ||
return 'ok' | ||
}) | ||
for (const prop of badNames) { | ||
const response = await fastify.inject({ | ||
method: 'POST', | ||
path: '/', | ||
headers: { | ||
'content-type': prop | ||
}, | ||
body: '' | ||
}) | ||
t.same(response.statusCode, 415) | ||
} | ||
}) | ||
test('Safeguard against malicious content-type / 2', async t => { | ||
t.plan(1) | ||
const fastify = Fastify() | ||
fastify.post('/', async () => { | ||
return 'ok' | ||
}) | ||
const response = await fastify.inject({ | ||
method: 'POST', | ||
path: '/', | ||
headers: { | ||
'content-type': '\\u0063\\u006fnstructor' | ||
}, | ||
body: '' | ||
}) | ||
t.same(response.statusCode, 415) | ||
}) | ||
test('Safeguard against malicious content-type / 3', async t => { | ||
t.plan(1) | ||
const fastify = Fastify() | ||
fastify.post('/', async () => { | ||
return 'ok' | ||
}) | ||
const response = await fastify.inject({ | ||
method: 'POST', | ||
path: '/', | ||
headers: { | ||
'content-type': 'constructor; charset=utf-8' | ||
}, | ||
body: '' | ||
}) | ||
t.same(response.statusCode, 415) | ||
}) | ||
test('Safeguard against content-type spoofing - string', async t => { | ||
t.plan(1) | ||
const fastify = Fastify() | ||
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: '' | ||
}) | ||
}) | ||
test('Safeguard against content-type spoofing - regexp', async t => { | ||
t.plan(1) | ||
const fastify = Fastify() | ||
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: '' | ||
}) | ||
}) | ||
test('content-type match parameters - string 1', async t => { | ||
t.plan(1) | ||
const fastify = Fastify() | ||
fastify.removeAllContentTypeParsers() | ||
fastify.addContentTypeParser('text/plain; charset=utf8', function (request, body, done) { | ||
t.fail('shouldn\'t be called') | ||
done(null, body) | ||
}) | ||
fastify.addContentTypeParser('application/json; charset=utf8', 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; charset=utf8' | ||
}, | ||
body: '' | ||
}) | ||
}) | ||
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 => { | ||
t.plan(1) | ||
const fastify = Fastify() | ||
fastify.removeAllContentTypeParsers() | ||
fastify.addContentTypeParser(/application\/json; charset=utf8/, 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; charset=utf8' | ||
}, | ||
body: '' | ||
}) | ||
}) | ||
test('content-type fail when parameters not match - string 1', async t => { | ||
t.plan(1) | ||
const fastify = Fastify() | ||
fastify.removeAllContentTypeParsers() | ||
fastify.addContentTypeParser('application/json; charset=utf8; foo=bar', function (request, body, done) { | ||
t.fail('shouldn\'t be called') | ||
done(null, body) | ||
}) | ||
fastify.post('/', async () => { | ||
return 'ok' | ||
}) | ||
const response = await fastify.inject({ | ||
method: 'POST', | ||
path: '/', | ||
headers: { | ||
'content-type': 'application/json; charset=utf8' | ||
}, | ||
body: '' | ||
}) | ||
t.same(response.statusCode, 415) | ||
}) | ||
test('content-type fail when parameters not match - 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.fail('shouldn\'t be called') | ||
done(null, body) | ||
}) | ||
fastify.post('/', async () => { | ||
return 'ok' | ||
}) | ||
const response = await fastify.inject({ | ||
method: 'POST', | ||
path: '/', | ||
headers: { | ||
'content-type': 'application/json; charset=utf8; foo=baz' | ||
}, | ||
body: '' | ||
}) | ||
t.same(response.statusCode, 415) | ||
}) | ||
test('content-type fail when parameters not match - regexp', async t => { | ||
t.plan(1) | ||
const fastify = Fastify() | ||
fastify.removeAllContentTypeParsers() | ||
fastify.addContentTypeParser(/application\/json; charset=utf8; foo=bar/, function (request, body, done) { | ||
t.fail('shouldn\'t be called') | ||
done(null, body) | ||
}) | ||
fastify.post('/', async () => { | ||
return 'ok' | ||
}) | ||
const response = await fastify.inject({ | ||
method: 'POST', | ||
path: '/', | ||
headers: { | ||
'content-type': 'application/json; charset=utf8' | ||
}, | ||
body: '' | ||
}) | ||
t.same(response.statusCode, 415) | ||
}) |
@@ -1123,3 +1123,3 @@ 'use strict' | ||
headers: { | ||
'Content-Type': 'application/json charset=utf-8' | ||
'Content-Type': 'application/json; charset=utf-8' | ||
} | ||
@@ -1307,3 +1307,3 @@ }, (err, response, body) => { | ||
headers: { | ||
'Content-Type': 'weird-content-type+json' | ||
'Content-Type': 'weird/content-type+json' | ||
} | ||
@@ -1338,3 +1338,3 @@ }, (err, response, body) => { | ||
fastify.addContentTypeParser(/.*\+myExtension$/, function (req, payload, done) { | ||
fastify.addContentTypeParser(/.*\+myExtension$/i, function (req, payload, done) { | ||
let data = '' | ||
@@ -1341,0 +1341,0 @@ payload.on('data', chunk => { data += chunk }) |
@@ -5,2 +5,3 @@ 'use strict' | ||
const t = require('tap') | ||
const semver = require('semver') | ||
const test = t.test | ||
@@ -157,3 +158,3 @@ const Fastify = require('..') | ||
test('default clientError handler destroys sockets in writable state', t => { | ||
t.plan(1) | ||
t.plan(2) | ||
@@ -174,2 +175,5 @@ const fastify = Fastify({ | ||
t.pass('destroy should be called') | ||
}, | ||
write (response) { | ||
t.match(response, /^HTTP\/1.1 400 Bad Request/) | ||
} | ||
@@ -195,2 +199,5 @@ }) | ||
t.pass('destroy should be called') | ||
}, | ||
write (response) { | ||
t.fail('write should not be called') | ||
} | ||
@@ -280,1 +287,40 @@ }) | ||
}) | ||
const skip = semver.lt(process.versions.node, '11.0.0') | ||
test('default clientError replies with bad request on reused keep-alive connection', { skip }, t => { | ||
t.plan(2) | ||
let response = '' | ||
const fastify = Fastify({ | ||
bodyLimit: 1, | ||
keepAliveTimeout: 100 | ||
}) | ||
fastify.get('/', (request, reply) => { | ||
reply.send('OK\n') | ||
}) | ||
fastify.listen({ port: 0 }, function (err) { | ||
t.error(err) | ||
fastify.server.unref() | ||
const client = connect(fastify.server.address().port) | ||
client.on('data', chunk => { | ||
response += chunk.toString('utf-8') | ||
}) | ||
client.on('end', () => { | ||
t.match(response, /^HTTP\/1.1 200 OK.*HTTP\/1.1 400 Bad Request/s) | ||
}) | ||
client.resume() | ||
client.write('GET / HTTP/1.1\r\n') | ||
client.write('\r\n\r\n') | ||
client.write('GET /?a b HTTP/1.1\r\n') | ||
client.write('Connection: close\r\n') | ||
client.write('\r\n\r\n') | ||
}) | ||
}) |
@@ -686,1 +686,49 @@ 'use strict' | ||
}) | ||
test('reply.send handles aborted requests', t => { | ||
t.plan(2) | ||
const spyLogger = { | ||
level: 'error', | ||
fatal: () => { }, | ||
error: () => { | ||
t.fail('should not log an error') | ||
}, | ||
warn: () => { }, | ||
info: () => { }, | ||
debug: () => { }, | ||
trace: () => { }, | ||
child: () => { return spyLogger } | ||
} | ||
const fastify = Fastify({ | ||
logger: spyLogger | ||
}) | ||
fastify.get('/', (req, reply) => { | ||
setTimeout(() => { | ||
const stream = new Readable({ | ||
read: function () { | ||
this.push(null) | ||
} | ||
}) | ||
reply.send(stream) | ||
}, 6) | ||
}) | ||
fastify.listen({ port: 0 }, err => { | ||
t.error(err) | ||
fastify.server.unref() | ||
const port = fastify.server.address().port | ||
const http = require('http') | ||
const req = http.get(`http://localhost:${port}`) | ||
.on('error', (err) => { | ||
t.equal(err.code, 'ECONNRESET') | ||
fastify.close() | ||
}) | ||
setTimeout(() => { | ||
req.abort() | ||
}, 1) | ||
}) | ||
}) |
@@ -1,2 +0,2 @@ | ||
import { FastifyError } from 'fastify-error' | ||
import { FastifyError } from '@fastify/error' | ||
import { expectAssignable, expectError, expectType } from 'tsd' | ||
@@ -3,0 +3,0 @@ import fastify, { |
@@ -1,2 +0,2 @@ | ||
import { expectType } from 'tsd' | ||
import { expectError, expectType } from 'tsd' | ||
import fastify, { FastifyLogFn, LogLevel, FastifyLoggerInstance, FastifyError, FastifyRequest, FastifyReply } from '../../fastify' | ||
@@ -186,1 +186,13 @@ import { Server, IncomingMessage, ServerResponse } from 'http' | ||
}) | ||
const childParent = fastify().log | ||
// we test different option variant here | ||
expectType<FastifyLoggerInstance>(childParent.child({}, { level: 'info' })) | ||
expectType<FastifyLoggerInstance>(childParent.child({}, { redact: ['pass', 'pin'] })) | ||
expectType<FastifyLoggerInstance>(childParent.child({}, { serializers: { key: () => {} } })) | ||
expectType<FastifyLoggerInstance>(childParent.child({}, { level: 'info', redact: ['pass', 'pin'], serializers: { key: () => {} } })) | ||
// no option pass | ||
expectError(childParent.child()) | ||
// wrong option | ||
expectError(childParent.child({}, { nonExist: true })) |
@@ -6,3 +6,3 @@ import fastify, { FastifyInstance, FastifyPluginOptions } from '../../fastify' | ||
import { FastifyPluginCallback, FastifyPluginAsync } from '../../types/plugin' | ||
import { FastifyError } from 'fastify-error' | ||
import { FastifyError } from '@fastify/error' | ||
@@ -9,0 +9,0 @@ // FastifyPlugin & FastifyRegister |
@@ -6,3 +6,3 @@ import fastify, { FastifyInstance, FastifyRequest, FastifyReply, RouteHandlerMethod } from '../../fastify' | ||
import { RequestPayload } from '../../types/hooks' | ||
import { FastifyError } from 'fastify-error' | ||
import { FastifyError } from '@fastify/error' | ||
@@ -9,0 +9,0 @@ /* |
@@ -7,3 +7,3 @@ import { Readable } from 'stream' | ||
import { FastifyReply } from './reply' | ||
import { FastifyError } from 'fastify-error' | ||
import { FastifyError } from '@fastify/error' | ||
import { FastifyLoggerInstance } from './logger' | ||
@@ -10,0 +10,0 @@ import { RegisterOptions } from './register' |
@@ -16,3 +16,3 @@ import { Chain as LightMyRequestChain, InjectOptions, Response as LightMyRequestResponse, CallbackFunc as LightMyRequestCallback } from 'light-my-request' | ||
import { FastifyReply } from './reply' | ||
import { FastifyError } from 'fastify-error' | ||
import { FastifyError } from '@fastify/error' | ||
import { AddContentTypeParser, hasContentTypeParser, getDefaultJsonParser, ProtoAction, ConstructorAction, FastifyBodyParser, removeContentTypeParser, removeAllContentTypeParsers } from './content-type-parser' | ||
@@ -19,0 +19,0 @@ |
@@ -21,3 +21,3 @@ /* | ||
import { FastifyError } from 'fastify-error' | ||
import { FastifyError } from '@fastify/error' | ||
import { RawServerBase, RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression } from './utils' | ||
@@ -40,2 +40,7 @@ import { RouteGenericInterface } from './route' | ||
export interface redactOptions { | ||
paths: string[]; | ||
censor?: string | ((v: any) => any) | undefined; | ||
remove?: boolean | undefined; | ||
} | ||
export interface Bindings { | ||
@@ -47,2 +52,8 @@ level?: LogLevel | string; | ||
export interface ChildLoggerOptions { | ||
level?: LogLevel | string; | ||
redact?: string[] | redactOptions | undefined; | ||
serializers?: { [key: string]: SerializerFn } | undefined; | ||
} | ||
export interface FastifyLoggerInstance { | ||
@@ -55,3 +66,3 @@ info: FastifyLogFn; | ||
debug: FastifyLogFn; | ||
child(bindings: Bindings): FastifyLoggerInstance; | ||
child(bindings: Bindings, options?: ChildLoggerOptions): FastifyLoggerInstance; | ||
} | ||
@@ -58,0 +69,0 @@ |
@@ -8,3 +8,3 @@ import { FastifyInstance } from './instance' | ||
import { preValidationHookHandler, preHandlerHookHandler, preSerializationHookHandler, onRequestHookHandler, preParsingHookHandler, onResponseHookHandler, onSendHookHandler, onErrorHookHandler, onTimeoutHookHandler } from './hooks' | ||
import { FastifyError } from 'fastify-error' | ||
import { FastifyError } from '@fastify/error' | ||
import { FastifyContext } from './context' | ||
@@ -11,0 +11,0 @@ |
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
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
1661386
40012
16
37
+ Added@fastify/error@^2.0.0
+ Addedcontent-type@^1.0.4
+ Added@fastify/error@2.0.0(transitive)
+ Addedcontent-type@1.0.5(transitive)
- Removedfastify-error@^0.3.0
- Removedfastify-error@0.3.1(transitive)