From 71b0e4e8182b1e4b75c7dac8510ec755b4d819df Mon Sep 17 00:00:00 2001
From: Yury Delendik <ydelendik@mozilla.com>
Date: Thu, 28 Sep 2017 16:45:04 -0500
Subject: [PATCH] Closes all promises/streams when handler is destroyed.

---
 src/core/worker.js | 11 ++++++-----
 src/display/api.js | 18 +++++++++---------
 src/shared/util.js | 27 ++++++++++++++++++++++++++-
 3 files changed, 41 insertions(+), 15 deletions(-)

diff --git a/src/core/worker.js b/src/core/worker.js
index a905efe27..40069215c 100644
--- a/src/core/worker.js
+++ b/src/core/worker.js
@@ -14,10 +14,11 @@
  */
 
 import {
-  arrayByteLength, arraysToBytes, assert, createPromiseCapability, info,
-  InvalidPDFException, isNodeJS, MessageHandler, MissingPDFException,
-  PasswordException, setVerbosityLevel, UnexpectedResponseException,
-  UnknownErrorException, UNSUPPORTED_FEATURES, warn, XRefParseException
+  AbortException, arrayByteLength, arraysToBytes, assert,
+  createPromiseCapability, info, InvalidPDFException, isNodeJS, MessageHandler,
+  MissingPDFException, PasswordException, setVerbosityLevel,
+  UnexpectedResponseException, UnknownErrorException, UNSUPPORTED_FEATURES,
+  warn, XRefParseException
 } from '../shared/util';
 import { LocalPdfManager, NetworkPdfManager } from './pdf_manager';
 import { Ref } from './primitives';
@@ -841,7 +842,7 @@ var WorkerMessageHandler = {
       return Promise.all(waitOn).then(function () {
         // Notice that even if we destroying handler, resolved response promise
         // must be sent back.
-        handler.destroy();
+        handler.close(new AbortException('Worker was terminated'));
         handler = null;
       });
     });
diff --git a/src/display/api.js b/src/display/api.js
index 63bb9fc85..74e9876b0 100644
--- a/src/display/api.js
+++ b/src/display/api.js
@@ -15,11 +15,11 @@
 /* globals requirejs, __non_webpack_require__ */
 
 import {
-  assert, createPromiseCapability, deprecated, getVerbosityLevel, info,
-  InvalidPDFException, isArrayBuffer, isSameOrigin, loadJpegStream,
-  MessageHandler, MissingPDFException, NativeImageDecoding, PageViewport,
-  PasswordException, StatTimer, stringToBytes, UnexpectedResponseException,
-  UnknownErrorException, Util, warn
+  AbortException, assert, createPromiseCapability, deprecated,
+  getVerbosityLevel, info, InvalidPDFException, isArrayBuffer, isSameOrigin,
+  loadJpegStream, MessageHandler, MissingPDFException, NativeImageDecoding,
+  PageViewport, PasswordException, StatTimer, stringToBytes,
+  UnexpectedResponseException, UnknownErrorException, Util, warn
 } from '../shared/util';
 import {
   DOMCanvasFactory, DOMCMapReaderFactory, getDefaultSetting,
@@ -1382,7 +1382,7 @@ var PDFWorker = (function PDFWorkerClosure() {
           var messageHandler = new MessageHandler('main', 'worker', worker);
           var terminateEarly = () => {
             worker.removeEventListener('error', onWorkerError);
-            messageHandler.destroy();
+            messageHandler.close(new Error('Worker was terminated'));
             worker.terminate();
             if (this.destroyed) {
               this._readyCapability.reject(new Error('Worker was destroyed'));
@@ -1424,7 +1424,7 @@ var PDFWorker = (function PDFWorkerClosure() {
               });
             } else {
               this._setupFakeWorker();
-              messageHandler.destroy();
+              messageHandler.close(new Error('Worker was terminated'));
               worker.terminate();
             }
           });
@@ -1527,7 +1527,7 @@ var PDFWorker = (function PDFWorkerClosure() {
       pdfWorkerPorts.delete(this._port);
       this._port = null;
       if (this._messageHandler) {
-        this._messageHandler.destroy();
+        this._messageHandler.close(new AbortException('Worker was destroyed'));
         this._messageHandler = null;
       }
     },
@@ -1607,7 +1607,7 @@ var WorkerTransport = (function WorkerTransportClosure() {
         }
 
         if (this.messageHandler) {
-          this.messageHandler.destroy();
+          this.messageHandler.close(new AbortException('Worker was destroyed'));
           this.messageHandler = null;
         }
         this.destroyCapability.resolve();
diff --git a/src/shared/util.js b/src/shared/util.js
index 28bf9221c..30751a935 100644
--- a/src/shared/util.js
+++ b/src/shared/util.js
@@ -1632,8 +1632,33 @@ MessageHandler.prototype = {
     }
   },
 
-  destroy() {
+  close(reason) {
     this.comObj.removeEventListener('message', this._onComObjOnMessage);
+
+    // Reject all promises and streams.
+    for (let i in this.callbacksCapabilities) {
+      const callbackCapability = this.callbacksCapabilities[i];
+      callbackCapability.reject(reason);
+    }
+    for (let i in this.streamSinks) {
+      const sink = this.streamSinks[i];
+      sink.sinkCapability.reject(reason);
+    }
+    for (let i in this.streamControllers) {
+      const controller = this.streamControllers[i];
+      if (!controller.isClosed) {
+        controller.controller.error(reason);
+      }
+      if (controller.startCall) {
+        controller.startCall.reject(reason);
+      }
+      if (controller.pullCall) {
+        controller.pullCall.reject(reason);
+      }
+      if (controller.cancelCall) {
+        controller.cancelCall.reject(reason);
+      }
+    }
   },
 };