undici 6.18.1 → 6.18.2
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.
|
@@ -46,6 +46,9 @@ It represents the retry state for a given request.
|
|
|
46
46
|
- **dispatch** `(options: Dispatch.DispatchOptions, handlers: Dispatch.DispatchHandlers) => Promise<Dispatch.DispatchResponse>` (required) - Dispatch function to be called after every retry.
|
|
47
47
|
- **handler** Extends [`Dispatch.DispatchHandlers`](Dispatcher.md#dispatcherdispatchoptions-handler) (required) - Handler function to be called after the request is successful or the retries are exhausted.
|
|
48
48
|
|
|
49
|
+
>__Note__: The `RetryHandler` does not retry over stateful bodies (e.g. streams, AsyncIterable) as those, once consumed, are left in an state that cannot be reutilized. For these situations the `RetryHandler` will identify
|
|
50
|
+
>the body as stateful and will not retry the request rejecting with the error `UND_ERR_REQ_RETRY`.
|
|
51
|
+
|
|
49
52
|
Examples:
|
|
50
53
|
|
|
51
54
|
```js
|
package/lib/core/symbols.js
CHANGED
package/lib/core/util.js
CHANGED
|
@@ -1,19 +1,72 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const assert = require('node:assert')
|
|
4
|
-
const { kDestroyed, kBodyUsed, kListeners } = require('./symbols')
|
|
4
|
+
const { kDestroyed, kBodyUsed, kListeners, kBody } = require('./symbols')
|
|
5
5
|
const { IncomingMessage } = require('node:http')
|
|
6
6
|
const stream = require('node:stream')
|
|
7
7
|
const net = require('node:net')
|
|
8
|
-
const { InvalidArgumentError } = require('./errors')
|
|
9
8
|
const { Blob } = require('node:buffer')
|
|
10
9
|
const nodeUtil = require('node:util')
|
|
11
10
|
const { stringify } = require('node:querystring')
|
|
11
|
+
const { EventEmitter: EE } = require('node:events')
|
|
12
|
+
const { InvalidArgumentError } = require('./errors')
|
|
12
13
|
const { headerNameLowerCasedRecord } = require('./constants')
|
|
13
14
|
const { tree } = require('./tree')
|
|
14
15
|
|
|
15
16
|
const [nodeMajor, nodeMinor] = process.versions.node.split('.').map(v => Number(v))
|
|
16
17
|
|
|
18
|
+
class BodyAsyncIterable {
|
|
19
|
+
constructor (body) {
|
|
20
|
+
this[kBody] = body
|
|
21
|
+
this[kBodyUsed] = false
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async * [Symbol.asyncIterator] () {
|
|
25
|
+
assert(!this[kBodyUsed], 'disturbed')
|
|
26
|
+
this[kBodyUsed] = true
|
|
27
|
+
yield * this[kBody]
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function wrapRequestBody (body) {
|
|
32
|
+
if (isStream(body)) {
|
|
33
|
+
// TODO (fix): Provide some way for the user to cache the file to e.g. /tmp
|
|
34
|
+
// so that it can be dispatched again?
|
|
35
|
+
// TODO (fix): Do we need 100-expect support to provide a way to do this properly?
|
|
36
|
+
if (bodyLength(body) === 0) {
|
|
37
|
+
body
|
|
38
|
+
.on('data', function () {
|
|
39
|
+
assert(false)
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (typeof body.readableDidRead !== 'boolean') {
|
|
44
|
+
body[kBodyUsed] = false
|
|
45
|
+
EE.prototype.on.call(body, 'data', function () {
|
|
46
|
+
this[kBodyUsed] = true
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return body
|
|
51
|
+
} else if (body && typeof body.pipeTo === 'function') {
|
|
52
|
+
// TODO (fix): We can't access ReadableStream internal state
|
|
53
|
+
// to determine whether or not it has been disturbed. This is just
|
|
54
|
+
// a workaround.
|
|
55
|
+
return new BodyAsyncIterable(body)
|
|
56
|
+
} else if (
|
|
57
|
+
body &&
|
|
58
|
+
typeof body !== 'string' &&
|
|
59
|
+
!ArrayBuffer.isView(body) &&
|
|
60
|
+
isIterable(body)
|
|
61
|
+
) {
|
|
62
|
+
// TODO: Should we allow re-using iterable if !this.opts.idempotent
|
|
63
|
+
// or through some other flag?
|
|
64
|
+
return new BodyAsyncIterable(body)
|
|
65
|
+
} else {
|
|
66
|
+
return body
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
17
70
|
function nop () {}
|
|
18
71
|
|
|
19
72
|
function isStream (obj) {
|
|
@@ -634,5 +687,6 @@ module.exports = {
|
|
|
634
687
|
isHttpOrHttpsPrefixed,
|
|
635
688
|
nodeMajor,
|
|
636
689
|
nodeMinor,
|
|
637
|
-
safeHTTPMethods: ['GET', 'HEAD', 'OPTIONS', 'TRACE']
|
|
690
|
+
safeHTTPMethods: ['GET', 'HEAD', 'OPTIONS', 'TRACE'],
|
|
691
|
+
wrapRequestBody
|
|
638
692
|
}
|
|
@@ -3,7 +3,12 @@ const assert = require('node:assert')
|
|
|
3
3
|
|
|
4
4
|
const { kRetryHandlerDefaultRetry } = require('../core/symbols')
|
|
5
5
|
const { RequestRetryError } = require('../core/errors')
|
|
6
|
-
const {
|
|
6
|
+
const {
|
|
7
|
+
isDisturbed,
|
|
8
|
+
parseHeaders,
|
|
9
|
+
parseRangeHeader,
|
|
10
|
+
wrapRequestBody
|
|
11
|
+
} = require('../core/util')
|
|
7
12
|
|
|
8
13
|
function calculateRetryAfterHeader (retryAfter) {
|
|
9
14
|
const current = Date.now()
|
|
@@ -29,7 +34,7 @@ class RetryHandler {
|
|
|
29
34
|
|
|
30
35
|
this.dispatch = handlers.dispatch
|
|
31
36
|
this.handler = handlers.handler
|
|
32
|
-
this.opts = dispatchOpts
|
|
37
|
+
this.opts = { ...dispatchOpts, body: wrapRequestBody(opts.body) }
|
|
33
38
|
this.abort = null
|
|
34
39
|
this.aborted = false
|
|
35
40
|
this.retryOpts = {
|
|
@@ -174,7 +179,9 @@ class RetryHandler {
|
|
|
174
179
|
this.abort(
|
|
175
180
|
new RequestRetryError('Request failed', statusCode, {
|
|
176
181
|
headers,
|
|
177
|
-
|
|
182
|
+
data: {
|
|
183
|
+
count: this.retryCount
|
|
184
|
+
}
|
|
178
185
|
})
|
|
179
186
|
)
|
|
180
187
|
return false
|
|
@@ -278,7 +285,7 @@ class RetryHandler {
|
|
|
278
285
|
|
|
279
286
|
const err = new RequestRetryError('Request failed', statusCode, {
|
|
280
287
|
headers,
|
|
281
|
-
count: this.retryCount
|
|
288
|
+
data: { count: this.retryCount }
|
|
282
289
|
})
|
|
283
290
|
|
|
284
291
|
this.abort(err)
|
package/lib/web/cookies/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { parseSetCookie } = require('./parse')
|
|
4
|
-
const { stringify
|
|
4
|
+
const { stringify } = require('./util')
|
|
5
5
|
const { webidl } = require('../fetch/webidl')
|
|
6
6
|
const { Headers } = require('../fetch/headers')
|
|
7
7
|
|
|
@@ -78,14 +78,13 @@ function getSetCookies (headers) {
|
|
|
78
78
|
|
|
79
79
|
webidl.brandCheck(headers, Headers, { strict: false })
|
|
80
80
|
|
|
81
|
-
const cookies =
|
|
81
|
+
const cookies = headers.getSetCookie()
|
|
82
82
|
|
|
83
83
|
if (!cookies) {
|
|
84
84
|
return []
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
return cookies.map((pair) => parseSetCookie(Array.isArray(pair) ? pair[1] : pair))
|
|
87
|
+
return cookies.map((pair) => parseSetCookie(pair))
|
|
89
88
|
}
|
|
90
89
|
|
|
91
90
|
/**
|
package/lib/web/cookies/util.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const assert = require('node:assert')
|
|
4
|
-
const { getHeadersList: internalGetHeadersList } = require('../fetch/headers')
|
|
5
|
-
|
|
6
3
|
/**
|
|
7
4
|
* @param {string} value
|
|
8
5
|
* @returns {boolean}
|
|
@@ -275,35 +272,11 @@ function stringify (cookie) {
|
|
|
275
272
|
return out.join('; ')
|
|
276
273
|
}
|
|
277
274
|
|
|
278
|
-
let kHeadersListNode
|
|
279
|
-
|
|
280
|
-
function getHeadersList (headers) {
|
|
281
|
-
try {
|
|
282
|
-
return internalGetHeadersList(headers)
|
|
283
|
-
} catch {
|
|
284
|
-
// fall-through
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
if (!kHeadersListNode) {
|
|
288
|
-
kHeadersListNode = Object.getOwnPropertySymbols(headers).find(
|
|
289
|
-
(symbol) => symbol.description === 'headers list'
|
|
290
|
-
)
|
|
291
|
-
|
|
292
|
-
assert(kHeadersListNode, 'Headers cannot be parsed')
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
const headersList = headers[kHeadersListNode]
|
|
296
|
-
assert(headersList)
|
|
297
|
-
|
|
298
|
-
return headersList
|
|
299
|
-
}
|
|
300
|
-
|
|
301
275
|
module.exports = {
|
|
302
276
|
isCTLExcludingHtab,
|
|
303
277
|
validateCookieName,
|
|
304
278
|
validateCookiePath,
|
|
305
279
|
validateCookieValue,
|
|
306
280
|
toIMFDate,
|
|
307
|
-
stringify
|
|
308
|
-
getHeadersList
|
|
281
|
+
stringify
|
|
309
282
|
}
|
package/lib/web/fetch/headers.js
CHANGED
|
@@ -641,14 +641,6 @@ Object.defineProperties(Headers.prototype, {
|
|
|
641
641
|
},
|
|
642
642
|
[util.inspect.custom]: {
|
|
643
643
|
enumerable: false
|
|
644
|
-
},
|
|
645
|
-
// Compatibility for global headers
|
|
646
|
-
[Symbol('headers list')]: {
|
|
647
|
-
configurable: false,
|
|
648
|
-
enumerable: false,
|
|
649
|
-
get: function () {
|
|
650
|
-
return getHeadersList(this)
|
|
651
|
-
}
|
|
652
644
|
}
|
|
653
645
|
})
|
|
654
646
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "undici",
|
|
3
|
-
"version": "6.18.
|
|
3
|
+
"version": "6.18.2",
|
|
4
4
|
"description": "An HTTP/1.1 client, written from scratch for Node.js",
|
|
5
5
|
"homepage": "https://undici.nodejs.org",
|
|
6
6
|
"bugs": {
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
"@sinonjs/fake-timers": "^11.1.0",
|
|
108
108
|
"@types/node": "^18.0.3",
|
|
109
109
|
"abort-controller": "^3.0.0",
|
|
110
|
-
"borp": "^0.
|
|
110
|
+
"borp": "^0.14.0",
|
|
111
111
|
"c8": "^9.1.0",
|
|
112
112
|
"cross-env": "^7.0.3",
|
|
113
113
|
"dns-packet": "^5.4.0",
|