undici 6.10.1 → 6.11.0
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.
- package/README.md +6 -2
- package/docs/docs/api/DiagnosticsChannel.md +0 -2
- package/lib/core/connect.js +1 -1
- package/lib/core/request.js +29 -10
- package/lib/core/util.js +0 -3
- package/lib/dispatcher/client-h1.js +1 -1
- package/lib/dispatcher/client-h2.js +33 -7
- package/lib/handler/retry-handler.js +2 -4
- package/lib/mock/pending-interceptors-formatter.js +4 -1
- package/lib/web/cookies/index.js +1 -1
- package/lib/web/eventsource/eventsource.js +11 -0
- package/lib/web/fetch/data-url.js +2 -2
- package/lib/web/fetch/headers.js +1 -1
- package/lib/web/fetch/index.js +0 -23
- package/lib/web/fetch/util.js +36 -0
- package/lib/web/websocket/receiver.js +2 -3
- package/lib/web/websocket/util.js +1 -3
- package/package.json +9 -5
- package/types/diagnostics-channel.d.ts +1 -2
- package/types/dispatcher.d.ts +2 -2
package/README.md
CHANGED
|
@@ -7,8 +7,12 @@ An HTTP/1.1 client, written from scratch for Node.js.
|
|
|
7
7
|
> Undici means eleven in Italian. 1.1 -> 11 -> Eleven -> Undici.
|
|
8
8
|
It is also a Stranger Things reference.
|
|
9
9
|
|
|
10
|
+
## How to get involved
|
|
11
|
+
|
|
10
12
|
Have a question about using Undici? Open a [Q&A Discussion](https://github.com/nodejs/undici/discussions/new) or join our official OpenJS [Slack](https://openjs-foundation.slack.com/archives/C01QF9Q31QD) channel.
|
|
11
13
|
|
|
14
|
+
Looking to contribute? Start by reading the [contributing guide](./CONTRIBUTING.md)
|
|
15
|
+
|
|
12
16
|
## Install
|
|
13
17
|
|
|
14
18
|
```
|
|
@@ -17,7 +21,7 @@ npm i undici
|
|
|
17
21
|
|
|
18
22
|
## Benchmarks
|
|
19
23
|
|
|
20
|
-
The benchmark is a simple getting data [example](benchmarks/benchmark.js) using a
|
|
24
|
+
The benchmark is a simple getting data [example](https://github.com/nodejs/undici/blob/main/benchmarks/benchmark.js) using a
|
|
21
25
|
50 TCP connections with a pipelining depth of 10 running on Node 20.10.0.
|
|
22
26
|
|
|
23
27
|
| _Tests_ | _Samples_ | _Result_ | _Tolerance_ | _Difference with slowest_ |
|
|
@@ -35,7 +39,7 @@ The benchmark is a simple getting data [example](benchmarks/benchmark.js) using
|
|
|
35
39
|
| undici - stream | 15 | 20317.29 req/sec | ± 2.13 % | + 448.46 % |
|
|
36
40
|
| undici - dispatch | 10 | 24883.28 req/sec | ± 1.54 % | + 571.72 % |
|
|
37
41
|
|
|
38
|
-
The benchmark is a simple sending data [example](benchmarks/post-benchmark.js) using a
|
|
42
|
+
The benchmark is a simple sending data [example](https://github.com/nodejs/undici/blob/main/benchmarks/post-benchmark.js) using a
|
|
39
43
|
50 TCP connections with a pipelining depth of 10 running on Node 20.10.0.
|
|
40
44
|
|
|
41
45
|
| _Tests_ | _Samples_ | _Result_ | _Tolerance_ | _Difference with slowest_ |
|
|
@@ -20,8 +20,6 @@ diagnosticsChannel.channel('undici:request:create').subscribe(({ request }) => {
|
|
|
20
20
|
console.log('method', request.method)
|
|
21
21
|
console.log('path', request.path)
|
|
22
22
|
console.log('headers') // array of strings, e.g: ['foo', 'bar']
|
|
23
|
-
request.addHeader('hello', 'world')
|
|
24
|
-
console.log('headers', request.headers) // e.g. ['foo', 'bar', 'hello', 'world']
|
|
25
23
|
})
|
|
26
24
|
```
|
|
27
25
|
|
package/lib/core/connect.js
CHANGED
|
@@ -185,7 +185,7 @@ function setupTimeout (onConnectTimeout, timeout) {
|
|
|
185
185
|
function onConnectTimeout (socket) {
|
|
186
186
|
let message = 'Connect Timeout Error'
|
|
187
187
|
if (Array.isArray(socket.autoSelectFamilyAttemptedAddresses)) {
|
|
188
|
-
message
|
|
188
|
+
message += ` (attempted addresses: ${socket.autoSelectFamilyAttemptedAddresses.join(', ')})`
|
|
189
189
|
}
|
|
190
190
|
util.destroy(socket, new ConnectTimeoutError(message))
|
|
191
191
|
}
|
package/lib/core/request.js
CHANGED
|
@@ -91,6 +91,8 @@ class Request {
|
|
|
91
91
|
|
|
92
92
|
this.abort = null
|
|
93
93
|
|
|
94
|
+
this.publicInterface = null
|
|
95
|
+
|
|
94
96
|
if (body == null) {
|
|
95
97
|
this.body = null
|
|
96
98
|
} else if (isStream(body)) {
|
|
@@ -187,10 +189,32 @@ class Request {
|
|
|
187
189
|
this[kHandler] = handler
|
|
188
190
|
|
|
189
191
|
if (channels.create.hasSubscribers) {
|
|
190
|
-
channels.create.publish({ request: this })
|
|
192
|
+
channels.create.publish({ request: this.getPublicInterface() })
|
|
191
193
|
}
|
|
192
194
|
}
|
|
193
195
|
|
|
196
|
+
getPublicInterface () {
|
|
197
|
+
const self = this
|
|
198
|
+
this.publicInterface ??= {
|
|
199
|
+
get origin () {
|
|
200
|
+
return self.origin
|
|
201
|
+
},
|
|
202
|
+
get method () {
|
|
203
|
+
return self.method
|
|
204
|
+
},
|
|
205
|
+
get path () {
|
|
206
|
+
return self.path
|
|
207
|
+
},
|
|
208
|
+
get headers () {
|
|
209
|
+
return self.headers
|
|
210
|
+
},
|
|
211
|
+
get completed () {
|
|
212
|
+
return self.completed
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return this.publicInterface
|
|
216
|
+
}
|
|
217
|
+
|
|
194
218
|
onBodySent (chunk) {
|
|
195
219
|
if (this[kHandler].onBodySent) {
|
|
196
220
|
try {
|
|
@@ -203,7 +227,7 @@ class Request {
|
|
|
203
227
|
|
|
204
228
|
onRequestSent () {
|
|
205
229
|
if (channels.bodySent.hasSubscribers) {
|
|
206
|
-
channels.bodySent.publish({ request: this })
|
|
230
|
+
channels.bodySent.publish({ request: this.getPublicInterface() })
|
|
207
231
|
}
|
|
208
232
|
|
|
209
233
|
if (this[kHandler].onRequestSent) {
|
|
@@ -236,7 +260,7 @@ class Request {
|
|
|
236
260
|
assert(!this.completed)
|
|
237
261
|
|
|
238
262
|
if (channels.headers.hasSubscribers) {
|
|
239
|
-
channels.headers.publish({ request: this, response: { statusCode, headers, statusText } })
|
|
263
|
+
channels.headers.publish({ request: this.getPublicInterface(), response: { statusCode, headers, statusText } })
|
|
240
264
|
}
|
|
241
265
|
|
|
242
266
|
try {
|
|
@@ -272,7 +296,7 @@ class Request {
|
|
|
272
296
|
|
|
273
297
|
this.completed = true
|
|
274
298
|
if (channels.trailers.hasSubscribers) {
|
|
275
|
-
channels.trailers.publish({ request: this, trailers })
|
|
299
|
+
channels.trailers.publish({ request: this.getPublicInterface(), trailers })
|
|
276
300
|
}
|
|
277
301
|
|
|
278
302
|
try {
|
|
@@ -287,7 +311,7 @@ class Request {
|
|
|
287
311
|
this.onFinally()
|
|
288
312
|
|
|
289
313
|
if (channels.error.hasSubscribers) {
|
|
290
|
-
channels.error.publish({ request: this, error })
|
|
314
|
+
channels.error.publish({ request: this.getPublicInterface(), error })
|
|
291
315
|
}
|
|
292
316
|
|
|
293
317
|
if (this.aborted) {
|
|
@@ -309,11 +333,6 @@ class Request {
|
|
|
309
333
|
this.endHandler = null
|
|
310
334
|
}
|
|
311
335
|
}
|
|
312
|
-
|
|
313
|
-
addHeader (key, value) {
|
|
314
|
-
processHeader(this, key, value)
|
|
315
|
-
return this
|
|
316
|
-
}
|
|
317
336
|
}
|
|
318
337
|
|
|
319
338
|
function processHeader (request, key, val) {
|
package/lib/core/util.js
CHANGED
|
@@ -246,9 +246,6 @@ function bufferToLowerCasedHeaderName (value) {
|
|
|
246
246
|
* @returns {Record<string, string | string[]>}
|
|
247
247
|
*/
|
|
248
248
|
function parseHeaders (headers, obj) {
|
|
249
|
-
// For H2 support
|
|
250
|
-
if (!Array.isArray(headers)) return headers
|
|
251
|
-
|
|
252
249
|
if (obj === undefined) obj = {}
|
|
253
250
|
for (let i = 0; i < headers.length; i += 2) {
|
|
254
251
|
const key = headerNameToString(headers[i])
|
|
@@ -993,7 +993,7 @@ function writeH1 (client, request) {
|
|
|
993
993
|
}
|
|
994
994
|
|
|
995
995
|
if (channels.sendHeaders.hasSubscribers) {
|
|
996
|
-
channels.sendHeaders.publish({ request, headers: header, socket })
|
|
996
|
+
channels.sendHeaders.publish({ request: request.getPublicInterface(), headers: header, socket })
|
|
997
997
|
}
|
|
998
998
|
|
|
999
999
|
/* istanbul ignore else: assertion */
|
|
@@ -54,6 +54,20 @@ const {
|
|
|
54
54
|
}
|
|
55
55
|
} = http2
|
|
56
56
|
|
|
57
|
+
function parseH2Headers (headers) {
|
|
58
|
+
// set-cookie is always an array. Duplicates are added to the array.
|
|
59
|
+
// For duplicate cookie headers, the values are joined together with '; '.
|
|
60
|
+
headers = Object.entries(headers).flat(2)
|
|
61
|
+
|
|
62
|
+
const result = []
|
|
63
|
+
|
|
64
|
+
for (const header of headers) {
|
|
65
|
+
result.push(Buffer.from(header))
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return result
|
|
69
|
+
}
|
|
70
|
+
|
|
57
71
|
async function connectH2 (client, socket) {
|
|
58
72
|
client[kSocket] = socket
|
|
59
73
|
|
|
@@ -391,9 +405,27 @@ function writeH2 (client, request) {
|
|
|
391
405
|
const { [HTTP2_HEADER_STATUS]: statusCode, ...realHeaders } = headers
|
|
392
406
|
request.onResponseStarted()
|
|
393
407
|
|
|
394
|
-
|
|
408
|
+
// Due to the stream nature, it is possible we face a race condition
|
|
409
|
+
// where the stream has been assigned, but the request has been aborted
|
|
410
|
+
// the request remains in-flight and headers hasn't been received yet
|
|
411
|
+
// for those scenarios, best effort is to destroy the stream immediately
|
|
412
|
+
// as there's no value to keep it open.
|
|
413
|
+
if (request.aborted || request.completed) {
|
|
414
|
+
const err = new RequestAbortedError()
|
|
415
|
+
errorRequest(client, request, err)
|
|
416
|
+
util.destroy(stream, err)
|
|
417
|
+
return
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if (request.onHeaders(Number(statusCode), parseH2Headers(realHeaders), stream.resume.bind(stream), '') === false) {
|
|
395
421
|
stream.pause()
|
|
396
422
|
}
|
|
423
|
+
|
|
424
|
+
stream.on('data', (chunk) => {
|
|
425
|
+
if (request.onData(chunk) === false) {
|
|
426
|
+
stream.pause()
|
|
427
|
+
}
|
|
428
|
+
})
|
|
397
429
|
})
|
|
398
430
|
|
|
399
431
|
stream.once('end', () => {
|
|
@@ -418,12 +450,6 @@ function writeH2 (client, request) {
|
|
|
418
450
|
util.destroy(stream, err)
|
|
419
451
|
})
|
|
420
452
|
|
|
421
|
-
stream.on('data', (chunk) => {
|
|
422
|
-
if (request.onData(chunk) === false) {
|
|
423
|
-
stream.pause()
|
|
424
|
-
}
|
|
425
|
-
})
|
|
426
|
-
|
|
427
453
|
stream.once('close', () => {
|
|
428
454
|
session[kOpenStreams] -= 1
|
|
429
455
|
// TODO(HTTP/2): unref only if current streams count is 0
|
|
@@ -242,14 +242,12 @@ class RetryHandler {
|
|
|
242
242
|
}
|
|
243
243
|
|
|
244
244
|
const { start, size, end = size } = range
|
|
245
|
-
|
|
246
245
|
assert(
|
|
247
|
-
start != null && Number.isFinite(start)
|
|
246
|
+
start != null && Number.isFinite(start),
|
|
248
247
|
'content-range mismatch'
|
|
249
248
|
)
|
|
250
|
-
assert(Number.isFinite(start))
|
|
251
249
|
assert(
|
|
252
|
-
end != null && Number.isFinite(end)
|
|
250
|
+
end != null && Number.isFinite(end),
|
|
253
251
|
'invalid content-length'
|
|
254
252
|
)
|
|
255
253
|
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
const { Transform } = require('node:stream')
|
|
4
4
|
const { Console } = require('node:console')
|
|
5
5
|
|
|
6
|
+
const PERSISTENT = process.versions.icu ? '✅' : 'Y '
|
|
7
|
+
const NOT_PERSISTENT = process.versions.icu ? '❌' : 'N '
|
|
8
|
+
|
|
6
9
|
/**
|
|
7
10
|
* Gets the output of `console.table(…)` as a string.
|
|
8
11
|
*/
|
|
@@ -29,7 +32,7 @@ module.exports = class PendingInterceptorsFormatter {
|
|
|
29
32
|
Origin: origin,
|
|
30
33
|
Path: path,
|
|
31
34
|
'Status code': statusCode,
|
|
32
|
-
Persistent: persist ?
|
|
35
|
+
Persistent: persist ? PERSISTENT : NOT_PERSISTENT,
|
|
33
36
|
Invocations: timesInvoked,
|
|
34
37
|
Remaining: persist ? Infinity : times - timesInvoked
|
|
35
38
|
}))
|
package/lib/web/cookies/index.js
CHANGED
|
@@ -10,6 +10,7 @@ const { parseMIMEType } = require('../fetch/data-url')
|
|
|
10
10
|
const { MessageEvent } = require('../websocket/events')
|
|
11
11
|
const { isNetworkError } = require('../fetch/response')
|
|
12
12
|
const { delay } = require('./util')
|
|
13
|
+
const { kEnumerableProperty } = require('../../core/util')
|
|
13
14
|
|
|
14
15
|
let experimentalWarned = false
|
|
15
16
|
|
|
@@ -459,6 +460,16 @@ const constantsPropertyDescriptors = {
|
|
|
459
460
|
Object.defineProperties(EventSource, constantsPropertyDescriptors)
|
|
460
461
|
Object.defineProperties(EventSource.prototype, constantsPropertyDescriptors)
|
|
461
462
|
|
|
463
|
+
Object.defineProperties(EventSource.prototype, {
|
|
464
|
+
close: kEnumerableProperty,
|
|
465
|
+
onerror: kEnumerableProperty,
|
|
466
|
+
onmessage: kEnumerableProperty,
|
|
467
|
+
onopen: kEnumerableProperty,
|
|
468
|
+
readyState: kEnumerableProperty,
|
|
469
|
+
url: kEnumerableProperty,
|
|
470
|
+
withCredentials: kEnumerableProperty
|
|
471
|
+
})
|
|
472
|
+
|
|
462
473
|
webidl.converters.EventSourceInitDict = webidl.dictionaryConverter([
|
|
463
474
|
{ key: 'withCredentials', converter: webidl.converters.boolean, defaultValue: false }
|
|
464
475
|
])
|
|
@@ -8,12 +8,12 @@ const encoder = new TextEncoder()
|
|
|
8
8
|
* @see https://mimesniff.spec.whatwg.org/#http-token-code-point
|
|
9
9
|
*/
|
|
10
10
|
const HTTP_TOKEN_CODEPOINTS = /^[!#$%&'*+-.^_|~A-Za-z0-9]+$/
|
|
11
|
-
const HTTP_WHITESPACE_REGEX = /[\u000A
|
|
11
|
+
const HTTP_WHITESPACE_REGEX = /[\u000A\u000D\u0009\u0020]/ // eslint-disable-line
|
|
12
12
|
const ASCII_WHITESPACE_REPLACE_REGEX = /[\u0009\u000A\u000C\u000D\u0020]/g // eslint-disable-line
|
|
13
13
|
/**
|
|
14
14
|
* @see https://mimesniff.spec.whatwg.org/#http-quoted-string-token-code-point
|
|
15
15
|
*/
|
|
16
|
-
const HTTP_QUOTED_STRING_TOKENS = /[\u0009
|
|
16
|
+
const HTTP_QUOTED_STRING_TOKENS = /[\u0009\u0020-\u007E\u0080-\u00FF]/ // eslint-disable-line
|
|
17
17
|
|
|
18
18
|
// https://fetch.spec.whatwg.org/#data-url-processor
|
|
19
19
|
/** @param {URL} dataURL */
|
package/lib/web/fetch/headers.js
CHANGED
|
@@ -12,7 +12,7 @@ const {
|
|
|
12
12
|
} = require('./util')
|
|
13
13
|
const { webidl } = require('./webidl')
|
|
14
14
|
const assert = require('node:assert')
|
|
15
|
-
const util = require('util')
|
|
15
|
+
const util = require('node:util')
|
|
16
16
|
|
|
17
17
|
const kHeadersMap = Symbol('headers map')
|
|
18
18
|
const kHeadersSortedMap = Symbol('headers map sorted')
|
package/lib/web/fetch/index.js
CHANGED
|
@@ -2141,29 +2141,6 @@ async function httpNetworkFetch (
|
|
|
2141
2141
|
codings = contentEncoding.toLowerCase().split(',').map((x) => x.trim())
|
|
2142
2142
|
}
|
|
2143
2143
|
location = headersList.get('location', true)
|
|
2144
|
-
} else {
|
|
2145
|
-
const keys = Object.keys(rawHeaders)
|
|
2146
|
-
for (let i = 0; i < keys.length; ++i) {
|
|
2147
|
-
// The header names are already in lowercase.
|
|
2148
|
-
const key = keys[i]
|
|
2149
|
-
const value = rawHeaders[key]
|
|
2150
|
-
if (key === 'set-cookie') {
|
|
2151
|
-
for (let j = 0; j < value.length; ++j) {
|
|
2152
|
-
headersList.append(key, value[j], true)
|
|
2153
|
-
}
|
|
2154
|
-
} else {
|
|
2155
|
-
headersList.append(key, value, true)
|
|
2156
|
-
}
|
|
2157
|
-
}
|
|
2158
|
-
// For H2, The header names are already in lowercase,
|
|
2159
|
-
// so we can avoid the `HeadersList#get` call here.
|
|
2160
|
-
const contentEncoding = rawHeaders['content-encoding']
|
|
2161
|
-
if (contentEncoding) {
|
|
2162
|
-
// https://www.rfc-editor.org/rfc/rfc7231#section-3.1.2.1
|
|
2163
|
-
// "All content-coding values are case-insensitive..."
|
|
2164
|
-
codings = contentEncoding.toLowerCase().split(',').map((x) => x.trim()).reverse()
|
|
2165
|
-
}
|
|
2166
|
-
location = rawHeaders.location
|
|
2167
2144
|
}
|
|
2168
2145
|
|
|
2169
2146
|
this.body = new Readable({ read: resume })
|
package/lib/web/fetch/util.js
CHANGED
|
@@ -44,6 +44,12 @@ function responseLocationURL (response, requestFragment) {
|
|
|
44
44
|
// 3. If location is a header value, then set location to the result of
|
|
45
45
|
// parsing location with response’s URL.
|
|
46
46
|
if (location !== null && isValidHeaderValue(location)) {
|
|
47
|
+
if (!isValidEncodedURL(location)) {
|
|
48
|
+
// Some websites respond location header in UTF-8 form without encoding them as ASCII
|
|
49
|
+
// and major browsers redirect them to correctly UTF-8 encoded addresses.
|
|
50
|
+
// Here, we handle that behavior in the same way.
|
|
51
|
+
location = normalizeBinaryStringToUtf8(location)
|
|
52
|
+
}
|
|
47
53
|
location = new URL(location, responseURL(response))
|
|
48
54
|
}
|
|
49
55
|
|
|
@@ -57,6 +63,36 @@ function responseLocationURL (response, requestFragment) {
|
|
|
57
63
|
return location
|
|
58
64
|
}
|
|
59
65
|
|
|
66
|
+
/**
|
|
67
|
+
* @see https://www.rfc-editor.org/rfc/rfc1738#section-2.2
|
|
68
|
+
* @param {string} url
|
|
69
|
+
* @returns {boolean}
|
|
70
|
+
*/
|
|
71
|
+
function isValidEncodedURL (url) {
|
|
72
|
+
for (const c of url) {
|
|
73
|
+
const code = c.charCodeAt(0)
|
|
74
|
+
// Not used in US-ASCII
|
|
75
|
+
if (code >= 0x80) {
|
|
76
|
+
return false
|
|
77
|
+
}
|
|
78
|
+
// Control characters
|
|
79
|
+
if ((code >= 0x00 && code <= 0x1F) || code === 0x7F) {
|
|
80
|
+
return false
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return true
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* If string contains non-ASCII characters, assumes it's UTF-8 encoded and decodes it.
|
|
88
|
+
* Since UTF-8 is a superset of ASCII, this will work for ASCII strings as well.
|
|
89
|
+
* @param {string} value
|
|
90
|
+
* @returns {string}
|
|
91
|
+
*/
|
|
92
|
+
function normalizeBinaryStringToUtf8 (value) {
|
|
93
|
+
return Buffer.from(value, 'binary').toString('utf8')
|
|
94
|
+
}
|
|
95
|
+
|
|
60
96
|
/** @returns {URL} */
|
|
61
97
|
function requestCurrentURL (request) {
|
|
62
98
|
return request.urlList[request.urlList.length - 1]
|
|
@@ -12,8 +12,6 @@ const { WebsocketFrameSend } = require('./frame')
|
|
|
12
12
|
// Copyright (c) 2013 Arnout Kazemier and contributors
|
|
13
13
|
// Copyright (c) 2016 Luigi Pinca and contributors
|
|
14
14
|
|
|
15
|
-
const textDecoder = new TextDecoder('utf-8', { fatal: true })
|
|
16
|
-
|
|
17
15
|
class ByteParser extends Writable {
|
|
18
16
|
#buffers = []
|
|
19
17
|
#byteOffset = 0
|
|
@@ -316,7 +314,8 @@ class ByteParser extends Writable {
|
|
|
316
314
|
}
|
|
317
315
|
|
|
318
316
|
try {
|
|
319
|
-
|
|
317
|
+
// TODO: optimize this
|
|
318
|
+
reason = new TextDecoder('utf-8', { fatal: true }).decode(reason)
|
|
320
319
|
} catch {
|
|
321
320
|
return null
|
|
322
321
|
}
|
|
@@ -68,8 +68,6 @@ function fireEvent (e, target, eventConstructor = Event, eventInitDict = {}) {
|
|
|
68
68
|
target.dispatchEvent(event)
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
const textDecoder = new TextDecoder('utf-8', { fatal: true })
|
|
72
|
-
|
|
73
71
|
/**
|
|
74
72
|
* @see https://websockets.spec.whatwg.org/#feedback-from-the-protocol
|
|
75
73
|
* @param {import('./websocket').WebSocket} ws
|
|
@@ -89,7 +87,7 @@ function websocketMessageReceived (ws, type, data) {
|
|
|
89
87
|
// -> type indicates that the data is Text
|
|
90
88
|
// a new DOMString containing data
|
|
91
89
|
try {
|
|
92
|
-
dataForEvent =
|
|
90
|
+
dataForEvent = new TextDecoder('utf-8', { fatal: true }).decode(data)
|
|
93
91
|
} catch {
|
|
94
92
|
failWebsocketConnection(ws, 'Received invalid UTF-8 in text frame.')
|
|
95
93
|
return
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "undici",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.11.0",
|
|
4
4
|
"description": "An HTTP/1.1 client, written from scratch for Node.js",
|
|
5
5
|
"homepage": "https://undici.nodejs.org",
|
|
6
6
|
"bugs": {
|
|
@@ -69,10 +69,13 @@
|
|
|
69
69
|
"lint:fix": "standard --fix | snazzy",
|
|
70
70
|
"test": "npm run test:javascript && cross-env NODE_V8_COVERAGE= npm run test:typescript",
|
|
71
71
|
"test:javascript": "node scripts/generate-pem && npm run test:unit && npm run test:node-fetch && npm run test:fetch && npm run test:cookies && npm run test:eventsource && npm run test:wpt && npm run test:websocket && npm run test:node-test && npm run test:jest",
|
|
72
|
+
"test:javascript:withoutintl": "node scripts/generate-pem && npm run test:unit && npm run test:node-fetch && npm run test:fetch:nobuild && npm run test:cookies && npm run test:eventsource:nobuild && npm run test:wpt:withoutintl && npm run test:node-test",
|
|
72
73
|
"test:cookies": "borp -p \"test/cookie/*.js\"",
|
|
73
74
|
"test:node-fetch": "borp -p \"test/node-fetch/**/*.js\"",
|
|
74
|
-
"test:eventsource": "npm run build:node &&
|
|
75
|
-
"test:
|
|
75
|
+
"test:eventsource": "npm run build:node && npm run test:eventsource:nobuild",
|
|
76
|
+
"test:eventsource:nobuild": "borp --expose-gc -p \"test/eventsource/*.js\"",
|
|
77
|
+
"test:fetch": "npm run build:node && npm run test:fetch:nobuild",
|
|
78
|
+
"test:fetch:nobuild": "borp --expose-gc -p \"test/fetch/*.js\" && borp -p \"test/webidl/*.js\" && borp -p \"test/busboy/*.js\"",
|
|
76
79
|
"test:jest": "cross-env NODE_V8_COVERAGE= jest",
|
|
77
80
|
"test:unit": "borp --expose-gc -p \"test/*.js\"",
|
|
78
81
|
"test:node-test": "borp -p \"test/node-test/**/*.js\"",
|
|
@@ -81,6 +84,7 @@
|
|
|
81
84
|
"test:typescript": "tsd && tsc --skipLibCheck test/imports/undici-import.ts",
|
|
82
85
|
"test:websocket": "borp -p \"test/websocket/*.js\"",
|
|
83
86
|
"test:wpt": "node test/wpt/start-fetch.mjs && node test/wpt/start-FileAPI.mjs && node test/wpt/start-mimesniff.mjs && node test/wpt/start-xhr.mjs && node test/wpt/start-websockets.mjs && node test/wpt/start-cacheStorage.mjs && node test/wpt/start-eventsource.mjs",
|
|
87
|
+
"test:wpt:withoutintl": "node test/wpt/start-fetch.mjs && node test/wpt/start-mimesniff.mjs && node test/wpt/start-xhr.mjs && node test/wpt/start-cacheStorage.mjs && node test/wpt/start-eventsource.mjs",
|
|
84
88
|
"coverage": "npm run coverage:clean && cross-env NODE_V8_COVERAGE=./coverage/tmp npm run test:javascript && npm run coverage:report",
|
|
85
89
|
"coverage:ci": "npm run coverage:clean && cross-env NODE_V8_COVERAGE=./coverage/tmp npm run test:javascript && npm run coverage:report:ci",
|
|
86
90
|
"coverage:clean": "node ./scripts/clean-coverage.js",
|
|
@@ -96,7 +100,7 @@
|
|
|
96
100
|
"@sinonjs/fake-timers": "^11.1.0",
|
|
97
101
|
"@types/node": "^18.0.3",
|
|
98
102
|
"abort-controller": "^3.0.0",
|
|
99
|
-
"borp": "^0.
|
|
103
|
+
"borp": "^0.10.0",
|
|
100
104
|
"c8": "^9.1.0",
|
|
101
105
|
"cross-env": "^7.0.3",
|
|
102
106
|
"dns-packet": "^5.4.0",
|
|
@@ -112,7 +116,7 @@
|
|
|
112
116
|
"proxy": "^2.1.1",
|
|
113
117
|
"snazzy": "^9.0.0",
|
|
114
118
|
"standard": "^17.0.0",
|
|
115
|
-
"tsd": "^0.
|
|
119
|
+
"tsd": "^0.31.0",
|
|
116
120
|
"typescript": "^5.0.2",
|
|
117
121
|
"ws": "^8.11.0"
|
|
118
122
|
},
|
package/types/dispatcher.d.ts
CHANGED
|
@@ -19,8 +19,8 @@ declare class Dispatcher extends EventEmitter {
|
|
|
19
19
|
connect(options: Dispatcher.ConnectOptions): Promise<Dispatcher.ConnectData>;
|
|
20
20
|
connect(options: Dispatcher.ConnectOptions, callback: (err: Error | null, data: Dispatcher.ConnectData) => void): void;
|
|
21
21
|
/** Compose a chain of dispatchers */
|
|
22
|
-
compose(dispatchers: Dispatcher[
|
|
23
|
-
compose(...dispatchers: Dispatcher[
|
|
22
|
+
compose(dispatchers: Dispatcher.DispatcherInterceptor[]): Dispatcher.ComposedDispatcher;
|
|
23
|
+
compose(...dispatchers: Dispatcher.DispatcherInterceptor[]): Dispatcher.ComposedDispatcher;
|
|
24
24
|
/** Performs an HTTP request. */
|
|
25
25
|
request(options: Dispatcher.RequestOptions): Promise<Dispatcher.ResponseData>;
|
|
26
26
|
request(options: Dispatcher.RequestOptions, callback: (err: Error | null, data: Dispatcher.ResponseData) => void): void;
|