undici 6.16.0 → 6.17.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/docs/docs/api/Dispatcher.md +32 -0
- package/index-fetch.js +1 -1
- package/index.js +3 -2
- package/lib/api/api-request.js +10 -1
- package/lib/core/connect.js +1 -1
- package/lib/core/symbols.js +0 -1
- package/lib/dispatcher/client-h1.js +1 -1
- package/lib/interceptor/dump.js +123 -0
- package/lib/web/cookies/util.js +5 -3
- package/lib/web/fetch/body.js +9 -0
- package/lib/web/fetch/headers.js +59 -31
- package/lib/web/fetch/index.js +1 -2
- package/lib/web/fetch/request.js +11 -11
- package/lib/web/fetch/response.js +8 -8
- package/lib/web/fetch/symbols.js +0 -1
- package/lib/web/fetch/util.js +20 -12
- package/lib/web/websocket/connection.js +6 -10
- package/lib/web/websocket/receiver.js +177 -146
- package/lib/web/websocket/util.js +29 -1
- package/lib/web/websocket/websocket.js +17 -5
- package/package.json +4 -2
- package/types/dispatcher.d.ts +3 -3
- package/types/index.d.ts +5 -0
- package/types/interceptors.d.ts +8 -2
|
@@ -952,6 +952,38 @@ const client = new Client("http://example.com").compose(
|
|
|
952
952
|
);
|
|
953
953
|
```
|
|
954
954
|
|
|
955
|
+
##### `dump`
|
|
956
|
+
|
|
957
|
+
The `dump` interceptor enables you to dump the response body from a request upon a given limit.
|
|
958
|
+
|
|
959
|
+
**Options**
|
|
960
|
+
- `maxSize` - The maximum size (in bytes) of the response body to dump. If the size of the request's body exceeds this value then the connection will be closed. Default: `1048576`.
|
|
961
|
+
|
|
962
|
+
> The `Dispatcher#options` also gets extended with the options `dumpMaxSize`, `abortOnDumped`, and `waitForTrailers` which can be used to configure the interceptor at a request-per-request basis.
|
|
963
|
+
|
|
964
|
+
**Example - Basic Dump Interceptor**
|
|
965
|
+
|
|
966
|
+
```js
|
|
967
|
+
const { Client, interceptors } = require("undici");
|
|
968
|
+
const { dump } = interceptors;
|
|
969
|
+
|
|
970
|
+
const client = new Client("http://example.com").compose(
|
|
971
|
+
dump({
|
|
972
|
+
maxSize: 1024,
|
|
973
|
+
})
|
|
974
|
+
);
|
|
975
|
+
|
|
976
|
+
// or
|
|
977
|
+
client.dispatch(
|
|
978
|
+
{
|
|
979
|
+
path: "/",
|
|
980
|
+
method: "GET",
|
|
981
|
+
dumpMaxSize: 1024,
|
|
982
|
+
},
|
|
983
|
+
handler
|
|
984
|
+
);
|
|
985
|
+
```
|
|
986
|
+
|
|
955
987
|
## Instance Events
|
|
956
988
|
|
|
957
989
|
### Event: `'connect'`
|
package/index-fetch.js
CHANGED
|
@@ -7,7 +7,7 @@ const fetchImpl = require('./lib/web/fetch').fetch
|
|
|
7
7
|
module.exports.fetch = function fetch (resource, init = undefined) {
|
|
8
8
|
return fetchImpl(resource, init).catch((err) => {
|
|
9
9
|
if (err && typeof err === 'object') {
|
|
10
|
-
Error.captureStackTrace(err
|
|
10
|
+
Error.captureStackTrace(err)
|
|
11
11
|
}
|
|
12
12
|
throw err
|
|
13
13
|
})
|
package/index.js
CHANGED
|
@@ -40,7 +40,8 @@ module.exports.RedirectHandler = RedirectHandler
|
|
|
40
40
|
module.exports.createRedirectInterceptor = createRedirectInterceptor
|
|
41
41
|
module.exports.interceptors = {
|
|
42
42
|
redirect: require('./lib/interceptor/redirect'),
|
|
43
|
-
retry: require('./lib/interceptor/retry')
|
|
43
|
+
retry: require('./lib/interceptor/retry'),
|
|
44
|
+
dump: require('./lib/interceptor/dump')
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
module.exports.buildConnector = buildConnector
|
|
@@ -108,7 +109,7 @@ module.exports.fetch = async function fetch (init, options = undefined) {
|
|
|
108
109
|
return await fetchImpl(init, options)
|
|
109
110
|
} catch (err) {
|
|
110
111
|
if (err && typeof err === 'object') {
|
|
111
|
-
Error.captureStackTrace(err
|
|
112
|
+
Error.captureStackTrace(err)
|
|
112
113
|
}
|
|
113
114
|
|
|
114
115
|
throw err
|
package/lib/api/api-request.js
CHANGED
|
@@ -44,6 +44,7 @@ class RequestHandler extends AsyncResource {
|
|
|
44
44
|
throw err
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
this.method = method
|
|
47
48
|
this.responseHeaders = responseHeaders || null
|
|
48
49
|
this.opaque = opaque || null
|
|
49
50
|
this.callback = callback
|
|
@@ -114,7 +115,15 @@ class RequestHandler extends AsyncResource {
|
|
|
114
115
|
const parsedHeaders = responseHeaders === 'raw' ? util.parseHeaders(rawHeaders) : headers
|
|
115
116
|
const contentType = parsedHeaders['content-type']
|
|
116
117
|
const contentLength = parsedHeaders['content-length']
|
|
117
|
-
const res = new Readable({
|
|
118
|
+
const res = new Readable({
|
|
119
|
+
resume,
|
|
120
|
+
abort,
|
|
121
|
+
contentType,
|
|
122
|
+
contentLength: this.method !== 'HEAD' && contentLength
|
|
123
|
+
? Number(contentLength)
|
|
124
|
+
: null,
|
|
125
|
+
highWaterMark
|
|
126
|
+
})
|
|
118
127
|
|
|
119
128
|
if (this.removeAbortListener) {
|
|
120
129
|
res.on('close', this.removeAbortListener)
|
package/lib/core/connect.js
CHANGED
|
@@ -165,7 +165,7 @@ function setupTimeout (onConnectTimeout, timeout) {
|
|
|
165
165
|
let s1 = null
|
|
166
166
|
let s2 = null
|
|
167
167
|
const timeoutId = setTimeout(() => {
|
|
168
|
-
// setImmediate is added to make sure that we
|
|
168
|
+
// setImmediate is added to make sure that we prioritize socket error events over timeouts
|
|
169
169
|
s1 = setImmediate(() => {
|
|
170
170
|
if (process.platform === 'win32') {
|
|
171
171
|
// Windows needs an extra setImmediate probably due to implementation differences in the socket logic
|
package/lib/core/symbols.js
CHANGED
|
@@ -8,7 +8,6 @@ module.exports = {
|
|
|
8
8
|
kQueue: Symbol('queue'),
|
|
9
9
|
kConnect: Symbol('connect'),
|
|
10
10
|
kConnecting: Symbol('connecting'),
|
|
11
|
-
kHeadersList: Symbol('headers list'),
|
|
12
11
|
kKeepAliveDefaultTimeout: Symbol('default keep alive timeout'),
|
|
13
12
|
kKeepAliveMaxTimeout: Symbol('max keep alive timeout'),
|
|
14
13
|
kKeepAliveTimeoutThreshold: Symbol('keep alive timeout threshold'),
|
|
@@ -1101,7 +1101,7 @@ function writeStream ({ abort, body, client, request, socket, contentLength, hea
|
|
|
1101
1101
|
}
|
|
1102
1102
|
}
|
|
1103
1103
|
|
|
1104
|
-
|
|
1104
|
+
function writeBuffer ({ abort, body, client, request, socket, contentLength, header, expectsPayload }) {
|
|
1105
1105
|
try {
|
|
1106
1106
|
if (!body) {
|
|
1107
1107
|
if (contentLength === 0) {
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const util = require('../core/util')
|
|
4
|
+
const { InvalidArgumentError, RequestAbortedError } = require('../core/errors')
|
|
5
|
+
const DecoratorHandler = require('../handler/decorator-handler')
|
|
6
|
+
|
|
7
|
+
class DumpHandler extends DecoratorHandler {
|
|
8
|
+
#maxSize = 1024 * 1024
|
|
9
|
+
#abort = null
|
|
10
|
+
#dumped = false
|
|
11
|
+
#aborted = false
|
|
12
|
+
#size = 0
|
|
13
|
+
#reason = null
|
|
14
|
+
#handler = null
|
|
15
|
+
|
|
16
|
+
constructor ({ maxSize }, handler) {
|
|
17
|
+
super(handler)
|
|
18
|
+
|
|
19
|
+
if (maxSize != null && (!Number.isFinite(maxSize) || maxSize < 1)) {
|
|
20
|
+
throw new InvalidArgumentError('maxSize must be a number greater than 0')
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
this.#maxSize = maxSize ?? this.#maxSize
|
|
24
|
+
this.#handler = handler
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
onConnect (abort) {
|
|
28
|
+
this.#abort = abort
|
|
29
|
+
|
|
30
|
+
this.#handler.onConnect(this.#customAbort.bind(this))
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
#customAbort (reason) {
|
|
34
|
+
this.#aborted = true
|
|
35
|
+
this.#reason = reason
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// TODO: will require adjustment after new hooks are out
|
|
39
|
+
onHeaders (statusCode, rawHeaders, resume, statusMessage) {
|
|
40
|
+
const headers = util.parseHeaders(rawHeaders)
|
|
41
|
+
const contentLength = headers['content-length']
|
|
42
|
+
|
|
43
|
+
if (contentLength != null && contentLength > this.#maxSize) {
|
|
44
|
+
throw new RequestAbortedError(
|
|
45
|
+
`Response size (${contentLength}) larger than maxSize (${
|
|
46
|
+
this.#maxSize
|
|
47
|
+
})`
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (this.#aborted) {
|
|
52
|
+
return true
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return this.#handler.onHeaders(
|
|
56
|
+
statusCode,
|
|
57
|
+
rawHeaders,
|
|
58
|
+
resume,
|
|
59
|
+
statusMessage
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
onError (err) {
|
|
64
|
+
if (this.#dumped) {
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
err = this.#reason ?? err
|
|
69
|
+
|
|
70
|
+
this.#handler.onError(err)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
onData (chunk) {
|
|
74
|
+
this.#size = this.#size + chunk.length
|
|
75
|
+
|
|
76
|
+
if (this.#size >= this.#maxSize) {
|
|
77
|
+
this.#dumped = true
|
|
78
|
+
|
|
79
|
+
if (this.#aborted) {
|
|
80
|
+
this.#handler.onError(this.#reason)
|
|
81
|
+
} else {
|
|
82
|
+
this.#handler.onComplete([])
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return true
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
onComplete (trailers) {
|
|
90
|
+
if (this.#dumped) {
|
|
91
|
+
return
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (this.#aborted) {
|
|
95
|
+
this.#handler.onError(this.reason)
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
this.#handler.onComplete(trailers)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function createDumpInterceptor (
|
|
104
|
+
{ maxSize: defaultMaxSize } = {
|
|
105
|
+
maxSize: 1024 * 1024
|
|
106
|
+
}
|
|
107
|
+
) {
|
|
108
|
+
return dispatch => {
|
|
109
|
+
return function Intercept (opts, handler) {
|
|
110
|
+
const { dumpMaxSize = defaultMaxSize } =
|
|
111
|
+
opts
|
|
112
|
+
|
|
113
|
+
const dumpHandler = new DumpHandler(
|
|
114
|
+
{ maxSize: dumpMaxSize },
|
|
115
|
+
handler
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
return dispatch(opts, dumpHandler)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
module.exports = createDumpInterceptor
|
package/lib/web/cookies/util.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const assert = require('node:assert')
|
|
4
|
-
const {
|
|
4
|
+
const { getHeadersList: internalGetHeadersList } = require('../fetch/headers')
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @param {string} value
|
|
@@ -278,8 +278,10 @@ function stringify (cookie) {
|
|
|
278
278
|
let kHeadersListNode
|
|
279
279
|
|
|
280
280
|
function getHeadersList (headers) {
|
|
281
|
-
|
|
282
|
-
return headers
|
|
281
|
+
try {
|
|
282
|
+
return internalGetHeadersList(headers)
|
|
283
|
+
} catch {
|
|
284
|
+
// fall-through
|
|
283
285
|
}
|
|
284
286
|
|
|
285
287
|
if (!kHeadersListNode) {
|
package/lib/web/fetch/body.js
CHANGED
|
@@ -385,6 +385,15 @@ function bodyMixinMethods (instance) {
|
|
|
385
385
|
'Content-Type was not one of "multipart/form-data" or "application/x-www-form-urlencoded".'
|
|
386
386
|
)
|
|
387
387
|
}, instance, false)
|
|
388
|
+
},
|
|
389
|
+
|
|
390
|
+
bytes () {
|
|
391
|
+
// The bytes() method steps are to return the result of running consume body
|
|
392
|
+
// with this and the following step given a byte sequence bytes: return the
|
|
393
|
+
// result of creating a Uint8Array from bytes in this’s relevant realm.
|
|
394
|
+
return consumeBody(this, (bytes) => {
|
|
395
|
+
return new Uint8Array(bytes.buffer, 0, bytes.byteLength)
|
|
396
|
+
}, instance, true)
|
|
388
397
|
}
|
|
389
398
|
}
|
|
390
399
|
|
package/lib/web/fetch/headers.js
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
'use strict'
|
|
4
4
|
|
|
5
|
-
const {
|
|
6
|
-
const { kGuard } = require('./symbols')
|
|
5
|
+
const { kConstruct } = require('../../core/symbols')
|
|
7
6
|
const { kEnumerableProperty } = require('../../core/util')
|
|
8
7
|
const {
|
|
9
8
|
iteratorMixin,
|
|
@@ -103,19 +102,18 @@ function appendHeader (headers, name, value) {
|
|
|
103
102
|
// 3. If headers’s guard is "immutable", then throw a TypeError.
|
|
104
103
|
// 4. Otherwise, if headers’s guard is "request" and name is a
|
|
105
104
|
// forbidden header name, return.
|
|
105
|
+
// 5. Otherwise, if headers’s guard is "request-no-cors":
|
|
106
|
+
// TODO
|
|
106
107
|
// Note: undici does not implement forbidden header names
|
|
107
|
-
if (headers
|
|
108
|
+
if (getHeadersGuard(headers) === 'immutable') {
|
|
108
109
|
throw new TypeError('immutable')
|
|
109
|
-
} else if (headers[kGuard] === 'request-no-cors') {
|
|
110
|
-
// 5. Otherwise, if headers’s guard is "request-no-cors":
|
|
111
|
-
// TODO
|
|
112
110
|
}
|
|
113
111
|
|
|
114
112
|
// 6. Otherwise, if headers’s guard is "response" and name is a
|
|
115
113
|
// forbidden response-header name, return.
|
|
116
114
|
|
|
117
115
|
// 7. Append (name, value) to headers’s header list.
|
|
118
|
-
return headers
|
|
116
|
+
return getHeadersList(headers).append(name, value, false)
|
|
119
117
|
|
|
120
118
|
// 8. If headers’s guard is "request-no-cors", then remove
|
|
121
119
|
// privileged no-CORS request headers from headers
|
|
@@ -357,16 +355,20 @@ class HeadersList {
|
|
|
357
355
|
|
|
358
356
|
// https://fetch.spec.whatwg.org/#headers-class
|
|
359
357
|
class Headers {
|
|
358
|
+
#guard
|
|
359
|
+
#headersList
|
|
360
|
+
|
|
360
361
|
constructor (init = undefined) {
|
|
361
362
|
if (init === kConstruct) {
|
|
362
363
|
return
|
|
363
364
|
}
|
|
364
|
-
|
|
365
|
+
|
|
366
|
+
this.#headersList = new HeadersList()
|
|
365
367
|
|
|
366
368
|
// The new Headers(init) constructor steps are:
|
|
367
369
|
|
|
368
370
|
// 1. Set this’s guard to "none".
|
|
369
|
-
this
|
|
371
|
+
this.#guard = 'none'
|
|
370
372
|
|
|
371
373
|
// 2. If init is given, then fill this with init.
|
|
372
374
|
if (init !== undefined) {
|
|
@@ -416,22 +418,20 @@ class Headers {
|
|
|
416
418
|
// 5. Otherwise, if this’s guard is "response" and name is
|
|
417
419
|
// a forbidden response-header name, return.
|
|
418
420
|
// Note: undici does not implement forbidden header names
|
|
419
|
-
if (this
|
|
421
|
+
if (this.#guard === 'immutable') {
|
|
420
422
|
throw new TypeError('immutable')
|
|
421
|
-
} else if (this[kGuard] === 'request-no-cors') {
|
|
422
|
-
// TODO
|
|
423
423
|
}
|
|
424
424
|
|
|
425
425
|
// 6. If this’s header list does not contain name, then
|
|
426
426
|
// return.
|
|
427
|
-
if (!this
|
|
427
|
+
if (!this.#headersList.contains(name, false)) {
|
|
428
428
|
return
|
|
429
429
|
}
|
|
430
430
|
|
|
431
431
|
// 7. Delete name from this’s header list.
|
|
432
432
|
// 8. If this’s guard is "request-no-cors", then remove
|
|
433
433
|
// privileged no-CORS request headers from this.
|
|
434
|
-
this
|
|
434
|
+
this.#headersList.delete(name, false)
|
|
435
435
|
}
|
|
436
436
|
|
|
437
437
|
// https://fetch.spec.whatwg.org/#dom-headers-get
|
|
@@ -454,7 +454,7 @@ class Headers {
|
|
|
454
454
|
|
|
455
455
|
// 2. Return the result of getting name from this’s header
|
|
456
456
|
// list.
|
|
457
|
-
return this
|
|
457
|
+
return this.#headersList.get(name, false)
|
|
458
458
|
}
|
|
459
459
|
|
|
460
460
|
// https://fetch.spec.whatwg.org/#dom-headers-has
|
|
@@ -477,7 +477,7 @@ class Headers {
|
|
|
477
477
|
|
|
478
478
|
// 2. Return true if this’s header list contains name;
|
|
479
479
|
// otherwise false.
|
|
480
|
-
return this
|
|
480
|
+
return this.#headersList.contains(name, false)
|
|
481
481
|
}
|
|
482
482
|
|
|
483
483
|
// https://fetch.spec.whatwg.org/#dom-headers-set
|
|
@@ -518,16 +518,14 @@ class Headers {
|
|
|
518
518
|
// 6. Otherwise, if this’s guard is "response" and name is a
|
|
519
519
|
// forbidden response-header name, return.
|
|
520
520
|
// Note: undici does not implement forbidden header names
|
|
521
|
-
if (this
|
|
521
|
+
if (this.#guard === 'immutable') {
|
|
522
522
|
throw new TypeError('immutable')
|
|
523
|
-
} else if (this[kGuard] === 'request-no-cors') {
|
|
524
|
-
// TODO
|
|
525
523
|
}
|
|
526
524
|
|
|
527
525
|
// 7. Set (name, value) in this’s header list.
|
|
528
526
|
// 8. If this’s guard is "request-no-cors", then remove
|
|
529
527
|
// privileged no-CORS request headers from this
|
|
530
|
-
this
|
|
528
|
+
this.#headersList.set(name, value, false)
|
|
531
529
|
}
|
|
532
530
|
|
|
533
531
|
// https://fetch.spec.whatwg.org/#dom-headers-getsetcookie
|
|
@@ -538,7 +536,7 @@ class Headers {
|
|
|
538
536
|
// 2. Return the values of all headers in this’s header list whose name is
|
|
539
537
|
// a byte-case-insensitive match for `Set-Cookie`, in order.
|
|
540
538
|
|
|
541
|
-
const list = this
|
|
539
|
+
const list = this.#headersList.cookies
|
|
542
540
|
|
|
543
541
|
if (list) {
|
|
544
542
|
return [...list]
|
|
@@ -549,8 +547,8 @@ class Headers {
|
|
|
549
547
|
|
|
550
548
|
// https://fetch.spec.whatwg.org/#concept-header-list-sort-and-combine
|
|
551
549
|
get [kHeadersSortedMap] () {
|
|
552
|
-
if (this[
|
|
553
|
-
return this[
|
|
550
|
+
if (this.#headersList[kHeadersSortedMap]) {
|
|
551
|
+
return this.#headersList[kHeadersSortedMap]
|
|
554
552
|
}
|
|
555
553
|
|
|
556
554
|
// 1. Let headers be an empty list of headers with the key being the name
|
|
@@ -559,14 +557,14 @@ class Headers {
|
|
|
559
557
|
|
|
560
558
|
// 2. Let names be the result of convert header names to a sorted-lowercase
|
|
561
559
|
// set with all the names of the headers in list.
|
|
562
|
-
const names = this
|
|
560
|
+
const names = this.#headersList.toSortedArray()
|
|
563
561
|
|
|
564
|
-
const cookies = this
|
|
562
|
+
const cookies = this.#headersList.cookies
|
|
565
563
|
|
|
566
564
|
// fast-path
|
|
567
565
|
if (cookies === null || cookies.length === 1) {
|
|
568
566
|
// Note: The non-null assertion of value has already been done by `HeadersList#toSortedArray`
|
|
569
|
-
return (this[
|
|
567
|
+
return (this.#headersList[kHeadersSortedMap] = names)
|
|
570
568
|
}
|
|
571
569
|
|
|
572
570
|
// 3. For each name of names:
|
|
@@ -596,16 +594,38 @@ class Headers {
|
|
|
596
594
|
}
|
|
597
595
|
|
|
598
596
|
// 4. Return headers.
|
|
599
|
-
return (this[
|
|
597
|
+
return (this.#headersList[kHeadersSortedMap] = headers)
|
|
600
598
|
}
|
|
601
599
|
|
|
602
600
|
[util.inspect.custom] (depth, options) {
|
|
603
601
|
options.depth ??= depth
|
|
604
602
|
|
|
605
|
-
return `Headers ${util.formatWithOptions(options, this
|
|
603
|
+
return `Headers ${util.formatWithOptions(options, this.#headersList.entries)}`
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
static getHeadersGuard (o) {
|
|
607
|
+
return o.#guard
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
static setHeadersGuard (o, guard) {
|
|
611
|
+
o.#guard = guard
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
static getHeadersList (o) {
|
|
615
|
+
return o.#headersList
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
static setHeadersList (o, list) {
|
|
619
|
+
o.#headersList = list
|
|
606
620
|
}
|
|
607
621
|
}
|
|
608
622
|
|
|
623
|
+
const { getHeadersGuard, setHeadersGuard, getHeadersList, setHeadersList } = Headers
|
|
624
|
+
Reflect.deleteProperty(Headers, 'getHeadersGuard')
|
|
625
|
+
Reflect.deleteProperty(Headers, 'setHeadersGuard')
|
|
626
|
+
Reflect.deleteProperty(Headers, 'getHeadersList')
|
|
627
|
+
Reflect.deleteProperty(Headers, 'setHeadersList')
|
|
628
|
+
|
|
609
629
|
Object.defineProperty(Headers.prototype, util.inspect.custom, {
|
|
610
630
|
enumerable: false
|
|
611
631
|
})
|
|
@@ -631,8 +651,12 @@ webidl.converters.HeadersInit = function (V, prefix, argument) {
|
|
|
631
651
|
|
|
632
652
|
// A work-around to ensure we send the properly-cased Headers when V is a Headers object.
|
|
633
653
|
// Read https://github.com/nodejs/undici/pull/3159#issuecomment-2075537226 before touching, please.
|
|
634
|
-
if (!util.types.isProxy(V) &&
|
|
635
|
-
|
|
654
|
+
if (!util.types.isProxy(V) && iterator === Headers.prototype.entries) { // Headers object
|
|
655
|
+
try {
|
|
656
|
+
return getHeadersList(V).entriesList
|
|
657
|
+
} catch {
|
|
658
|
+
// fall-through
|
|
659
|
+
}
|
|
636
660
|
}
|
|
637
661
|
|
|
638
662
|
if (typeof iterator === 'function') {
|
|
@@ -654,5 +678,9 @@ module.exports = {
|
|
|
654
678
|
// for test.
|
|
655
679
|
compareHeaderName,
|
|
656
680
|
Headers,
|
|
657
|
-
HeadersList
|
|
681
|
+
HeadersList,
|
|
682
|
+
getHeadersGuard,
|
|
683
|
+
setHeadersGuard,
|
|
684
|
+
setHeadersList,
|
|
685
|
+
getHeadersList
|
|
658
686
|
}
|
package/lib/web/fetch/index.js
CHANGED
|
@@ -444,8 +444,7 @@ function fetching ({
|
|
|
444
444
|
// 9. If request’s origin is "client", then set request’s origin to request’s
|
|
445
445
|
// client’s origin.
|
|
446
446
|
if (request.origin === 'client') {
|
|
447
|
-
|
|
448
|
-
request.origin = request.client?.origin
|
|
447
|
+
request.origin = request.client.origin
|
|
449
448
|
}
|
|
450
449
|
|
|
451
450
|
// 10. If all of the following conditions are true:
|
package/lib/web/fetch/request.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
'use strict'
|
|
4
4
|
|
|
5
5
|
const { extractBody, mixinBody, cloneBody } = require('./body')
|
|
6
|
-
const { Headers, fill: fillHeaders, HeadersList } = require('./headers')
|
|
6
|
+
const { Headers, fill: fillHeaders, HeadersList, setHeadersGuard, getHeadersGuard, setHeadersList, getHeadersList } = require('./headers')
|
|
7
7
|
const { FinalizationRegistry } = require('./dispatcher-weakref')()
|
|
8
8
|
const util = require('../../core/util')
|
|
9
9
|
const nodeUtil = require('node:util')
|
|
@@ -25,10 +25,10 @@ const {
|
|
|
25
25
|
requestDuplex
|
|
26
26
|
} = require('./constants')
|
|
27
27
|
const { kEnumerableProperty } = util
|
|
28
|
-
const { kHeaders, kSignal, kState,
|
|
28
|
+
const { kHeaders, kSignal, kState, kDispatcher } = require('./symbols')
|
|
29
29
|
const { webidl } = require('./webidl')
|
|
30
30
|
const { URLSerializer } = require('./data-url')
|
|
31
|
-
const {
|
|
31
|
+
const { kConstruct } = require('../../core/symbols')
|
|
32
32
|
const assert = require('node:assert')
|
|
33
33
|
const { getMaxListeners, setMaxListeners, getEventListeners, defaultMaxListeners } = require('node:events')
|
|
34
34
|
|
|
@@ -445,8 +445,8 @@ class Request {
|
|
|
445
445
|
// Realm, whose header list is request’s header list and guard is
|
|
446
446
|
// "request".
|
|
447
447
|
this[kHeaders] = new Headers(kConstruct)
|
|
448
|
-
this[kHeaders]
|
|
449
|
-
this[kHeaders]
|
|
448
|
+
setHeadersList(this[kHeaders], request.headersList)
|
|
449
|
+
setHeadersGuard(this[kHeaders], 'request')
|
|
450
450
|
|
|
451
451
|
// 31. If this’s request’s mode is "no-cors", then:
|
|
452
452
|
if (mode === 'no-cors') {
|
|
@@ -459,13 +459,13 @@ class Request {
|
|
|
459
459
|
}
|
|
460
460
|
|
|
461
461
|
// 2. Set this’s headers’s guard to "request-no-cors".
|
|
462
|
-
this[kHeaders]
|
|
462
|
+
setHeadersGuard(this[kHeaders], 'request-no-cors')
|
|
463
463
|
}
|
|
464
464
|
|
|
465
465
|
// 32. If init is not empty, then:
|
|
466
466
|
if (initHasKey) {
|
|
467
467
|
/** @type {HeadersList} */
|
|
468
|
-
const headersList = this[kHeaders]
|
|
468
|
+
const headersList = getHeadersList(this[kHeaders])
|
|
469
469
|
// 1. Let headers be a copy of this’s headers and its associated header
|
|
470
470
|
// list.
|
|
471
471
|
// 2. If init["headers"] exists, then set headers to init["headers"].
|
|
@@ -519,7 +519,7 @@ class Request {
|
|
|
519
519
|
// 3, If Content-Type is non-null and this’s headers’s header list does
|
|
520
520
|
// not contain `Content-Type`, then append `Content-Type`/Content-Type to
|
|
521
521
|
// this’s headers.
|
|
522
|
-
if (contentType && !this[kHeaders]
|
|
522
|
+
if (contentType && !getHeadersList(this[kHeaders]).contains('content-type', true)) {
|
|
523
523
|
this[kHeaders].append('content-type', contentType)
|
|
524
524
|
}
|
|
525
525
|
}
|
|
@@ -785,7 +785,7 @@ class Request {
|
|
|
785
785
|
}
|
|
786
786
|
|
|
787
787
|
// 4. Return clonedRequestObject.
|
|
788
|
-
return fromInnerRequest(clonedRequest, ac.signal, this[kHeaders]
|
|
788
|
+
return fromInnerRequest(clonedRequest, ac.signal, getHeadersGuard(this[kHeaders]))
|
|
789
789
|
}
|
|
790
790
|
|
|
791
791
|
[nodeUtil.inspect.custom] (depth, options) {
|
|
@@ -894,8 +894,8 @@ function fromInnerRequest (innerRequest, signal, guard) {
|
|
|
894
894
|
request[kState] = innerRequest
|
|
895
895
|
request[kSignal] = signal
|
|
896
896
|
request[kHeaders] = new Headers(kConstruct)
|
|
897
|
-
request[kHeaders]
|
|
898
|
-
request[kHeaders]
|
|
897
|
+
setHeadersList(request[kHeaders], innerRequest.headersList)
|
|
898
|
+
setHeadersGuard(request[kHeaders], guard)
|
|
899
899
|
return request
|
|
900
900
|
}
|
|
901
901
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { Headers, HeadersList, fill } = require('./headers')
|
|
3
|
+
const { Headers, HeadersList, fill, getHeadersGuard, setHeadersGuard, setHeadersList } = require('./headers')
|
|
4
4
|
const { extractBody, cloneBody, mixinBody } = require('./body')
|
|
5
5
|
const util = require('../../core/util')
|
|
6
6
|
const nodeUtil = require('node:util')
|
|
@@ -19,11 +19,11 @@ const {
|
|
|
19
19
|
redirectStatusSet,
|
|
20
20
|
nullBodyStatus
|
|
21
21
|
} = require('./constants')
|
|
22
|
-
const { kState, kHeaders
|
|
22
|
+
const { kState, kHeaders } = require('./symbols')
|
|
23
23
|
const { webidl } = require('./webidl')
|
|
24
24
|
const { FormData } = require('./formdata')
|
|
25
25
|
const { URLSerializer } = require('./data-url')
|
|
26
|
-
const {
|
|
26
|
+
const { kConstruct } = require('../../core/symbols')
|
|
27
27
|
const assert = require('node:assert')
|
|
28
28
|
const { types } = require('node:util')
|
|
29
29
|
const { isDisturbed, isErrored } = require('node:stream')
|
|
@@ -141,8 +141,8 @@ class Response {
|
|
|
141
141
|
// Realm, whose header list is this’s response’s header list and guard
|
|
142
142
|
// is "response".
|
|
143
143
|
this[kHeaders] = new Headers(kConstruct)
|
|
144
|
-
this[kHeaders]
|
|
145
|
-
this[kHeaders]
|
|
144
|
+
setHeadersGuard(this[kHeaders], 'response')
|
|
145
|
+
setHeadersList(this[kHeaders], this[kState].headersList)
|
|
146
146
|
|
|
147
147
|
// 3. Let bodyWithType be null.
|
|
148
148
|
let bodyWithType = null
|
|
@@ -255,7 +255,7 @@ class Response {
|
|
|
255
255
|
|
|
256
256
|
// 3. Return the result of creating a Response object, given
|
|
257
257
|
// clonedResponse, this’s headers’s guard, and this’s relevant Realm.
|
|
258
|
-
return fromInnerResponse(clonedResponse, this[kHeaders]
|
|
258
|
+
return fromInnerResponse(clonedResponse, getHeadersGuard(this[kHeaders]))
|
|
259
259
|
}
|
|
260
260
|
|
|
261
261
|
[nodeUtil.inspect.custom] (depth, options) {
|
|
@@ -522,8 +522,8 @@ function fromInnerResponse (innerResponse, guard) {
|
|
|
522
522
|
const response = new Response(kConstruct)
|
|
523
523
|
response[kState] = innerResponse
|
|
524
524
|
response[kHeaders] = new Headers(kConstruct)
|
|
525
|
-
response[kHeaders]
|
|
526
|
-
response[kHeaders]
|
|
525
|
+
setHeadersList(response[kHeaders], innerResponse.headersList)
|
|
526
|
+
setHeadersGuard(response[kHeaders], guard)
|
|
527
527
|
|
|
528
528
|
if (hasFinalizationRegistry && innerResponse.body?.stream) {
|
|
529
529
|
registry.register(response, innerResponse.body.stream)
|