Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add requestTimeout option #3407

Merged
merged 2 commits into from Oct 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions build/build-validation.js
Expand Up @@ -16,6 +16,7 @@ const defaultInitOptions = {
connectionTimeout: 0, // 0 sec
keepAliveTimeout: 5000, // 5 sec
maxRequestsPerSocket: 0, // no limit
requestTimeout: 0, // no limit
bodyLimit: 1024 * 1024, // 1 MiB
caseSensitive: true,
disableRequestLogging: false,
Expand Down Expand Up @@ -49,6 +50,7 @@ const schema = {
connectionTimeout: { type: 'integer', default: defaultInitOptions.connectionTimeout },
keepAliveTimeout: { type: 'integer', default: defaultInitOptions.keepAliveTimeout },
maxRequestsPerSocket: { type: 'integer', default: defaultInitOptions.maxRequestsPerSocket, nullable: true },
requestTimeout: { type: 'integer', default: defaultInitOptions.requestTimeout },
bodyLimit: { type: 'integer', default: defaultInitOptions.bodyLimit },
caseSensitive: { type: 'boolean', default: defaultInitOptions.caseSensitive },
http2: { type: 'boolean' },
Expand Down
12 changes: 12 additions & 0 deletions docs/Server.md
Expand Up @@ -13,6 +13,7 @@ document describes the properties available in that options object.
- [connectionTimeout](./Server.md#connectiontimeout)
- [keepAliveTimeout](./Server.md#keepalivetimeout)
- [maxRequestsPerSocket](./Server.md#maxRequestsPerSocket)
- [requestTimeout](./Server.md#requestTimeout)
- [ignoreTrailingSlash](./Server.md#ignoretrailingslash)
- [maxParamLength](./Server.md#maxparamlength)
- [onProtoPoisoning](./Server.md#onprotopoisoning)
Expand Down Expand Up @@ -94,6 +95,17 @@ is in use. Also, when `serverFactory` option is specified, this option is ignore

+ Default: `0` (no limit)

<a name="factory-request-timeout"></a>
### `requestTimeout`

Defines the maximum number of milliseconds for receiving the entire request from the client.
[`server.requestTimeout` property](https://nodejs.org/dist/latest/docs/api/http.html#http_server_requesttimeout)
to understand the effect of this option. Also, when `serverFactory` option is specified, this option is ignored.
It must be set to a non-zero value (e.g. 120 seconds) to protect against potential Denial-of-Service attacks in case the server is deployed without a reverse proxy in front.
> At the time of this writing, only node version greater or equal to 14.11.0 support this option. Check the Node.js documentation for availability in the version you are running.

+ Default: `0` (no limit)

<a name="factory-ignore-slash"></a>
### `ignoreTrailingSlash`

Expand Down
2 changes: 2 additions & 0 deletions fastify.d.ts
Expand Up @@ -97,6 +97,8 @@ export type FastifyServerOptions<
ignoreTrailingSlash?: boolean,
connectionTimeout?: number,
keepAliveTimeout?: number,
maxRequestsPerSocket?: number,
requestTimeout?: number,
pluginTimeout?: number,
bodyLimit?: number,
maxParamLength?: number,
Expand Down
1 change: 1 addition & 0 deletions fastify.js
Expand Up @@ -133,6 +133,7 @@ function fastify (options) {
options.connectionTimeout = options.connectionTimeout || defaultInitOptions.connectionTimeout
options.keepAliveTimeout = options.keepAliveTimeout || defaultInitOptions.keepAliveTimeout
options.maxRequestsPerSocket = options.maxRequestsPerSocket || defaultInitOptions.maxRequestsPerSocket
options.requestTimeout = options.requestTimeout || defaultInitOptions.requestTimeout
options.logger = logger
options.genReqId = genReqId
options.requestIdHeader = requestIdHeader
Expand Down
878 changes: 455 additions & 423 deletions lib/configValidator.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions lib/server.js
Expand Up @@ -28,6 +28,7 @@ function createServer (options, httpHandler) {
} else {
server = http.createServer(httpHandler)
server.keepAliveTimeout = options.keepAliveTimeout
server.requestTimeout = options.requestTimeout
// we treat zero as null
// and null is the default setting from nodejs
// so we do not pass the option to server
Expand Down
2 changes: 2 additions & 0 deletions test/internals/initialConfig.test.js
Expand Up @@ -25,6 +25,7 @@ test('without options passed to Fastify, initialConfig should expose default val
connectionTimeout: 0,
keepAliveTimeout: 5000,
maxRequestsPerSocket: 0,
requestTimeout: 0,
bodyLimit: 1024 * 1024,
caseSensitive: true,
disableRequestLogging: false,
Expand Down Expand Up @@ -242,6 +243,7 @@ test('Should not have issues when passing stream options to Pino.js', t => {
connectionTimeout: 0,
keepAliveTimeout: 5000,
maxRequestsPerSocket: 0,
requestTimeout: 0,
bodyLimit: 1024 * 1024,
caseSensitive: true,
disableRequestLogging: false,
Expand Down
50 changes: 50 additions & 0 deletions test/requestTimeout.test.js
@@ -0,0 +1,50 @@
'use strict'

const http = require('http')
const { test } = require('tap')
const Fastify = require('../fastify')

test('requestTimeout passed to server', t => {
t.plan(4)

try {
Fastify({ requestTimeout: 500.1 })
t.fail('option must be an integer')
} catch (err) {
t.ok(err)
}

try {
Fastify({ requestTimeout: [] })
t.fail('option must be an integer')
} catch (err) {
t.ok(err)
}

const httpServer = Fastify({ requestTimeout: 1000 }).server
t.equal(httpServer.requestTimeout, 1000)

const serverFactory = (handler, _) => {
const server = http.createServer((req, res) => {
handler(req, res)
})
server.requestTimeout = 5000
return server
}
const customServer = Fastify({ requestTimeout: 4000, serverFactory }).server
t.equal(customServer.requestTimeout, 5000)
})

test('requestTimeout should be set', async (t) => {
t.plan(1)

const initialConfig = Fastify({ requestTimeout: 5000 }).initialConfig
t.same(initialConfig.requestTimeout, 5000)
})

test('requestTimeout should 0', async (t) => {
t.plan(1)

const initialConfig = Fastify().initialConfig
t.same(initialConfig.requestTimeout, 0)
})