undici 5.28.2 → 6.0.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 +0 -2
- package/docs/api/BalancedPool.md +1 -1
- package/index.js +36 -40
- package/lib/client.js +4 -4
- package/lib/compat/dispatcher-weakref.js +1 -6
- package/lib/core/connect.js +5 -1
- package/lib/core/constants.js +116 -0
- package/lib/core/request.js +0 -4
- package/lib/core/util.js +18 -24
- package/lib/fetch/body.js +14 -19
- package/lib/fetch/constants.js +0 -36
- package/lib/fetch/dataURL.js +8 -2
- package/lib/fetch/index.js +241 -113
- package/lib/fetch/request.js +0 -6
- package/lib/fetch/response.js +20 -10
- package/lib/fetch/util.js +169 -12
- package/lib/fetch/webidl.js +3 -3
- package/lib/fileapi/util.js +0 -1
- package/lib/handler/RedirectHandler.js +2 -2
- package/lib/handler/RetryHandler.js +16 -7
- package/lib/websocket/connection.js +1 -0
- package/lib/websocket/util.js +1 -0
- package/lib/websocket/websocket.js +0 -1
- package/package.json +2 -2
package/lib/fetch/util.js
CHANGED
|
@@ -890,14 +890,7 @@ async function fullyReadBody (body, processBody, processBodyError) {
|
|
|
890
890
|
}
|
|
891
891
|
}
|
|
892
892
|
|
|
893
|
-
/** @type {ReadableStream} */
|
|
894
|
-
let ReadableStream = globalThis.ReadableStream
|
|
895
|
-
|
|
896
893
|
function isReadableStreamLike (stream) {
|
|
897
|
-
if (!ReadableStream) {
|
|
898
|
-
ReadableStream = require('stream/web').ReadableStream
|
|
899
|
-
}
|
|
900
|
-
|
|
901
894
|
return stream instanceof ReadableStream || (
|
|
902
895
|
stream[Symbol.toStringTag] === 'ReadableStream' &&
|
|
903
896
|
typeof stream.tee === 'function'
|
|
@@ -928,9 +921,10 @@ function isomorphicDecode (input) {
|
|
|
928
921
|
function readableStreamClose (controller) {
|
|
929
922
|
try {
|
|
930
923
|
controller.close()
|
|
924
|
+
controller.byobRequest?.respond(0)
|
|
931
925
|
} catch (err) {
|
|
932
926
|
// TODO: add comment explaining why this error occurs.
|
|
933
|
-
if (!err.message.includes('Controller is already closed')) {
|
|
927
|
+
if (!err.message.includes('Controller is already closed') && !err.message.includes('ReadableStream is already closed')) {
|
|
934
928
|
throw err
|
|
935
929
|
}
|
|
936
930
|
}
|
|
@@ -1018,10 +1012,172 @@ function urlIsHttpHttpsScheme (url) {
|
|
|
1018
1012
|
return protocol === 'http:' || protocol === 'https:'
|
|
1019
1013
|
}
|
|
1020
1014
|
|
|
1015
|
+
/** @type {import('./dataURL')['collectASequenceOfCodePoints']} */
|
|
1016
|
+
let collectASequenceOfCodePoints
|
|
1017
|
+
|
|
1018
|
+
/**
|
|
1019
|
+
* @see https://fetch.spec.whatwg.org/#simple-range-header-value
|
|
1020
|
+
* @param {string} value
|
|
1021
|
+
* @param {boolean} allowWhitespace
|
|
1022
|
+
*/
|
|
1023
|
+
function simpleRangeHeaderValue (value, allowWhitespace) {
|
|
1024
|
+
// Note: avoid circular require
|
|
1025
|
+
collectASequenceOfCodePoints ??= require('./dataURL').collectASequenceOfCodePoints
|
|
1026
|
+
|
|
1027
|
+
// 1. Let data be the isomorphic decoding of value.
|
|
1028
|
+
// Note: isomorphic decoding takes a sequence of bytes (ie. a Uint8Array) and turns it into a string,
|
|
1029
|
+
// nothing more. We obviously don't need to do that if value is a string already.
|
|
1030
|
+
const data = value
|
|
1031
|
+
|
|
1032
|
+
// 2. If data does not start with "bytes", then return failure.
|
|
1033
|
+
if (!data.startsWith('bytes')) {
|
|
1034
|
+
return 'failure'
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
// 3. Let position be a position variable for data, initially pointing at the 5th code point of data.
|
|
1038
|
+
const position = { position: 5 }
|
|
1039
|
+
|
|
1040
|
+
// 4. If allowWhitespace is true, collect a sequence of code points that are HTTP tab or space,
|
|
1041
|
+
// from data given position.
|
|
1042
|
+
if (allowWhitespace) {
|
|
1043
|
+
collectASequenceOfCodePoints(
|
|
1044
|
+
(char) => char === '\t' || char === ' ',
|
|
1045
|
+
data,
|
|
1046
|
+
position
|
|
1047
|
+
)
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
// 5. If the code point at position within data is not U+003D (=), then return failure.
|
|
1051
|
+
if (data.charCodeAt(position.position) !== 0x3D) {
|
|
1052
|
+
return 'failure'
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
// 6. Advance position by 1.
|
|
1056
|
+
position.position++
|
|
1057
|
+
|
|
1058
|
+
// 7. If allowWhitespace is true, collect a sequence of code points that are HTTP tab or space, from
|
|
1059
|
+
// data given position.
|
|
1060
|
+
if (allowWhitespace) {
|
|
1061
|
+
collectASequenceOfCodePoints(
|
|
1062
|
+
(char) => char === '\t' || char === ' ',
|
|
1063
|
+
data,
|
|
1064
|
+
position
|
|
1065
|
+
)
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
// 8. Let rangeStart be the result of collecting a sequence of code points that are ASCII digits,
|
|
1069
|
+
// from data given position.
|
|
1070
|
+
const rangeStart = collectASequenceOfCodePoints(
|
|
1071
|
+
(char) => {
|
|
1072
|
+
const code = char.charCodeAt(0)
|
|
1073
|
+
|
|
1074
|
+
return code >= 0x30 && code <= 0x39
|
|
1075
|
+
},
|
|
1076
|
+
data,
|
|
1077
|
+
position
|
|
1078
|
+
)
|
|
1079
|
+
|
|
1080
|
+
// 9. Let rangeStartValue be rangeStart, interpreted as decimal number, if rangeStart is not the
|
|
1081
|
+
// empty string; otherwise null.
|
|
1082
|
+
const rangeStartValue = rangeStart.length ? Number(rangeStart) : null
|
|
1083
|
+
|
|
1084
|
+
// 10. If allowWhitespace is true, collect a sequence of code points that are HTTP tab or space,
|
|
1085
|
+
// from data given position.
|
|
1086
|
+
if (allowWhitespace) {
|
|
1087
|
+
collectASequenceOfCodePoints(
|
|
1088
|
+
(char) => char === '\t' || char === ' ',
|
|
1089
|
+
data,
|
|
1090
|
+
position
|
|
1091
|
+
)
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
// 11. If the code point at position within data is not U+002D (-), then return failure.
|
|
1095
|
+
if (data.charCodeAt(position.position) !== 0x2D) {
|
|
1096
|
+
return 'failure'
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
// 12. Advance position by 1.
|
|
1100
|
+
position.position++
|
|
1101
|
+
|
|
1102
|
+
// 13. If allowWhitespace is true, collect a sequence of code points that are HTTP tab
|
|
1103
|
+
// or space, from data given position.
|
|
1104
|
+
// Note from Khafra: its the same fucking step again lol
|
|
1105
|
+
if (allowWhitespace) {
|
|
1106
|
+
collectASequenceOfCodePoints(
|
|
1107
|
+
(char) => char === '\t' || char === ' ',
|
|
1108
|
+
data,
|
|
1109
|
+
position
|
|
1110
|
+
)
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
// 14. Let rangeEnd be the result of collecting a sequence of code points that are
|
|
1114
|
+
// ASCII digits, from data given position.
|
|
1115
|
+
// Note from Khafra: you wouldn't guess it, but this is also the same step as #8
|
|
1116
|
+
const rangeEnd = collectASequenceOfCodePoints(
|
|
1117
|
+
(char) => {
|
|
1118
|
+
const code = char.charCodeAt(0)
|
|
1119
|
+
|
|
1120
|
+
return code >= 0x30 && code <= 0x39
|
|
1121
|
+
},
|
|
1122
|
+
data,
|
|
1123
|
+
position
|
|
1124
|
+
)
|
|
1125
|
+
|
|
1126
|
+
// 15. Let rangeEndValue be rangeEnd, interpreted as decimal number, if rangeEnd
|
|
1127
|
+
// is not the empty string; otherwise null.
|
|
1128
|
+
// Note from Khafra: THE SAME STEP, AGAIN!!!
|
|
1129
|
+
// Note: why interpret as a decimal if we only collect ascii digits?
|
|
1130
|
+
const rangeEndValue = rangeEnd.length ? Number(rangeEnd) : null
|
|
1131
|
+
|
|
1132
|
+
// 16. If position is not past the end of data, then return failure.
|
|
1133
|
+
if (position.position < data.length) {
|
|
1134
|
+
return 'failure'
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
// 17. If rangeEndValue and rangeStartValue are null, then return failure.
|
|
1138
|
+
if (rangeEndValue === null && rangeStartValue === null) {
|
|
1139
|
+
return 'failure'
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
// 18. If rangeStartValue and rangeEndValue are numbers, and rangeStartValue is
|
|
1143
|
+
// greater than rangeEndValue, then return failure.
|
|
1144
|
+
// Note: ... when can they not be numbers?
|
|
1145
|
+
if (rangeStartValue > rangeEndValue) {
|
|
1146
|
+
return 'failure'
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
// 19. Return (rangeStartValue, rangeEndValue).
|
|
1150
|
+
return { rangeStartValue, rangeEndValue }
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1021
1153
|
/**
|
|
1022
|
-
*
|
|
1154
|
+
* @see https://fetch.spec.whatwg.org/#build-a-content-range
|
|
1155
|
+
* @param {number} rangeStart
|
|
1156
|
+
* @param {number} rangeEnd
|
|
1157
|
+
* @param {number} fullLength
|
|
1023
1158
|
*/
|
|
1024
|
-
|
|
1159
|
+
function buildContentRange (rangeStart, rangeEnd, fullLength) {
|
|
1160
|
+
// 1. Let contentRange be `bytes `.
|
|
1161
|
+
let contentRange = 'bytes '
|
|
1162
|
+
|
|
1163
|
+
// 2. Append rangeStart, serialized and isomorphic encoded, to contentRange.
|
|
1164
|
+
contentRange += isomorphicEncode(`${rangeStart}`)
|
|
1165
|
+
|
|
1166
|
+
// 3. Append 0x2D (-) to contentRange.
|
|
1167
|
+
contentRange += '-'
|
|
1168
|
+
|
|
1169
|
+
// 4. Append rangeEnd, serialized and isomorphic encoded to contentRange.
|
|
1170
|
+
contentRange += isomorphicEncode(`${rangeEnd}`)
|
|
1171
|
+
|
|
1172
|
+
// 5. Append 0x2F (/) to contentRange.
|
|
1173
|
+
contentRange += '/'
|
|
1174
|
+
|
|
1175
|
+
// 6. Append fullLength, serialized and isomorphic encoded to contentRange.
|
|
1176
|
+
contentRange += isomorphicEncode(`${fullLength}`)
|
|
1177
|
+
|
|
1178
|
+
// 7. Return contentRange.
|
|
1179
|
+
return contentRange
|
|
1180
|
+
}
|
|
1025
1181
|
|
|
1026
1182
|
module.exports = {
|
|
1027
1183
|
isAborted,
|
|
@@ -1055,7 +1211,6 @@ module.exports = {
|
|
|
1055
1211
|
makeIterator,
|
|
1056
1212
|
isValidHeaderName,
|
|
1057
1213
|
isValidHeaderValue,
|
|
1058
|
-
hasOwn,
|
|
1059
1214
|
isErrorLike,
|
|
1060
1215
|
fullyReadBody,
|
|
1061
1216
|
bytesMatch,
|
|
@@ -1067,5 +1222,7 @@ module.exports = {
|
|
|
1067
1222
|
urlHasHttpsScheme,
|
|
1068
1223
|
urlIsHttpHttpsScheme,
|
|
1069
1224
|
readAllBytes,
|
|
1070
|
-
normalizeMethodRecord
|
|
1225
|
+
normalizeMethodRecord,
|
|
1226
|
+
simpleRangeHeaderValue,
|
|
1227
|
+
buildContentRange
|
|
1071
1228
|
}
|
package/lib/fetch/webidl.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { types } = require('util')
|
|
4
|
-
const {
|
|
4
|
+
const { toUSVString } = require('./util')
|
|
5
5
|
|
|
6
6
|
/** @type {import('../../types/webidl').Webidl} */
|
|
7
7
|
const webidl = {}
|
|
@@ -346,7 +346,7 @@ webidl.dictionaryConverter = function (converters) {
|
|
|
346
346
|
const { key, defaultValue, required, converter } = options
|
|
347
347
|
|
|
348
348
|
if (required === true) {
|
|
349
|
-
if (!hasOwn(dictionary, key)) {
|
|
349
|
+
if (!Object.hasOwn(dictionary, key)) {
|
|
350
350
|
throw webidl.errors.exception({
|
|
351
351
|
header: 'Dictionary',
|
|
352
352
|
message: `Missing required key "${key}".`
|
|
@@ -355,7 +355,7 @@ webidl.dictionaryConverter = function (converters) {
|
|
|
355
355
|
}
|
|
356
356
|
|
|
357
357
|
let value = dictionary[key]
|
|
358
|
-
const hasDefault = hasOwn(options, 'defaultValue')
|
|
358
|
+
const hasDefault = Object.hasOwn(options, 'defaultValue')
|
|
359
359
|
|
|
360
360
|
// Only use defaultValue if value is undefined and
|
|
361
361
|
// a defaultValue options was provided.
|
package/lib/fileapi/util.js
CHANGED
|
@@ -9,7 +9,6 @@ const {
|
|
|
9
9
|
} = require('./symbols')
|
|
10
10
|
const { ProgressEvent } = require('./progressevent')
|
|
11
11
|
const { getEncoding } = require('./encoding')
|
|
12
|
-
const { DOMException } = require('../fetch/constants')
|
|
13
12
|
const { serializeAMimeType, parseMIMEType } = require('../fetch/dataURL')
|
|
14
13
|
const { types } = require('util')
|
|
15
14
|
const { StringDecoder } = require('string_decoder')
|
|
@@ -135,7 +135,7 @@ class RedirectHandler {
|
|
|
135
135
|
|
|
136
136
|
For status 300, which is "Multiple Choices", the spec mentions both generating a Location
|
|
137
137
|
response header AND a response body with the other possible location to follow.
|
|
138
|
-
Since the spec
|
|
138
|
+
Since the spec explicitly chooses not to specify a format for such body and leave it to
|
|
139
139
|
servers and browsers implementors, we ignore the body as there is no specified way to eventually parse it.
|
|
140
140
|
*/
|
|
141
141
|
} else {
|
|
@@ -151,7 +151,7 @@ class RedirectHandler {
|
|
|
151
151
|
TLDR: undici always ignores 3xx response trailers as they are not expected in case of redirections
|
|
152
152
|
and neither are useful if present.
|
|
153
153
|
|
|
154
|
-
See comment on onData method above for more detailed
|
|
154
|
+
See comment on onData method above for more detailed information.
|
|
155
155
|
*/
|
|
156
156
|
|
|
157
157
|
this.location = null
|
|
@@ -172,13 +172,22 @@ class RetryHandler {
|
|
|
172
172
|
this.retryCount += 1
|
|
173
173
|
|
|
174
174
|
if (statusCode >= 300) {
|
|
175
|
-
this.
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
175
|
+
if (this.retryOpts.statusCodes.includes(statusCode) === false) {
|
|
176
|
+
return this.handler.onHeaders(
|
|
177
|
+
statusCode,
|
|
178
|
+
rawHeaders,
|
|
179
|
+
resume,
|
|
180
|
+
statusMessage
|
|
181
|
+
)
|
|
182
|
+
} else {
|
|
183
|
+
this.abort(
|
|
184
|
+
new RequestRetryError('Request failed', statusCode, {
|
|
185
|
+
headers,
|
|
186
|
+
count: this.retryCount
|
|
187
|
+
})
|
|
188
|
+
)
|
|
189
|
+
return false
|
|
190
|
+
}
|
|
182
191
|
}
|
|
183
192
|
|
|
184
193
|
// Checkpoint for resume from where we left it
|
|
@@ -261,6 +261,7 @@ function onSocketClose () {
|
|
|
261
261
|
// attribute initialized to the result of applying UTF-8
|
|
262
262
|
// decode without BOM to the WebSocket connection close
|
|
263
263
|
// reason.
|
|
264
|
+
// TODO: process.nextTick
|
|
264
265
|
fireEvent('close', ws, CloseEvent, {
|
|
265
266
|
wasClean, code, reason
|
|
266
267
|
})
|
package/lib/websocket/util.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { webidl } = require('../fetch/webidl')
|
|
4
|
-
const { DOMException } = require('../fetch/constants')
|
|
5
4
|
const { URLSerializer } = require('../fetch/dataURL')
|
|
6
5
|
const { getGlobalOrigin } = require('../fetch/global')
|
|
7
6
|
const { staticPropertyDescriptors, states, opcodes, emptyBuffer } = require('./constants')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "undici",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.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": {
|
|
@@ -135,7 +135,7 @@
|
|
|
135
135
|
"ws": "^8.11.0"
|
|
136
136
|
},
|
|
137
137
|
"engines": {
|
|
138
|
-
"node": ">=
|
|
138
|
+
"node": ">=18.0"
|
|
139
139
|
},
|
|
140
140
|
"standard": {
|
|
141
141
|
"env": [
|