undici 5.26.5 → 5.27.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.
- package/lib/client.js +16 -21
- package/lib/core/request.js +48 -1
- package/lib/core/util.js +1 -1
- package/lib/fetch/body.js +12 -9
- package/lib/fetch/constants.js +16 -1
- package/lib/fetch/file.js +2 -1
- package/lib/fetch/index.js +9 -8
- package/lib/fetch/request.js +4 -4
- package/lib/fetch/response.js +4 -3
- package/lib/fetch/util.js +4 -4
- package/lib/pool.js +1 -1
- package/package.json +2 -2
package/lib/client.js
CHANGED
|
@@ -1462,23 +1462,7 @@ function _resume (client, sync) {
|
|
|
1462
1462
|
return
|
|
1463
1463
|
}
|
|
1464
1464
|
|
|
1465
|
-
if (
|
|
1466
|
-
request.body
|
|
1467
|
-
.on('data', /* istanbul ignore next */ function () {
|
|
1468
|
-
/* istanbul ignore next */
|
|
1469
|
-
assert(false)
|
|
1470
|
-
})
|
|
1471
|
-
.on('error', function (err) {
|
|
1472
|
-
errorRequest(client, request, err)
|
|
1473
|
-
})
|
|
1474
|
-
.on('end', function () {
|
|
1475
|
-
util.destroy(this)
|
|
1476
|
-
})
|
|
1477
|
-
|
|
1478
|
-
request.body = null
|
|
1479
|
-
}
|
|
1480
|
-
|
|
1481
|
-
if (client[kRunning] > 0 &&
|
|
1465
|
+
if (client[kRunning] > 0 && util.bodyLength(request.body) !== 0 &&
|
|
1482
1466
|
(util.isStream(request.body) || util.isAsyncIterable(request.body))) {
|
|
1483
1467
|
// Request with stream or iterator body can error while other requests
|
|
1484
1468
|
// are inflight and indirectly error those as well.
|
|
@@ -1499,6 +1483,11 @@ function _resume (client, sync) {
|
|
|
1499
1483
|
}
|
|
1500
1484
|
}
|
|
1501
1485
|
|
|
1486
|
+
// https://www.rfc-editor.org/rfc/rfc7230#section-3.3.2
|
|
1487
|
+
function shouldSendContentLength (method) {
|
|
1488
|
+
return method !== 'GET' && method !== 'HEAD' && method !== 'OPTIONS' && method !== 'TRACE' && method !== 'CONNECT'
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1502
1491
|
function write (client, request) {
|
|
1503
1492
|
if (client[kHTTPConnVersion] === 'h2') {
|
|
1504
1493
|
writeH2(client, client[kHTTP2Session], request)
|
|
@@ -1527,7 +1516,9 @@ function write (client, request) {
|
|
|
1527
1516
|
body.read(0)
|
|
1528
1517
|
}
|
|
1529
1518
|
|
|
1530
|
-
|
|
1519
|
+
const bodyLength = util.bodyLength(body)
|
|
1520
|
+
|
|
1521
|
+
let contentLength = bodyLength
|
|
1531
1522
|
|
|
1532
1523
|
if (contentLength === null) {
|
|
1533
1524
|
contentLength = request.contentLength
|
|
@@ -1542,7 +1533,9 @@ function write (client, request) {
|
|
|
1542
1533
|
contentLength = null
|
|
1543
1534
|
}
|
|
1544
1535
|
|
|
1545
|
-
|
|
1536
|
+
// https://github.com/nodejs/undici/issues/2046
|
|
1537
|
+
// A user agent may send a Content-Length header with 0 value, this should be allowed.
|
|
1538
|
+
if (shouldSendContentLength(method) && contentLength > 0 && request.contentLength !== null && request.contentLength !== contentLength) {
|
|
1546
1539
|
if (client[kStrictContentLength]) {
|
|
1547
1540
|
errorRequest(client, request, new RequestContentLengthMismatchError())
|
|
1548
1541
|
return false
|
|
@@ -1623,7 +1616,7 @@ function write (client, request) {
|
|
|
1623
1616
|
}
|
|
1624
1617
|
|
|
1625
1618
|
/* istanbul ignore else: assertion */
|
|
1626
|
-
if (!body) {
|
|
1619
|
+
if (!body || bodyLength === 0) {
|
|
1627
1620
|
if (contentLength === 0) {
|
|
1628
1621
|
socket.write(`${header}content-length: 0\r\n\r\n`, 'latin1')
|
|
1629
1622
|
} else {
|
|
@@ -1763,7 +1756,9 @@ function writeH2 (client, session, request) {
|
|
|
1763
1756
|
contentLength = null
|
|
1764
1757
|
}
|
|
1765
1758
|
|
|
1766
|
-
|
|
1759
|
+
// https://github.com/nodejs/undici/issues/2046
|
|
1760
|
+
// A user agent may send a Content-Length header with 0 value, this should be allowed.
|
|
1761
|
+
if (shouldSendContentLength(method) && contentLength > 0 && request.contentLength != null && request.contentLength !== contentLength) {
|
|
1767
1762
|
if (client[kStrictContentLength]) {
|
|
1768
1763
|
errorRequest(client, request, new RequestContentLengthMismatchError())
|
|
1769
1764
|
return false
|
package/lib/core/request.js
CHANGED
|
@@ -112,10 +112,28 @@ class Request {
|
|
|
112
112
|
|
|
113
113
|
this.method = method
|
|
114
114
|
|
|
115
|
+
this.abort = null
|
|
116
|
+
|
|
115
117
|
if (body == null) {
|
|
116
118
|
this.body = null
|
|
117
119
|
} else if (util.isStream(body)) {
|
|
118
120
|
this.body = body
|
|
121
|
+
|
|
122
|
+
if (!this.body._readableState?.autoDestroy) {
|
|
123
|
+
this.endHandler = function autoDestroy () {
|
|
124
|
+
util.destroy(this)
|
|
125
|
+
}
|
|
126
|
+
this.body.on('end', this.endHandler)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
this.errorHandler = err => {
|
|
130
|
+
if (this.abort) {
|
|
131
|
+
this.abort(err)
|
|
132
|
+
} else {
|
|
133
|
+
this.error = err
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
this.body.on('error', this.errorHandler)
|
|
119
137
|
} else if (util.isBuffer(body)) {
|
|
120
138
|
this.body = body.byteLength ? body : null
|
|
121
139
|
} else if (ArrayBuffer.isView(body)) {
|
|
@@ -222,13 +240,26 @@ class Request {
|
|
|
222
240
|
if (channels.bodySent.hasSubscribers) {
|
|
223
241
|
channels.bodySent.publish({ request: this })
|
|
224
242
|
}
|
|
243
|
+
|
|
244
|
+
if (this[kHandler].onRequestSent) {
|
|
245
|
+
try {
|
|
246
|
+
this[kHandler].onRequestSent()
|
|
247
|
+
} catch (err) {
|
|
248
|
+
this.onError(err)
|
|
249
|
+
}
|
|
250
|
+
}
|
|
225
251
|
}
|
|
226
252
|
|
|
227
253
|
onConnect (abort) {
|
|
228
254
|
assert(!this.aborted)
|
|
229
255
|
assert(!this.completed)
|
|
230
256
|
|
|
231
|
-
|
|
257
|
+
if (this.error) {
|
|
258
|
+
abort(this.error)
|
|
259
|
+
} else {
|
|
260
|
+
this.abort = abort
|
|
261
|
+
return this[kHandler].onConnect(abort)
|
|
262
|
+
}
|
|
232
263
|
}
|
|
233
264
|
|
|
234
265
|
onHeaders (statusCode, headers, resume, statusText) {
|
|
@@ -257,6 +288,8 @@ class Request {
|
|
|
257
288
|
}
|
|
258
289
|
|
|
259
290
|
onComplete (trailers) {
|
|
291
|
+
this.onFinally()
|
|
292
|
+
|
|
260
293
|
assert(!this.aborted)
|
|
261
294
|
|
|
262
295
|
this.completed = true
|
|
@@ -267,6 +300,8 @@ class Request {
|
|
|
267
300
|
}
|
|
268
301
|
|
|
269
302
|
onError (error) {
|
|
303
|
+
this.onFinally()
|
|
304
|
+
|
|
270
305
|
if (channels.error.hasSubscribers) {
|
|
271
306
|
channels.error.publish({ request: this, error })
|
|
272
307
|
}
|
|
@@ -278,6 +313,18 @@ class Request {
|
|
|
278
313
|
return this[kHandler].onError(error)
|
|
279
314
|
}
|
|
280
315
|
|
|
316
|
+
onFinally () {
|
|
317
|
+
if (this.errorHandler) {
|
|
318
|
+
this.body.off('error', this.errorHandler)
|
|
319
|
+
this.errorHandler = null
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (this.endHandler) {
|
|
323
|
+
this.body.off('end', this.endHandler)
|
|
324
|
+
this.endHandler = null
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
281
328
|
// TODO: adjust to support H2
|
|
282
329
|
addHeader (key, value) {
|
|
283
330
|
processHeader(this, key, value)
|
package/lib/core/util.js
CHANGED
package/lib/fetch/body.js
CHANGED
|
@@ -26,6 +26,8 @@ let ReadableStream = globalThis.ReadableStream
|
|
|
26
26
|
|
|
27
27
|
/** @type {globalThis['File']} */
|
|
28
28
|
const File = NativeFile ?? UndiciFile
|
|
29
|
+
const textEncoder = new TextEncoder()
|
|
30
|
+
const textDecoder = new TextDecoder()
|
|
29
31
|
|
|
30
32
|
// https://fetch.spec.whatwg.org/#concept-bodyinit-extract
|
|
31
33
|
function extractBody (object, keepalive = false) {
|
|
@@ -49,7 +51,7 @@ function extractBody (object, keepalive = false) {
|
|
|
49
51
|
stream = new ReadableStream({
|
|
50
52
|
async pull (controller) {
|
|
51
53
|
controller.enqueue(
|
|
52
|
-
typeof source === 'string' ?
|
|
54
|
+
typeof source === 'string' ? textEncoder.encode(source) : source
|
|
53
55
|
)
|
|
54
56
|
queueMicrotask(() => readableStreamClose(controller))
|
|
55
57
|
},
|
|
@@ -119,7 +121,6 @@ function extractBody (object, keepalive = false) {
|
|
|
119
121
|
// - That the content-length is calculated in advance.
|
|
120
122
|
// - And that all parts are pre-encoded and ready to be sent.
|
|
121
123
|
|
|
122
|
-
const enc = new TextEncoder()
|
|
123
124
|
const blobParts = []
|
|
124
125
|
const rn = new Uint8Array([13, 10]) // '\r\n'
|
|
125
126
|
length = 0
|
|
@@ -127,13 +128,13 @@ function extractBody (object, keepalive = false) {
|
|
|
127
128
|
|
|
128
129
|
for (const [name, value] of object) {
|
|
129
130
|
if (typeof value === 'string') {
|
|
130
|
-
const chunk =
|
|
131
|
+
const chunk = textEncoder.encode(prefix +
|
|
131
132
|
`; name="${escape(normalizeLinefeeds(name))}"` +
|
|
132
133
|
`\r\n\r\n${normalizeLinefeeds(value)}\r\n`)
|
|
133
134
|
blobParts.push(chunk)
|
|
134
135
|
length += chunk.byteLength
|
|
135
136
|
} else {
|
|
136
|
-
const chunk =
|
|
137
|
+
const chunk = textEncoder.encode(`${prefix}; name="${escape(normalizeLinefeeds(name))}"` +
|
|
137
138
|
(value.name ? `; filename="${escape(value.name)}"` : '') + '\r\n' +
|
|
138
139
|
`Content-Type: ${
|
|
139
140
|
value.type || 'application/octet-stream'
|
|
@@ -147,7 +148,7 @@ function extractBody (object, keepalive = false) {
|
|
|
147
148
|
}
|
|
148
149
|
}
|
|
149
150
|
|
|
150
|
-
const chunk =
|
|
151
|
+
const chunk = textEncoder.encode(`--${boundary}--`)
|
|
151
152
|
blobParts.push(chunk)
|
|
152
153
|
length += chunk.byteLength
|
|
153
154
|
if (hasUnknownSizeValue) {
|
|
@@ -443,14 +444,16 @@ function bodyMixinMethods (instance) {
|
|
|
443
444
|
let text = ''
|
|
444
445
|
// application/x-www-form-urlencoded parser will keep the BOM.
|
|
445
446
|
// https://url.spec.whatwg.org/#concept-urlencoded-parser
|
|
446
|
-
|
|
447
|
+
// Note that streaming decoder is stateful and cannot be reused
|
|
448
|
+
const streamingDecoder = new TextDecoder('utf-8', { ignoreBOM: true })
|
|
449
|
+
|
|
447
450
|
for await (const chunk of consumeBody(this[kState].body)) {
|
|
448
451
|
if (!isUint8Array(chunk)) {
|
|
449
452
|
throw new TypeError('Expected Uint8Array chunk')
|
|
450
453
|
}
|
|
451
|
-
text +=
|
|
454
|
+
text += streamingDecoder.decode(chunk, { stream: true })
|
|
452
455
|
}
|
|
453
|
-
text +=
|
|
456
|
+
text += streamingDecoder.decode()
|
|
454
457
|
entries = new URLSearchParams(text)
|
|
455
458
|
} catch (err) {
|
|
456
459
|
// istanbul ignore next: Unclear when new URLSearchParams can fail on a string.
|
|
@@ -565,7 +568,7 @@ function utf8DecodeBytes (buffer) {
|
|
|
565
568
|
|
|
566
569
|
// 3. Process a queue with an instance of UTF-8’s
|
|
567
570
|
// decoder, ioQueue, output, and "replacement".
|
|
568
|
-
const output =
|
|
571
|
+
const output = textDecoder.decode(buffer)
|
|
569
572
|
|
|
570
573
|
// 4. Return output.
|
|
571
574
|
return output
|
package/lib/fetch/constants.js
CHANGED
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
const { MessageChannel, receiveMessageOnPort } = require('worker_threads')
|
|
4
4
|
|
|
5
5
|
const corsSafeListedMethods = ['GET', 'HEAD', 'POST']
|
|
6
|
+
const corsSafeListedMethodsSet = new Set(corsSafeListedMethods)
|
|
6
7
|
|
|
7
8
|
const nullBodyStatus = [101, 204, 205, 304]
|
|
8
9
|
|
|
9
10
|
const redirectStatus = [301, 302, 303, 307, 308]
|
|
11
|
+
const redirectStatusSet = new Set(redirectStatus)
|
|
10
12
|
|
|
11
13
|
// https://fetch.spec.whatwg.org/#block-bad-port
|
|
12
14
|
const badPorts = [
|
|
@@ -18,6 +20,8 @@ const badPorts = [
|
|
|
18
20
|
'10080'
|
|
19
21
|
]
|
|
20
22
|
|
|
23
|
+
const badPortsSet = new Set(badPorts)
|
|
24
|
+
|
|
21
25
|
// https://w3c.github.io/webappsec-referrer-policy/#referrer-policies
|
|
22
26
|
const referrerPolicy = [
|
|
23
27
|
'',
|
|
@@ -30,10 +34,12 @@ const referrerPolicy = [
|
|
|
30
34
|
'strict-origin-when-cross-origin',
|
|
31
35
|
'unsafe-url'
|
|
32
36
|
]
|
|
37
|
+
const referrerPolicySet = new Set(referrerPolicy)
|
|
33
38
|
|
|
34
39
|
const requestRedirect = ['follow', 'manual', 'error']
|
|
35
40
|
|
|
36
41
|
const safeMethods = ['GET', 'HEAD', 'OPTIONS', 'TRACE']
|
|
42
|
+
const safeMethodsSet = new Set(safeMethods)
|
|
37
43
|
|
|
38
44
|
const requestMode = ['navigate', 'same-origin', 'no-cors', 'cors']
|
|
39
45
|
|
|
@@ -68,6 +74,7 @@ const requestDuplex = [
|
|
|
68
74
|
|
|
69
75
|
// http://fetch.spec.whatwg.org/#forbidden-method
|
|
70
76
|
const forbiddenMethods = ['CONNECT', 'TRACE', 'TRACK']
|
|
77
|
+
const forbiddenMethodsSet = new Set(forbiddenMethods)
|
|
71
78
|
|
|
72
79
|
const subresource = [
|
|
73
80
|
'audio',
|
|
@@ -83,6 +90,7 @@ const subresource = [
|
|
|
83
90
|
'xslt',
|
|
84
91
|
''
|
|
85
92
|
]
|
|
93
|
+
const subresourceSet = new Set(subresource)
|
|
86
94
|
|
|
87
95
|
/** @type {globalThis['DOMException']} */
|
|
88
96
|
const DOMException = globalThis.DOMException ?? (() => {
|
|
@@ -132,5 +140,12 @@ module.exports = {
|
|
|
132
140
|
nullBodyStatus,
|
|
133
141
|
safeMethods,
|
|
134
142
|
badPorts,
|
|
135
|
-
requestDuplex
|
|
143
|
+
requestDuplex,
|
|
144
|
+
subresourceSet,
|
|
145
|
+
badPortsSet,
|
|
146
|
+
redirectStatusSet,
|
|
147
|
+
corsSafeListedMethodsSet,
|
|
148
|
+
safeMethodsSet,
|
|
149
|
+
forbiddenMethodsSet,
|
|
150
|
+
referrerPolicySet
|
|
136
151
|
}
|
package/lib/fetch/file.js
CHANGED
|
@@ -7,6 +7,7 @@ const { isBlobLike } = require('./util')
|
|
|
7
7
|
const { webidl } = require('./webidl')
|
|
8
8
|
const { parseMIMEType, serializeAMimeType } = require('./dataURL')
|
|
9
9
|
const { kEnumerableProperty } = require('../core/util')
|
|
10
|
+
const encoder = new TextEncoder()
|
|
10
11
|
|
|
11
12
|
class File extends Blob {
|
|
12
13
|
constructor (fileBits, fileName, options = {}) {
|
|
@@ -280,7 +281,7 @@ function processBlobParts (parts, options) {
|
|
|
280
281
|
}
|
|
281
282
|
|
|
282
283
|
// 3. Append the result of UTF-8 encoding s to bytes.
|
|
283
|
-
bytes.push(
|
|
284
|
+
bytes.push(encoder.encode(s))
|
|
284
285
|
} else if (
|
|
285
286
|
types.isAnyArrayBuffer(element) ||
|
|
286
287
|
types.isTypedArray(element)
|
package/lib/fetch/index.js
CHANGED
|
@@ -46,11 +46,11 @@ const { kState, kHeaders, kGuard, kRealm } = require('./symbols')
|
|
|
46
46
|
const assert = require('assert')
|
|
47
47
|
const { safelyExtractBody } = require('./body')
|
|
48
48
|
const {
|
|
49
|
-
|
|
49
|
+
redirectStatusSet,
|
|
50
50
|
nullBodyStatus,
|
|
51
|
-
|
|
51
|
+
safeMethodsSet,
|
|
52
52
|
requestBodyHeader,
|
|
53
|
-
|
|
53
|
+
subresourceSet,
|
|
54
54
|
DOMException
|
|
55
55
|
} = require('./constants')
|
|
56
56
|
const { kHeadersList } = require('../core/symbols')
|
|
@@ -62,6 +62,7 @@ const { TransformStream } = require('stream/web')
|
|
|
62
62
|
const { getGlobalDispatcher } = require('../global')
|
|
63
63
|
const { webidl } = require('./webidl')
|
|
64
64
|
const { STATUS_CODES } = require('http')
|
|
65
|
+
const GET_OR_HEAD = ['GET', 'HEAD']
|
|
65
66
|
|
|
66
67
|
/** @type {import('buffer').resolveObjectURL} */
|
|
67
68
|
let resolveObjectURL
|
|
@@ -509,7 +510,7 @@ function fetching ({
|
|
|
509
510
|
}
|
|
510
511
|
|
|
511
512
|
// 15. If request is a subresource request, then:
|
|
512
|
-
if (
|
|
513
|
+
if (subresourceSet.has(request.destination)) {
|
|
513
514
|
// TODO
|
|
514
515
|
}
|
|
515
516
|
|
|
@@ -1063,7 +1064,7 @@ async function httpFetch (fetchParams) {
|
|
|
1063
1064
|
}
|
|
1064
1065
|
|
|
1065
1066
|
// 8. If actualResponse’s status is a redirect status, then:
|
|
1066
|
-
if (
|
|
1067
|
+
if (redirectStatusSet.has(actualResponse.status)) {
|
|
1067
1068
|
// 1. If actualResponse’s status is not 303, request’s body is not null,
|
|
1068
1069
|
// and the connection uses HTTP/2, then user agents may, and are even
|
|
1069
1070
|
// encouraged to, transmit an RST_STREAM frame.
|
|
@@ -1181,7 +1182,7 @@ function httpRedirectFetch (fetchParams, response) {
|
|
|
1181
1182
|
if (
|
|
1182
1183
|
([301, 302].includes(actualResponse.status) && request.method === 'POST') ||
|
|
1183
1184
|
(actualResponse.status === 303 &&
|
|
1184
|
-
!
|
|
1185
|
+
!GET_OR_HEAD.includes(request.method))
|
|
1185
1186
|
) {
|
|
1186
1187
|
// then:
|
|
1187
1188
|
// 1. Set request’s method to `GET` and request’s body to null.
|
|
@@ -1465,7 +1466,7 @@ async function httpNetworkOrCacheFetch (
|
|
|
1465
1466
|
// responses in httpCache, as per the "Invalidation" chapter of HTTP
|
|
1466
1467
|
// Caching, and set storedResponse to null. [HTTP-CACHING]
|
|
1467
1468
|
if (
|
|
1468
|
-
!
|
|
1469
|
+
!safeMethodsSet.has(httpRequest.method) &&
|
|
1469
1470
|
forwardResponse.status >= 200 &&
|
|
1470
1471
|
forwardResponse.status <= 399
|
|
1471
1472
|
) {
|
|
@@ -2025,7 +2026,7 @@ async function httpNetworkFetch (
|
|
|
2025
2026
|
|
|
2026
2027
|
const willFollow = request.redirect === 'follow' &&
|
|
2027
2028
|
location &&
|
|
2028
|
-
|
|
2029
|
+
redirectStatusSet.has(status)
|
|
2029
2030
|
|
|
2030
2031
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding
|
|
2031
2032
|
if (request.method !== 'HEAD' && request.method !== 'CONNECT' && !nullBodyStatus.includes(status) && !willFollow) {
|
package/lib/fetch/request.js
CHANGED
|
@@ -13,8 +13,8 @@ const {
|
|
|
13
13
|
makePolicyContainer
|
|
14
14
|
} = require('./util')
|
|
15
15
|
const {
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
forbiddenMethodsSet,
|
|
17
|
+
corsSafeListedMethodsSet,
|
|
18
18
|
referrerPolicy,
|
|
19
19
|
requestRedirect,
|
|
20
20
|
requestMode,
|
|
@@ -319,7 +319,7 @@ class Request {
|
|
|
319
319
|
throw TypeError(`'${init.method}' is not a valid HTTP method.`)
|
|
320
320
|
}
|
|
321
321
|
|
|
322
|
-
if (
|
|
322
|
+
if (forbiddenMethodsSet.has(method.toUpperCase())) {
|
|
323
323
|
throw TypeError(`'${init.method}' HTTP method is unsupported.`)
|
|
324
324
|
}
|
|
325
325
|
|
|
@@ -404,7 +404,7 @@ class Request {
|
|
|
404
404
|
if (mode === 'no-cors') {
|
|
405
405
|
// 1. If this’s request’s method is not a CORS-safelisted method,
|
|
406
406
|
// then throw a TypeError.
|
|
407
|
-
if (!
|
|
407
|
+
if (!corsSafeListedMethodsSet.has(request.method)) {
|
|
408
408
|
throw new TypeError(
|
|
409
409
|
`'${request.method} is unsupported in no-cors mode.`
|
|
410
410
|
)
|
package/lib/fetch/response.js
CHANGED
|
@@ -14,7 +14,7 @@ const {
|
|
|
14
14
|
isomorphicEncode
|
|
15
15
|
} = require('./util')
|
|
16
16
|
const {
|
|
17
|
-
|
|
17
|
+
redirectStatusSet,
|
|
18
18
|
nullBodyStatus,
|
|
19
19
|
DOMException
|
|
20
20
|
} = require('./constants')
|
|
@@ -28,6 +28,7 @@ const assert = require('assert')
|
|
|
28
28
|
const { types } = require('util')
|
|
29
29
|
|
|
30
30
|
const ReadableStream = globalThis.ReadableStream || require('stream/web').ReadableStream
|
|
31
|
+
const textEncoder = new TextEncoder('utf-8')
|
|
31
32
|
|
|
32
33
|
// https://fetch.spec.whatwg.org/#response-class
|
|
33
34
|
class Response {
|
|
@@ -57,7 +58,7 @@ class Response {
|
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
// 1. Let bytes the result of running serialize a JavaScript value to JSON bytes on data.
|
|
60
|
-
const bytes =
|
|
61
|
+
const bytes = textEncoder.encode(
|
|
61
62
|
serializeJavascriptValueToJSONString(data)
|
|
62
63
|
)
|
|
63
64
|
|
|
@@ -102,7 +103,7 @@ class Response {
|
|
|
102
103
|
}
|
|
103
104
|
|
|
104
105
|
// 3. If status is not a redirect status, then throw a RangeError.
|
|
105
|
-
if (!
|
|
106
|
+
if (!redirectStatusSet.has(status)) {
|
|
106
107
|
throw new RangeError('Invalid status code ' + status)
|
|
107
108
|
}
|
|
108
109
|
|
package/lib/fetch/util.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const { redirectStatusSet, referrerPolicySet: referrerPolicyTokens, badPortsSet } = require('./constants')
|
|
4
4
|
const { getGlobalOrigin } = require('./global')
|
|
5
5
|
const { performance } = require('perf_hooks')
|
|
6
6
|
const { isBlobLike, toUSVString, ReadableStreamFrom } = require('../core/util')
|
|
@@ -29,7 +29,7 @@ function responseURL (response) {
|
|
|
29
29
|
// https://fetch.spec.whatwg.org/#concept-response-location-url
|
|
30
30
|
function responseLocationURL (response, requestFragment) {
|
|
31
31
|
// 1. If response’s status is not a redirect status, then return null.
|
|
32
|
-
if (!
|
|
32
|
+
if (!redirectStatusSet.has(response.status)) {
|
|
33
33
|
return null
|
|
34
34
|
}
|
|
35
35
|
|
|
@@ -64,7 +64,7 @@ function requestBadPort (request) {
|
|
|
64
64
|
|
|
65
65
|
// 2. If url’s scheme is an HTTP(S) scheme and url’s port is a bad port,
|
|
66
66
|
// then return blocked.
|
|
67
|
-
if (urlIsHttpHttpsScheme(url) &&
|
|
67
|
+
if (urlIsHttpHttpsScheme(url) && badPortsSet.has(url.port)) {
|
|
68
68
|
return 'blocked'
|
|
69
69
|
}
|
|
70
70
|
|
|
@@ -206,7 +206,7 @@ function setRequestReferrerPolicyOnRedirect (request, actualResponse) {
|
|
|
206
206
|
// The left-most policy is the fallback.
|
|
207
207
|
for (let i = policyHeader.length; i !== 0; i--) {
|
|
208
208
|
const token = policyHeader[i - 1].trim()
|
|
209
|
-
if (referrerPolicyTokens.
|
|
209
|
+
if (referrerPolicyTokens.has(token)) {
|
|
210
210
|
policy = token
|
|
211
211
|
break
|
|
212
212
|
}
|
package/lib/pool.js
CHANGED
|
@@ -57,7 +57,7 @@ class Pool extends PoolBase {
|
|
|
57
57
|
maxCachedSessions,
|
|
58
58
|
allowH2,
|
|
59
59
|
socketPath,
|
|
60
|
-
timeout: connectTimeout
|
|
60
|
+
timeout: connectTimeout,
|
|
61
61
|
...(util.nodeHasAutoSelectFamily && autoSelectFamily ? { autoSelectFamily, autoSelectFamilyAttemptTimeout } : undefined),
|
|
62
62
|
...connect
|
|
63
63
|
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "undici",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.27.1",
|
|
4
4
|
"description": "An HTTP/1.1 client, written from scratch for Node.js",
|
|
5
5
|
"homepage": "https://undici.nodejs.org",
|
|
6
6
|
"bugs": {
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"test:tdd": "tap test/*.js test/diagnostics-channel/*.js -w",
|
|
85
85
|
"test:typescript": "node scripts/verifyVersion.js 14 || tsd && tsc --skipLibCheck test/imports/undici-import.ts",
|
|
86
86
|
"test:websocket": "node scripts/verifyVersion.js 18 || tap test/websocket/*.js",
|
|
87
|
-
"test:wpt": "node scripts/verifyVersion 18 || (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
|
|
87
|
+
"test:wpt": "node scripts/verifyVersion 18 || (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)",
|
|
88
88
|
"coverage": "nyc --reporter=text --reporter=html npm run test",
|
|
89
89
|
"coverage:ci": "nyc --reporter=lcov npm run test",
|
|
90
90
|
"bench": "PORT=3042 concurrently -k -s first npm:bench:server npm:bench:run",
|