diff --git a/services/web/app/src/Features/Compile/CompileController.js b/services/web/app/src/Features/Compile/CompileController.js
index 897ca5c14f..c5fd9b64b2 100644
--- a/services/web/app/src/Features/Compile/CompileController.js
+++ b/services/web/app/src/Features/Compile/CompileController.js
@@ -58,33 +58,16 @@ const getSplitTestOptions = callbackify(async function (req, res) {
res,
'pdf-download-domain'
)
- const { variant: forceNewDomainVariant } =
- await SplitTestHandler.promises.getAssignment(
- editorReq,
- res,
- 'force-new-compile-domain'
- )
const pdfDownloadDomain =
- (domainVariant === 'user' || forceNewDomainVariant === 'enabled') &&
- Settings.compilesUserContentDomain
+ domainVariant === 'user' && Settings.compilesUserContentDomain
? Settings.compilesUserContentDomain
: Settings.pdfDownloadDomain
- const { variant: hybridDomainVariant } =
- await SplitTestHandler.promises.getAssignment(
- editorReq,
- res,
- 'pdf-download-domain-hybrid'
- )
- const enableHybridPdfDownload = hybridDomainVariant === 'enabled'
-
if (!req.query.enable_pdf_caching) {
// The frontend does not want to do pdf caching.
return {
pdfDownloadDomain,
- enableHybridPdfDownload,
enablePdfCaching: false,
- forceNewDomainVariant,
}
}
@@ -101,18 +84,14 @@ const getSplitTestOptions = callbackify(async function (req, res) {
// Skip the lookup of the chunk size when caching is not enabled.
return {
pdfDownloadDomain,
- enableHybridPdfDownload,
enablePdfCaching: false,
- forceNewDomainVariant,
}
}
const pdfCachingMinChunkSize = await getPdfCachingMinChunkSize(editorReq, res)
return {
pdfDownloadDomain,
- enableHybridPdfDownload,
enablePdfCaching,
pdfCachingMinChunkSize,
- forceNewDomainVariant,
}
})
@@ -154,13 +133,8 @@ module.exports = CompileController = {
getSplitTestOptions(req, res, (err, splitTestOptions) => {
if (err) return next(err)
- let {
- enablePdfCaching,
- pdfCachingMinChunkSize,
- pdfDownloadDomain,
- enableHybridPdfDownload,
- forceNewDomainVariant,
- } = splitTestOptions
+ let { enablePdfCaching, pdfCachingMinChunkSize, pdfDownloadDomain } =
+ splitTestOptions
options.enablePdfCaching = enablePdfCaching
if (enablePdfCaching) {
options.pdfCachingMinChunkSize = pdfCachingMinChunkSize
@@ -227,8 +201,6 @@ module.exports = CompileController = {
timings,
pdfDownloadDomain,
pdfCachingMinChunkSize,
- enableHybridPdfDownload,
- forceNewDomainVariant,
})
}
)
diff --git a/services/web/app/src/Features/Project/ProjectController.js b/services/web/app/src/Features/Project/ProjectController.js
index ccaa065850..e015d47871 100644
--- a/services/web/app/src/Features/Project/ProjectController.js
+++ b/services/web/app/src/Features/Project/ProjectController.js
@@ -713,72 +713,6 @@ const ProjectController = {
}
)
},
- accessCheckForOldCompileDomainAssigment(cb) {
- SplitTestHandler.getAssignment(
- req,
- res,
- 'access-check-for-old-compile-domain',
- () => {
- // We'll pick up the assignment from the res.locals assignment.
- cb()
- }
- )
- },
- forceNewDomainAssignment(cb) {
- SplitTestHandler.getAssignment(
- req,
- res,
- 'force-new-compile-domain',
- () => {
- // We'll pick up the assignment from the res.locals assignment.
- cb()
- }
- )
- },
- userContentDomainAccessCheckAssigment(cb) {
- SplitTestHandler.getAssignment(
- req,
- res,
- 'user-content-domain-access-check',
- () => {
- // We'll pick up the assignment from the res.locals assignment.
- cb()
- }
- )
- },
- userContentDomainAccessCheckDelayAssigment(cb) {
- SplitTestHandler.getAssignment(
- req,
- res,
- 'user-content-domain-access-check-delay',
- () => {
- // We'll pick up the assignment from the res.locals assignment.
- cb()
- }
- )
- },
- userContentDomainAccessCheckMaxChecksAssigment(cb) {
- SplitTestHandler.getAssignment(
- req,
- res,
- 'user-content-domain-access-check-max-checks',
- () => {
- // We'll pick up the assignment from the res.locals assignment.
- cb()
- }
- )
- },
- reportUserContentDomainAccessCheckErrorAssigment(cb) {
- SplitTestHandler.getAssignment(
- req,
- res,
- 'report-user-content-domain-access-check-error',
- () => {
- // We'll pick up the assignment from the res.locals assignment.
- cb()
- }
- )
- },
},
(
err,
diff --git a/services/web/app/src/Features/UserContentDomainCheck/UserContentDomainController.js b/services/web/app/src/Features/UserContentDomainCheck/UserContentDomainController.js
deleted file mode 100644
index 06cc7223c6..0000000000
--- a/services/web/app/src/Features/UserContentDomainCheck/UserContentDomainController.js
+++ /dev/null
@@ -1,30 +0,0 @@
-const Metrics = require('@overleaf/metrics')
-
-function recordCheckResult(req, res) {
- const path = req.body.isOldDomain ? 'old' : ''
- Metrics.count('user_content_domain_check', req.body.succeeded, 1, {
- status: 'success',
- path,
- })
- Metrics.count('user_content_domain_check', req.body.failed, 1, {
- status: 'failure',
- path,
- })
- res.sendStatus(204)
-}
-
-function recordFallbackUsage(_req, res) {
- Metrics.inc('user_content_domain_fallback')
- res.sendStatus(204)
-}
-
-function recordMaxAccessChecksHit(_req, res) {
- Metrics.inc('user_content_domain_max_access_checks_hit')
- res.sendStatus(204)
-}
-
-module.exports = {
- recordCheckResult,
- recordFallbackUsage,
- recordMaxAccessChecksHit,
-}
diff --git a/services/web/app/src/router.js b/services/web/app/src/router.js
index 082cd9ae85..fc50d138b5 100644
--- a/services/web/app/src/router.js
+++ b/services/web/app/src/router.js
@@ -67,7 +67,6 @@ const logger = require('@overleaf/logger')
const _ = require('underscore')
const { plainTextResponse } = require('./infrastructure/Response')
const PublicAccessLevels = require('./Features/Authorization/PublicAccessLevels')
-const UserContentDomainController = require('./Features/UserContentDomainCheck/UserContentDomainController')
const rateLimiters = {
addEmail: new RateLimiter('add-email', {
@@ -201,21 +200,6 @@ const rateLimiters = {
points: 10,
duration: 60,
}),
- userContentDomainAccessCheckResult: new RateLimiter(
- 'user-content-domain-a-c-r',
- {
- points: 30,
- duration: 60,
- }
- ),
- userContentDomainFallbackUsage: new RateLimiter('user-content-fb-u', {
- points: 15,
- duration: 60,
- }),
- userContentDomainMaxAccessChecksHit: new RateLimiter('user-content-mach', {
- points: 15,
- duration: 60,
- }),
}
function initialize(webRouter, privateApiRouter, publicApiRouter) {
@@ -1333,35 +1317,6 @@ function initialize(webRouter, privateApiRouter, publicApiRouter) {
res.sendStatus(204)
})
- webRouter.post(
- '/record-user-content-domain-access-check-result',
- validate({
- body: Joi.object({
- failed: Joi.number().min(0).max(6),
- succeeded: Joi.number().min(0).max(6),
- isOldDomain: Joi.boolean().default(false),
- }),
- }),
- RateLimiterMiddleware.rateLimit(
- rateLimiters.userContentDomainAccessCheckResult
- ),
- UserContentDomainController.recordCheckResult
- )
- webRouter.post(
- '/record-user-content-domain-fallback-usage',
- RateLimiterMiddleware.rateLimit(
- rateLimiters.userContentDomainFallbackUsage
- ),
- UserContentDomainController.recordFallbackUsage
- )
- webRouter.post(
- '/record-user-content-domain-max-access-checks-hit',
- RateLimiterMiddleware.rateLimit(
- rateLimiters.userContentDomainMaxAccessChecksHit
- ),
- UserContentDomainController.recordMaxAccessChecksHit
- )
-
webRouter.get(
`/read/:token(${TokenAccessController.READ_ONLY_TOKEN_PATTERN})`,
RateLimiterMiddleware.rateLimit(rateLimiters.readOnlyToken),
diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json
index abcd898b29..282692528d 100644
--- a/services/web/frontend/extracted-translations.json
+++ b/services/web/frontend/extracted-translations.json
@@ -609,7 +609,7 @@
"need_to_leave": "",
"need_to_upgrade_for_more_collabs": "",
"need_to_upgrade_for_more_collabs_variant": "",
- "new_compile_domain_trouble_shooting": "",
+ "new_compile_domain_notice": "",
"new_file": "",
"new_folder": "",
"new_name": "",
diff --git a/services/web/frontend/js/features/pdf-preview/components/pdf-js-viewer.js b/services/web/frontend/js/features/pdf-preview/components/pdf-js-viewer.js
index c33aa3ca31..a25a72d8c9 100644
--- a/services/web/frontend/js/features/pdf-preview/components/pdf-js-viewer.js
+++ b/services/web/frontend/js/features/pdf-preview/components/pdf-js-viewer.js
@@ -11,10 +11,6 @@ import PdfPreviewErrorBoundaryFallback from './pdf-preview-error-boundary-fallba
import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
import { captureException } from '../../../infrastructure/error-reporter'
import { getPdfCachingMetrics } from '../util/metrics'
-import { userContentDomainAccessCheckFailed } from '../../user-content-domain-access-check'
-import { isURLOnUserContentDomain } from '../util/fetchFromCompileDomain'
-import { isNetworkError } from '../../../utils/isNetworkError'
-import OError from '@overleaf/o-error'
function PdfJsViewer({ url, pdfFile }) {
const { _id: projectId } = useProjectContext()
@@ -130,15 +126,7 @@ function PdfJsViewer({ url, pdfFile }) {
if (abortController.signal.aborted) return
// The error is already logged at the call-site with additional context.
if (err instanceof pdfJsWrapper.PDFJS.MissingPDFException) {
- if (
- // 404 is unrelated to new domain
- OError.getFullInfo(err).statusCode !== 404 &&
- isURLOnUserContentDomain(OError.getFullInfo(err).url)
- ) {
- setError('rendering-error-new-domain')
- } else {
- setError('rendering-error-expected')
- }
+ setError('rendering-error-expected')
} else {
setError('rendering-error')
}
@@ -148,22 +136,7 @@ function PdfJsViewer({ url, pdfFile }) {
.catch(error => {
if (abortController.signal.aborted) return
console.error(error)
- if (
- isURLOnUserContentDomain(url) &&
- error instanceof pdfJsWrapper.PDFJS.UnexpectedResponseException
- ) {
- setError('rendering-error-new-domain')
- } else if (
- isURLOnUserContentDomain(url) &&
- error.name === 'UnknownErrorException' &&
- (isNetworkError(error) || userContentDomainAccessCheckFailed())
- ) {
- // For some reason, pdfJsWrapper.PDFJS.UnknownErrorException is
- // not available for an instance check.
- setError('rendering-error-new-domain')
- } else {
- setError('rendering-error')
- }
+ setError('rendering-error')
})
return () => {
abortController.abort()
diff --git a/services/web/frontend/js/features/pdf-preview/components/pdf-preview-error.js b/services/web/frontend/js/features/pdf-preview/components/pdf-preview-error.js
index 3b1b5d238d..6c9d533352 100644
--- a/services/web/frontend/js/features/pdf-preview/components/pdf-preview-error.js
+++ b/services/web/frontend/js/features/pdf-preview/components/pdf-preview-error.js
@@ -13,32 +13,6 @@ function PdfPreviewError({ error }) {
const { startCompile } = useCompileContext()
switch (error) {
- case 'rendering-error-new-domain':
- return (
- ,
- /* eslint-disable-next-line jsx-a11y/anchor-has-content */
- ,
- ]}
- />
- }
- level="warning"
- />
- )
case 'rendering-error-expected':
return (
,
]}
/>
+ {getMeta('ol-compilesUserContentDomain') && (
+ <>
+
+
+ ,
+ /* eslint-disable-next-line jsx-a11y/anchor-has-content */
+ ,
+ ]}
+ />
+ >
+ )}
)
diff --git a/services/web/frontend/js/features/pdf-preview/util/fetchFromCompileDomain.ts b/services/web/frontend/js/features/pdf-preview/util/fetchFromCompileDomain.ts
deleted file mode 100644
index 7ac76313e9..0000000000
--- a/services/web/frontend/js/features/pdf-preview/util/fetchFromCompileDomain.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-import { isNetworkError } from '../../../utils/isNetworkError'
-import getMeta from '../../../utils/meta'
-import OError from '@overleaf/o-error'
-import { postJSON } from '../../../infrastructure/fetch-json'
-import { isSplitTestEnabled } from '../../../utils/splitTestUtils'
-
-let useFallbackDomainUntil = performance.now()
-const ONE_HOUR_IN_MS = 1000 * 60 * 60
-
-class MaybeBlockedByProxyError extends OError {}
-
-function checkForBlockingByProxy(url: string, 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,
- url,
- statusCode,
- })
- }
-}
-
-export function isURLOnUserContentDomain(url: string) {
- const userContentDomain = getMeta('ol-compilesUserContentDomain')
- return (
- userContentDomain &&
- url &&
- new URL(url).hostname === new URL(userContentDomain).hostname
- )
-}
-
-export async function fetchFromCompileDomain(url: string, init: RequestInit) {
- let isUserContentDomain = isURLOnUserContentDomain(url)
- const fallbackAllowed = !isSplitTestEnabled('force-new-compile-domain')
-
- if (fallbackAllowed && useFallbackDomainUntil > performance.now()) {
- isUserContentDomain = false
- url = withFallbackCompileDomain(url)
- }
- try {
- const res = await fetch(url, init)
- if (isUserContentDomain) {
- // Only throw a MaybeBlockedByProxyError when the request will be retried
- // on the fallback domain below.
- checkForBlockingByProxy(url, res)
- }
- return res
- } catch (err) {
- if (
- fallbackAllowed &&
- isUserContentDomain &&
- (isNetworkError(err) || err instanceof MaybeBlockedByProxyError)
- ) {
- 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
- }
-}
-
-export function swapDomain(url: string, domain: string) {
- const u = new URL(url)
- u.hostname = new URL(domain).hostname
- return u.href
-}
-
-function withFallbackCompileDomain(url: string) {
- return swapDomain(url, getMeta('ol-fallbackCompileDomain'))
-}
-
-function recordFallbackUsage() {
- setTimeout(() => {
- postJSON('/record-user-content-domain-fallback-usage').catch(() => {})
- }, 1_000)
-}
diff --git a/services/web/frontend/js/features/pdf-preview/util/output-files.js b/services/web/frontend/js/features/pdf-preview/util/output-files.js
index 586356461a..e04a33c0e9 100644
--- a/services/web/frontend/js/features/pdf-preview/util/output-files.js
+++ b/services/web/frontend/js/features/pdf-preview/util/output-files.js
@@ -3,8 +3,6 @@ import HumanReadableLogs from '../../../ide/human-readable-logs/HumanReadableLog
import BibLogParser from '../../../ide/log-parser/bib-log-parser'
import { v4 as uuid } from 'uuid'
import { enablePdfCaching } from './pdf-caching-flags'
-import { fetchFromCompileDomain, swapDomain } from './fetchFromCompileDomain'
-import { userContentDomainAccessCheckPassed } from '../../user-content-domain-access-check'
// Warnings that may disappear after a second LaTeX pass
const TRANSIENT_WARNING_REGEX = /^(Reference|Citation).+undefined on input line/
@@ -29,8 +27,7 @@ export function handleOutputFiles(outputFiles, projectId, data) {
outputFile.pdfUrl = `${buildURL(
outputFile,
- data.pdfDownloadDomain,
- data.enableHybridPdfDownload
+ data.pdfDownloadDomain
)}?${params}`
// build the URL for downloading the PDF
@@ -72,10 +69,9 @@ export const handleLogFiles = async (outputFiles, data, signal) => {
if (logFile) {
try {
- const response = await fetchFromCompileDomain(
- buildURL(logFile, data.pdfDownloadDomain, data.enableHybridPdfDownload),
- { signal }
- )
+ const response = await fetch(buildURL(logFile, data.pdfDownloadDomain), {
+ signal,
+ })
result.log = await response.text()
@@ -108,10 +104,9 @@ export const handleLogFiles = async (outputFiles, data, signal) => {
}
for (const blgFile of blgFiles) {
try {
- const response = await fetchFromCompileDomain(
- buildURL(blgFile, data.pdfDownloadDomain, data.enableHybridPdfDownload),
- { signal }
- )
+ const response = await fetch(buildURL(blgFile, data.pdfDownloadDomain), {
+ signal,
+ })
const log = await response.text()
@@ -166,20 +161,7 @@ export function buildLogEntryAnnotations(entries, fileTreeManager) {
return logEntryAnnotations
}
-function buildURL(file, pdfDownloadDomain, enableHybridPdfDownload) {
- const userContentDomain = getMeta('ol-compilesUserContentDomain')
- if (
- enableHybridPdfDownload &&
- userContentDomainAccessCheckPassed() &&
- file.build &&
- userContentDomain
- ) {
- // This user is enrolled in the hybrid download of compile output.
- // The access check passed, so try to use the new user content domain.
- // Downloads from the compiles domains must include a build id.
- // The build id is used implicitly for access control.
- return swapDomain(`${pdfDownloadDomain}${file.url}`, userContentDomain)
- }
+function buildURL(file, pdfDownloadDomain) {
if (file.build && pdfDownloadDomain) {
// Downloads from the compiles domain must include a build id.
// The build id is used implicitly for access control.
diff --git a/services/web/frontend/js/features/pdf-preview/util/pdf-caching-transport.js b/services/web/frontend/js/features/pdf-preview/util/pdf-caching-transport.js
index 626570b76f..017d488eb0 100644
--- a/services/web/frontend/js/features/pdf-preview/util/pdf-caching-transport.js
+++ b/services/web/frontend/js/features/pdf-preview/util/pdf-caching-transport.js
@@ -10,8 +10,6 @@ import {
trackPdfDownloadEnabled,
} from './pdf-caching-flags'
import { isNetworkError } from '../../../utils/isNetworkError'
-import { isSplitTestEnabled } from '../../../utils/splitTestUtils'
-import { isURLOnUserContentDomain } from './fetchFromCompileDomain'
// 30 seconds: The shutdown grace period of a clsi pre-emp instance.
const STALE_OUTPUT_REQUEST_THRESHOLD_MS = 30 * 1000
@@ -78,10 +76,6 @@ export function generatePdfCachingTransportFactory(PDFJS) {
end,
metrics,
})
- const isExpectedFailureOnNewCompileDomain = err =>
- isSplitTestEnabled('force-new-compile-domain') &&
- isURLOnUserContentDomain(OError.getFullInfo(err).url) &&
- OError.getFullInfo(err).responseSize !== this.pdfFile.size
const isStaleOutputRequest = () =>
performance.now() - this.startTime > STALE_OUTPUT_REQUEST_THRESHOLD_MS
@@ -97,9 +91,8 @@ export function generatePdfCachingTransportFactory(PDFJS) {
// - requests for the main output.pdf file
// A fallback request would not be able to retrieve the PDF either.
const isExpectedError = err =>
- ((is404(err) || isNetworkError(err)) &&
- (isStaleOutputRequest() || isFromOutputPDFRequest(err))) ||
- isExpectedFailureOnNewCompileDomain(err)
+ (is404(err) || isNetworkError(err)) &&
+ (isStaleOutputRequest() || isFromOutputPDFRequest(err))
fetchRange({
url: this.url,
@@ -120,8 +113,6 @@ export function generatePdfCachingTransportFactory(PDFJS) {
if (isExpectedError(err)) {
if (is404(err)) {
// A regular pdf-js request would have seen this 404 as well.
- } else if (isExpectedFailureOnNewCompileDomain(err)) {
- // A regular pdf-js request would have seen this proxy-error as well.
} else {
// Flaky network, switch back to regular pdf-js requests.
metrics.failedCount++
diff --git a/services/web/frontend/js/features/pdf-preview/util/pdf-caching.js b/services/web/frontend/js/features/pdf-preview/util/pdf-caching.js
index 4a2a40a571..0e3a40d730 100644
--- a/services/web/frontend/js/features/pdf-preview/util/pdf-caching.js
+++ b/services/web/frontend/js/features/pdf-preview/util/pdf-caching.js
@@ -1,5 +1,4 @@
import OError from '@overleaf/o-error'
-import { fetchFromCompileDomain } from './fetchFromCompileDomain'
const PDF_JS_CHUNK_SIZE = 128 * 1024
const MAX_SUB_REQUEST_COUNT = 4
@@ -485,7 +484,7 @@ export async function fallbackRequest({ url, start, end, abortSignal }) {
headers: { Range: `bytes=${start}-${end - 1}` },
signal: abortSignal,
}
- const response = await fetchFromCompileDomain(url, init)
+ const response = await fetch(url, init)
checkChunkResponse(response, end - start, init)
return await response.arrayBuffer()
} catch (e) {
@@ -564,7 +563,7 @@ async function fetchChunk({
// result all the browser cache keys (aka urls) get invalidated.
// We memorize the previous browser cache keys in `cachedUrls`.
try {
- const response = await fetchFromCompileDomain(oldUrl, init)
+ const response = await fetch(oldUrl, init)
if (response.status === 200) {
checkChunkResponse(response, estimatedSize, init)
metrics.oldUrlHitCount += 1
@@ -579,7 +578,7 @@ async function fetchChunk({
// Fallback to the latest url.
}
}
- const response = await fetchFromCompileDomain(url, init)
+ const response = await fetch(url, init)
checkChunkResponse(response, estimatedSize, init)
if (chunk.hash) cachedUrls.set(chunk.hash, url)
return response
diff --git a/services/web/frontend/js/features/user-content-domain-access-check/index.ts b/services/web/frontend/js/features/user-content-domain-access-check/index.ts
deleted file mode 100644
index 4236603d2b..0000000000
--- a/services/web/frontend/js/features/user-content-domain-access-check/index.ts
+++ /dev/null
@@ -1,314 +0,0 @@
-import {
- checkChunkResponse,
- estimateSizeOfMultipartResponse,
- getMultipartBoundary,
- resolveMultiPartResponses,
-} from '../pdf-preview/util/pdf-caching'
-import getMeta from '../../utils/meta'
-import OError from '@overleaf/o-error'
-import { captureException } from '../../infrastructure/error-reporter'
-import { postJSON } from '../../infrastructure/fetch-json'
-import {
- isSplitTestEnabled,
- parseIntFromSplitTest,
-} from '../../utils/splitTestUtils'
-
-const MAX_CHECKS_PER_PAGE_LOAD = parseIntFromSplitTest(
- 'user-content-domain-access-check-max-checks',
- 3
-)
-const INITIAL_DELAY_MS = parseIntFromSplitTest(
- 'user-content-domain-access-check-delay',
- 30_000
-)
-const TIMEOUT_MS = 30_000
-const FULL_SIZE = 739
-const FULL_HASH =
- 'b7d25591c18da373709d3d88ddf5eeab0b5089359e580f051314fd8935df0b73'
-const CHUNKS = [
- {
- start: 0,
- end: 21,
- hash: 'd2ad9cbf1bc669646c0dfc43fa3167d30ab75077bb46bc9e3624b9e7e168abc2',
- },
- {
- start: 21,
- end: 42,
- hash: 'd6d110ec0f3f4e27a4050bc2be9c5552cc9092f86b74fec75072c2c9e8483454',
- },
- {
- start: 42,
- end: 64,
- hash: '8278914487a3a099c9af5aa22ed836d6587ca0beb7bf9a059fb0409667b3eb3d',
- },
-]
-
-function pickZone() {
- const x = Math.random()
- switch (true) {
- case x > 0.66:
- return 'b'
- case x > 0.33:
- return 'c'
- default:
- return 'd'
- }
-}
-
-function arrayLikeToHex(a: Uint8Array) {
- return Array.from(a)
- .map(i => i.toString(16).padStart(2, '0'))
- .join('')
-}
-
-async function hashBody(body: ArrayBuffer) {
- const digest = await crypto.subtle.digest('SHA-256', body)
- return arrayLikeToHex(new Uint8Array(digest))
-}
-
-async function checkHash(
- res: Response,
- data: ArrayBuffer,
- expectedHash: string
-) {
- const actualHash = await hashBody(data)
- if (actualHash !== expectedHash) {
- throw new OError('content hash mismatch', {
- actualHash,
- expectedHash,
- headers: Object.fromEntries(res.headers.entries()),
- })
- }
-}
-
-function randomHex(bytes: number) {
- const buf = new Uint8Array(bytes)
- crypto.getRandomValues(buf)
- return arrayLikeToHex(buf)
-}
-
-function genBuildId() {
- const date = Date.now().toString(16)
- const random = randomHex(8)
- return `${date}-${random}`
-}
-
-async function singleCheck(
- url: string,
- init: RequestInit,
- estimatedSize: number,
- expectedHash: string,
- chunks?: Array
-) {
- const ac = new AbortController()
- setTimeout(() => ac.abort(), TIMEOUT_MS)
- init.signal = ac.signal
- init.cache = 'no-store'
-
- const res = await fetch(url, init)
- checkChunkResponse(res, estimatedSize, init)
-
- const body = await res.arrayBuffer()
- if (chunks) {
- const boundary = getMultipartBoundary(res, chunks)
- const parts = resolveMultiPartResponses({
- file: { size: FULL_SIZE },
- chunks,
- data: new Uint8Array(body),
- boundary,
- metrics: {},
- })
- for (const part of parts) {
- await checkHash(res, part.data, part.chunk.hash)
- }
- } else {
- await checkHash(res, body, expectedHash)
- }
-}
-
-export async function checkUserContentDomainAccess(
- compileDomainOrigin: string
-) {
- // Note: The ids are zero prefixed. No actual user/project uses these ids.
- // mongo-id 000000000000000000000000 -> 1970-01-01T00:00:00.000Z
- // mongo-id 000000010000000000000000 -> 1970-01-01T00:00:01.000Z
- // mongo-id 100000000000000000000000 -> 1978-07-04T21:24:16.000Z
- // This allows us to distinguish between check-traffic and regular output
- // traffic.
- const projectId = `0${randomHex(12).slice(1)}`
- const userId = `0${randomHex(12).slice(1)}`
- const buildId = genBuildId()
- const zone = pickZone()
- const urls = []
- if (getMeta('ol-user_id')) {
- // Logged-in user
- urls.push(
- `${compileDomainOrigin}/zone/${zone}/project/${projectId}/user/${userId}/build/${buildId}/output/output.pdf`
- )
- } else {
- // Anonymous user
- urls.push(
- `${compileDomainOrigin}/zone/${zone}/project/${projectId}/build/${buildId}/output/output.pdf`
- )
- }
-
- const cases = []
- for (const url of urls) {
- // full download
- cases.push({
- url,
- init: {},
- estimatedSize: FULL_SIZE,
- hash: FULL_HASH,
- })
-
- // range request
- const chunk = CHUNKS[0]
- cases.push({
- url,
- init: {
- headers: {
- Range: `bytes=${chunk.start}-${chunk.end - 1}`,
- },
- },
- estimatedSize: chunk.end - chunk.start,
- hash: chunk.hash,
- })
-
- // multipart request
- cases.push({
- url,
- init: {
- headers: {
- Range: `bytes=${CHUNKS.map(c => `${c.start}-${c.end - 1}`).join(
- ','
- )}`,
- },
- },
- estimatedSize: estimateSizeOfMultipartResponse(CHUNKS),
- hash: chunk.hash,
- chunks: CHUNKS,
- })
- }
-
- let failed = 0
- let ignoreResult = false
- const epochBeforeCheck = networkEpoch
- await Promise.all(
- cases.map(async ({ url, init, estimatedSize, hash, chunks }) => {
- try {
- await singleCheck(url, init, estimatedSize, hash, chunks)
- } catch (err: any) {
- if (!navigator.onLine || epochBeforeCheck !== networkEpoch) {
- // It is very likely that the request failed because we are offline or
- // the network connection changed just now.
- ignoreResult = true
- }
- if (ignoreResult) return
-
- failed++
- OError.tag(err, 'user-content-domain-access-check failed', {
- url,
- init,
- })
- if (
- isSplitTestEnabled('report-user-content-domain-access-check-error')
- ) {
- captureException(err, {
- tags: { compileDomain: new URL(compileDomainOrigin).hostname },
- })
- } else {
- console.error(OError.getFullStack(err), OError.getFullInfo(err))
- }
- }
- })
- )
- if (ignoreResult) return false
-
- try {
- await postJSON('/record-user-content-domain-access-check-result', {
- body: {
- failed,
- succeeded: cases.length - failed,
- isOldDomain:
- compileDomainOrigin === getMeta('ol-fallbackCompileDomain'),
- },
- })
- } catch (e) {}
-
- return failed === 0
-}
-
-const ACCESS_CHECK_PASSED = 'passed'
-const ACCESS_CHECK_PENDING = 'pending'
-const ACCESS_CHECK_FAILED = 'failed'
-let accessCheckStatus = ACCESS_CHECK_PENDING
-
-export function userContentDomainAccessCheckPassed() {
- return accessCheckStatus === ACCESS_CHECK_PASSED
-}
-export function userContentDomainAccessCheckFailed() {
- return accessCheckStatus === ACCESS_CHECK_FAILED
-}
-
-let networkEpoch = performance.now()
-window.addEventListener('offline', () => {
- // We are offline. Abort any scheduled check.
- clearTimeout(lastScheduledCheck)
- accessCheckStatus = ACCESS_CHECK_PENDING
- networkEpoch = performance.now()
-})
-window.addEventListener('online', () => {
- // We are online again. Schedule another check for this network.
- accessCheckStatus = ACCESS_CHECK_PENDING
- networkEpoch = performance.now()
- scheduleUserContentDomainAccessCheck()
-})
-try {
- // Note: navigator.connection is not available on Firefox and Safari.
- // Docs: https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation
- // @ts-ignore
- navigator.connection.addEventListener('change', () => {
- // The network changed. Schedule another check for it.
- accessCheckStatus = ACCESS_CHECK_PENDING
- networkEpoch = performance.now()
- scheduleUserContentDomainAccessCheck()
- })
-} catch (e) {}
-
-let lastScheduledCheck: number
-let remainingChecks = MAX_CHECKS_PER_PAGE_LOAD
-export function scheduleUserContentDomainAccessCheck() {
- if (!isSplitTestEnabled('user-content-domain-access-check')) return
- clearTimeout(lastScheduledCheck)
- const networkEpochBeforeDelay = networkEpoch
- lastScheduledCheck = window.setTimeout(() => {
- if (!window.navigator.onLine || networkEpochBeforeDelay !== networkEpoch) {
- // Must be online for more than INITIAL_DELAY_MS before we check.
- // We want to avoid false-positives from flaky network connections.
- // Try again in INITIAL_DELAY_MS.
- return scheduleUserContentDomainAccessCheck()
- }
- if (userContentDomainAccessCheckPassed()) return
- if (remainingChecks === 0) {
- recordMaxAccessChecksHit()
- }
- if (remainingChecks-- <= 0) return
- if (isSplitTestEnabled('access-check-for-old-compile-domain')) {
- checkUserContentDomainAccess(getMeta('ol-fallbackCompileDomain')).catch(
- () => {}
- )
- }
- checkUserContentDomainAccess(getMeta('ol-compilesUserContentDomain'))
- .then(ok => {
- accessCheckStatus = ok ? ACCESS_CHECK_PASSED : ACCESS_CHECK_FAILED
- })
- .catch(err => {
- captureException(err)
- })
- }, INITIAL_DELAY_MS)
-}
-
-function recordMaxAccessChecksHit() {
- postJSON('/record-user-content-domain-max-access-checks-hit').catch(() => {})
-}
diff --git a/services/web/frontend/js/ide.js b/services/web/frontend/js/ide.js
index 77badf44a9..e1b9a6066f 100644
--- a/services/web/frontend/js/ide.js
+++ b/services/web/frontend/js/ide.js
@@ -73,7 +73,6 @@ import './features/history/controllers/history-file-tree-controller'
import { cleanupServiceWorker } from './utils/service-worker-cleanup'
import { reportCM6Perf } from './infrastructure/cm6-performance'
import { reportAcePerf } from './ide/editor/ace-performance'
-import { scheduleUserContentDomainAccessCheck } from './features/user-content-domain-access-check'
App.controller(
'IdeController',
@@ -487,7 +486,6 @@ If the project has been renamed please look in your project list for a new proje
)
cleanupServiceWorker()
-scheduleUserContentDomainAccessCheck()
angular.module('SharelatexApp').config(function ($provide) {
$provide.decorator('$browser', [
diff --git a/services/web/frontend/js/shared/context/detach-compile-context.js b/services/web/frontend/js/shared/context/detach-compile-context.js
index 14491a826f..fd743fe5a2 100644
--- a/services/web/frontend/js/shared/context/detach-compile-context.js
+++ b/services/web/frontend/js/shared/context/detach-compile-context.js
@@ -1,4 +1,4 @@
-import { createContext, useContext, useEffect, useMemo } from 'react'
+import { createContext, useContext, useMemo } from 'react'
import PropTypes from 'prop-types'
import {
useLocalCompileContext,
@@ -7,7 +7,6 @@ import {
import useDetachStateWatcher from '../hooks/use-detach-state-watcher'
import useDetachAction from '../hooks/use-detach-action'
import useCompileTriggers from '../../features/pdf-preview/hooks/use-compile-triggers'
-import getMeta from '../../utils/meta'
export const DetachCompileContext = createContext()
@@ -33,7 +32,6 @@ export function DetachCompileProvider({ children }) {
editedSinceCompileStarted: _editedSinceCompileStarted,
error: _error,
fileList: _fileList,
- forceNewDomainVariant: _forceNewDomainVariant,
hasChanges: _hasChanges,
highlights: _highlights,
lastCompileOptions: _lastCompileOptions,
@@ -125,12 +123,6 @@ export function DetachCompileProvider({ children }) {
'detacher',
'detached'
)
- const [forceNewDomainVariant] = useDetachStateWatcher(
- 'forceNewDomainVariant',
- _forceNewDomainVariant,
- 'detacher',
- 'detached'
- )
const [hasChanges] = useDetachStateWatcher(
'hasChanges',
_hasChanges,
@@ -375,11 +367,6 @@ export function DetachCompileProvider({ children }) {
)
useCompileTriggers(startCompile, setChangedAt, setSavedAt)
- useEffect(() => {
- // Sync the split test variant across the editor and pdf-detach.
- const variants = getMeta('ol-splitTestVariants') || {}
- variants['force-new-compile-domain'] = forceNewDomainVariant
- }, [forceNewDomainVariant])
const value = useMemo(
() => ({
@@ -395,7 +382,6 @@ export function DetachCompileProvider({ children }) {
editedSinceCompileStarted,
error,
fileList,
- forceNewDomainVariant,
hasChanges,
highlights,
lastCompileOptions,
@@ -449,7 +435,6 @@ export function DetachCompileProvider({ children }) {
error,
editedSinceCompileStarted,
fileList,
- forceNewDomainVariant,
hasChanges,
highlights,
lastCompileOptions,
diff --git a/services/web/frontend/js/shared/context/local-compile-context.js b/services/web/frontend/js/shared/context/local-compile-context.js
index 14db362f5d..fc50661c48 100644
--- a/services/web/frontend/js/shared/context/local-compile-context.js
+++ b/services/web/frontend/js/shared/context/local-compile-context.js
@@ -29,7 +29,6 @@ import { useEditorContext } from './editor-context'
import { buildFileList } from '../../features/pdf-preview/util/file-list'
import { useLayoutContext } from './layout-context'
import { useUserContext } from './user-context'
-import getMeta from '../../utils/meta'
export const LocalCompileContext = createContext()
@@ -44,7 +43,6 @@ export const CompileContextPropTypes = {
draft: PropTypes.bool.isRequired,
error: PropTypes.string,
fileList: PropTypes.object,
- forceNewDomainVariant: PropTypes.string,
hasChanges: PropTypes.bool.isRequired,
highlights: PropTypes.arrayOf(PropTypes.object),
logEntries: PropTypes.object,
@@ -174,11 +172,6 @@ export function LocalCompileProvider({ children }) {
// the list of files that can be downloaded
const [fileList, setFileList] = useState()
- // Split test variant for disabling the fallback, refreshed on re-compile.
- const [forceNewDomainVariant, setForceNewDomainVariant] = useState(
- getMeta('ol-splitTestVariants')?.['force-new-compile-domain']
- )
-
// the raw contents of the log file
const [rawLog, setRawLog] = useState()
@@ -323,7 +316,6 @@ export function LocalCompileProvider({ children }) {
setShowFasterCompilesFeedbackUI(
Boolean(data.showFasterCompilesFeedbackUI)
)
- setForceNewDomainVariant(data.forceNewDomainVariant || 'default')
if (data.outputFiles) {
const outputFiles = new Map()
@@ -561,7 +553,6 @@ export function LocalCompileProvider({ children }) {
editedSinceCompileStarted,
error,
fileList,
- forceNewDomainVariant,
hasChanges,
highlights,
lastCompileOptions,
@@ -616,7 +607,6 @@ export function LocalCompileProvider({ children }) {
editedSinceCompileStarted,
error,
fileList,
- forceNewDomainVariant,
hasChanges,
highlights,
lastCompileOptions,
diff --git a/services/web/locales/en.json b/services/web/locales/en.json
index f693bd9e12..0c31e815a7 100644
--- a/services/web/locales/en.json
+++ b/services/web/locales/en.json
@@ -1004,7 +1004,7 @@
"need_to_leave": "Need to leave?",
"need_to_upgrade_for_more_collabs": "You need to upgrade your account to add more collaborators",
"need_to_upgrade_for_more_collabs_variant": "You have reached the maximum number of collaborators. Upgrade your account to add more.",
- "new_compile_domain_trouble_shooting": "We are migrating PDF downloads to a new domain. It looks like something is blocking your browser from accessing that new domain, <0>__compilesUserContentDomain__0>. This could be caused by network blocking or a strict browser plugin rule. Please follow our <1>troubleshooting guide1>.",
+ "new_compile_domain_notice": "We’ve recently migrated PDF downloads to a new domain. Something might be blocking your browser from accessing that new domain, <0>__compilesUserContentDomain__0>. This could be caused by network blocking or a strict browser plugin rule. Please follow our <1>troubleshooting guide1>.",
"new_file": "New File",
"new_folder": "New Folder",
"new_name": "New Name",
diff --git a/services/web/test/frontend/components/pdf-preview/pdf-preview.spec.tsx b/services/web/test/frontend/components/pdf-preview/pdf-preview.spec.tsx
index 887c44961a..9a3cefc7af 100644
--- a/services/web/test/frontend/components/pdf-preview/pdf-preview.spec.tsx
+++ b/services/web/test/frontend/components/pdf-preview/pdf-preview.spec.tsx
@@ -23,6 +23,10 @@ const Layout: FC<{ layout: string; view?: string }> = ({ layout, view }) => {
describe('', function () {
beforeEach(function () {
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
+ window.metaAttributesCache.set(
+ 'ol-compilesUserContentDomain',
+ 'https://compiles-user.dev-overleaf.com'
+ )
cy.interceptEvents()
})
diff --git a/services/web/test/unit/src/Compile/CompileControllerTests.js b/services/web/test/unit/src/Compile/CompileControllerTests.js
index 1b1889ff82..45e8da9450 100644
--- a/services/web/test/unit/src/Compile/CompileControllerTests.js
+++ b/services/web/test/unit/src/Compile/CompileControllerTests.js
@@ -126,8 +126,6 @@ describe('CompileController', function () {
},
],
pdfDownloadDomain: 'https://compiles.overleaf.test',
- enableHybridPdfDownload: false,
- forceNewDomainVariant: 'default',
})
)
})
@@ -170,8 +168,6 @@ describe('CompileController', function () {
},
],
pdfDownloadDomain: 'https://compiles.overleaf.test/zone/b',
- enableHybridPdfDownload: false,
- forceNewDomainVariant: 'default',
})
)
})
@@ -213,8 +209,6 @@ describe('CompileController', function () {
JSON.stringify({
status: this.status,
outputFiles: this.outputFiles,
- enableHybridPdfDownload: false,
- forceNewDomainVariant: 'default',
})
)
})