@openclaw/slack 2026.7.2-beta.7 → 2026.8.1-beta.3
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/dist/{account-inspect-DEKpg9Ip.js → account-inspect-YJvFBbCR.js} +1 -1
- package/dist/account-inspect-api.js +1 -1
- package/dist/{accounts-CHAeNZOX.js → accounts-BlzxuYle.js} +7 -3
- package/dist/{accounts.runtime-BHD4Ma2R.js → accounts.runtime-CbabBL8x.js} +1 -1
- package/dist/{action-runtime-DfuYoMjG.js → action-runtime-D6jg2CQd.js} +193 -125
- package/dist/action-runtime.runtime-JtoOK9l5.js +2 -0
- package/dist/{actions-D3NuJvva.js → actions-DFk0ANVB.js} +116 -235
- package/dist/actions.runtime-CYLsYRai.js +2 -0
- package/dist/api.js +17 -17
- package/dist/{approval-handler.runtime-BA05P0QT.js → approval-handler.runtime-BNvAoKdK.js} +53 -14
- package/dist/{channel-B9fVdW3s.js → channel-CA5w7qDF.js} +209 -110
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel-type-DXyos1d2.js → channel-type-CZWv55Wu.js} +9 -12
- package/dist/{config-adapter-CxBQH8fq.js → channel.setup-CpyYsEXH.js} +83 -25
- package/dist/{config-schema-SgZT6nXV.js → config-schema-CN3XZRX5.js} +27 -17
- package/dist/conversation-binding-route-DFVLUdYF.js +115 -0
- package/dist/{directory-config-CnCIAktf.js → directory-config-BGYyuzWh.js} +3 -3
- package/dist/directory-contract-api.js +1 -1
- package/dist/{directory-live-DKunWh3A.js → directory-live-DjUJQLbq.js} +13 -22
- package/dist/{doctor-contract-CsGH1Dfc.js → doctor-contract-BAy7-EUQ.js} +30 -3
- package/dist/doctor-contract-api.js +1 -1
- package/dist/{group-policy-NQZti9t-.js → group-policy-DyfB_ZIE.js} +282 -183
- package/dist/index.js +4 -1
- package/dist/{message-tool-api-DkhFpMoy.js → message-tool-api-CqMr5Rmc.js} +14 -3
- package/dist/message-tool-api.js +1 -1
- package/dist/{monitor-CmKz0wtI.js → monitor-Chrecrb9.js} +3 -3
- package/dist/{outbound-adapter-BkuMp2Vs.js → outbound-adapter-DuRqAQXK.js} +35 -23
- package/dist/{pipeline.runtime-DgtmuYCP.js → pipeline.runtime-Bbfd5VFW.js} +1386 -929
- package/dist/{policy-PRysPn23.js → policy-BKXSxrIS.js} +18 -14
- package/dist/{probe-CgDsSops.js → probe-BVA65leh.js} +38 -18
- package/dist/{provider-DmRizMZt.js → provider-CUUiwsg2.js} +3454 -2601
- package/dist/{relay-source-Blxj8xb4.js → relay-source-mhpMMRG-.js} +11 -21
- package/dist/{replies-4s_Vq_z9.js → replies-SnWyXcsL.js} +84 -27
- package/dist/{resolve-channels-yEqmM-3I.js → resolve-channels-BSpqC8jU.js} +39 -12
- package/dist/{resolve-users-BOrt5K-5.js → resolve-users-Dvz9pDe0.js} +28 -5
- package/dist/{runtime-api-QMb-Q5Ko.js → runtime-api-DBi7xc_g.js} +3 -3
- package/dist/runtime-api.js +11 -11
- package/dist/{scopes-BJSrkAp6.js → scopes-BSk4GZvZ.js} +1 -1
- package/dist/security-contract-api.js +1 -1
- package/dist/{send-DsLeZpST.js → send-CtnOxKCc.js} +249 -163
- package/dist/{send.runtime-gUdK6V3h.js → send.runtime-kYctMHSd.js} +1 -1
- package/dist/setup-entry.js +1 -4
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{setup-surface-BeNzrMrJ.js → setup-surface-BPFfp6So.js} +6 -6
- package/dist/{shared-DgIN3Dcr.js → shared-DJBaslN7.js} +45 -45
- package/dist/{block-text-DkHaoGem.js → slack-client-kind-BXyOOICI.js} +17 -2
- package/dist/{slash-dispatch.runtime-zPkyl7dB.js → slash-dispatch.runtime-Cf2FTrnf.js} +2 -2
- package/dist/{streaming-compat-3_X-21wW.js → streaming-compat-B-e0mqM0.js} +3 -8
- package/dist/{target-parsing-N6lHogYZ.js → target-parsing-BnMD2ZqZ.js} +40 -2
- package/dist/{targets-KmjP2E8s.js → targets-Cx5W_n3W.js} +1 -1
- package/node_modules/@slack/bolt/node_modules/@types/node/README.md +1 -1
- package/node_modules/@slack/bolt/node_modules/@types/node/crypto.d.ts +1 -1
- package/node_modules/@slack/bolt/node_modules/@types/node/package.json +2 -2
- package/node_modules/@slack/socket-mode/node_modules/@types/node/README.md +1 -1
- package/node_modules/@slack/socket-mode/node_modules/@types/node/crypto.d.ts +1 -1
- package/node_modules/@slack/socket-mode/node_modules/@types/node/package.json +2 -2
- package/node_modules/@slack/web-api/node_modules/@types/node/README.md +1 -1
- package/node_modules/@slack/web-api/node_modules/@types/node/crypto.d.ts +1 -1
- package/node_modules/@slack/web-api/node_modules/@types/node/package.json +2 -2
- package/node_modules/undici/lib/cache/memory-cache-store.js +54 -9
- package/node_modules/undici/lib/cache/sqlite-cache-store.js +7 -1
- package/node_modules/undici/lib/core/request.js +12 -1
- package/node_modules/undici/lib/dispatcher/client-h1.js +11 -2
- package/node_modules/undici/lib/handler/cache-handler.js +246 -64
- package/node_modules/undici/lib/handler/cache-revalidation-handler.js +3 -3
- package/node_modules/undici/lib/handler/retry-handler.js +24 -0
- package/node_modules/undici/lib/interceptor/cache.js +159 -52
- package/node_modules/undici/lib/util/cache.js +324 -62
- package/node_modules/undici/lib/util/date.js +23 -6
- package/node_modules/undici/lib/web/cookies/util.js +79 -9
- package/node_modules/undici/package.json +1 -1
- package/openclaw.plugin.json +280 -33
- package/package.json +9 -11
- package/skills/slack/SKILL.md +10 -68
- package/dist/account-reply-mode-DrUXogvO.js +0 -14
- package/dist/action-runtime.runtime-DQErZYpz.js +0 -2
- package/dist/actions.runtime-BIRU_G4M.js +0 -2
- package/dist/channel.setup-CLP5oTvh.js +0 -56
- package/dist/preflight-audio.runtime-D5Bgags0.js +0 -3
- package/dist/slash-plugin-commands.runtime-Dosfcx3X.js +0 -2
- package/node_modules/p-map/index.d.ts +0 -155
- package/node_modules/p-map/index.js +0 -285
- package/node_modules/p-map/license +0 -9
- package/node_modules/p-map/package.json +0 -57
- package/node_modules/p-map/readme.md +0 -190
- package/dist/{security-audit-DR097212.js → security-audit-B_yKr7MW.js} +1 -1
|
@@ -3,11 +3,147 @@
|
|
|
3
3
|
const {
|
|
4
4
|
safeHTTPMethods,
|
|
5
5
|
pathHasQueryOrFragment,
|
|
6
|
-
hasSafeIterator
|
|
6
|
+
hasSafeIterator,
|
|
7
|
+
isValidHTTPToken
|
|
7
8
|
} = require('../core/util')
|
|
8
9
|
|
|
9
10
|
const { serializePathWithQuery } = require('../core/util')
|
|
10
11
|
|
|
12
|
+
const MAX_DELTA_SECONDS = 2147483647
|
|
13
|
+
const RESTRICTIVE_DIRECTIVE_NAMES = ['no-store', 'private', 'no-cache']
|
|
14
|
+
const kInvalidCacheControlDirectives = Symbol('invalid cache-control directives')
|
|
15
|
+
|
|
16
|
+
function trimOWS (value) {
|
|
17
|
+
return value.replace(/^[\t ]+|[\t ]+$/g, '')
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function arrayIncludes (array, value) {
|
|
21
|
+
for (let i = 0; i < array.length; i++) {
|
|
22
|
+
if (array[i] === value) {
|
|
23
|
+
return true
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return false
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function trimOWSStart (value) {
|
|
31
|
+
return value.replace(/^[\t ]+/, '')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function trimOWSEnd (value) {
|
|
35
|
+
return value.replace(/[\t ]+$/, '')
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function findUnescapedQuote (value, start) {
|
|
39
|
+
let escaped = false
|
|
40
|
+
for (let i = start; i < value.length; i++) {
|
|
41
|
+
if (escaped) {
|
|
42
|
+
escaped = false
|
|
43
|
+
} else if (value[i] === '\\') {
|
|
44
|
+
escaped = true
|
|
45
|
+
} else if (value[i] === '"') {
|
|
46
|
+
return i
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return -1
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function splitCacheControlHeaderValue (value) {
|
|
54
|
+
const directives = []
|
|
55
|
+
let start = 0
|
|
56
|
+
let quoteStart = -1
|
|
57
|
+
let inQuote = false
|
|
58
|
+
let escaped = false
|
|
59
|
+
|
|
60
|
+
for (let i = 0; i < value.length; i++) {
|
|
61
|
+
if (inQuote) {
|
|
62
|
+
if (escaped) {
|
|
63
|
+
escaped = false
|
|
64
|
+
} else if (value[i] === '\\') {
|
|
65
|
+
escaped = true
|
|
66
|
+
} else if (value[i] === '"') {
|
|
67
|
+
inQuote = false
|
|
68
|
+
quoteStart = -1
|
|
69
|
+
}
|
|
70
|
+
} else if (value[i] === '"') {
|
|
71
|
+
inQuote = true
|
|
72
|
+
quoteStart = i
|
|
73
|
+
} else if (value[i] === ',') {
|
|
74
|
+
directives.push({ value: value.substring(start, i), fromMalformedQuote: false })
|
|
75
|
+
start = i + 1
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!inQuote) {
|
|
80
|
+
directives.push({ value: value.substring(start), fromMalformedQuote: false })
|
|
81
|
+
return directives
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const tail = value.substring(start)
|
|
85
|
+
const quoteOffset = quoteStart - start
|
|
86
|
+
let tailStart = 0
|
|
87
|
+
for (let i = 0; i < tail.length; i++) {
|
|
88
|
+
if (tail[i] === ',') {
|
|
89
|
+
directives.push({
|
|
90
|
+
value: tail.substring(tailStart, i),
|
|
91
|
+
fromMalformedQuote: tailStart > quoteOffset
|
|
92
|
+
})
|
|
93
|
+
tailStart = i + 1
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
directives.push({
|
|
98
|
+
value: tail.substring(tailStart),
|
|
99
|
+
fromMalformedQuote: tailStart > quoteOffset
|
|
100
|
+
})
|
|
101
|
+
return directives
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function markInvalidCacheControlDirective (directives, key) {
|
|
105
|
+
let invalidDirectives = directives[kInvalidCacheControlDirectives]
|
|
106
|
+
|
|
107
|
+
if (invalidDirectives === undefined) {
|
|
108
|
+
invalidDirectives = new Set()
|
|
109
|
+
Object.defineProperty(directives, kInvalidCacheControlDirectives, {
|
|
110
|
+
value: invalidDirectives
|
|
111
|
+
})
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
invalidDirectives.add(key)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function hasInvalidCacheControlDirective (directives, key) {
|
|
118
|
+
return directives[kInvalidCacheControlDirectives]?.has(key) === true
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function getMalformedRestrictiveDirectiveName (key) {
|
|
122
|
+
for (const directiveName of RESTRICTIVE_DIRECTIVE_NAMES) {
|
|
123
|
+
if (
|
|
124
|
+
key.startsWith(directiveName) &&
|
|
125
|
+
key.length > directiveName.length &&
|
|
126
|
+
!isValidHTTPToken(key[directiveName.length])
|
|
127
|
+
) {
|
|
128
|
+
return directiveName
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
let tokenOnlyKey = ''
|
|
133
|
+
let hasInvalidTokenChar = false
|
|
134
|
+
for (let i = 0; i < key.length; i++) {
|
|
135
|
+
if (isValidHTTPToken(key[i])) {
|
|
136
|
+
tokenOnlyKey += key[i]
|
|
137
|
+
} else {
|
|
138
|
+
hasInvalidTokenChar = true
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (hasInvalidTokenChar && arrayIncludes(RESTRICTIVE_DIRECTIVE_NAMES, tokenOnlyKey)) {
|
|
143
|
+
return tokenOnlyKey
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
11
147
|
/**
|
|
12
148
|
* @param {import('../../types/dispatcher.d.ts').default.DispatchOptions} opts
|
|
13
149
|
*/
|
|
@@ -30,6 +166,20 @@ function makeCacheKey (opts) {
|
|
|
30
166
|
}
|
|
31
167
|
}
|
|
32
168
|
|
|
169
|
+
function appendHeader (headers, key, val) {
|
|
170
|
+
const headerName = key.toLowerCase()
|
|
171
|
+
const current = headers[headerName]
|
|
172
|
+
const values = Array.isArray(val) ? val : [val]
|
|
173
|
+
|
|
174
|
+
if (current === undefined) {
|
|
175
|
+
headers[headerName] = Array.isArray(val) ? val.slice() : val
|
|
176
|
+
} else if (Array.isArray(current)) {
|
|
177
|
+
current.push(...values)
|
|
178
|
+
} else {
|
|
179
|
+
headers[headerName] = [current, ...values]
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
33
183
|
/**
|
|
34
184
|
* @param {Record<string, string[] | string>}
|
|
35
185
|
* @returns {Record<string, string[] | string>}
|
|
@@ -50,11 +200,11 @@ function normalizeHeaders (opts) {
|
|
|
50
200
|
if (typeof key !== 'string' || typeof val !== 'string') {
|
|
51
201
|
throw new Error('opts.headers is not a valid header map')
|
|
52
202
|
}
|
|
53
|
-
headers
|
|
203
|
+
appendHeader(headers, key, val)
|
|
54
204
|
}
|
|
55
205
|
} else {
|
|
56
206
|
for (const key of Object.keys(opts.headers)) {
|
|
57
|
-
headers
|
|
207
|
+
appendHeader(headers, key, opts.headers[key])
|
|
58
208
|
}
|
|
59
209
|
}
|
|
60
210
|
} else {
|
|
@@ -126,29 +276,37 @@ function parseCacheControlHeader (header) {
|
|
|
126
276
|
* @type {import('../../types/cache-interceptor.d.ts').default.CacheControlDirectives}
|
|
127
277
|
*/
|
|
128
278
|
const output = {}
|
|
279
|
+
const invalidNumericDirectives = new Set()
|
|
280
|
+
const invalidNoArgumentDirectives = new Set()
|
|
129
281
|
|
|
130
|
-
|
|
131
|
-
if (Array.isArray(header)) {
|
|
132
|
-
directives = []
|
|
133
|
-
|
|
134
|
-
for (const directive of header) {
|
|
135
|
-
directives.push(...directive.split(','))
|
|
136
|
-
}
|
|
137
|
-
} else {
|
|
138
|
-
directives = header.split(',')
|
|
139
|
-
}
|
|
282
|
+
const directives = splitCacheControlHeaderValue(Array.isArray(header) ? header.join(',') : header)
|
|
140
283
|
|
|
141
284
|
for (let i = 0; i < directives.length; i++) {
|
|
142
|
-
const
|
|
285
|
+
const directiveRecord = directives[i]
|
|
286
|
+
const directive = directiveRecord.value.toLowerCase()
|
|
287
|
+
const fromMalformedQuote = directiveRecord.fromMalformedQuote
|
|
143
288
|
const keyValueDelimiter = directive.indexOf('=')
|
|
144
289
|
|
|
145
290
|
let key
|
|
146
291
|
let value
|
|
292
|
+
let keyHasTrailingWhitespace = false
|
|
293
|
+
let valueHasLeadingWhitespace = false
|
|
147
294
|
if (keyValueDelimiter !== -1) {
|
|
148
|
-
|
|
149
|
-
|
|
295
|
+
const rawKey = directive.substring(0, keyValueDelimiter)
|
|
296
|
+
const rawValue = directive.substring(keyValueDelimiter + 1)
|
|
297
|
+
|
|
298
|
+
keyHasTrailingWhitespace = trimOWSEnd(rawKey) !== rawKey
|
|
299
|
+
valueHasLeadingWhitespace = trimOWSStart(rawValue) !== rawValue
|
|
300
|
+
key = trimOWS(rawKey)
|
|
301
|
+
value = trimOWSStart(rawValue)
|
|
150
302
|
} else {
|
|
151
|
-
key = directive
|
|
303
|
+
key = trimOWS(directive)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const malformedRestrictiveDirectiveName = getMalformedRestrictiveDirectiveName(key)
|
|
307
|
+
if (malformedRestrictiveDirectiveName !== undefined) {
|
|
308
|
+
output[malformedRestrictiveDirectiveName] = true
|
|
309
|
+
continue
|
|
152
310
|
}
|
|
153
311
|
|
|
154
312
|
switch (key) {
|
|
@@ -158,7 +316,14 @@ function parseCacheControlHeader (header) {
|
|
|
158
316
|
case 's-maxage':
|
|
159
317
|
case 'stale-while-revalidate':
|
|
160
318
|
case 'stale-if-error': {
|
|
161
|
-
if (
|
|
319
|
+
if (fromMalformedQuote || invalidNumericDirectives.has(key)) {
|
|
320
|
+
continue
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (value === undefined || keyHasTrailingWhitespace || valueHasLeadingWhitespace) {
|
|
324
|
+
delete output[key]
|
|
325
|
+
invalidNumericDirectives.add(key)
|
|
326
|
+
markInvalidCacheControlDirective(output, key)
|
|
162
327
|
continue
|
|
163
328
|
}
|
|
164
329
|
|
|
@@ -170,22 +335,37 @@ function parseCacheControlHeader (header) {
|
|
|
170
335
|
value = value.substring(1, value.length - 1)
|
|
171
336
|
}
|
|
172
337
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
338
|
+
if (!/^[0-9]+$/.test(value)) {
|
|
339
|
+
delete output[key]
|
|
340
|
+
invalidNumericDirectives.add(key)
|
|
341
|
+
markInvalidCacheControlDirective(output, key)
|
|
176
342
|
continue
|
|
177
343
|
}
|
|
178
344
|
|
|
179
|
-
|
|
180
|
-
continue
|
|
181
|
-
}
|
|
345
|
+
const parsedValue = Math.min(parseInt(value, 10), MAX_DELTA_SECONDS)
|
|
182
346
|
|
|
183
|
-
|
|
347
|
+
if (key === 'min-fresh') {
|
|
348
|
+
if (!(key in output) || output[key] < parsedValue) {
|
|
349
|
+
output[key] = parsedValue
|
|
350
|
+
}
|
|
351
|
+
} else if (!(key in output) || output[key] > parsedValue) {
|
|
352
|
+
output[key] = parsedValue
|
|
353
|
+
}
|
|
184
354
|
|
|
185
355
|
break
|
|
186
356
|
}
|
|
187
357
|
case 'private':
|
|
188
358
|
case 'no-cache': {
|
|
359
|
+
if (fromMalformedQuote) {
|
|
360
|
+
output[key] = true
|
|
361
|
+
break
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if (value !== undefined && value.length === 0) {
|
|
365
|
+
output[key] = true
|
|
366
|
+
break
|
|
367
|
+
}
|
|
368
|
+
|
|
189
369
|
if (value) {
|
|
190
370
|
// The private and no-cache directives can be unqualified (aka just
|
|
191
371
|
// `private` or `no-cache`) or qualified (w/ a value). When they're
|
|
@@ -193,45 +373,64 @@ function parseCacheControlHeader (header) {
|
|
|
193
373
|
// `no-cache="header1"`, or `no-cache="header1, header2"`
|
|
194
374
|
// If we're given multiple headers, the comma messes us up since
|
|
195
375
|
// we split the full header by commas. So, let's loop through the
|
|
196
|
-
// remaining parts in front of us until we find one that
|
|
197
|
-
// quote. We can then
|
|
198
|
-
//
|
|
199
|
-
// and continue parsing like normal.
|
|
376
|
+
// remaining parts in front of us until we find one that contains a
|
|
377
|
+
// closing quote. We can then skip the consumed quoted-list fragments and
|
|
378
|
+
// continue parsing like normal.
|
|
200
379
|
// https://www.rfc-editor.org/rfc/rfc9111.html#name-no-cache-2
|
|
201
380
|
if (value[0] === '"') {
|
|
202
381
|
// Something like `no-cache="some-header"` OR `no-cache="some-header, another-header"`.
|
|
382
|
+
value = trimOWSEnd(value)
|
|
203
383
|
|
|
204
|
-
|
|
205
|
-
|
|
384
|
+
let fieldList = ''
|
|
385
|
+
let lastQuotedPart = i
|
|
386
|
+
let foundEndingQuote = false
|
|
387
|
+
const closingQuote = findUnescapedQuote(value, 1)
|
|
206
388
|
|
|
207
|
-
|
|
208
|
-
|
|
389
|
+
if (closingQuote !== -1) {
|
|
390
|
+
fieldList = value.substring(1, closingQuote)
|
|
391
|
+
foundEndingQuote = true
|
|
392
|
+
} else {
|
|
209
393
|
// Something like `no-cache="some-header, another-header"`
|
|
210
394
|
// This can still be something invalid, e.g. `no-cache="some-header, ...`
|
|
395
|
+
const fieldListParts = [value.substring(1)]
|
|
396
|
+
|
|
211
397
|
for (let j = i + 1; j < directives.length; j++) {
|
|
212
|
-
const nextPart = directives[j]
|
|
213
|
-
const
|
|
398
|
+
const nextPart = trimOWS(directives[j].value)
|
|
399
|
+
const closingQuote = findUnescapedQuote(nextPart, 0)
|
|
214
400
|
|
|
215
|
-
|
|
401
|
+
lastQuotedPart = j
|
|
216
402
|
|
|
217
|
-
if (
|
|
403
|
+
if (closingQuote !== -1) {
|
|
404
|
+
fieldListParts.push(nextPart.substring(0, closingQuote))
|
|
218
405
|
foundEndingQuote = true
|
|
219
406
|
break
|
|
220
407
|
}
|
|
408
|
+
|
|
409
|
+
fieldListParts.push(nextPart)
|
|
221
410
|
}
|
|
411
|
+
|
|
412
|
+
fieldList = fieldListParts.join(',')
|
|
222
413
|
}
|
|
223
414
|
|
|
224
|
-
if (foundEndingQuote) {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
headers[headers.length - 1] = lastHeader
|
|
229
|
-
}
|
|
415
|
+
if (!foundEndingQuote) {
|
|
416
|
+
output[key] = true
|
|
417
|
+
break
|
|
418
|
+
}
|
|
230
419
|
|
|
231
|
-
|
|
232
|
-
|
|
420
|
+
i = lastQuotedPart
|
|
421
|
+
|
|
422
|
+
const headers = fieldList.split(',')
|
|
423
|
+
let validFieldNames = true
|
|
424
|
+
for (let j = 0; j < headers.length; j++) {
|
|
425
|
+
headers[j] = trimOWS(headers[j])
|
|
426
|
+
if (!isValidHTTPToken(headers[j])) {
|
|
427
|
+
validFieldNames = false
|
|
233
428
|
}
|
|
429
|
+
}
|
|
234
430
|
|
|
431
|
+
if (!validFieldNames) {
|
|
432
|
+
output[key] = true
|
|
433
|
+
} else if (output[key] !== true) {
|
|
235
434
|
if (key in output) {
|
|
236
435
|
output[key] = output[key].concat(headers)
|
|
237
436
|
} else {
|
|
@@ -239,13 +438,17 @@ function parseCacheControlHeader (header) {
|
|
|
239
438
|
}
|
|
240
439
|
}
|
|
241
440
|
} else {
|
|
242
|
-
// Something like `no-cache=
|
|
243
|
-
const fieldName = value
|
|
441
|
+
// Something like `no-cache=some-header`
|
|
442
|
+
const fieldName = trimOWS(value)
|
|
244
443
|
|
|
245
|
-
if (
|
|
246
|
-
output[key] =
|
|
247
|
-
} else {
|
|
248
|
-
|
|
444
|
+
if (!isValidHTTPToken(fieldName)) {
|
|
445
|
+
output[key] = true
|
|
446
|
+
} else if (output[key] !== true) {
|
|
447
|
+
if (key in output) {
|
|
448
|
+
output[key] = output[key].concat(fieldName)
|
|
449
|
+
} else {
|
|
450
|
+
output[key] = [fieldName]
|
|
451
|
+
}
|
|
249
452
|
}
|
|
250
453
|
}
|
|
251
454
|
|
|
@@ -254,19 +457,27 @@ function parseCacheControlHeader (header) {
|
|
|
254
457
|
}
|
|
255
458
|
// eslint-disable-next-line no-fallthrough
|
|
256
459
|
case 'public':
|
|
257
|
-
case 'no-store':
|
|
258
460
|
case 'must-revalidate':
|
|
259
461
|
case 'proxy-revalidate':
|
|
260
462
|
case 'immutable':
|
|
261
463
|
case 'no-transform':
|
|
262
464
|
case 'must-understand':
|
|
263
465
|
case 'only-if-cached':
|
|
264
|
-
if (
|
|
466
|
+
if (fromMalformedQuote || invalidNoArgumentDirectives.has(key)) {
|
|
467
|
+
continue
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (value !== undefined) {
|
|
265
471
|
// These are qualified (something like `public=...`) when they aren't
|
|
266
|
-
// allowed to be, skip
|
|
472
|
+
// allowed to be, skip all instances of the malformed directive.
|
|
473
|
+
delete output[key]
|
|
474
|
+
invalidNoArgumentDirectives.add(key)
|
|
267
475
|
continue
|
|
268
476
|
}
|
|
269
477
|
|
|
478
|
+
output[key] = true
|
|
479
|
+
break
|
|
480
|
+
case 'no-store':
|
|
270
481
|
output[key] = true
|
|
271
482
|
break
|
|
272
483
|
default:
|
|
@@ -278,31 +489,79 @@ function parseCacheControlHeader (header) {
|
|
|
278
489
|
return output
|
|
279
490
|
}
|
|
280
491
|
|
|
492
|
+
/**
|
|
493
|
+
* @param {string | string[]} varyHeader Vary header from the server
|
|
494
|
+
* @returns {string[]}
|
|
495
|
+
*/
|
|
496
|
+
function splitVaryHeader (varyHeader) {
|
|
497
|
+
const values = Array.isArray(varyHeader) ? varyHeader : [varyHeader]
|
|
498
|
+
const output = []
|
|
499
|
+
|
|
500
|
+
for (let i = 0; i < values.length; i++) {
|
|
501
|
+
const parts = values[i].split(',')
|
|
502
|
+
for (let j = 0; j < parts.length; j++) {
|
|
503
|
+
output.push(parts[j])
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
return output
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* @param {string | string[]} varyHeader Vary header from the server
|
|
512
|
+
* @returns {boolean}
|
|
513
|
+
*/
|
|
514
|
+
function hasVaryStar (varyHeader) {
|
|
515
|
+
const values = splitVaryHeader(varyHeader)
|
|
516
|
+
for (let i = 0; i < values.length; i++) {
|
|
517
|
+
if (trimOWS(values[i]).indexOf('*') !== -1) {
|
|
518
|
+
return true
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
return false
|
|
523
|
+
}
|
|
524
|
+
|
|
281
525
|
/**
|
|
282
526
|
* @param {string | string[]} varyHeader Vary header from the server
|
|
283
527
|
* @param {Record<string, string | string[]>} headers Request headers
|
|
284
|
-
* @returns {Record<string, string | string[]>}
|
|
528
|
+
* @returns {Record<string, string | string[] | null> | undefined}
|
|
285
529
|
*/
|
|
286
530
|
function parseVaryHeader (varyHeader, headers) {
|
|
287
|
-
if (
|
|
531
|
+
if (hasVaryStar(varyHeader)) {
|
|
288
532
|
return headers
|
|
289
533
|
}
|
|
290
534
|
|
|
291
535
|
const output = /** @type {Record<string, string | string[] | null>} */ ({})
|
|
292
536
|
|
|
293
|
-
const varyingHeaders =
|
|
294
|
-
? varyHeader.split(',')
|
|
295
|
-
: varyHeader
|
|
537
|
+
const varyingHeaders = splitVaryHeader(varyHeader)
|
|
296
538
|
|
|
297
539
|
for (const header of varyingHeaders) {
|
|
298
|
-
const trimmedHeader = header
|
|
540
|
+
const trimmedHeader = trimOWS(header).toLowerCase()
|
|
541
|
+
|
|
542
|
+
if (trimmedHeader.length === 0) {
|
|
543
|
+
continue
|
|
544
|
+
}
|
|
299
545
|
|
|
300
|
-
|
|
546
|
+
if (!isValidHTTPToken(trimmedHeader)) {
|
|
547
|
+
return undefined
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
const headerValue = headers[trimmedHeader]
|
|
551
|
+
output[trimmedHeader] = Array.isArray(headerValue) ? headerValue.slice() : headerValue ?? null
|
|
301
552
|
}
|
|
302
553
|
|
|
303
554
|
return output
|
|
304
555
|
}
|
|
305
556
|
|
|
557
|
+
/**
|
|
558
|
+
* @param {string | string[]} varyHeader Vary header from the server
|
|
559
|
+
* @returns {boolean}
|
|
560
|
+
*/
|
|
561
|
+
function isInvalidOrWildcardVaryHeader (varyHeader) {
|
|
562
|
+
return hasVaryStar(varyHeader) || parseVaryHeader(varyHeader, {}) === undefined
|
|
563
|
+
}
|
|
564
|
+
|
|
306
565
|
/**
|
|
307
566
|
* Note: this deviates from the spec a little. Empty etags ("", W/"") are valid,
|
|
308
567
|
* however, including them in cached resposnes serves little to no purpose.
|
|
@@ -366,7 +625,7 @@ function assertCacheMethods (methods, name = 'CacheMethods') {
|
|
|
366
625
|
}
|
|
367
626
|
|
|
368
627
|
for (const method of methods) {
|
|
369
|
-
if (!safeHTTPMethods
|
|
628
|
+
if (!arrayIncludes(safeHTTPMethods, method)) {
|
|
370
629
|
throw new TypeError(`element of ${name}-array needs to be one of following values: ${safeHTTPMethods.join(', ')}, got ${method}`)
|
|
371
630
|
}
|
|
372
631
|
}
|
|
@@ -406,7 +665,10 @@ module.exports = {
|
|
|
406
665
|
assertCacheKey,
|
|
407
666
|
assertCacheValue,
|
|
408
667
|
parseCacheControlHeader,
|
|
668
|
+
hasInvalidCacheControlDirective,
|
|
409
669
|
parseVaryHeader,
|
|
670
|
+
hasVaryStar,
|
|
671
|
+
isInvalidOrWildcardVaryHeader,
|
|
410
672
|
isEtagUsable,
|
|
411
673
|
assertCacheMethods,
|
|
412
674
|
assertCacheStore,
|
|
@@ -18,6 +18,26 @@ function parseHttpDate (date) {
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
function makeDate (year, monthIdx, day, hour, minute, second, weekday) {
|
|
22
|
+
const result = new Date(Date.UTC(year, monthIdx, day, hour, minute, second))
|
|
23
|
+
|
|
24
|
+
// Date.UTC treats years 0-99 as 1900-1999. Reset the full year so component
|
|
25
|
+
// checks below validate the HTTP date as written.
|
|
26
|
+
if (year >= 0 && year <= 99) {
|
|
27
|
+
result.setUTCFullYear(year)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return result.getUTCFullYear() === year &&
|
|
31
|
+
result.getUTCMonth() === monthIdx &&
|
|
32
|
+
result.getUTCDate() === day &&
|
|
33
|
+
result.getUTCHours() === hour &&
|
|
34
|
+
result.getUTCMinutes() === minute &&
|
|
35
|
+
result.getUTCSeconds() === second &&
|
|
36
|
+
result.getUTCDay() === weekday
|
|
37
|
+
? result
|
|
38
|
+
: undefined
|
|
39
|
+
}
|
|
40
|
+
|
|
21
41
|
/**
|
|
22
42
|
* @see https://httpwg.org/specs/rfc9110.html#preferred.date.format
|
|
23
43
|
*
|
|
@@ -224,8 +244,7 @@ function parseImfDate (date) {
|
|
|
224
244
|
second = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
|
|
225
245
|
}
|
|
226
246
|
|
|
227
|
-
|
|
228
|
-
return result.getUTCDay() === weekday ? result : undefined
|
|
247
|
+
return makeDate(year, monthIdx, day, hour, minute, second, weekday)
|
|
229
248
|
}
|
|
230
249
|
|
|
231
250
|
/**
|
|
@@ -429,8 +448,7 @@ function parseAscTimeDate (date) {
|
|
|
429
448
|
}
|
|
430
449
|
const year = (yearDigit1 - 48) * 1000 + (yearDigit2 - 48) * 100 + (yearDigit3 - 48) * 10 + (yearDigit4 - 48)
|
|
431
450
|
|
|
432
|
-
|
|
433
|
-
return result.getUTCDay() === weekday ? result : undefined
|
|
451
|
+
return makeDate(year, monthIdx, day, hour, minute, second, weekday)
|
|
434
452
|
}
|
|
435
453
|
|
|
436
454
|
/**
|
|
@@ -644,8 +662,7 @@ function parseRfc850Date (date) {
|
|
|
644
662
|
second = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
|
|
645
663
|
}
|
|
646
664
|
|
|
647
|
-
|
|
648
|
-
return result.getUTCDay() === weekday ? result : undefined
|
|
665
|
+
return makeDate(year, monthIdx, day, hour, minute, second, weekday)
|
|
649
666
|
}
|
|
650
667
|
|
|
651
668
|
module.exports = {
|