undici 6.13.0 → 6.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/docs/docs/api/Client.md +1 -1
  2. package/docs/docs/api/EnvHttpProxyAgent.md +162 -0
  3. package/docs/docs/api/EventSource.md +27 -3
  4. package/docs/docs/api/Fetch.md +0 -6
  5. package/index.js +3 -1
  6. package/lib/api/util.js +14 -7
  7. package/lib/core/request.js +3 -5
  8. package/lib/core/symbols.js +4 -1
  9. package/lib/core/util.js +45 -20
  10. package/lib/dispatcher/client-h2.js +2 -4
  11. package/lib/dispatcher/client.js +3 -2
  12. package/lib/dispatcher/dispatcher-base.js +1 -3
  13. package/lib/dispatcher/env-http-proxy-agent.js +160 -0
  14. package/lib/dispatcher/pool.js +1 -1
  15. package/lib/llhttp/.gitkeep +0 -0
  16. package/lib/llhttp/llhttp-wasm.js +3 -1
  17. package/lib/llhttp/llhttp_simd-wasm.js +3 -1
  18. package/lib/util/timers.js +5 -3
  19. package/lib/web/cache/cache.js +2 -3
  20. package/lib/web/eventsource/eventsource.js +35 -38
  21. package/lib/web/fetch/body.js +12 -10
  22. package/lib/web/fetch/file.js +5 -216
  23. package/lib/web/fetch/formdata-parser.js +2 -2
  24. package/lib/web/fetch/formdata.js +3 -3
  25. package/lib/web/fetch/index.js +3 -6
  26. package/lib/web/fetch/request.js +8 -26
  27. package/lib/web/fetch/response.js +9 -22
  28. package/lib/web/fetch/symbols.js +0 -1
  29. package/lib/web/fetch/util.js +34 -8
  30. package/lib/web/websocket/util.js +6 -13
  31. package/package.json +4 -3
  32. package/types/dispatcher.d.ts +1 -1
  33. package/types/env-http-proxy-agent.d.ts +21 -0
  34. package/types/eventsource.d.ts +4 -2
  35. package/types/index.d.ts +2 -1
  36. package/lib/llhttp/constants.d.ts +0 -199
  37. package/lib/llhttp/constants.js.map +0 -1
  38. package/lib/llhttp/utils.d.ts +0 -4
  39. package/lib/llhttp/utils.js.map +0 -1
  40. package/lib/llhttp/wasm_build_env.txt +0 -32
@@ -23,7 +23,7 @@ Returns: `Client`
23
23
  * **headersTimeout** `number | null` (optional) - Default: `300e3` - The amount of time, in milliseconds, the parser will wait to receive the complete HTTP headers while not sending the request. Defaults to 300 seconds.
24
24
  * **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.
25
25
  * **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.
26
- * **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.
26
+ * **keepAliveTimeoutThreshold** `number | null` (optional) - Default: `2e3` - 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 2 seconds.
27
27
  * **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.
28
28
  * **maxResponseSize** `number | null` (optional) - Default: `-1` - The maximum length of response body in bytes. Set to `-1` to disable.
29
29
  * **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.
@@ -0,0 +1,162 @@
1
+ # Class: EnvHttpProxyAgent
2
+
3
+ Stability: Experimental.
4
+
5
+ Extends: `undici.Dispatcher`
6
+
7
+ EnvHttpProxyAgent automatically reads the proxy configuration from the environment variables `http_proxy`, `https_proxy`, and `no_proxy` and sets up the proxy agents accordingly. When `http_proxy` and `https_proxy` are set, `http_proxy` is used for HTTP requests and `https_proxy` is used for HTTPS requests. If only `http_proxy` is set, `http_proxy` is used for both HTTP and HTTPS requests. If only `https_proxy` is set, it is only used for HTTPS requests.
8
+
9
+ `no_proxy` is a comma or space-separated list of hostnames that should not be proxied. The list may contain leading wildcard characters (`*`). If `no_proxy` is set, the EnvHttpProxyAgent will bypass the proxy for requests to hosts that match the list. If `no_proxy` is set to `"*"`, the EnvHttpProxyAgent will bypass the proxy for all requests.
10
+
11
+ Uppercase environment variables are also supported: `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY`. However, if both the lowercase and uppercase environment variables are set, the uppercase environment variables will be ignored.
12
+
13
+ ## `new EnvHttpProxyAgent([options])`
14
+
15
+ Arguments:
16
+
17
+ * **options** `EnvHttpProxyAgentOptions` (optional) - extends the `Agent` options.
18
+
19
+ Returns: `EnvHttpProxyAgent`
20
+
21
+ ### Parameter: `EnvHttpProxyAgentOptions`
22
+
23
+ Extends: [`AgentOptions`](Agent.md#parameter-agentoptions)
24
+
25
+ * **httpProxy** `string` (optional) - When set, it will override the `HTTP_PROXY` environment variable.
26
+ * **httpsProxy** `string` (optional) - When set, it will override the `HTTPS_PROXY` environment variable.
27
+ * **noProxy** `string` (optional) - When set, it will override the `NO_PROXY` environment variable.
28
+
29
+ Examples:
30
+
31
+ ```js
32
+ import { EnvHttpProxyAgent } from 'undici'
33
+
34
+ const envHttpProxyAgent = new EnvHttpProxyAgent()
35
+ // or
36
+ const envHttpProxyAgent = new EnvHttpProxyAgent({ httpProxy: 'my.proxy.server:8080', httpsProxy: 'my.proxy.server:8443', noProxy: 'localhost' })
37
+ ```
38
+
39
+ #### Example - EnvHttpProxyAgent instantiation
40
+
41
+ This will instantiate the EnvHttpProxyAgent. It will not do anything until registered as the agent to use with requests.
42
+
43
+ ```js
44
+ import { EnvHttpProxyAgent } from 'undici'
45
+
46
+ const envHttpProxyAgent = new EnvHttpProxyAgent()
47
+ ```
48
+
49
+ #### Example - Basic Proxy Fetch with global agent dispatcher
50
+
51
+ ```js
52
+ import { setGlobalDispatcher, fetch, EnvHttpProxyAgent } from 'undici'
53
+
54
+ const envHttpProxyAgent = new EnvHttpProxyAgent()
55
+ setGlobalDispatcher(envHttpProxyAgent)
56
+
57
+ const { status, json } = await fetch('http://localhost:3000/foo')
58
+
59
+ console.log('response received', status) // response received 200
60
+
61
+ const data = await json() // data { foo: "bar" }
62
+ ```
63
+
64
+ #### Example - Basic Proxy Request with global agent dispatcher
65
+
66
+ ```js
67
+ import { setGlobalDispatcher, request, EnvHttpProxyAgent } from 'undici'
68
+
69
+ const envHttpProxyAgent = new EnvHttpProxyAgent()
70
+ setGlobalDispatcher(envHttpProxyAgent)
71
+
72
+ const { statusCode, body } = await request('http://localhost:3000/foo')
73
+
74
+ console.log('response received', statusCode) // response received 200
75
+
76
+ for await (const data of body) {
77
+ console.log('data', data.toString('utf8')) // data foo
78
+ }
79
+ ```
80
+
81
+ #### Example - Basic Proxy Request with local agent dispatcher
82
+
83
+ ```js
84
+ import { EnvHttpProxyAgent, request } from 'undici'
85
+
86
+ const envHttpProxyAgent = new EnvHttpProxyAgent()
87
+
88
+ const {
89
+ statusCode,
90
+ body
91
+ } = await request('http://localhost:3000/foo', { dispatcher: envHttpProxyAgent })
92
+
93
+ console.log('response received', statusCode) // response received 200
94
+
95
+ for await (const data of body) {
96
+ console.log('data', data.toString('utf8')) // data foo
97
+ }
98
+ ```
99
+
100
+ #### Example - Basic Proxy Fetch with local agent dispatcher
101
+
102
+ ```js
103
+ import { EnvHttpProxyAgent, fetch } from 'undici'
104
+
105
+ const envHttpProxyAgent = new EnvHttpProxyAgent()
106
+
107
+ const {
108
+ status,
109
+ json
110
+ } = await fetch('http://localhost:3000/foo', { dispatcher: envHttpProxyAgent })
111
+
112
+ console.log('response received', status) // response received 200
113
+
114
+ const data = await json() // data { foo: "bar" }
115
+ ```
116
+
117
+ ## Instance Methods
118
+
119
+ ### `EnvHttpProxyAgent.close([callback])`
120
+
121
+ Implements [`Dispatcher.close([callback])`](Dispatcher.md#dispatcherclosecallback-promise).
122
+
123
+ ### `EnvHttpProxyAgent.destroy([error, callback])`
124
+
125
+ Implements [`Dispatcher.destroy([error, callback])`](Dispatcher.md#dispatcherdestroyerror-callback-promise).
126
+
127
+ ### `EnvHttpProxyAgent.dispatch(options, handler: AgentDispatchOptions)`
128
+
129
+ Implements [`Dispatcher.dispatch(options, handler)`](Dispatcher.md#dispatcherdispatchoptions-handler).
130
+
131
+ #### Parameter: `AgentDispatchOptions`
132
+
133
+ Extends: [`DispatchOptions`](Dispatcher.md#parameter-dispatchoptions)
134
+
135
+ * **origin** `string | URL`
136
+ * **maxRedirections** `Integer`.
137
+
138
+ Implements [`Dispatcher.destroy([error, callback])`](Dispatcher.md#dispatcherdestroyerror-callback-promise).
139
+
140
+ ### `EnvHttpProxyAgent.connect(options[, callback])`
141
+
142
+ See [`Dispatcher.connect(options[, callback])`](Dispatcher.md#dispatcherconnectoptions-callback).
143
+
144
+ ### `EnvHttpProxyAgent.dispatch(options, handler)`
145
+
146
+ Implements [`Dispatcher.dispatch(options, handler)`](Dispatcher.md#dispatcherdispatchoptions-handler).
147
+
148
+ ### `EnvHttpProxyAgent.pipeline(options, handler)`
149
+
150
+ See [`Dispatcher.pipeline(options, handler)`](Dispatcher.md#dispatcherpipelineoptions-handler).
151
+
152
+ ### `EnvHttpProxyAgent.request(options[, callback])`
153
+
154
+ See [`Dispatcher.request(options [, callback])`](Dispatcher.md#dispatcherrequestoptions-callback).
155
+
156
+ ### `EnvHttpProxyAgent.stream(options, factory[, callback])`
157
+
158
+ See [`Dispatcher.stream(options, factory[, callback])`](Dispatcher.md#dispatcherstreamoptions-factory-callback).
159
+
160
+ ### `EnvHttpProxyAgent.upgrade(options[, callback])`
161
+
162
+ See [`Dispatcher.upgrade(options[, callback])`](Dispatcher.md#dispatcherupgradeoptions-callback).
@@ -1,5 +1,7 @@
1
1
  # EventSource
2
2
 
3
+ > ⚠️ Warning: the EventSource API is experimental.
4
+
3
5
  Undici exposes a WHATWG spec-compliant implementation of [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource)
4
6
  for [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events).
5
7
 
@@ -11,11 +13,33 @@ follows:
11
13
  ```mjs
12
14
  import { EventSource } from 'undici'
13
15
 
14
- const evenSource = new EventSource('http://localhost:3000')
15
- evenSource.onmessage = (event) => {
16
+ const eventSource = new EventSource('http://localhost:3000')
17
+ eventSource.onmessage = (event) => {
16
18
  console.log(event.data)
17
19
  }
18
20
  ```
19
21
 
22
+ ## Using a custom Dispatcher
23
+
24
+ undici allows you to set your own Dispatcher in the EventSource constructor.
25
+
26
+ An example which allows you to modify the request headers is:
27
+
28
+ ```mjs
29
+ import { EventSource, Agent } from 'undici'
30
+
31
+ class CustomHeaderAgent extends Agent {
32
+ dispatch (opts) {
33
+ opts.headers['x-custom-header'] = 'hello world'
34
+ return super.dispatch(...arguments)
35
+ }
36
+ }
37
+
38
+ const eventSource = new EventSource('http://localhost:3000', {
39
+ dispatcher: new CustomHeaderAgent()
40
+ })
41
+
42
+ ```
43
+
20
44
  More information about the EventSource API can be found on
21
- [MDN](https://developer.mozilla.org/en-US/docs/Web/API/EventSource).
45
+ [MDN](https://developer.mozilla.org/en-US/docs/Web/API/EventSource).
@@ -4,12 +4,6 @@ Undici exposes a fetch() method starts the process of fetching a resource from t
4
4
 
5
5
  Documentation and examples can be found on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/fetch).
6
6
 
7
- ## File
8
-
9
- This API is implemented as per the standard, you can find documentation on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/File)
10
-
11
- In Node versions v18.13.0 and above and v19.2.0 and above, undici will default to using Node's [File](https://nodejs.org/api/buffer.html#class-file) class. In versions where it's not available, it will default to the undici one.
12
-
13
7
  ## FormData
14
8
 
15
9
  This API is implemented as per the standard, you can find documentation on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/FormData).
package/index.js CHANGED
@@ -6,6 +6,7 @@ const Pool = require('./lib/dispatcher/pool')
6
6
  const BalancedPool = require('./lib/dispatcher/balanced-pool')
7
7
  const Agent = require('./lib/dispatcher/agent')
8
8
  const ProxyAgent = require('./lib/dispatcher/proxy-agent')
9
+ const EnvHttpProxyAgent = require('./lib/dispatcher/env-http-proxy-agent')
9
10
  const RetryAgent = require('./lib/dispatcher/retry-agent')
10
11
  const errors = require('./lib/core/errors')
11
12
  const util = require('./lib/core/util')
@@ -30,6 +31,7 @@ module.exports.Pool = Pool
30
31
  module.exports.BalancedPool = BalancedPool
31
32
  module.exports.Agent = Agent
32
33
  module.exports.ProxyAgent = ProxyAgent
34
+ module.exports.EnvHttpProxyAgent = EnvHttpProxyAgent
33
35
  module.exports.RetryAgent = RetryAgent
34
36
  module.exports.RetryHandler = RetryHandler
35
37
 
@@ -116,7 +118,7 @@ module.exports.Headers = require('./lib/web/fetch/headers').Headers
116
118
  module.exports.Response = require('./lib/web/fetch/response').Response
117
119
  module.exports.Request = require('./lib/web/fetch/request').Request
118
120
  module.exports.FormData = require('./lib/web/fetch/formdata').FormData
119
- module.exports.File = require('./lib/web/fetch/file').File
121
+ module.exports.File = globalThis.File ?? require('node:buffer').File
120
122
  module.exports.FileReader = require('./lib/web/fileapi/filereader').FileReader
121
123
 
122
124
  const { setGlobalOrigin, getGlobalOrigin } = require('./lib/web/fetch/global')
package/lib/api/util.js CHANGED
@@ -12,18 +12,25 @@ async function getResolveErrorBodyCallback ({ callback, body, contentType, statu
12
12
  let chunks = []
13
13
  let length = 0
14
14
 
15
- for await (const chunk of body) {
16
- chunks.push(chunk)
17
- length += chunk.length
18
- if (length > CHUNK_LIMIT) {
19
- chunks = null
20
- break
15
+ try {
16
+ for await (const chunk of body) {
17
+ chunks.push(chunk)
18
+ length += chunk.length
19
+ if (length > CHUNK_LIMIT) {
20
+ chunks = []
21
+ length = 0
22
+ break
23
+ }
21
24
  }
25
+ } catch {
26
+ chunks = []
27
+ length = 0
28
+ // Do nothing....
22
29
  }
23
30
 
24
31
  const message = `Response status code ${statusCode}${statusMessage ? `: ${statusMessage}` : ''}`
25
32
 
26
- if (statusCode === 204 || !contentType || !chunks) {
33
+ if (statusCode === 204 || !contentType || !length) {
27
34
  queueMicrotask(() => callback(new ResponseStatusCodeError(message, statusCode, headers)))
28
35
  return
29
36
  }
@@ -7,7 +7,7 @@ const {
7
7
  const assert = require('node:assert')
8
8
  const {
9
9
  isValidHTTPToken,
10
- isValidHeaderChar,
10
+ isValidHeaderValue,
11
11
  isStream,
12
12
  destroy,
13
13
  isBuffer,
@@ -336,7 +336,7 @@ function processHeader (request, key, val) {
336
336
  const arr = []
337
337
  for (let i = 0; i < val.length; i++) {
338
338
  if (typeof val[i] === 'string') {
339
- if (!isValidHeaderChar(val[i])) {
339
+ if (!isValidHeaderValue(val[i])) {
340
340
  throw new InvalidArgumentError(`invalid ${key} header`)
341
341
  }
342
342
  arr.push(val[i])
@@ -350,13 +350,11 @@ function processHeader (request, key, val) {
350
350
  }
351
351
  val = arr
352
352
  } else if (typeof val === 'string') {
353
- if (!isValidHeaderChar(val)) {
353
+ if (!isValidHeaderValue(val)) {
354
354
  throw new InvalidArgumentError(`invalid ${key} header`)
355
355
  }
356
356
  } else if (val === null) {
357
357
  val = ''
358
- } else if (typeof val === 'object') {
359
- throw new InvalidArgumentError(`invalid ${key} header`)
360
358
  } else {
361
359
  val = `${val}`
362
360
  }
@@ -60,5 +60,8 @@ module.exports = {
60
60
  kConstruct: Symbol('constructable'),
61
61
  kListeners: Symbol('listeners'),
62
62
  kHTTPContext: Symbol('http context'),
63
- kMaxConcurrentStreams: Symbol('max concurrent streams')
63
+ kMaxConcurrentStreams: Symbol('max concurrent streams'),
64
+ kNoProxyAgent: Symbol('no proxy agent'),
65
+ kHttpProxyAgent: Symbol('http proxy agent'),
66
+ kHttpsProxyAgent: Symbol('https proxy agent')
64
67
  }
package/lib/core/util.js CHANGED
@@ -52,11 +52,37 @@ function buildURL (url, queryParams) {
52
52
  return url
53
53
  }
54
54
 
55
+ function isValidPort (port) {
56
+ const value = parseInt(port, 10)
57
+ return (
58
+ value === Number(port) &&
59
+ value >= 0 &&
60
+ value <= 65535
61
+ )
62
+ }
63
+
64
+ function isHttpOrHttpsPrefixed (value) {
65
+ return (
66
+ value != null &&
67
+ value[0] === 'h' &&
68
+ value[1] === 't' &&
69
+ value[2] === 't' &&
70
+ value[3] === 'p' &&
71
+ (
72
+ value[4] === ':' ||
73
+ (
74
+ value[4] === 's' &&
75
+ value[5] === ':'
76
+ )
77
+ )
78
+ )
79
+ }
80
+
55
81
  function parseURL (url) {
56
82
  if (typeof url === 'string') {
57
83
  url = new URL(url)
58
84
 
59
- if (!/^https?:/.test(url.origin || url.protocol)) {
85
+ if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) {
60
86
  throw new InvalidArgumentError('Invalid URL protocol: the URL must start with `http:` or `https:`.')
61
87
  }
62
88
 
@@ -67,12 +93,8 @@ function parseURL (url) {
67
93
  throw new InvalidArgumentError('Invalid URL: The URL argument must be a non-null object.')
68
94
  }
69
95
 
70
- if (!/^https?:/.test(url.origin || url.protocol)) {
71
- throw new InvalidArgumentError('Invalid URL protocol: the URL must start with `http:` or `https:`.')
72
- }
73
-
74
96
  if (!(url instanceof URL)) {
75
- if (url.port != null && url.port !== '' && !Number.isFinite(parseInt(url.port))) {
97
+ if (url.port != null && url.port !== '' && isValidPort(url.port) === false) {
76
98
  throw new InvalidArgumentError('Invalid URL: port must be a valid integer or a string representation of an integer.')
77
99
  }
78
100
 
@@ -92,28 +114,36 @@ function parseURL (url) {
92
114
  throw new InvalidArgumentError('Invalid URL origin: the origin must be a string or null/undefined.')
93
115
  }
94
116
 
117
+ if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) {
118
+ throw new InvalidArgumentError('Invalid URL protocol: the URL must start with `http:` or `https:`.')
119
+ }
120
+
95
121
  const port = url.port != null
96
122
  ? url.port
97
123
  : (url.protocol === 'https:' ? 443 : 80)
98
124
  let origin = url.origin != null
99
125
  ? url.origin
100
- : `${url.protocol}//${url.hostname}:${port}`
126
+ : `${url.protocol || ''}//${url.hostname || ''}:${port}`
101
127
  let path = url.path != null
102
128
  ? url.path
103
129
  : `${url.pathname || ''}${url.search || ''}`
104
130
 
105
- if (origin.endsWith('/')) {
106
- origin = origin.substring(0, origin.length - 1)
131
+ if (origin[origin.length - 1] === '/') {
132
+ origin = origin.slice(0, origin.length - 1)
107
133
  }
108
134
 
109
- if (path && !path.startsWith('/')) {
135
+ if (path && path[0] !== '/') {
110
136
  path = `/${path}`
111
137
  }
112
138
  // new URL(path, origin) is unsafe when `path` contains an absolute URL
113
139
  // From https://developer.mozilla.org/en-US/docs/Web/API/URL/URL:
114
140
  // If first parameter is a relative URL, second param is required, and will be used as the base URL.
115
141
  // If first parameter is an absolute URL, a given second param will be ignored.
116
- url = new URL(origin + path)
142
+ return new URL(`${origin}${path}`)
143
+ }
144
+
145
+ if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) {
146
+ throw new InvalidArgumentError('Invalid URL protocol: the URL must start with `http:` or `https:`.')
117
147
  }
118
148
 
119
149
  return url
@@ -193,11 +223,6 @@ function isDestroyed (body) {
193
223
  return body && !!(body.destroyed || body[kDestroyed] || (stream.isDestroyed?.(body)))
194
224
  }
195
225
 
196
- function isReadableAborted (stream) {
197
- const state = stream?._readableState
198
- return isDestroyed(stream) && state && !state.endEmitted
199
- }
200
-
201
226
  function destroy (stream, err) {
202
227
  if (stream == null || !isStream(stream) || isDestroyed(stream)) {
203
228
  return
@@ -522,7 +547,7 @@ const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/
522
547
  /**
523
548
  * @param {string} characters
524
549
  */
525
- function isValidHeaderChar (characters) {
550
+ function isValidHeaderValue (characters) {
526
551
  return !headerCharRegex.test(characters)
527
552
  }
528
553
 
@@ -575,7 +600,6 @@ module.exports = {
575
600
  isReadable,
576
601
  toUSVString,
577
602
  isUSVString,
578
- isReadableAborted,
579
603
  isBlobLike,
580
604
  parseOrigin,
581
605
  parseURL,
@@ -603,11 +627,12 @@ module.exports = {
603
627
  buildURL,
604
628
  addAbortListener,
605
629
  isValidHTTPToken,
606
- isValidHeaderChar,
630
+ isValidHeaderValue,
607
631
  isTokenCharCode,
608
632
  parseRangeHeader,
633
+ isValidPort,
634
+ isHttpOrHttpsPrefixed,
609
635
  nodeMajor,
610
636
  nodeMinor,
611
- nodeHasAutoSelectFamily: nodeMajor > 18 || (nodeMajor === 18 && nodeMinor >= 13),
612
637
  safeHTTPMethods: ['GET', 'HEAD', 'OPTIONS', 'TRACE']
613
638
  }
@@ -208,10 +208,9 @@ function onHttp2SessionEnd () {
208
208
  * This is the root cause of #3011
209
209
  * We need to handle GOAWAY frames properly, and trigger the session close
210
210
  * along with the socket right away
211
- * Find a way to trigger the close cycle from here on.
212
211
  */
213
212
  function onHTTP2GoAway (code) {
214
- const err = new InformationalError(`HTTP/2: "GOAWAY" frame received with code ${code}`)
213
+ const err = new RequestAbortedError(`HTTP/2: "GOAWAY" frame received with code ${code}`)
215
214
 
216
215
  // We need to trigger the close cycle right away
217
216
  // We need to destroy the session and the socket
@@ -220,8 +219,7 @@ function onHTTP2GoAway (code) {
220
219
  this[kClient][kOnError](err)
221
220
 
222
221
  this.unref()
223
- // We send the GOAWAY frame response as no error
224
- this.destroy()
222
+
225
223
  util.destroy(this[kSocket], err)
226
224
  }
227
225
 
@@ -203,7 +203,7 @@ class Client extends DispatcherBase {
203
203
  allowH2,
204
204
  socketPath,
205
205
  timeout: connectTimeout,
206
- ...(util.nodeHasAutoSelectFamily && autoSelectFamily ? { autoSelectFamily, autoSelectFamilyAttemptTimeout } : undefined),
206
+ ...(autoSelectFamily ? { autoSelectFamily, autoSelectFamilyAttemptTimeout } : undefined),
207
207
  ...connect
208
208
  })
209
209
  }
@@ -226,7 +226,7 @@ class Client extends DispatcherBase {
226
226
  this[kMaxHeadersSize] = maxHeaderSize || http.maxHeaderSize
227
227
  this[kKeepAliveDefaultTimeout] = keepAliveTimeout == null ? 4e3 : keepAliveTimeout
228
228
  this[kKeepAliveMaxTimeout] = keepAliveMaxTimeout == null ? 600e3 : keepAliveMaxTimeout
229
- this[kKeepAliveTimeoutThreshold] = keepAliveTimeoutThreshold == null ? 1e3 : keepAliveTimeoutThreshold
229
+ this[kKeepAliveTimeoutThreshold] = keepAliveTimeoutThreshold == null ? 2e3 : keepAliveTimeoutThreshold
230
230
  this[kKeepAliveTimeoutValue] = this[kKeepAliveDefaultTimeout]
231
231
  this[kServerName] = null
232
232
  this[kLocalAddress] = localAddress != null ? localAddress : null
@@ -376,6 +376,7 @@ function onError (client, err) {
376
376
  assert(client[kPendingIdx] === client[kRunningIdx])
377
377
 
378
378
  const requests = client[kQueue].splice(client[kRunningIdx])
379
+
379
380
  for (let i = 0; i < requests.length; i++) {
380
381
  const request = requests[i]
381
382
  util.errorRequest(client, request, err)
@@ -6,10 +6,8 @@ const {
6
6
  ClientClosedError,
7
7
  InvalidArgumentError
8
8
  } = require('../core/errors')
9
- const { kDestroy, kClose, kDispatch, kInterceptors } = require('../core/symbols')
9
+ const { kDestroy, kClose, kClosed, kDestroyed, kDispatch, kInterceptors } = require('../core/symbols')
10
10
 
11
- const kDestroyed = Symbol('destroyed')
12
- const kClosed = Symbol('closed')
13
11
  const kOnDestroyed = Symbol('onDestroyed')
14
12
  const kOnClosed = Symbol('onClosed')
15
13
  const kInterceptedDispatch = Symbol('Intercepted Dispatch')