From c4fdb2857367dcf1c1edfac7f27e5959455463de Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sun, 28 Jul 2024 16:08:09 +0200 Subject: [PATCH] Remove `PDFWorkerUtil` and move its contents into `PDFWorker` instead This is possible thanks to features, i.e. private fields and in particular static initialization blocks, that didn't exist back when we started using classes in the code-base. --- src/display/api.js | 98 ++++++++++++++++++++++--------------------- test/unit/api_spec.js | 55 +++++++++++------------- 2 files changed, 75 insertions(+), 78 deletions(-) diff --git a/src/display/api.js b/src/display/api.js index 02e2bad9995ed..571f1e677f02f 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -1998,47 +1998,6 @@ class LoopbackPort { * the constants from {@link VerbosityLevel} should be used. */ -const PDFWorkerUtil = { - isWorkerDisabled: false, - fakeWorkerId: 0, -}; -if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) { - if (isNodeJS) { - // Workers aren't supported in Node.js, force-disabling them there. - PDFWorkerUtil.isWorkerDisabled = true; - - GlobalWorkerOptions.workerSrc ||= PDFJSDev.test("LIB") - ? "../pdf.worker.js" - : "./pdf.worker.mjs"; - } - - // Check if URLs have the same origin. For non-HTTP based URLs, returns false. - PDFWorkerUtil.isSameOrigin = function (baseUrl, otherUrl) { - let base; - try { - base = new URL(baseUrl); - if (!base.origin || base.origin === "null") { - return false; // non-HTTP url - } - } catch { - return false; - } - - const other = new URL(otherUrl, base); - return base.origin === other.origin; - }; - - PDFWorkerUtil.createCDNWrapper = function (url) { - // We will rely on blob URL's property to specify origin. - // We want this function to fail in case if createObjectURL or Blob do not - // exist or fail for some reason -- our Worker creation will fail anyway. - const wrapper = `await import("${url}");`; - return URL.createObjectURL( - new Blob([wrapper], { type: "text/javascript" }) - ); - }; -} - /** * PDF.js web worker abstraction that controls the instantiation of PDF * documents. Message handlers are used to pass information from the main @@ -2048,8 +2007,52 @@ if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) { * @param {PDFWorkerParameters} params - The worker initialization parameters. */ class PDFWorker { + static #fakeWorkerId = 0; + + static #isWorkerDisabled = false; + static #workerPorts; + static { + if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) { + if (isNodeJS) { + // Workers aren't supported in Node.js, force-disabling them there. + this.#isWorkerDisabled = true; + + GlobalWorkerOptions.workerSrc ||= PDFJSDev.test("LIB") + ? "../pdf.worker.js" + : "./pdf.worker.mjs"; + } + + // Check if URLs have the same origin. For non-HTTP based URLs, returns + // false. + this._isSameOrigin = (baseUrl, otherUrl) => { + let base; + try { + base = new URL(baseUrl); + if (!base.origin || base.origin === "null") { + return false; // non-HTTP url + } + } catch { + return false; + } + const other = new URL(otherUrl, base); + return base.origin === other.origin; + }; + + this._createCDNWrapper = url => { + // We will rely on blob URL's property to specify origin. + // We want this function to fail in case if createObjectURL or Blob do + // not exist or fail for some reason -- our Worker creation will fail + // anyway. + const wrapper = `await import("${url}");`; + return URL.createObjectURL( + new Blob([wrapper], { type: "text/javascript" }) + ); + }; + } + } + constructor({ name = null, port = null, @@ -2138,7 +2141,7 @@ class PDFWorker { // Right now, the requirement is, that an Uint8Array is still an // Uint8Array as it arrives on the worker. if ( - PDFWorkerUtil.isWorkerDisabled || + PDFWorker.#isWorkerDisabled || PDFWorker.#mainThreadWorkerMessageHandler ) { this._setupFakeWorker(); @@ -2152,9 +2155,9 @@ class PDFWorker { if ( typeof PDFJSDev !== "undefined" && PDFJSDev.test("GENERIC") && - !PDFWorkerUtil.isSameOrigin(window.location.href, workerSrc) + !PDFWorker._isSameOrigin(window.location.href, workerSrc) ) { - workerSrc = PDFWorkerUtil.createCDNWrapper( + workerSrc = PDFWorker._createCDNWrapper( new URL(workerSrc, window.location).href ); } @@ -2234,9 +2237,9 @@ class PDFWorker { } _setupFakeWorker() { - if (!PDFWorkerUtil.isWorkerDisabled) { + if (!PDFWorker.#isWorkerDisabled) { warn("Setting up fake worker."); - PDFWorkerUtil.isWorkerDisabled = true; + PDFWorker.#isWorkerDisabled = true; } PDFWorker._setupFakeWorkerGlobal @@ -2249,7 +2252,7 @@ class PDFWorker { this._port = port; // All fake workers use the same port, making id unique. - const id = `fake${PDFWorkerUtil.fakeWorkerId++}`; + const id = `fake${PDFWorker.#fakeWorkerId++}`; // If the main thread is our worker, setup the handling for the // messages -- the main thread sends to it self. @@ -3470,7 +3473,6 @@ export { PDFDocumentProxy, PDFPageProxy, PDFWorker, - PDFWorkerUtil, RenderTask, version, }; diff --git a/test/unit/api_spec.js b/test/unit/api_spec.js index aaa20a7ccbfb8..94b1458923e39 100644 --- a/test/unit/api_spec.js +++ b/test/unit/api_spec.js @@ -43,7 +43,6 @@ import { PDFDocumentProxy, PDFPageProxy, PDFWorker, - PDFWorkerUtil, RenderTask, } from "../../src/display/api.js"; import { @@ -929,6 +928,31 @@ describe("api", function () { expect(typeof workerSrc).toEqual("string"); expect(workerSrc).toEqual(GlobalWorkerOptions.workerSrc); }); + + describe("isSameOrigin", function () { + it("handles invalid base URLs", function () { + // The base URL is not valid. + expect(PDFWorker._isSameOrigin("/foo", "/bar")).toEqual(false); + + // The base URL has no origin. + expect(PDFWorker._isSameOrigin("blob:foo", "/bar")).toEqual(false); + }); + + it("correctly checks if the origin of both URLs matches", function () { + expect( + PDFWorker._isSameOrigin( + "https://www.mozilla.org/foo", + "https://www.mozilla.org/bar" + ) + ).toEqual(true); + expect( + PDFWorker._isSameOrigin( + "https://www.mozilla.org/foo", + "https://www.example.com/bar" + ) + ).toEqual(false); + }); + }); }); describe("GlobalWorkerOptions", function () { @@ -4885,33 +4909,4 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`) } ); }); - - describe("PDFWorkerUtil", function () { - describe("isSameOrigin", function () { - const { isSameOrigin } = PDFWorkerUtil; - - it("handles invalid base URLs", function () { - // The base URL is not valid. - expect(isSameOrigin("/foo", "/bar")).toEqual(false); - - // The base URL has no origin. - expect(isSameOrigin("blob:foo", "/bar")).toEqual(false); - }); - - it("correctly checks if the origin of both URLs matches", function () { - expect( - isSameOrigin( - "https://www.mozilla.org/foo", - "https://www.mozilla.org/bar" - ) - ).toEqual(true); - expect( - isSameOrigin( - "https://www.mozilla.org/foo", - "https://www.example.com/bar" - ) - ).toEqual(false); - }); - }); - }); });