From 7d3632d5d543ed05e75cc254b4be6f1659f26dbd Mon Sep 17 00:00:00 2001
From: Jonas Jenwald <jonas.jenwald@gmail.com>
Date: Thu, 7 Jan 2021 10:22:02 +0100
Subject: [PATCH] Improve the `PDFViewerApplication._contentLength` handling in
 the viewer, related mostly to scripting

Ensure that `PDFViewerApplication._contentLength` is always updated with the *correct* length, as returned by `PDFDocumentProxy.getDownloadInfo`, and only let the `PDFViewerApplication._initializeMetadata` method overwrite if it's not already been set.

Finally, in `PDFViewerApplication._initializeJavaScript`, the fallback `_contentLength` handling is now moved to just after the fallback `documentInfo` handling, such that all the fallback code is in one place within the method.
---
 web/app.js | 38 ++++++++++++++++++++++----------------
 1 file changed, 22 insertions(+), 16 deletions(-)

diff --git a/web/app.js b/web/app.js
index 1c44dc548..534b39b73 100644
--- a/web/app.js
+++ b/web/app.js
@@ -1242,7 +1242,8 @@ const PDFViewerApplication = {
   load(pdfDocument) {
     this.pdfDocument = pdfDocument;
 
-    pdfDocument.getDownloadInfo().then(() => {
+    pdfDocument.getDownloadInfo().then(({ length }) => {
+      this._contentLength = length; // Ensure that the correct length is used.
       this.downloadComplete = true;
       this.loadingBar.hide();
 
@@ -1498,6 +1499,25 @@ const PDFViewerApplication = {
         return; // The document was closed while the metadata resolved.
       }
     }
+    if (!this._contentLength) {
+      // Always waiting for the entire PDF document to be loaded will, most
+      // likely, delay sandbox-creation too much in the general case for all
+      // PDF documents which are not provided as binary data to the API.
+      // Hence we'll simply have to trust that the `contentLength` (as provided
+      // by the server), when it exists, is accurate enough here.
+      await new Promise(resolve => {
+        this.eventBus._on(
+          "documentloaded",
+          evt => {
+            resolve();
+          },
+          { once: true }
+        );
+      });
+      if (pdfDocument !== this.pdfDocument) {
+        return; // The document was closed while the downloadInfo resolved.
+      }
+    }
 
     const updateFromSandbox = ({ detail }) => {
       const { id, command, value } = detail;
@@ -1564,20 +1584,6 @@ const PDFViewerApplication = {
       window.addEventListener(name, listener);
     }
 
-    if (!this._contentLength) {
-      // Always waiting for the entire PDF document to be loaded will, most
-      // likely, delay sandbox-creation too much in the general case for all
-      // PDF documents which are not provided as binary data to the API.
-      // Hence we'll simply have to trust that the `contentLength` (as provided
-      // by the server), when it exists, is accurate enough here.
-      const { length } = await pdfDocument.getDownloadInfo();
-
-      if (pdfDocument !== this.pdfDocument) {
-        return; // The document was closed while the download info resolved.
-      }
-      this._contentLength = length;
-    }
-
     try {
       await scripting.createSandbox({
         objects,
@@ -1701,7 +1707,7 @@ const PDFViewerApplication = {
     this.documentInfo = info;
     this.metadata = metadata;
     this._contentDispositionFilename = contentDispositionFilename;
-    this._contentLength = contentLength;
+    this._contentLength ??= contentLength; // See `getDownloadInfo`-call above.
 
     // Provides some basic debug information
     console.log(