undici 6.10.2 → 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 +4 -0
- package/docs/docs/api/DiagnosticsChannel.md +0 -2
- 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 +27 -1
- package/lib/mock/pending-interceptors-formatter.js +4 -1
- 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/package.json +9 -5
- package/types/diagnostics-channel.d.ts +1 -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
|
```
|
|
@@ -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/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,7 +405,19 @@ 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
|
}
|
|
397
423
|
|
|
@@ -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
|
}))
|
|
@@ -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/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
|
},
|