undici 7.0.0-alpha.7 → 7.0.0-alpha.9
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/docs/docs/api/Dispatcher.md +15 -189
- package/index.js +1 -0
- package/lib/cache/memory-cache-store.js +2 -0
- package/lib/cache/sqlite-cache-store.js +32 -43
- package/lib/core/errors.js +2 -2
- package/lib/dispatcher/dispatcher-base.js +4 -2
- package/lib/handler/cache-handler.js +148 -49
- package/lib/handler/cache-revalidation-handler.js +21 -10
- package/lib/handler/decorator-handler.js +3 -0
- package/lib/handler/redirect-handler.js +15 -38
- package/lib/handler/retry-handler.js +65 -100
- package/lib/handler/unwrap-handler.js +2 -2
- package/lib/handler/wrap-handler.js +2 -2
- package/lib/interceptor/cache.js +250 -201
- package/lib/interceptor/response-error.js +9 -5
- package/lib/util/cache.js +42 -31
- package/package.json +4 -3
- package/types/cache-interceptor.d.ts +40 -0
- package/types/dispatcher.d.ts +1 -1
|
@@ -10,7 +10,9 @@ const {
|
|
|
10
10
|
function noop () {}
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* @
|
|
13
|
+
* @typedef {import('../../types/dispatcher.d.ts').default.DispatchHandler} DispatchHandler
|
|
14
|
+
*
|
|
15
|
+
* @implements {DispatchHandler}
|
|
14
16
|
*/
|
|
15
17
|
class CacheHandler {
|
|
16
18
|
/**
|
|
@@ -18,6 +20,16 @@ class CacheHandler {
|
|
|
18
20
|
*/
|
|
19
21
|
#cacheKey
|
|
20
22
|
|
|
23
|
+
/**
|
|
24
|
+
* @type {import('../../types/cache-interceptor.d.ts').default.CacheHandlerOptions['type']}
|
|
25
|
+
*/
|
|
26
|
+
#cacheType
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @type {number | undefined}
|
|
30
|
+
*/
|
|
31
|
+
#cacheByDefault
|
|
32
|
+
|
|
21
33
|
/**
|
|
22
34
|
* @type {import('../../types/cache-interceptor.d.ts').default.CacheStore}
|
|
23
35
|
*/
|
|
@@ -38,10 +50,10 @@ class CacheHandler {
|
|
|
38
50
|
* @param {import('../../types/cache-interceptor.d.ts').default.CacheKey} cacheKey
|
|
39
51
|
* @param {import('../../types/dispatcher.d.ts').default.DispatchHandler} handler
|
|
40
52
|
*/
|
|
41
|
-
constructor (
|
|
42
|
-
const { store } = opts
|
|
43
|
-
|
|
53
|
+
constructor ({ store, type, cacheByDefault }, cacheKey, handler) {
|
|
44
54
|
this.#store = store
|
|
55
|
+
this.#cacheType = type
|
|
56
|
+
this.#cacheByDefault = cacheByDefault
|
|
45
57
|
this.#cacheKey = cacheKey
|
|
46
58
|
this.#handler = handler
|
|
47
59
|
}
|
|
@@ -59,15 +71,15 @@ class CacheHandler {
|
|
|
59
71
|
onResponseStart (
|
|
60
72
|
controller,
|
|
61
73
|
statusCode,
|
|
62
|
-
|
|
63
|
-
|
|
74
|
+
headers,
|
|
75
|
+
statusMessage
|
|
64
76
|
) {
|
|
65
77
|
const downstreamOnHeaders = () =>
|
|
66
78
|
this.#handler.onResponseStart?.(
|
|
67
79
|
controller,
|
|
68
80
|
statusCode,
|
|
69
|
-
|
|
70
|
-
|
|
81
|
+
headers,
|
|
82
|
+
statusMessage
|
|
71
83
|
)
|
|
72
84
|
|
|
73
85
|
if (
|
|
@@ -85,24 +97,47 @@ class CacheHandler {
|
|
|
85
97
|
}
|
|
86
98
|
|
|
87
99
|
const cacheControlHeader = headers['cache-control']
|
|
88
|
-
if (!cacheControlHeader) {
|
|
100
|
+
if (!cacheControlHeader && !headers['expires'] && !this.#cacheByDefault) {
|
|
89
101
|
// Don't have the cache control header or the cache is full
|
|
90
102
|
return downstreamOnHeaders()
|
|
91
103
|
}
|
|
92
104
|
|
|
93
|
-
const cacheControlDirectives = parseCacheControlHeader(cacheControlHeader)
|
|
94
|
-
if (!canCacheResponse(statusCode, headers, cacheControlDirectives)) {
|
|
105
|
+
const cacheControlDirectives = cacheControlHeader ? parseCacheControlHeader(cacheControlHeader) : {}
|
|
106
|
+
if (!canCacheResponse(this.#cacheType, statusCode, headers, cacheControlDirectives)) {
|
|
95
107
|
return downstreamOnHeaders()
|
|
96
108
|
}
|
|
97
109
|
|
|
110
|
+
const age = getAge(headers)
|
|
111
|
+
|
|
98
112
|
const now = Date.now()
|
|
99
|
-
const staleAt = determineStaleAt(now, headers, cacheControlDirectives)
|
|
113
|
+
const staleAt = determineStaleAt(this.#cacheType, now, headers, cacheControlDirectives) ?? this.#cacheByDefault
|
|
100
114
|
if (staleAt) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
115
|
+
let baseTime = now
|
|
116
|
+
if (headers['date']) {
|
|
117
|
+
const parsedDate = parseInt(headers['date'])
|
|
118
|
+
const date = new Date(isNaN(parsedDate) ? headers['date'] : parsedDate)
|
|
119
|
+
if (date instanceof Date && !isNaN(date)) {
|
|
120
|
+
baseTime = date.getTime()
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const absoluteStaleAt = staleAt + baseTime
|
|
105
125
|
|
|
126
|
+
if (now >= absoluteStaleAt || (age && age >= staleAt)) {
|
|
127
|
+
// Response is already stale
|
|
128
|
+
return downstreamOnHeaders()
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
let varyDirectives
|
|
132
|
+
if (this.#cacheKey.headers && headers.vary) {
|
|
133
|
+
varyDirectives = parseVaryHeader(headers.vary, this.#cacheKey.headers)
|
|
134
|
+
if (!varyDirectives) {
|
|
135
|
+
// Parse error
|
|
136
|
+
return downstreamOnHeaders()
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const deleteAt = determineDeleteAt(cacheControlDirectives, absoluteStaleAt)
|
|
106
141
|
const strippedHeaders = stripNecessaryHeaders(headers, cacheControlDirectives)
|
|
107
142
|
|
|
108
143
|
/**
|
|
@@ -113,8 +148,9 @@ class CacheHandler {
|
|
|
113
148
|
statusMessage,
|
|
114
149
|
headers: strippedHeaders,
|
|
115
150
|
vary: varyDirectives,
|
|
116
|
-
|
|
117
|
-
|
|
151
|
+
cacheControlDirectives,
|
|
152
|
+
cachedAt: age ? now - (age * 1000) : now,
|
|
153
|
+
staleAt: absoluteStaleAt,
|
|
118
154
|
deleteAt
|
|
119
155
|
}
|
|
120
156
|
|
|
@@ -130,6 +166,7 @@ class CacheHandler {
|
|
|
130
166
|
.on('drain', () => controller.resume())
|
|
131
167
|
.on('error', function () {
|
|
132
168
|
// TODO (fix): Make error somehow observable?
|
|
169
|
+
handler.#writeStream = undefined
|
|
133
170
|
})
|
|
134
171
|
.on('close', function () {
|
|
135
172
|
if (handler.#writeStream === this) {
|
|
@@ -168,25 +205,29 @@ class CacheHandler {
|
|
|
168
205
|
/**
|
|
169
206
|
* @see https://www.rfc-editor.org/rfc/rfc9111.html#name-storing-responses-to-authen
|
|
170
207
|
*
|
|
208
|
+
* @param {import('../../types/cache-interceptor.d.ts').default.CacheOptions['type']} cacheType
|
|
171
209
|
* @param {number} statusCode
|
|
172
210
|
* @param {Record<string, string | string[]>} headers
|
|
173
|
-
* @param {import('
|
|
211
|
+
* @param {import('../../types/cache-interceptor.d.ts').default.CacheControlDirectives} cacheControlDirectives
|
|
174
212
|
*/
|
|
175
|
-
function canCacheResponse (statusCode, headers, cacheControlDirectives) {
|
|
213
|
+
function canCacheResponse (cacheType, statusCode, headers, cacheControlDirectives) {
|
|
176
214
|
if (statusCode !== 200 && statusCode !== 307) {
|
|
177
215
|
return false
|
|
178
216
|
}
|
|
179
217
|
|
|
180
218
|
if (
|
|
181
|
-
cacheControlDirectives.private === true ||
|
|
182
219
|
cacheControlDirectives['no-cache'] === true ||
|
|
183
220
|
cacheControlDirectives['no-store']
|
|
184
221
|
) {
|
|
185
222
|
return false
|
|
186
223
|
}
|
|
187
224
|
|
|
225
|
+
if (cacheType === 'shared' && cacheControlDirectives.private === true) {
|
|
226
|
+
return false
|
|
227
|
+
}
|
|
228
|
+
|
|
188
229
|
// https://www.rfc-editor.org/rfc/rfc9111.html#section-4.1-5
|
|
189
|
-
if (headers.vary
|
|
230
|
+
if (headers.vary?.includes('*')) {
|
|
190
231
|
return false
|
|
191
232
|
}
|
|
192
233
|
|
|
@@ -215,63 +256,120 @@ function canCacheResponse (statusCode, headers, cacheControlDirectives) {
|
|
|
215
256
|
}
|
|
216
257
|
|
|
217
258
|
/**
|
|
259
|
+
* @param {Record<string, string | string[]>} headers
|
|
260
|
+
* @returns {number | undefined}
|
|
261
|
+
*/
|
|
262
|
+
function getAge (headers) {
|
|
263
|
+
if (!headers.age) {
|
|
264
|
+
return undefined
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const age = parseInt(Array.isArray(headers.age) ? headers.age[0] : headers.age)
|
|
268
|
+
if (isNaN(age) || age >= 2147483647) {
|
|
269
|
+
return undefined
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return age
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* @param {import('../../types/cache-interceptor.d.ts').default.CacheOptions['type']} cacheType
|
|
218
277
|
* @param {number} now
|
|
219
278
|
* @param {Record<string, string | string[]>} headers
|
|
220
|
-
* @param {import('
|
|
279
|
+
* @param {import('../../types/cache-interceptor.d.ts').default.CacheControlDirectives} cacheControlDirectives
|
|
221
280
|
*
|
|
222
281
|
* @returns {number | undefined} time that the value is stale at or undefined if it shouldn't be cached
|
|
223
282
|
*/
|
|
224
|
-
function determineStaleAt (now, headers, cacheControlDirectives) {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
if (cacheControlDirectives.immutable) {
|
|
234
|
-
// https://www.rfc-editor.org/rfc/rfc8246.html#section-2.2
|
|
235
|
-
return now + 31536000
|
|
283
|
+
function determineStaleAt (cacheType, now, headers, cacheControlDirectives) {
|
|
284
|
+
if (cacheType === 'shared') {
|
|
285
|
+
// Prioritize s-maxage since we're a shared cache
|
|
286
|
+
// s-maxage > max-age > Expire
|
|
287
|
+
// https://www.rfc-editor.org/rfc/rfc9111.html#section-5.2.2.10-3
|
|
288
|
+
const sMaxAge = cacheControlDirectives['s-maxage']
|
|
289
|
+
if (sMaxAge) {
|
|
290
|
+
return sMaxAge * 1000
|
|
291
|
+
}
|
|
236
292
|
}
|
|
237
293
|
|
|
238
294
|
const maxAge = cacheControlDirectives['max-age']
|
|
239
295
|
if (maxAge) {
|
|
240
|
-
return
|
|
296
|
+
return maxAge * 1000
|
|
241
297
|
}
|
|
242
298
|
|
|
243
|
-
if (headers.
|
|
299
|
+
if (headers.expires && typeof headers.expires === 'string') {
|
|
244
300
|
// https://www.rfc-editor.org/rfc/rfc9111.html#section-5.3
|
|
245
|
-
const expiresDate = new Date(headers.
|
|
301
|
+
const expiresDate = new Date(headers.expires)
|
|
246
302
|
if (expiresDate instanceof Date && Number.isFinite(expiresDate.valueOf())) {
|
|
247
|
-
|
|
303
|
+
if (now >= expiresDate.getTime()) {
|
|
304
|
+
return undefined
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return expiresDate.getTime() - now
|
|
248
308
|
}
|
|
249
309
|
}
|
|
250
310
|
|
|
311
|
+
if (cacheControlDirectives.immutable) {
|
|
312
|
+
// https://www.rfc-editor.org/rfc/rfc8246.html#section-2.2
|
|
313
|
+
return 31536000
|
|
314
|
+
}
|
|
315
|
+
|
|
251
316
|
return undefined
|
|
252
317
|
}
|
|
253
318
|
|
|
254
319
|
/**
|
|
255
|
-
* @param {
|
|
256
|
-
* @param {import('../util/cache.js').CacheControlDirectives} cacheControlDirectives
|
|
320
|
+
* @param {import('../../types/cache-interceptor.d.ts').default.CacheControlDirectives} cacheControlDirectives
|
|
257
321
|
* @param {number} staleAt
|
|
258
322
|
*/
|
|
259
|
-
function determineDeleteAt (
|
|
323
|
+
function determineDeleteAt (cacheControlDirectives, staleAt) {
|
|
324
|
+
let staleWhileRevalidate = -Infinity
|
|
325
|
+
let staleIfError = -Infinity
|
|
326
|
+
let immutable = -Infinity
|
|
327
|
+
|
|
260
328
|
if (cacheControlDirectives['stale-while-revalidate']) {
|
|
261
|
-
|
|
329
|
+
staleWhileRevalidate = staleAt + (cacheControlDirectives['stale-while-revalidate'] * 1000)
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (cacheControlDirectives['stale-if-error']) {
|
|
333
|
+
staleIfError = staleAt + (cacheControlDirectives['stale-if-error'] * 1000)
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (staleWhileRevalidate === -Infinity && staleIfError === -Infinity) {
|
|
337
|
+
immutable = 31536000
|
|
262
338
|
}
|
|
263
339
|
|
|
264
|
-
return staleAt
|
|
340
|
+
return Math.max(staleAt, staleWhileRevalidate, staleIfError, immutable)
|
|
265
341
|
}
|
|
266
342
|
|
|
267
343
|
/**
|
|
268
344
|
* Strips headers required to be removed in cached responses
|
|
269
345
|
* @param {Record<string, string | string[]>} headers
|
|
270
|
-
* @param {import('
|
|
346
|
+
* @param {import('../../types/cache-interceptor.d.ts').default.CacheControlDirectives} cacheControlDirectives
|
|
271
347
|
* @returns {Record<string, string | string []>}
|
|
272
348
|
*/
|
|
273
349
|
function stripNecessaryHeaders (headers, cacheControlDirectives) {
|
|
274
|
-
const headersToRemove = [
|
|
350
|
+
const headersToRemove = [
|
|
351
|
+
'connection',
|
|
352
|
+
'proxy-authenticate',
|
|
353
|
+
'proxy-authentication-info',
|
|
354
|
+
'proxy-authorization',
|
|
355
|
+
'proxy-connection',
|
|
356
|
+
'te',
|
|
357
|
+
'transfer-encoding',
|
|
358
|
+
'upgrade',
|
|
359
|
+
// We'll add age back when serving it
|
|
360
|
+
'age'
|
|
361
|
+
]
|
|
362
|
+
|
|
363
|
+
if (headers['connection']) {
|
|
364
|
+
if (Array.isArray(headers['connection'])) {
|
|
365
|
+
// connection: a
|
|
366
|
+
// connection: b
|
|
367
|
+
headersToRemove.push(...headers['connection'].map(header => header.trim()))
|
|
368
|
+
} else {
|
|
369
|
+
// connection: a, b
|
|
370
|
+
headersToRemove.push(...headers['connection'].split(',').map(header => header.trim()))
|
|
371
|
+
}
|
|
372
|
+
}
|
|
275
373
|
|
|
276
374
|
if (Array.isArray(cacheControlDirectives['no-cache'])) {
|
|
277
375
|
headersToRemove.push(...cacheControlDirectives['no-cache'])
|
|
@@ -282,12 +380,13 @@ function stripNecessaryHeaders (headers, cacheControlDirectives) {
|
|
|
282
380
|
}
|
|
283
381
|
|
|
284
382
|
let strippedHeaders
|
|
285
|
-
for (const headerName of
|
|
286
|
-
if (
|
|
383
|
+
for (const headerName of headersToRemove) {
|
|
384
|
+
if (headers[headerName]) {
|
|
287
385
|
strippedHeaders ??= { ...headers }
|
|
288
|
-
delete
|
|
386
|
+
delete strippedHeaders[headerName]
|
|
289
387
|
}
|
|
290
388
|
}
|
|
389
|
+
|
|
291
390
|
return strippedHeaders ?? headers
|
|
292
391
|
}
|
|
293
392
|
|
|
@@ -17,10 +17,12 @@ const assert = require('node:assert')
|
|
|
17
17
|
*/
|
|
18
18
|
class CacheRevalidationHandler {
|
|
19
19
|
#successful = false
|
|
20
|
+
|
|
20
21
|
/**
|
|
21
22
|
* @type {((boolean, any) => void) | null}
|
|
22
23
|
*/
|
|
23
24
|
#callback
|
|
25
|
+
|
|
24
26
|
/**
|
|
25
27
|
* @type {(import('../../types/dispatcher.d.ts').default.DispatchHandler)}
|
|
26
28
|
*/
|
|
@@ -29,19 +31,26 @@ class CacheRevalidationHandler {
|
|
|
29
31
|
#context
|
|
30
32
|
|
|
31
33
|
/**
|
|
32
|
-
* @
|
|
33
|
-
|
|
34
|
+
* @type {boolean}
|
|
35
|
+
*/
|
|
36
|
+
#allowErrorStatusCodes
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @param {(boolean) => void} callback Function to call if the cached value is valid
|
|
40
|
+
* @param {import('../../types/dispatcher.d.ts').default.DispatchHandlers} handler
|
|
41
|
+
* @param {boolean} allowErrorStatusCodes
|
|
34
42
|
*/
|
|
35
|
-
constructor (callback, handler) {
|
|
43
|
+
constructor (callback, handler, allowErrorStatusCodes) {
|
|
36
44
|
if (typeof callback !== 'function') {
|
|
37
45
|
throw new TypeError('callback must be a function')
|
|
38
46
|
}
|
|
39
47
|
|
|
40
48
|
this.#callback = callback
|
|
41
49
|
this.#handler = handler
|
|
50
|
+
this.#allowErrorStatusCodes = allowErrorStatusCodes
|
|
42
51
|
}
|
|
43
52
|
|
|
44
|
-
onRequestStart (
|
|
53
|
+
onRequestStart (_, context) {
|
|
45
54
|
this.#successful = false
|
|
46
55
|
this.#context = context
|
|
47
56
|
}
|
|
@@ -53,13 +62,15 @@ class CacheRevalidationHandler {
|
|
|
53
62
|
onResponseStart (
|
|
54
63
|
controller,
|
|
55
64
|
statusCode,
|
|
56
|
-
|
|
57
|
-
|
|
65
|
+
headers,
|
|
66
|
+
statusMessage
|
|
58
67
|
) {
|
|
59
68
|
assert(this.#callback != null)
|
|
60
69
|
|
|
61
70
|
// https://www.rfc-editor.org/rfc/rfc9111.html#name-handling-a-validation-respo
|
|
62
|
-
|
|
71
|
+
// https://datatracker.ietf.org/doc/html/rfc5861#section-4
|
|
72
|
+
this.#successful = statusCode === 304 ||
|
|
73
|
+
(this.#allowErrorStatusCodes && statusCode >= 500 && statusCode <= 504)
|
|
63
74
|
this.#callback(this.#successful, this.#context)
|
|
64
75
|
this.#callback = null
|
|
65
76
|
|
|
@@ -71,8 +82,8 @@ class CacheRevalidationHandler {
|
|
|
71
82
|
this.#handler.onResponseStart?.(
|
|
72
83
|
controller,
|
|
73
84
|
statusCode,
|
|
74
|
-
|
|
75
|
-
|
|
85
|
+
headers,
|
|
86
|
+
statusMessage
|
|
76
87
|
)
|
|
77
88
|
}
|
|
78
89
|
|
|
@@ -81,7 +92,7 @@ class CacheRevalidationHandler {
|
|
|
81
92
|
return
|
|
82
93
|
}
|
|
83
94
|
|
|
84
|
-
return this.#handler.onResponseData(controller, chunk)
|
|
95
|
+
return this.#handler.onResponseData?.(controller, chunk)
|
|
85
96
|
}
|
|
86
97
|
|
|
87
98
|
onResponseEnd (controller, trailers) {
|
|
@@ -42,7 +42,6 @@ class RedirectHandler {
|
|
|
42
42
|
|
|
43
43
|
this.dispatch = dispatch
|
|
44
44
|
this.location = null
|
|
45
|
-
this.abort = null
|
|
46
45
|
this.opts = { ...opts, maxRedirections: 0 } // opts must be a copy
|
|
47
46
|
this.maxRedirections = maxRedirections
|
|
48
47
|
this.handler = handler
|
|
@@ -83,20 +82,15 @@ class RedirectHandler {
|
|
|
83
82
|
}
|
|
84
83
|
}
|
|
85
84
|
|
|
86
|
-
|
|
87
|
-
this.
|
|
88
|
-
this.handler.onConnect(abort, { history: this.history })
|
|
85
|
+
onRequestStart (controller, context) {
|
|
86
|
+
this.handler.onRequestStart?.(controller, { ...context, history: this.history })
|
|
89
87
|
}
|
|
90
88
|
|
|
91
|
-
|
|
92
|
-
this.handler.
|
|
89
|
+
onRequestUpgrade (controller, statusCode, headers, socket) {
|
|
90
|
+
this.handler.onRequestUpgrade?.(controller, statusCode, headers, socket)
|
|
93
91
|
}
|
|
94
92
|
|
|
95
|
-
|
|
96
|
-
this.handler.onError(error)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
onHeaders (statusCode, rawHeaders, resume, statusText) {
|
|
93
|
+
onResponseStart (controller, statusCode, headers, statusMessage) {
|
|
100
94
|
if (this.opts.throwOnMaxRedirect && this.history.length >= this.maxRedirections) {
|
|
101
95
|
throw new Error('max redirects')
|
|
102
96
|
}
|
|
@@ -122,16 +116,17 @@ class RedirectHandler {
|
|
|
122
116
|
this.opts.body = null
|
|
123
117
|
}
|
|
124
118
|
|
|
125
|
-
this.location = this.history.length >= this.maxRedirections || util.isDisturbed(this.opts.body)
|
|
119
|
+
this.location = this.history.length >= this.maxRedirections || util.isDisturbed(this.opts.body) || redirectableStatusCodes.indexOf(statusCode) === -1
|
|
126
120
|
? null
|
|
127
|
-
:
|
|
121
|
+
: headers.location
|
|
128
122
|
|
|
129
123
|
if (this.opts.origin) {
|
|
130
124
|
this.history.push(new URL(this.opts.path, this.opts.origin))
|
|
131
125
|
}
|
|
132
126
|
|
|
133
127
|
if (!this.location) {
|
|
134
|
-
|
|
128
|
+
this.handler.onResponseStart?.(controller, statusCode, headers, statusMessage)
|
|
129
|
+
return
|
|
135
130
|
}
|
|
136
131
|
|
|
137
132
|
const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)))
|
|
@@ -147,7 +142,7 @@ class RedirectHandler {
|
|
|
147
142
|
this.opts.query = null
|
|
148
143
|
}
|
|
149
144
|
|
|
150
|
-
|
|
145
|
+
onResponseData (controller, chunk) {
|
|
151
146
|
if (this.location) {
|
|
152
147
|
/*
|
|
153
148
|
https://tools.ietf.org/html/rfc7231#section-6.4
|
|
@@ -167,11 +162,11 @@ class RedirectHandler {
|
|
|
167
162
|
servers and browsers implementors, we ignore the body as there is no specified way to eventually parse it.
|
|
168
163
|
*/
|
|
169
164
|
} else {
|
|
170
|
-
|
|
165
|
+
this.handler.onResponseData?.(controller, chunk)
|
|
171
166
|
}
|
|
172
167
|
}
|
|
173
168
|
|
|
174
|
-
|
|
169
|
+
onResponseEnd (controller, trailers) {
|
|
175
170
|
if (this.location) {
|
|
176
171
|
/*
|
|
177
172
|
https://tools.ietf.org/html/rfc7231#section-6.4
|
|
@@ -181,32 +176,14 @@ class RedirectHandler {
|
|
|
181
176
|
|
|
182
177
|
See comment on onData method above for more detailed information.
|
|
183
178
|
*/
|
|
184
|
-
|
|
185
|
-
this.location = null
|
|
186
|
-
this.abort = null
|
|
187
|
-
|
|
188
179
|
this.dispatch(this.opts, this)
|
|
189
180
|
} else {
|
|
190
|
-
this.handler.
|
|
181
|
+
this.handler.onResponseEnd(controller, trailers)
|
|
191
182
|
}
|
|
192
183
|
}
|
|
193
184
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
this.handler.onBodySent(chunk)
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
function parseLocation (statusCode, rawHeaders) {
|
|
202
|
-
if (redirectableStatusCodes.indexOf(statusCode) === -1) {
|
|
203
|
-
return null
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
for (let i = 0; i < rawHeaders.length; i += 2) {
|
|
207
|
-
if (rawHeaders[i].length === 8 && util.headerNameToString(rawHeaders[i]) === 'location') {
|
|
208
|
-
return rawHeaders[i + 1]
|
|
209
|
-
}
|
|
185
|
+
onResponseError (controller, error) {
|
|
186
|
+
this.handler.onResponseError?.(controller, error)
|
|
210
187
|
}
|
|
211
188
|
}
|
|
212
189
|
|