Просмотр исходного кода

Merge pull request #11442 from overleaf/jpa-hybrid-pdf-download

[web] add hybrid download of compile output

GitOrigin-RevId: b9c6dfc86e3af2f7b1728e791f074ec6d5e0badf
Jakob Ackermann 3 лет назад
Родитель
Сommit
1f14e08fa1

+ 31 - 5
services/web/app/src/Features/Compile/CompileController.js

@@ -58,9 +58,21 @@ const getSplitTestOptions = callbackify(async function (req, res) {
       ? 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, enablePdfCaching: false }
+    return {
+      pdfDownloadDomain,
+      enableHybridPdfDownload,
+      enablePdfCaching: false,
+    }
   }
 
   // Double check with the latest split test assignment.
@@ -74,10 +86,19 @@ const getSplitTestOptions = callbackify(async function (req, res) {
   const enablePdfCaching = variant === 'enabled'
   if (!enablePdfCaching) {
     // Skip the lookup of the chunk size when caching is not enabled.
-    return { pdfDownloadDomain, enablePdfCaching: false }
+    return {
+      pdfDownloadDomain,
+      enableHybridPdfDownload,
+      enablePdfCaching: false,
+    }
   }
   const pdfCachingMinChunkSize = await getPdfCachingMinChunkSize(editorReq, res)
-  return { pdfDownloadDomain, enablePdfCaching, pdfCachingMinChunkSize }
+  return {
+    pdfDownloadDomain,
+    enableHybridPdfDownload,
+    enablePdfCaching,
+    pdfCachingMinChunkSize,
+  }
 })
 
 module.exports = CompileController = {
@@ -118,8 +139,12 @@ module.exports = CompileController = {
 
     getSplitTestOptions(req, res, (err, splitTestOptions) => {
       if (err) return next(err)
-      let { enablePdfCaching, pdfCachingMinChunkSize, pdfDownloadDomain } =
-        splitTestOptions
+      let {
+        enablePdfCaching,
+        pdfCachingMinChunkSize,
+        pdfDownloadDomain,
+        enableHybridPdfDownload,
+      } = splitTestOptions
       options.enablePdfCaching = enablePdfCaching
       if (enablePdfCaching) {
         options.pdfCachingMinChunkSize = pdfCachingMinChunkSize
@@ -186,6 +211,7 @@ module.exports = CompileController = {
             timings,
             pdfDownloadDomain,
             pdfCachingMinChunkSize,
+            enableHybridPdfDownload,
           })
         }
       )

+ 6 - 2
services/web/frontend/js/features/pdf-preview/util/fetchFromCompileDomain.ts

@@ -38,12 +38,16 @@ export async function fetchFromCompileDomain(url: string, init: RequestInit) {
   }
 }
 
-function withFallbackCompileDomain(url: string) {
+export function swapDomain(url: string, domain: string) {
   const u = new URL(url)
-  u.hostname = new URL(getMeta('ol-fallbackCompileDomain')).hostname
+  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(() => {})

+ 20 - 5
services/web/frontend/js/features/pdf-preview/util/output-files.js

@@ -3,7 +3,8 @@ 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 } from './fetchFromCompileDomain'
+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/
@@ -28,7 +29,8 @@ export function handleOutputFiles(outputFiles, projectId, data) {
 
   outputFile.pdfUrl = `${buildURL(
     outputFile,
-    data.pdfDownloadDomain
+    data.pdfDownloadDomain,
+    data.enableHybridPdfDownload
   )}?${params}`
 
   // build the URL for downloading the PDF
@@ -71,7 +73,7 @@ export const handleLogFiles = async (outputFiles, data, signal) => {
   if (logFile) {
     try {
       const response = await fetchFromCompileDomain(
-        buildURL(logFile, data.pdfDownloadDomain),
+        buildURL(logFile, data.pdfDownloadDomain, data.enableHybridPdfDownload),
         { signal }
       )
 
@@ -102,7 +104,7 @@ export const handleLogFiles = async (outputFiles, data, signal) => {
   if (blgFile) {
     try {
       const response = await fetchFromCompileDomain(
-        buildURL(blgFile, data.pdfDownloadDomain),
+        buildURL(blgFile, data.pdfDownloadDomain, data.enableHybridPdfDownload),
         { signal }
       )
 
@@ -159,7 +161,20 @@ export function buildLogEntryAnnotations(entries, fileTreeManager) {
   return logEntryAnnotations
 }
 
-function buildURL(file, pdfDownloadDomain) {
+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)
+  }
   if (file.build && pdfDownloadDomain) {
     // Downloads from the compiles domain must include a build id.
     // The build id is used implicitly for access control.

+ 15 - 3
services/web/frontend/js/features/user-content-domain-access-check/index.ts

@@ -204,12 +204,24 @@ export async function checkUserContentDomainAccess() {
       body: { failed, succeeded: cases.length - failed },
     })
   } catch (e) {}
+
+  return failed === 0
+}
+
+let accessCheckPassed = false
+
+export function userContentDomainAccessCheckPassed() {
+  return accessCheckPassed
 }
 
 export function scheduleUserContentDomainAccessCheck() {
   sleep(INITIAL_DELAY_MS).then(() => {
-    checkUserContentDomainAccess().catch(err => {
-      captureException(err)
-    })
+    checkUserContentDomainAccess()
+      .then(ok => {
+        accessCheckPassed = ok
+      })
+      .catch(err => {
+        captureException(err)
+      })
   })
 }

+ 3 - 0
services/web/test/unit/src/Compile/CompileControllerTests.js

@@ -121,6 +121,7 @@ describe('CompileController', function () {
                 },
               ],
               pdfDownloadDomain: 'https://compiles.overleaf.test',
+              enableHybridPdfDownload: false,
             })
           )
         })
@@ -163,6 +164,7 @@ describe('CompileController', function () {
                 },
               ],
               pdfDownloadDomain: 'https://compiles.overleaf.test/zone/b',
+              enableHybridPdfDownload: false,
             })
           )
         })
@@ -204,6 +206,7 @@ describe('CompileController', function () {
           JSON.stringify({
             status: this.status,
             outputFiles: this.outputFiles,
+            enableHybridPdfDownload: false,
           })
         )
       })