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

feat: respect --max-http-header-size Node.js flag #2234

Merged
2 changes: 1 addition & 1 deletion docs/api/Client.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Returns: `Client`
* **keepAliveMaxTimeout** `number | null` (optional) - Default: `600e3` - The maximum allowed `keepAliveTimeout`, in milliseconds, when overridden by *keep-alive* hints from the server. Defaults to 10 minutes.
* **keepAliveTimeout** `number | null` (optional) - Default: `4e3` - The timeout, in milliseconds, after which a socket without active requests will time out. Monitors time between activity on a connected socket. This value may be overridden by *keep-alive* hints from the server. See [MDN: HTTP - Headers - Keep-Alive directives](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Keep-Alive#directives) for more details. Defaults to 4 seconds.
* **keepAliveTimeoutThreshold** `number | null` (optional) - Default: `1e3` - A number of milliseconds subtracted from server *keep-alive* hints when overriding `keepAliveTimeout` to account for timing inaccuracies caused by e.g. transport latency. Defaults to 1 second.
* **maxHeaderSize** `number | null` (optional) - Default: `16384` - The maximum length of request headers in bytes. Defaults to 16KiB.
* **maxHeaderSize** `number | null` (optional) - Default: `--max-http-header-size` or `16384` - The maximum length of request headers in bytes. Defaults to Node.js' --max-http-header-size or 16KiB.
metcoder95 marked this conversation as resolved.
Show resolved Hide resolved
* **maxResponseSize** `number | null` (optional) - Default: `-1` - The maximum length of response body in bytes. Set to `-1` to disable.
* **pipelining** `number | null` (optional) - Default: `1` - The amount of concurrent requests to be sent over the single TCP/TLS connection according to [RFC7230](https://tools.ietf.org/html/rfc7230#section-6.3.2). Carefully consider your workload and environment before enabling concurrent requests as pipelining may reduce performance if used incorrectly. Pipelining is sensitive to network stack settings as well as head of line blocking caused by e.g. long running requests. Set to `0` to disable keep-alive connections.
* **connect** `ConnectOptions | Function | null` (optional) - Default: `null`.
Expand Down
3 changes: 2 additions & 1 deletion lib/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

const assert = require('assert')
const net = require('net')
const http = require('http')
const { pipeline } = require('stream')
const util = require('./core/util')
const timers = require('./timers')
Expand Down Expand Up @@ -269,7 +270,7 @@ class Client extends DispatcherBase {
this[kConnector] = connect
this[kSocket] = null
this[kPipelining] = pipelining != null ? pipelining : 1
this[kMaxHeadersSize] = maxHeaderSize || 16384
this[kMaxHeadersSize] = maxHeaderSize || http.maxHeaderSize
this[kKeepAliveDefaultTimeout] = keepAliveTimeout == null ? 4e3 : keepAliveTimeout
this[kKeepAliveMaxTimeout] = keepAliveMaxTimeout == null ? 600e3 : keepAliveMaxTimeout
this[kKeepAliveTimeoutThreshold] = keepAliveTimeoutThreshold == null ? 1e3 : keepAliveTimeoutThreshold
Expand Down
23 changes: 23 additions & 0 deletions test/client-node-max-header-size.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
'use strict'

const { execSync } = require('node:child_process')
balazsorban44 marked this conversation as resolved.
Show resolved Hide resolved
const { test } = require('tap')

const command = 'node -e "require(\'.\').request(\'https://httpbin.org/get\')"'

test("respect Node.js' --max-http-header-size", async (t) => {
t.throws(
// TODO: Drop the `--unhandled-rejections=throw` once we drop Node.js 14
() => execSync(`${command} --max-http-header-size=1 --unhandled-rejections=throw`),
/UND_ERR_HEADERS_OVERFLOW/,
'max-http-header-size=1 should throw'
)

t.doesNotThrow(
() => execSync(command),
/UND_ERR_HEADERS_OVERFLOW/,
'default max-http-header-size should not throw'
)

t.end()
})
23 changes: 23 additions & 0 deletions test/fetch/client-node-max-header-size.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
'use strict'

const { execSync } = require('node:child_process')
const { test } = require('tap')

const command = 'node -e "require(\'./undici-fetch.js\').fetch(\'https://httpbin.org/get\')"'

test("respect Node.js' --max-http-header-size", async (t) => {
t.throws(
// TODO: Drop the `--unhandled-rejections=throw` once we drop Node.js 14
() => execSync(`${command} --max-http-header-size=1 --unhandled-rejections=throw`),
/UND_ERR_HEADERS_OVERFLOW/,
'max-http-header-size=1 should throw'
)

t.doesNotThrow(
() => execSync(command),
/UND_ERR_HEADERS_OVERFLOW/,
'default max-http-header-size should not throw'
)

t.end()
})
2 changes: 1 addition & 1 deletion types/client.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export declare namespace Client {
export interface Options {
/** TODO */
interceptors?: OptionsInterceptors;
/** The maximum length of request headers in bytes. Default: `16384` (16KiB). */
metcoder95 marked this conversation as resolved.
Show resolved Hide resolved
/** The maximum length of request headers in bytes. Default: Node.js' `--max-http-header-size` or `16384` (16KiB). */
maxHeaderSize?: number;
/** The amount of time, in milliseconds, the parser will wait to receive the complete HTTP headers (Node 14 and above only). Default: `300e3` milliseconds (300s). */
headersTimeout?: number;
Expand Down
Loading