From 84c5bd9f67495b744d6a110535a4d0a0424c9867 Mon Sep 17 00:00:00 2001 From: hugoalh <32359235+hugoalh@users.noreply.github.com> Date: Wed, 15 Nov 2023 18:22:58 +0800 Subject: [PATCH] EIR stage 3 --- exfetch.ts | 50 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/exfetch.ts b/exfetch.ts index 79a1789..95acc4c 100644 --- a/exfetch.ts +++ b/exfetch.ts @@ -190,7 +190,7 @@ interface ExFetchRedirectOptionsInternal { delay: ExFetchDelayOptionsInternal; /** * Maximum amount of redirects to allow. - * @default 5 + * @default Infinity */ maximum: number; /** @@ -270,7 +270,7 @@ export interface ExFetchOptions { */ paginate?: ExFetchPaginateOptions; /** - * Redirect options. This only apply when define property `redirect` as `"manual"` in the request. + * Redirect options. This only apply when define property `redirect` as `"follow"` in the request, and define property `maximum` in this option. */ redirect?: ExFetchRedirectOptions; /** @@ -421,7 +421,7 @@ export class ExFetch { maximum: 0, minimum: 0 }, - maximum: 5, + maximum: Infinity, onEvent: undefined }; #retry: ExFetchRetryOptionsInternal = { @@ -549,12 +549,12 @@ export class ExFetch { if (new URL(input).protocol === "file:") { return fetch(input, init); } - const requestCacheOption: RequestCache | undefined = init?.cache; const requestCacheCommonCondition: boolean = new URL(input).protocol === "https:" && ( typeof init === "undefined" || typeof init.method === "undefined" || init.method.toUpperCase() === "GET" ); + const requestCacheOption: RequestCache | undefined = init?.cache; const requestFuzzy: Request = new Request(input, { ...init, cache: undefined, @@ -589,6 +589,7 @@ export class ExFetch { if (!requestHeaders.has("User-Agent") && this.#userAgent.length > 0) { requestHeaders.set("User-Agent", this.#userAgent); } + const requestRedirectControl: boolean = init?.redirect === "follow" && this.#redirect.maximum !== Infinity; let requestSignal: AbortSignal | undefined = init?.signal ?? undefined; if (typeof requestSignal === "undefined" && this.#timeout !== Infinity) { requestSignal = AbortSignal.timeout(this.#timeout); @@ -597,6 +598,7 @@ export class ExFetch { const requestFetchInit: RequestInit = { ...init, headers: requestHeaders, + redirect: requestRedirectControl ? "manual" : init?.redirect, signal: requestSignal }; let redirects = 0; @@ -604,15 +606,39 @@ export class ExFetch { let response: Response; do { response = await fetch(requestFetchInput, requestFetchInit); - if (typeof responseCached !== "undefined" && responseCachedIsValid && response.status === 304) { - return responseCached; + if (response.status === 304) { + if (typeof responseCached !== "undefined" && responseCachedIsValid) { + return responseCached; + } + break; } - if (httpStatusCodesRedirectable.includes(response.status)) { + if (requestRedirectControl && httpStatusCodesRedirectable.includes(response.status)) { + if (redirects >= this.#redirect.maximum) { + break; + } + const redirectURL: string | null = response.headers.get("Location"); + if (redirectURL === null) { + break; + } + redirects += 1; try { - + requestFetchInput = new URL(redirectURL, input); } catch { - + break; + } + const delayTime: number = resolveDelayTime(this.#redirect.delay); + if (typeof this.#redirect.onEvent !== "undefined") { + void this.#redirect.onEvent({ + countCurrent: redirects, + countMaximum: this.#redirect.maximum, + redirectAfter: delayTime, + redirectURL: new URL(requestFetchInput), + statusCode: response.status, + statusText: response.statusText + }); } + await setDelay(delayTime, requestSignal); + continue; } if ( response.ok || @@ -621,6 +647,7 @@ export class ExFetch { ) { break; } + retries += 1; let delayTime: number; try { delayTime = new HTTPHeaderRetryAfter(response).getRemainTimeMilliseconds(); @@ -629,7 +656,7 @@ export class ExFetch { } if (typeof this.#retry.onEvent !== "undefined") { void this.#retry.onEvent({ - countCurrent: retries + 1, + countCurrent: retries, countMaximum: this.#retry.maximum, retryAfter: delayTime, retryURL: new URL(requestFetchInput), @@ -638,9 +665,8 @@ export class ExFetch { }); } await setDelay(delayTime, requestSignal); - retries += 1; } while (retries <= this.#retry.maximum); - if (requestCacheCommonCondition && requestCacheOption !== "no-store" && response.ok && response.status >= 200 && response.status < 300 && ( + if (requestCacheCommonCondition && requestCacheOption !== "no-store" && response.ok && ( response.headers.has("ETag") || response.headers.has("Last-Modified") )) {