From 548ca74c938b62411bda1e19b6b501ebc12a7617 Mon Sep 17 00:00:00 2001 From: JonnyBurger Date: Tue, 30 Sep 2025 14:59:48 +0200 Subject: [PATCH] getRetryDelay() takes src as well --- src/misc.ts | 4 ++-- src/source.ts | 29 ++++++++++++++++++++++------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/misc.ts b/src/misc.ts index ba26c5d..74f6bff 100644 --- a/src/misc.ts +++ b/src/misc.ts @@ -578,7 +578,7 @@ export const retriedFetch = async ( fetchFn: typeof fetch, url: string | URL | Request, requestInit: RequestInit, - getRetryDelay: (previousAttempts: number, error: unknown) => number | null, + getRetryDelay: (previousAttempts: number, error: unknown, url: string | URL | Request) => number | null, ) => { let attempts = 0; @@ -587,7 +587,7 @@ export const retriedFetch = async ( return await fetchFn(url, requestInit); } catch (error) { attempts++; - const retryDelayInSeconds = getRetryDelay(attempts, error); + const retryDelayInSeconds = getRetryDelay(attempts, error, url); if (retryDelayInSeconds === null) { throw error; diff --git a/src/source.ts b/src/source.ts index 7303e63..dbbd105 100644 --- a/src/source.ts +++ b/src/source.ts @@ -255,7 +255,7 @@ export class BlobSource extends Source { const URL_SOURCE_MIN_LOAD_AMOUNT = 0.5 * 2 ** 20; // 0.5 MiB const DEFAULT_RETRY_DELAY - = ((previousAttempts, error) => { + = ((previousAttempts, error, src) => { // Check if this could be a CORS error. If so, we cannot recover from it and // should not attempt to retry. // CORS errors are intentionally not opaque, so we need to rely on heuristics. @@ -265,9 +265,24 @@ const DEFAULT_RETRY_DELAY || error.message.includes('NetworkError when attempting to fetch resource') // Firefox ); - // Being offline would lead to the same error, in that case it would not be a CORS error - if (couldBeCorsError && navigator.onLine) { - return null; + if (couldBeCorsError) { + let originOfSrc: string | null = null; + // Checking if the origin is different, because only then a CORS error could originate + try { + if (typeof window !== 'undefined' && typeof window.location !== 'undefined') { + originOfSrc = new URL(src instanceof Request ? src.url : src, window.location.href).origin; + } + } catch { + // URL parse failed + } + + // If user is offline, it is probably not a CORS error. + const isOnline + = typeof navigator !== 'undefined' && typeof navigator.onLine === 'boolean' ? navigator.onLine : true; + + if (isOnline && originOfSrc !== null && originOfSrc !== window.location.origin) { + return null; + } } return Math.min(2 ** (previousAttempts - 2), 16); @@ -293,7 +308,7 @@ export type UrlSourceOptions = { * By default, it uses an exponential backoff algorithm that never gives up unless * a CORS error is suspected (`fetch()` did reject even though `navigator.onLine` is true) */ - getRetryDelay?: (previousAttempts: number, error: unknown) => number | null; + getRetryDelay?: (previousAttempts: number, error: unknown, url: string | URL | Request) => number | null; /** The maximum number of bytes the cache is allowed to hold in memory. Defaults to 64 MiB. */ maxCacheSize?: number; @@ -315,7 +330,7 @@ export class UrlSource extends Source { /** @internal */ _url: string | URL | Request; /** @internal */ - _getRetryDelay: (previousAttempts: number, error: unknown) => number | null; + _getRetryDelay: (previousAttempts: number, error: unknown, url: string | URL | Request) => number | null; /** @internal */ _options: UrlSourceOptions; /** @internal */ @@ -508,7 +523,7 @@ export class UrlSource extends Source { try { readResult = await reader.read(); } catch (error) { - const retryDelayInSeconds = this._getRetryDelay(1, error); + const retryDelayInSeconds = this._getRetryDelay(1, error, this._url); if (retryDelayInSeconds !== null) { console.error('Error while reading response stream. Attempting to resume.', error); await new Promise(resolve => setTimeout(resolve, 1000 * retryDelayInSeconds));