@psnext/slingcli 2.4.20260525-4 → 2.4.20260526-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/node_modules/@earendil-works/pi-ai/dist/models.generated.js +5 -5
- package/node_modules/undici/lib/api/api-request.js +1 -1
- package/node_modules/undici/lib/cache/sqlite-cache-store.js +3 -3
- package/node_modules/undici/lib/core/connect.js +16 -0
- package/node_modules/undici/lib/core/request.js +17 -2
- package/node_modules/undici/lib/core/socks5-client.js +10 -5
- package/node_modules/undici/lib/core/socks5-utils.js +17 -22
- package/node_modules/undici/lib/dispatcher/client-h1.js +64 -20
- package/node_modules/undici/lib/dispatcher/client.js +6 -2
- package/node_modules/undici/lib/dispatcher/h2c-client.js +1 -1
- package/node_modules/undici/lib/mock/mock-call-history.js +15 -15
- package/node_modules/undici/lib/util/cache.js +8 -7
- package/node_modules/undici/lib/web/fetch/formdata-parser.js +17 -6
- package/node_modules/undici/lib/web/fetch/index.js +5 -2
- package/node_modules/undici/lib/web/webidl/index.js +5 -5
- package/node_modules/undici/lib/web/websocket/stream/websocketstream.js +1 -7
- package/node_modules/undici/package.json +1 -1
- package/package.json +2 -2
- package/slingshot/index.js +195 -194
|
@@ -7039,7 +7039,7 @@ export const MODELS = {
|
|
|
7039
7039
|
cacheWrite: 0,
|
|
7040
7040
|
},
|
|
7041
7041
|
contextWindow: 200000,
|
|
7042
|
-
maxTokens:
|
|
7042
|
+
maxTokens: 32000,
|
|
7043
7043
|
},
|
|
7044
7044
|
"claude-haiku-4-5": {
|
|
7045
7045
|
id: "claude-haiku-4-5",
|
|
@@ -8498,13 +8498,13 @@ export const MODELS = {
|
|
|
8498
8498
|
reasoning: false,
|
|
8499
8499
|
input: ["text"],
|
|
8500
8500
|
cost: {
|
|
8501
|
-
input: 0.
|
|
8502
|
-
output: 0.
|
|
8501
|
+
input: 0.2288,
|
|
8502
|
+
output: 0.9144,
|
|
8503
8503
|
cacheRead: 0,
|
|
8504
8504
|
cacheWrite: 0,
|
|
8505
8505
|
},
|
|
8506
|
-
contextWindow:
|
|
8507
|
-
maxTokens:
|
|
8506
|
+
contextWindow: 131072,
|
|
8507
|
+
maxTokens: 16000,
|
|
8508
8508
|
},
|
|
8509
8509
|
"deepseek/deepseek-chat-v3-0324": {
|
|
8510
8510
|
id: "deepseek/deepseek-chat-v3-0324",
|
|
@@ -21,7 +21,7 @@ class RequestHandler extends AsyncResource {
|
|
|
21
21
|
throw new InvalidArgumentError('invalid callback')
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
if (highWaterMark && (
|
|
24
|
+
if (highWaterMark != null && (!Number.isFinite(highWaterMark) || highWaterMark < 0)) {
|
|
25
25
|
throw new InvalidArgumentError('invalid highWaterMark')
|
|
26
26
|
}
|
|
27
27
|
|
|
@@ -216,7 +216,7 @@ module.exports = class SqliteCacheStore {
|
|
|
216
216
|
SELECT
|
|
217
217
|
id
|
|
218
218
|
FROM cacheInterceptorV${VERSION}
|
|
219
|
-
ORDER BY cachedAt
|
|
219
|
+
ORDER BY cachedAt ASC
|
|
220
220
|
LIMIT ?
|
|
221
221
|
)
|
|
222
222
|
`)
|
|
@@ -283,7 +283,6 @@ module.exports = class SqliteCacheStore {
|
|
|
283
283
|
existingValue.id
|
|
284
284
|
)
|
|
285
285
|
} else {
|
|
286
|
-
this.#prune()
|
|
287
286
|
// New response, let's insert it
|
|
288
287
|
this.#insertValueQuery.run(
|
|
289
288
|
url,
|
|
@@ -299,6 +298,7 @@ module.exports = class SqliteCacheStore {
|
|
|
299
298
|
value.cachedAt,
|
|
300
299
|
value.staleAt
|
|
301
300
|
)
|
|
301
|
+
this.#prune()
|
|
302
302
|
}
|
|
303
303
|
}
|
|
304
304
|
|
|
@@ -409,7 +409,7 @@ module.exports = class SqliteCacheStore {
|
|
|
409
409
|
const now = Date.now()
|
|
410
410
|
for (const value of values) {
|
|
411
411
|
if (now >= value.deleteAt && !canBeExpired) {
|
|
412
|
-
|
|
412
|
+
continue
|
|
413
413
|
}
|
|
414
414
|
|
|
415
415
|
let matches = true
|
|
@@ -38,6 +38,22 @@ const SessionCache = class WeakSessionCache {
|
|
|
38
38
|
return
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
if (this._sessionCache.has(sessionKey)) {
|
|
42
|
+
this._sessionCache.delete(sessionKey)
|
|
43
|
+
} else if (this._sessionCache.size >= this._maxCachedSessions) {
|
|
44
|
+
for (const [key, ref] of this._sessionCache) {
|
|
45
|
+
if (ref.deref() === undefined) {
|
|
46
|
+
this._sessionCache.delete(key)
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const oldest = this._sessionCache.keys().next()
|
|
52
|
+
if (!oldest.done) {
|
|
53
|
+
this._sessionCache.delete(oldest.value)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
41
57
|
this._sessionCache.set(sessionKey, new WeakRef(session))
|
|
42
58
|
this._sessionRegistry.register(session, sessionKey)
|
|
43
59
|
}
|
|
@@ -27,6 +27,21 @@ const { headerNameLowerCasedRecord } = require('./constants')
|
|
|
27
27
|
// Verifies that a given path is valid does not contain control chars \x00 to \x20
|
|
28
28
|
const invalidPathRegex = /[^\u0021-\u00ff]/
|
|
29
29
|
|
|
30
|
+
function isValidContentLengthHeaderValue (val) {
|
|
31
|
+
if (typeof val !== 'string' || val.length === 0) {
|
|
32
|
+
return false
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
for (let i = 0; i < val.length; i++) {
|
|
36
|
+
const charCode = val.charCodeAt(i)
|
|
37
|
+
if (charCode < 48 || charCode > 57) {
|
|
38
|
+
return false
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return true
|
|
43
|
+
}
|
|
44
|
+
|
|
30
45
|
const kHandler = Symbol('handler')
|
|
31
46
|
|
|
32
47
|
class Request {
|
|
@@ -402,10 +417,10 @@ function processHeader (request, key, val) {
|
|
|
402
417
|
if (request.contentLength !== null) {
|
|
403
418
|
throw new InvalidArgumentError('duplicate content-length header')
|
|
404
419
|
}
|
|
405
|
-
|
|
406
|
-
if (!Number.isFinite(request.contentLength)) {
|
|
420
|
+
if (!isValidContentLengthHeaderValue(val)) {
|
|
407
421
|
throw new InvalidArgumentError('invalid content-length header')
|
|
408
422
|
}
|
|
423
|
+
request.contentLength = parseInt(val, 10)
|
|
409
424
|
} else if (request.contentType === null && headerName === 'content-type') {
|
|
410
425
|
request.contentType = val
|
|
411
426
|
request.headers.push(key, val)
|
|
@@ -7,6 +7,7 @@ const { debuglog } = require('node:util')
|
|
|
7
7
|
const { parseAddress } = require('./socks5-utils')
|
|
8
8
|
|
|
9
9
|
const debug = debuglog('undici:socks5')
|
|
10
|
+
const EMPTY_BUFFER = Buffer.alloc(0)
|
|
10
11
|
|
|
11
12
|
// SOCKS5 constants
|
|
12
13
|
const SOCKS_VERSION = 0x05
|
|
@@ -72,7 +73,10 @@ class Socks5Client extends EventEmitter {
|
|
|
72
73
|
this.socket = socket
|
|
73
74
|
this.options = options
|
|
74
75
|
this.state = STATES.INITIAL
|
|
75
|
-
this.buffer =
|
|
76
|
+
this.buffer = EMPTY_BUFFER
|
|
77
|
+
this.onSocketData = this.onData.bind(this)
|
|
78
|
+
this.onSocketError = this.onError.bind(this)
|
|
79
|
+
this.onSocketClose = this.onClose.bind(this)
|
|
76
80
|
|
|
77
81
|
// Authentication settings
|
|
78
82
|
this.authMethods = []
|
|
@@ -82,9 +86,9 @@ class Socks5Client extends EventEmitter {
|
|
|
82
86
|
this.authMethods.push(AUTH_METHODS.NO_AUTH)
|
|
83
87
|
|
|
84
88
|
// Socket event handlers
|
|
85
|
-
this.socket.on('data', this.
|
|
86
|
-
this.socket.on('error', this.
|
|
87
|
-
this.socket.on('close', this.
|
|
89
|
+
this.socket.on('data', this.onSocketData)
|
|
90
|
+
this.socket.on('error', this.onSocketError)
|
|
91
|
+
this.socket.on('close', this.onSocketClose)
|
|
88
92
|
}
|
|
89
93
|
|
|
90
94
|
/**
|
|
@@ -363,8 +367,9 @@ class Socks5Client extends EventEmitter {
|
|
|
363
367
|
|
|
364
368
|
const boundPort = this.buffer.readUInt16BE(offset)
|
|
365
369
|
|
|
366
|
-
this.buffer =
|
|
370
|
+
this.buffer = EMPTY_BUFFER
|
|
367
371
|
this.state = STATES.CONNECTED
|
|
372
|
+
this.socket.removeListener('data', this.onSocketData)
|
|
368
373
|
|
|
369
374
|
debug('connected, bound address:', boundAddress, 'port:', boundPort)
|
|
370
375
|
this.emit('connected', { address: boundAddress, port: boundPort })
|
|
@@ -46,34 +46,29 @@ function parseAddress (address) {
|
|
|
46
46
|
*/
|
|
47
47
|
function parseIPv6 (address) {
|
|
48
48
|
const buffer = Buffer.alloc(16)
|
|
49
|
-
const parts = address.split(':')
|
|
50
|
-
let partIndex = 0
|
|
51
|
-
let bufferIndex = 0
|
|
52
49
|
|
|
53
50
|
// Handle compressed notation (::)
|
|
54
51
|
const doubleColonIndex = address.indexOf('::')
|
|
55
52
|
if (doubleColonIndex !== -1) {
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
53
|
+
const before = address.slice(0, doubleColonIndex)
|
|
54
|
+
const after = address.slice(doubleColonIndex + 2)
|
|
55
|
+
const beforeParts = before === '' ? [] : before.split(':')
|
|
56
|
+
const afterParts = after === '' ? [] : after.split(':')
|
|
57
|
+
|
|
58
|
+
let bufferIndex = 0
|
|
59
|
+
for (const part of beforeParts) {
|
|
60
|
+
buffer.writeUInt16BE(parseInt(part, 16), bufferIndex)
|
|
61
|
+
bufferIndex += 2
|
|
62
|
+
}
|
|
63
|
+
bufferIndex = 16 - afterParts.length * 2
|
|
64
|
+
for (const part of afterParts) {
|
|
65
|
+
buffer.writeUInt16BE(parseInt(part, 16), bufferIndex)
|
|
66
|
+
bufferIndex += 2
|
|
69
67
|
}
|
|
70
68
|
} else {
|
|
71
|
-
|
|
72
|
-
for (
|
|
73
|
-
|
|
74
|
-
const value = parseInt(part, 16)
|
|
75
|
-
buffer.writeUInt16BE(value, partIndex * 2)
|
|
76
|
-
partIndex++
|
|
69
|
+
const parts = address.split(':')
|
|
70
|
+
for (let i = 0; i < parts.length; i++) {
|
|
71
|
+
buffer.writeUInt16BE(parseInt(parts[i], 16), i * 2)
|
|
77
72
|
}
|
|
78
73
|
}
|
|
79
74
|
|
|
@@ -69,9 +69,9 @@ function lazyllhttp () {
|
|
|
69
69
|
let useWasmSIMD = process.arch !== 'ppc64'
|
|
70
70
|
// The Env Variable UNDICI_NO_WASM_SIMD allows explicitly overriding the default behavior
|
|
71
71
|
if (process.env.UNDICI_NO_WASM_SIMD === '1') {
|
|
72
|
-
useWasmSIMD = true
|
|
73
|
-
} else if (process.env.UNDICI_NO_WASM_SIMD === '0') {
|
|
74
72
|
useWasmSIMD = false
|
|
73
|
+
} else if (process.env.UNDICI_NO_WASM_SIMD === '0') {
|
|
74
|
+
useWasmSIMD = true
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
if (useWasmSIMD) {
|
|
@@ -216,6 +216,7 @@ class Parser {
|
|
|
216
216
|
*/
|
|
217
217
|
this.socket = socket
|
|
218
218
|
this.timeout = null
|
|
219
|
+
this.timeoutWeakRef = new WeakRef(this)
|
|
219
220
|
this.timeoutValue = null
|
|
220
221
|
this.timeoutType = null
|
|
221
222
|
this.statusCode = 0
|
|
@@ -253,9 +254,9 @@ class Parser {
|
|
|
253
254
|
|
|
254
255
|
if (delay) {
|
|
255
256
|
if (type & USE_FAST_TIMER) {
|
|
256
|
-
this.timeout = timers.setFastTimeout(onParserTimeout, delay,
|
|
257
|
+
this.timeout = timers.setFastTimeout(onParserTimeout, delay, this.timeoutWeakRef)
|
|
257
258
|
} else {
|
|
258
|
-
this.timeout = setTimeout(onParserTimeout, delay,
|
|
259
|
+
this.timeout = setTimeout(onParserTimeout, delay, this.timeoutWeakRef)
|
|
259
260
|
this.timeout?.unref()
|
|
260
261
|
}
|
|
261
262
|
}
|
|
@@ -349,16 +350,7 @@ class Parser {
|
|
|
349
350
|
this.paused = true
|
|
350
351
|
socket.unshift(data)
|
|
351
352
|
} else {
|
|
352
|
-
|
|
353
|
-
let message = ''
|
|
354
|
-
if (ptr) {
|
|
355
|
-
const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0)
|
|
356
|
-
message =
|
|
357
|
-
'Response does not match the HTTP/1.1 protocol (' +
|
|
358
|
-
Buffer.from(llhttp.memory.buffer, ptr, len).toString() +
|
|
359
|
-
')'
|
|
360
|
-
}
|
|
361
|
-
throw new HTTPParserError(message, constants.ERROR[ret], data)
|
|
353
|
+
throw this.createError(ret, data)
|
|
362
354
|
}
|
|
363
355
|
}
|
|
364
356
|
} catch (err) {
|
|
@@ -366,6 +358,54 @@ class Parser {
|
|
|
366
358
|
}
|
|
367
359
|
}
|
|
368
360
|
|
|
361
|
+
finish () {
|
|
362
|
+
assert(currentParser === null)
|
|
363
|
+
assert(this.ptr != null)
|
|
364
|
+
assert(!this.paused)
|
|
365
|
+
|
|
366
|
+
const { llhttp } = this
|
|
367
|
+
|
|
368
|
+
let ret
|
|
369
|
+
|
|
370
|
+
try {
|
|
371
|
+
currentParser = this
|
|
372
|
+
ret = llhttp.llhttp_finish(this.ptr)
|
|
373
|
+
} finally {
|
|
374
|
+
currentParser = null
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (ret === constants.ERROR.OK) {
|
|
378
|
+
return null
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if (ret === constants.ERROR.PAUSED || ret === constants.ERROR.PAUSED_UPGRADE) {
|
|
382
|
+
this.paused = true
|
|
383
|
+
return null
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return this.createError(ret, EMPTY_BUF)
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
createError (ret, data) {
|
|
390
|
+
const { llhttp, contentLength, bytesRead } = this
|
|
391
|
+
|
|
392
|
+
if (contentLength && bytesRead !== parseInt(contentLength, 10)) {
|
|
393
|
+
return new ResponseContentLengthMismatchError()
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const ptr = llhttp.llhttp_get_error_reason(this.ptr)
|
|
397
|
+
let message = ''
|
|
398
|
+
if (ptr) {
|
|
399
|
+
const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0)
|
|
400
|
+
message =
|
|
401
|
+
'Response does not match the HTTP/1.1 protocol (' +
|
|
402
|
+
Buffer.from(llhttp.memory.buffer, ptr, len).toString() +
|
|
403
|
+
')'
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return new HTTPParserError(message, constants.ERROR[ret], data)
|
|
407
|
+
}
|
|
408
|
+
|
|
369
409
|
destroy () {
|
|
370
410
|
assert(currentParser === null)
|
|
371
411
|
assert(this.ptr != null)
|
|
@@ -870,8 +910,11 @@ function onHttpSocketError (err) {
|
|
|
870
910
|
// On Mac OS, we get an ECONNRESET even if there is a full body to be forwarded
|
|
871
911
|
// to the user.
|
|
872
912
|
if (err.code === 'ECONNRESET' && parser.statusCode && !parser.shouldKeepAlive) {
|
|
873
|
-
|
|
874
|
-
|
|
913
|
+
const parserErr = parser.finish()
|
|
914
|
+
if (parserErr) {
|
|
915
|
+
this[kError] = parserErr
|
|
916
|
+
this[kClient][kOnError](parserErr)
|
|
917
|
+
}
|
|
875
918
|
return
|
|
876
919
|
}
|
|
877
920
|
|
|
@@ -888,8 +931,10 @@ function onHttpSocketEnd () {
|
|
|
888
931
|
const parser = this[kParser]
|
|
889
932
|
|
|
890
933
|
if (parser.statusCode && !parser.shouldKeepAlive) {
|
|
891
|
-
|
|
892
|
-
|
|
934
|
+
const parserErr = parser.finish()
|
|
935
|
+
if (parserErr) {
|
|
936
|
+
util.destroy(this, parserErr)
|
|
937
|
+
}
|
|
893
938
|
return
|
|
894
939
|
}
|
|
895
940
|
|
|
@@ -901,8 +946,7 @@ function onHttpSocketClose () {
|
|
|
901
946
|
|
|
902
947
|
if (parser) {
|
|
903
948
|
if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) {
|
|
904
|
-
|
|
905
|
-
parser.onMessageComplete()
|
|
949
|
+
this[kError] = parser.finish() || this[kError]
|
|
906
950
|
}
|
|
907
951
|
|
|
908
952
|
this[kParser].destroy()
|
|
@@ -235,9 +235,13 @@ class Client extends DispatcherBase {
|
|
|
235
235
|
...(typeof autoSelectFamily === 'boolean' ? { autoSelectFamily, autoSelectFamilyAttemptTimeout } : undefined),
|
|
236
236
|
...connect
|
|
237
237
|
})
|
|
238
|
-
} else
|
|
238
|
+
} else {
|
|
239
239
|
const customConnect = connect
|
|
240
|
-
connect = (opts, callback) => customConnect({
|
|
240
|
+
connect = (opts, callback) => customConnect({
|
|
241
|
+
...opts,
|
|
242
|
+
...(socketPath != null ? { socketPath } : null),
|
|
243
|
+
...(allowH2 != null ? { allowH2 } : null)
|
|
244
|
+
}, callback)
|
|
241
245
|
}
|
|
242
246
|
|
|
243
247
|
this[kUrl] = util.parseOrigin(url)
|
|
@@ -15,7 +15,7 @@ class H2CClient extends Client {
|
|
|
15
15
|
)
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
const {
|
|
18
|
+
const { maxConcurrentStreams, pipelining, ...opts } =
|
|
19
19
|
clientOpts ?? {}
|
|
20
20
|
let defaultMaxConcurrentStreams = 100
|
|
21
21
|
let defaultPipelining = 100
|
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
const { kMockCallHistoryAddLog } = require('./mock-symbols')
|
|
4
4
|
const { InvalidArgumentError } = require('../core/errors')
|
|
5
5
|
|
|
6
|
-
function handleFilterCallsWithOptions (criteria, options, handler, store) {
|
|
6
|
+
function handleFilterCallsWithOptions (criteria, options, handler, store, allLogs) {
|
|
7
7
|
switch (options.operator) {
|
|
8
8
|
case 'OR':
|
|
9
|
-
store.push(...handler(criteria))
|
|
9
|
+
store.push(...handler(criteria, allLogs))
|
|
10
10
|
|
|
11
11
|
return store
|
|
12
12
|
case 'AND':
|
|
13
|
-
return handler
|
|
13
|
+
return handler(criteria, store)
|
|
14
14
|
default:
|
|
15
15
|
// guard -- should never happens because buildAndValidateFilterCallsOptions is called before
|
|
16
16
|
throw new InvalidArgumentError('options.operator must to be a case insensitive string equal to \'OR\' or \'AND\'')
|
|
@@ -35,14 +35,14 @@ function buildAndValidateFilterCallsOptions (options = {}) {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
function makeFilterCalls (parameterName) {
|
|
38
|
-
return (parameterValue) => {
|
|
38
|
+
return (parameterValue, logs) => {
|
|
39
39
|
if (typeof parameterValue === 'string' || parameterValue == null) {
|
|
40
|
-
return
|
|
40
|
+
return logs.filter((log) => {
|
|
41
41
|
return log[parameterName] === parameterValue
|
|
42
42
|
})
|
|
43
43
|
}
|
|
44
44
|
if (parameterValue instanceof RegExp) {
|
|
45
|
-
return
|
|
45
|
+
return logs.filter((log) => {
|
|
46
46
|
return parameterValue.test(log[parameterName])
|
|
47
47
|
})
|
|
48
48
|
}
|
|
@@ -175,30 +175,30 @@ class MockCallHistory {
|
|
|
175
175
|
|
|
176
176
|
const finalOptions = { operator: 'OR', ...buildAndValidateFilterCallsOptions(options) }
|
|
177
177
|
|
|
178
|
-
let maybeDuplicatedLogsFiltered = []
|
|
178
|
+
let maybeDuplicatedLogsFiltered = finalOptions.operator === 'AND' ? this.logs : []
|
|
179
179
|
if ('protocol' in criteria) {
|
|
180
|
-
maybeDuplicatedLogsFiltered = handleFilterCallsWithOptions(criteria.protocol, finalOptions, this.filterCallsByProtocol, maybeDuplicatedLogsFiltered)
|
|
180
|
+
maybeDuplicatedLogsFiltered = handleFilterCallsWithOptions(criteria.protocol, finalOptions, this.filterCallsByProtocol, maybeDuplicatedLogsFiltered, this.logs)
|
|
181
181
|
}
|
|
182
182
|
if ('host' in criteria) {
|
|
183
|
-
maybeDuplicatedLogsFiltered = handleFilterCallsWithOptions(criteria.host, finalOptions, this.filterCallsByHost, maybeDuplicatedLogsFiltered)
|
|
183
|
+
maybeDuplicatedLogsFiltered = handleFilterCallsWithOptions(criteria.host, finalOptions, this.filterCallsByHost, maybeDuplicatedLogsFiltered, this.logs)
|
|
184
184
|
}
|
|
185
185
|
if ('port' in criteria) {
|
|
186
|
-
maybeDuplicatedLogsFiltered = handleFilterCallsWithOptions(criteria.port, finalOptions, this.filterCallsByPort, maybeDuplicatedLogsFiltered)
|
|
186
|
+
maybeDuplicatedLogsFiltered = handleFilterCallsWithOptions(criteria.port, finalOptions, this.filterCallsByPort, maybeDuplicatedLogsFiltered, this.logs)
|
|
187
187
|
}
|
|
188
188
|
if ('origin' in criteria) {
|
|
189
|
-
maybeDuplicatedLogsFiltered = handleFilterCallsWithOptions(criteria.origin, finalOptions, this.filterCallsByOrigin, maybeDuplicatedLogsFiltered)
|
|
189
|
+
maybeDuplicatedLogsFiltered = handleFilterCallsWithOptions(criteria.origin, finalOptions, this.filterCallsByOrigin, maybeDuplicatedLogsFiltered, this.logs)
|
|
190
190
|
}
|
|
191
191
|
if ('path' in criteria) {
|
|
192
|
-
maybeDuplicatedLogsFiltered = handleFilterCallsWithOptions(criteria.path, finalOptions, this.filterCallsByPath, maybeDuplicatedLogsFiltered)
|
|
192
|
+
maybeDuplicatedLogsFiltered = handleFilterCallsWithOptions(criteria.path, finalOptions, this.filterCallsByPath, maybeDuplicatedLogsFiltered, this.logs)
|
|
193
193
|
}
|
|
194
194
|
if ('hash' in criteria) {
|
|
195
|
-
maybeDuplicatedLogsFiltered = handleFilterCallsWithOptions(criteria.hash, finalOptions, this.filterCallsByHash, maybeDuplicatedLogsFiltered)
|
|
195
|
+
maybeDuplicatedLogsFiltered = handleFilterCallsWithOptions(criteria.hash, finalOptions, this.filterCallsByHash, maybeDuplicatedLogsFiltered, this.logs)
|
|
196
196
|
}
|
|
197
197
|
if ('fullUrl' in criteria) {
|
|
198
|
-
maybeDuplicatedLogsFiltered = handleFilterCallsWithOptions(criteria.fullUrl, finalOptions, this.filterCallsByFullUrl, maybeDuplicatedLogsFiltered)
|
|
198
|
+
maybeDuplicatedLogsFiltered = handleFilterCallsWithOptions(criteria.fullUrl, finalOptions, this.filterCallsByFullUrl, maybeDuplicatedLogsFiltered, this.logs)
|
|
199
199
|
}
|
|
200
200
|
if ('method' in criteria) {
|
|
201
|
-
maybeDuplicatedLogsFiltered = handleFilterCallsWithOptions(criteria.method, finalOptions, this.filterCallsByMethod, maybeDuplicatedLogsFiltered)
|
|
201
|
+
maybeDuplicatedLogsFiltered = handleFilterCallsWithOptions(criteria.method, finalOptions, this.filterCallsByMethod, maybeDuplicatedLogsFiltered, this.logs)
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
const uniqLogsFiltered = [...new Set(maybeDuplicatedLogsFiltered)]
|
|
@@ -18,7 +18,7 @@ function makeCacheKey (opts) {
|
|
|
18
18
|
|
|
19
19
|
let fullPath = opts.path || '/'
|
|
20
20
|
|
|
21
|
-
if (opts.query && !pathHasQueryOrFragment(
|
|
21
|
+
if (opts.query && !pathHasQueryOrFragment(fullPath)) {
|
|
22
22
|
fullPath = serializePathWithQuery(fullPath, opts.query)
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -374,9 +374,11 @@ function assertCacheMethods (methods, name = 'CacheMethods') {
|
|
|
374
374
|
* @returns {string}
|
|
375
375
|
*/
|
|
376
376
|
function makeDeduplicationKey (cacheKey, excludeHeaders) {
|
|
377
|
-
//
|
|
378
|
-
//
|
|
379
|
-
|
|
377
|
+
// Use JSON.stringify to produce a collision-resistant key.
|
|
378
|
+
// Previous format used `:` and `=` delimiters without escaping, which
|
|
379
|
+
// allowed different header sets to produce identical keys (e.g.
|
|
380
|
+
// {a:"x:b=y"} vs {a:"x", b:"y"}). See: https://github.com/nodejs/undici/issues/5012
|
|
381
|
+
const headers = {}
|
|
380
382
|
|
|
381
383
|
if (cacheKey.headers) {
|
|
382
384
|
const sortedHeaders = Object.keys(cacheKey.headers).sort()
|
|
@@ -385,12 +387,11 @@ function makeDeduplicationKey (cacheKey, excludeHeaders) {
|
|
|
385
387
|
if (excludeHeaders?.has(header.toLowerCase())) {
|
|
386
388
|
continue
|
|
387
389
|
}
|
|
388
|
-
|
|
389
|
-
key += `:${header}=${Array.isArray(value) ? value.join(',') : value}`
|
|
390
|
+
headers[header] = cacheKey.headers[header]
|
|
390
391
|
}
|
|
391
392
|
}
|
|
392
393
|
|
|
393
|
-
return
|
|
394
|
+
return JSON.stringify([cacheKey.origin, cacheKey.method, cacheKey.path, headers])
|
|
394
395
|
}
|
|
395
396
|
|
|
396
397
|
module.exports = {
|
|
@@ -204,7 +204,7 @@ function multipartFormDataParser (input, mimeType) {
|
|
|
204
204
|
* Parses content-disposition attributes (e.g., name="value" or filename*=utf-8''encoded)
|
|
205
205
|
* @param {Buffer} input
|
|
206
206
|
* @param {{ position: number }} position
|
|
207
|
-
* @returns {{ name: string, value: string }}
|
|
207
|
+
* @returns {{ name: string, value: string, extended: boolean } | null}
|
|
208
208
|
*/
|
|
209
209
|
function parseContentDispositionAttribute (input, position) {
|
|
210
210
|
// Skip leading semicolon and whitespace
|
|
@@ -304,7 +304,7 @@ function parseContentDispositionAttribute (input, position) {
|
|
|
304
304
|
value = decoder.decode(tokenValue)
|
|
305
305
|
}
|
|
306
306
|
|
|
307
|
-
return { name: attrNameStr, value }
|
|
307
|
+
return { name: attrNameStr, value, extended: isExtended }
|
|
308
308
|
}
|
|
309
309
|
|
|
310
310
|
/**
|
|
@@ -368,6 +368,9 @@ function parseMultipartFormDataHeaders (input, position) {
|
|
|
368
368
|
switch (bufferToLowerCasedHeaderName(headerName)) {
|
|
369
369
|
case 'content-disposition': {
|
|
370
370
|
name = filename = null
|
|
371
|
+
// Track whether filename was set from the extended (RFC 5987) form so
|
|
372
|
+
// a subsequent legacy `filename` attribute does not override it.
|
|
373
|
+
let filenameIsExtended = false
|
|
371
374
|
|
|
372
375
|
// Collect the disposition type (should be "form-data")
|
|
373
376
|
const dispositionType = collectASequenceOfBytes(
|
|
@@ -383,8 +386,8 @@ function parseMultipartFormDataHeaders (input, position) {
|
|
|
383
386
|
// Parse attributes recursively until CRLF
|
|
384
387
|
while (
|
|
385
388
|
position.position < input.length &&
|
|
386
|
-
input[position.position] !== 0x0d
|
|
387
|
-
input[position.position + 1] !== 0x0a
|
|
389
|
+
(input[position.position] !== 0x0d ||
|
|
390
|
+
input[position.position + 1] !== 0x0a)
|
|
388
391
|
) {
|
|
389
392
|
const attribute = parseContentDispositionAttribute(input, position)
|
|
390
393
|
|
|
@@ -395,7 +398,15 @@ function parseMultipartFormDataHeaders (input, position) {
|
|
|
395
398
|
if (attribute.name === 'name') {
|
|
396
399
|
name = attribute.value
|
|
397
400
|
} else if (attribute.name === 'filename') {
|
|
398
|
-
|
|
401
|
+
// Per RFC 5987 §4.1, when both legacy and extended forms of the
|
|
402
|
+
// same parameter are present, the extended (filename*) form takes
|
|
403
|
+
// precedence regardless of the order they appear in.
|
|
404
|
+
if (attribute.extended) {
|
|
405
|
+
filename = attribute.value
|
|
406
|
+
filenameIsExtended = true
|
|
407
|
+
} else if (!filenameIsExtended) {
|
|
408
|
+
filename = attribute.value
|
|
409
|
+
}
|
|
399
410
|
}
|
|
400
411
|
}
|
|
401
412
|
|
|
@@ -448,7 +459,7 @@ function parseMultipartFormDataHeaders (input, position) {
|
|
|
448
459
|
|
|
449
460
|
// 2.9. If position does not point to a sequence of bytes starting with 0x0D 0x0A
|
|
450
461
|
// (CR LF), return failure. Otherwise, advance position by 2 (past the newline).
|
|
451
|
-
if (input[position.position] !== 0x0d
|
|
462
|
+
if (input[position.position] !== 0x0d || input[position.position + 1] !== 0x0a) {
|
|
452
463
|
throw parsingError('expected CRLF')
|
|
453
464
|
} else {
|
|
454
465
|
position.position += 2
|
|
@@ -1030,7 +1030,7 @@ function fetchFinale (fetchParams, response) {
|
|
|
1030
1030
|
let responseStatus = 0
|
|
1031
1031
|
|
|
1032
1032
|
// 7. If fetchParams’s request’s mode is not "navigate" or response’s has-cross-origin-redirects is false:
|
|
1033
|
-
if (fetchParams.request.mode !== '
|
|
1033
|
+
if (fetchParams.request.mode !== 'navigate' || !response.hasCrossOriginRedirects) {
|
|
1034
1034
|
// 1. Set responseStatus to response’s status.
|
|
1035
1035
|
responseStatus = response.status
|
|
1036
1036
|
|
|
@@ -1433,7 +1433,10 @@ async function httpNetworkOrCacheFetch (
|
|
|
1433
1433
|
// 8. If contentLengthHeaderValue is non-null, then append
|
|
1434
1434
|
// `Content-Length`/contentLengthHeaderValue to httpRequest’s header
|
|
1435
1435
|
// list.
|
|
1436
|
-
if (
|
|
1436
|
+
if (
|
|
1437
|
+
contentLengthHeaderValue != null &&
|
|
1438
|
+
!httpRequest.headersList.contains('content-length', true)
|
|
1439
|
+
) {
|
|
1437
1440
|
httpRequest.headersList.append('content-length', contentLengthHeaderValue, true)
|
|
1438
1441
|
}
|
|
1439
1442
|
|
|
@@ -190,10 +190,10 @@ webidl.util.ConvertToInt = function (V, bitLength, signedness, flags) {
|
|
|
190
190
|
} else {
|
|
191
191
|
// 3. Otherwise:
|
|
192
192
|
|
|
193
|
-
// 1. Let lowerBound be -2^bitLength − 1.
|
|
194
|
-
lowerBound = Math.pow(
|
|
193
|
+
// 1. Let lowerBound be -2^(bitLength − 1).
|
|
194
|
+
lowerBound = -Math.pow(2, bitLength - 1)
|
|
195
195
|
|
|
196
|
-
// 2. Let upperBound be 2^bitLength − 1 − 1.
|
|
196
|
+
// 2. Let upperBound be 2^(bitLength − 1) − 1.
|
|
197
197
|
upperBound = Math.pow(2, bitLength - 1) - 1
|
|
198
198
|
}
|
|
199
199
|
|
|
@@ -272,9 +272,9 @@ webidl.util.ConvertToInt = function (V, bitLength, signedness, flags) {
|
|
|
272
272
|
// 10. Set x to x modulo 2^bitLength.
|
|
273
273
|
x = x % Math.pow(2, bitLength)
|
|
274
274
|
|
|
275
|
-
// 11. If signedness is "signed" and x ≥ 2^bitLength − 1,
|
|
275
|
+
// 11. If signedness is "signed" and x ≥ 2^(bitLength − 1),
|
|
276
276
|
// then return x − 2^bitLength.
|
|
277
|
-
if (signedness === 'signed' && x >= Math.pow(2, bitLength
|
|
277
|
+
if (signedness === 'signed' && x >= Math.pow(2, bitLength - 1)) {
|
|
278
278
|
return x - Math.pow(2, bitLength)
|
|
279
279
|
}
|
|
280
280
|
|
|
@@ -284,12 +284,6 @@ class WebSocketStream {
|
|
|
284
284
|
start: (controller) => {
|
|
285
285
|
this.#readableStreamController = controller
|
|
286
286
|
},
|
|
287
|
-
pull (controller) {
|
|
288
|
-
let chunk
|
|
289
|
-
while (controller.desiredSize > 0 && (chunk = response.socket.read()) !== null) {
|
|
290
|
-
controller.enqueue(chunk)
|
|
291
|
-
}
|
|
292
|
-
},
|
|
293
287
|
cancel: (reason) => this.#cancel(reason)
|
|
294
288
|
})
|
|
295
289
|
|
|
@@ -338,7 +332,7 @@ class WebSocketStream {
|
|
|
338
332
|
try {
|
|
339
333
|
chunk = utf8Decode(data)
|
|
340
334
|
} catch {
|
|
341
|
-
failWebsocketConnection(this.#handler, 'Received invalid UTF-8 in text frame.')
|
|
335
|
+
failWebsocketConnection(this.#handler, 1007, 'Received invalid UTF-8 in text frame.')
|
|
342
336
|
return
|
|
343
337
|
}
|
|
344
338
|
} else if (type === opcodes.BINARY) {
|