2023-01-17 10:23:51 -05:00
|
|
|
import { isNetworkError } from '../../../utils/isNetworkError'
|
|
|
|
import getMeta from '../../../utils/meta'
|
|
|
|
import OError from '@overleaf/o-error'
|
|
|
|
import { postJSON } from '../../../infrastructure/fetch-json'
|
|
|
|
|
|
|
|
let useFallbackDomainUntil = performance.now()
|
|
|
|
const ONE_HOUR_IN_MS = 1000 * 60 * 60
|
|
|
|
|
2023-02-13 05:19:18 -05:00
|
|
|
class MaybeBlockedByProxyError extends OError {}
|
|
|
|
|
|
|
|
function checkForBlockingByProxy(res: Response) {
|
|
|
|
const statusCode = res.status
|
|
|
|
switch (statusCode) {
|
|
|
|
case 200: // full response
|
|
|
|
case 206: // range response
|
|
|
|
case 404: // file not found
|
|
|
|
case 416: // range not found
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
throw new MaybeBlockedByProxyError('request might be blocked by proxy', {
|
|
|
|
res,
|
|
|
|
statusCode,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-17 10:23:51 -05:00
|
|
|
export async function fetchFromCompileDomain(url: string, init: RequestInit) {
|
|
|
|
const userContentDomain = getMeta('ol-compilesUserContentDomain')
|
|
|
|
let isUserContentDomain =
|
|
|
|
userContentDomain &&
|
|
|
|
new URL(url).hostname === new URL(userContentDomain).hostname
|
|
|
|
|
|
|
|
if (useFallbackDomainUntil > performance.now()) {
|
|
|
|
isUserContentDomain = false
|
|
|
|
url = withFallbackCompileDomain(url)
|
|
|
|
}
|
|
|
|
try {
|
2023-02-13 05:19:18 -05:00
|
|
|
const res = await fetch(url, init)
|
|
|
|
if (isUserContentDomain) {
|
|
|
|
// Only throw a MaybeBlockedByProxyError when the request will be retried
|
|
|
|
// on the fallback domain below.
|
|
|
|
checkForBlockingByProxy(res)
|
|
|
|
}
|
|
|
|
return res
|
2023-01-17 10:23:51 -05:00
|
|
|
} catch (err) {
|
2023-02-13 05:19:18 -05:00
|
|
|
if (
|
|
|
|
(isNetworkError(err) || err instanceof MaybeBlockedByProxyError) &&
|
|
|
|
isUserContentDomain
|
|
|
|
) {
|
2023-01-17 10:23:51 -05:00
|
|
|
try {
|
|
|
|
const res = await fetch(withFallbackCompileDomain(url), init)
|
|
|
|
// Only switch to the fallback when fetch does not throw there as well.
|
|
|
|
if (useFallbackDomainUntil < performance.now()) {
|
|
|
|
useFallbackDomainUntil = performance.now() + ONE_HOUR_IN_MS
|
|
|
|
recordFallbackUsage()
|
|
|
|
}
|
|
|
|
return res
|
|
|
|
} catch (err2: any) {
|
|
|
|
throw OError.tag(err2, 'fallback request failed', {
|
|
|
|
errUserContentDomain: err,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
throw err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-26 07:58:52 -05:00
|
|
|
export function swapDomain(url: string, domain: string) {
|
2023-01-17 10:23:51 -05:00
|
|
|
const u = new URL(url)
|
2023-01-26 07:58:52 -05:00
|
|
|
u.hostname = new URL(domain).hostname
|
2023-01-17 10:23:51 -05:00
|
|
|
return u.href
|
|
|
|
}
|
|
|
|
|
2023-01-26 07:58:52 -05:00
|
|
|
function withFallbackCompileDomain(url: string) {
|
|
|
|
return swapDomain(url, getMeta('ol-fallbackCompileDomain'))
|
|
|
|
}
|
|
|
|
|
2023-01-17 10:23:51 -05:00
|
|
|
function recordFallbackUsage() {
|
|
|
|
setTimeout(() => {
|
|
|
|
postJSON('/record-user-content-domain-fallback-usage').catch(() => {})
|
|
|
|
}, 1_000)
|
|
|
|
}
|