diff --git a/src/display/api.js b/src/display/api.js index 38ab1bfe7..6cfbe74f4 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -523,18 +523,20 @@ function getUrlProp(val) { if (val instanceof URL) { return val.href; } - try { - // The full path is required in the 'url' field. - return new URL(val, window.location).href; - } catch { + if (typeof val === "string") { if ( typeof PDFJSDev !== "undefined" && PDFJSDev.test("GENERIC") && - isNodeJS && - typeof val === "string" + isNodeJS ) { return val; // Use the url as-is in Node.js environments. } + + // The full path is required in the 'url' field. + const url = URL.parse(val, window.location); + if (url) { + return url.href; + } } throw new Error( "Invalid PDF url data: " + @@ -2080,14 +2082,9 @@ class PDFWorker { // 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 base = URL.parse(baseUrl); + if (!base?.origin || base.origin === "null") { + return false; // non-HTTP url } const other = new URL(otherUrl, base); return base.origin === other.origin; @@ -2200,7 +2197,7 @@ class PDFWorker { if ( typeof PDFJSDev !== "undefined" && PDFJSDev.test("GENERIC") && - !PDFWorker._isSameOrigin(window.location.href, workerSrc) + !PDFWorker._isSameOrigin(window.location, workerSrc) ) { workerSrc = PDFWorker._createCDNWrapper( new URL(workerSrc, window.location).href diff --git a/src/display/display_utils.js b/src/display/display_utils.js index 6e625d867..fae0abce3 100644 --- a/src/display/display_utils.js +++ b/src/display/display_utils.js @@ -402,13 +402,9 @@ function isValidFetchUrl(url, baseUrl) { if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) { throw new Error("Not implemented: isValidFetchUrl"); } - try { - const { protocol } = baseUrl ? new URL(url, baseUrl) : new URL(url); - // The Fetch API only supports the http/https protocols, and not file/ftp. - return protocol === "http:" || protocol === "https:"; - } catch { - return false; // `new URL()` will throw on incorrect data. - } + const res = baseUrl ? URL.parse(url, baseUrl) : URL.parse(url); + // The Fetch API only supports the http/https protocols, and not file/ftp. + return res?.protocol === "http:" || res?.protocol === "https:"; } /** diff --git a/src/display/network_utils.js b/src/display/network_utils.js index f7b2df614..5af942a9f 100644 --- a/src/display/network_utils.js +++ b/src/display/network_utils.js @@ -33,13 +33,8 @@ function createHeaders(isHttp, httpHeaders) { } function getResponseOrigin(url) { - try { - return new URL(url).origin; - } catch { - // `new URL()` will throw on incorrect data. - } // Notably, null is distinct from "null" string (e.g. from file:-URLs). - return null; + return URL.parse(url)?.origin ?? null; } function validateRangeRequestCapabilities({ diff --git a/src/shared/util.js b/src/shared/util.js index 30c1d4f5e..baf53a1b0 100644 --- a/src/shared/util.js +++ b/src/shared/util.js @@ -412,35 +412,28 @@ function createValidAbsoluteUrl(url, baseUrl = null, options = null) { if (!url) { return null; } - try { - if (options && typeof url === "string") { - // Let URLs beginning with "www." default to using the "http://" protocol. - if (options.addDefaultProtocol && url.startsWith("www.")) { - const dots = url.match(/\./g); - // Avoid accidentally matching a *relative* URL pointing to a file named - // e.g. "www.pdf" or similar. - if (dots?.length >= 2) { - url = `http://${url}`; - } - } - - // According to ISO 32000-1:2008, section 12.6.4.7, URIs should be encoded - // in 7-bit ASCII. Some bad PDFs use UTF-8 encoding; see bug 1122280. - if (options.tryConvertEncoding) { - try { - url = stringToUTF8String(url); - } catch {} + if (options && typeof url === "string") { + // Let URLs beginning with "www." default to using the "http://" protocol. + if (options.addDefaultProtocol && url.startsWith("www.")) { + const dots = url.match(/\./g); + // Avoid accidentally matching a *relative* URL pointing to a file named + // e.g. "www.pdf" or similar. + if (dots?.length >= 2) { + url = `http://${url}`; } } - const absoluteUrl = baseUrl ? new URL(url, baseUrl) : new URL(url); - if (_isValidProtocol(absoluteUrl)) { - return absoluteUrl; + // According to ISO 32000-1:2008, section 12.6.4.7, URIs should be encoded + // in 7-bit ASCII. Some bad PDFs use UTF-8 encoding; see bug 1122280. + if (options.tryConvertEncoding) { + try { + url = stringToUTF8String(url); + } catch {} } - } catch { - /* `new URL()` will throw on incorrect data. */ } - return null; + + const absoluteUrl = baseUrl ? URL.parse(url, baseUrl) : URL.parse(url); + return _isValidProtocol(absoluteUrl) ? absoluteUrl : null; } function shadow(obj, prop, value, nonSerializable = false) { diff --git a/web/app.js b/web/app.js index b84251bc4..9647cd63f 100644 --- a/web/app.js +++ b/web/app.js @@ -2274,35 +2274,34 @@ if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("MOZCENTRAL")) { } if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) { - const HOSTED_VIEWER_ORIGINS = [ + const HOSTED_VIEWER_ORIGINS = new Set([ "null", "http://mozilla.github.io", "https://mozilla.github.io", - ]; + ]); // eslint-disable-next-line no-var var validateFileURL = function (file) { if (!file) { return; } - try { - const viewerOrigin = new URL(window.location.href).origin || "null"; - if (HOSTED_VIEWER_ORIGINS.includes(viewerOrigin)) { - // Hosted or local viewer, allow for any file locations - return; - } - const fileOrigin = new URL(file, window.location.href).origin; - // Removing of the following line will not guarantee that the viewer will - // start accepting URLs from foreign origin -- CORS headers on the remote - // server must be properly configured. - if (fileOrigin !== viewerOrigin) { - throw new Error("file origin does not match viewer's"); - } - } catch (ex) { - PDFViewerApplication._documentError("pdfjs-loading-error", { - message: ex.message, - }); - throw ex; + const viewerOrigin = URL.parse(window.location)?.origin || "null"; + if (HOSTED_VIEWER_ORIGINS.has(viewerOrigin)) { + // Hosted or local viewer, allow for any file locations + return; } + const fileOrigin = URL.parse(file, window.location)?.origin; + if (fileOrigin === viewerOrigin) { + return; + } + const ex = new Error("file origin does not match viewer's"); + + PDFViewerApplication._documentError("pdfjs-loading-error", { + message: ex.message, + }); + // Removing of the following line will not guarantee that the viewer will + // start accepting URLs from foreign origin -- CORS headers on the remote + // server must be properly configured. + throw ex; }; // eslint-disable-next-line no-var