From 959ce38f5bbeaeb79dda44b66db1f967412c3953 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Fri, 5 Jun 2026 12:25:53 +0200 Subject: [PATCH] Reject the stream-capability when aborting the `ChunkedStreamManager` Given that any incoming data is already being ignored after loading has been aborted, it seems reasonable to reject the stream-capability to avoid it remaining in a pending state indefinitely. *Note:* This is something that I noticed while looking at the coverage data, since the `ChunkedStreamManager.prototype.onError` method is not used and from a brief look at the history of the code it never appears to have been used either. --- src/core/chunked_stream.js | 19 ++++++++----------- src/core/worker.js | 13 +++++++++---- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/core/chunked_stream.js b/src/core/chunked_stream.js index 277e51ce0..86f7d7660 100644 --- a/src/core/chunked_stream.js +++ b/src/core/chunked_stream.js @@ -260,13 +260,13 @@ class ChunkedStream extends Stream { } class ChunkedStreamManager { - aborted = false; + #aborted = false; currRequestId = 0; _chunksNeededByRequest = new Map(); - _loadedStreamCapability = Promise.withResolvers(); + #loadedStreamCapability = Promise.withResolvers(); _promisesByRequest = new Map(); @@ -288,7 +288,7 @@ class ChunkedStreamManager { while (true) { const { value, done } = await rangeReader.read(); - if (this.aborted) { + if (this.#aborted) { chunks = null; return; // Ignoring any data after abort. } @@ -323,7 +323,7 @@ class ChunkedStreamManager { const missingChunks = this.stream.getMissingChunks(); this._requestChunks(missingChunks); } - return this._loadedStreamCapability.promise; + return this.#loadedStreamCapability.promise; } _requestChunks(chunks) { @@ -369,7 +369,7 @@ class ChunkedStreamManager { } return capability.promise.catch(reason => { - if (this.aborted) { + if (this.#aborted) { return; // Ignoring any pending requests after abort. } throw reason; @@ -459,7 +459,7 @@ class ChunkedStreamManager { } if (stream.isDataLoaded) { - this._loadedStreamCapability.resolve(stream); + this.#loadedStreamCapability.resolve(stream); } const loadedRequests = []; @@ -520,10 +520,6 @@ class ChunkedStreamManager { }); } - onError(err) { - this._loadedStreamCapability.reject(err); - } - getBeginChunk(begin) { return Math.floor(begin / this.chunkSize); } @@ -533,12 +529,13 @@ class ChunkedStreamManager { } abort(reason) { - this.aborted = true; + this.#aborted = true; this.pdfStream?.cancelAllRequests(reason); for (const capability of this._promisesByRequest.values()) { capability.reject(reason); } + this.#loadedStreamCapability.reject(reason); } } diff --git a/src/core/worker.js b/src/core/worker.js index b5a4a28be..43f135189 100644 --- a/src/core/worker.js +++ b/src/core/worker.js @@ -355,7 +355,7 @@ class WorkerMessageHandler { ensureNotTerminated(); loadDocument(true).then(onSuccess, onFailure); - }); + }, onFailure); }); } @@ -373,9 +373,14 @@ class WorkerMessageHandler { } pdfManager = newPdfManager; - pdfManager.requestLoadedStream(/* noFetch = */ true).then(stream => { - handler.send("DataLoaded", { length: stream.bytes.byteLength }); - }); + pdfManager.requestLoadedStream(/* noFetch = */ true).then( + stream => { + handler.send("DataLoaded", { length: stream.bytes.byteLength }); + }, + () => { + // Avoid errors if document loading was terminated. + } + ); }) .then(pdfManagerReady, onFailure); }