Merge pull request #19493 from Snuffleupagus/URL-parse

Introduce some `URL.parse()` usage in the code-base
This commit is contained in:
Jonas Jenwald 2025-02-21 10:40:32 +01:00 committed by GitHub
commit e3ea92603d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 52 additions and 72 deletions

View File

@ -525,18 +525,20 @@ function getUrlProp(val) {
if (val instanceof URL) { if (val instanceof URL) {
return val.href; return val.href;
} }
try { if (typeof val === "string") {
// The full path is required in the 'url' field.
return new URL(val, window.location).href;
} catch {
if ( if (
typeof PDFJSDev !== "undefined" && typeof PDFJSDev !== "undefined" &&
PDFJSDev.test("GENERIC") && PDFJSDev.test("GENERIC") &&
isNodeJS && isNodeJS
typeof val === "string"
) { ) {
return val; // Use the url as-is in Node.js environments. 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( throw new Error(
"Invalid PDF url data: " + "Invalid PDF url data: " +
@ -2082,14 +2084,9 @@ class PDFWorker {
// Check if URLs have the same origin. For non-HTTP based URLs, returns // Check if URLs have the same origin. For non-HTTP based URLs, returns
// false. // false.
this._isSameOrigin = (baseUrl, otherUrl) => { this._isSameOrigin = (baseUrl, otherUrl) => {
let base; const base = URL.parse(baseUrl);
try { if (!base?.origin || base.origin === "null") {
base = new URL(baseUrl); return false; // non-HTTP url
if (!base.origin || base.origin === "null") {
return false; // non-HTTP url
}
} catch {
return false;
} }
const other = new URL(otherUrl, base); const other = new URL(otherUrl, base);
return base.origin === other.origin; return base.origin === other.origin;
@ -2202,7 +2199,7 @@ class PDFWorker {
if ( if (
typeof PDFJSDev !== "undefined" && typeof PDFJSDev !== "undefined" &&
PDFJSDev.test("GENERIC") && PDFJSDev.test("GENERIC") &&
!PDFWorker._isSameOrigin(window.location.href, workerSrc) !PDFWorker._isSameOrigin(window.location, workerSrc)
) { ) {
workerSrc = PDFWorker._createCDNWrapper( workerSrc = PDFWorker._createCDNWrapper(
new URL(workerSrc, window.location).href new URL(workerSrc, window.location).href

View File

@ -402,13 +402,9 @@ function isValidFetchUrl(url, baseUrl) {
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) { if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
throw new Error("Not implemented: isValidFetchUrl"); throw new Error("Not implemented: isValidFetchUrl");
} }
try { const res = baseUrl ? URL.parse(url, baseUrl) : URL.parse(url);
const { protocol } = baseUrl ? new URL(url, baseUrl) : new URL(url); // The Fetch API only supports the http/https protocols, and not file/ftp.
// The Fetch API only supports the http/https protocols, and not file/ftp. return res?.protocol === "http:" || res?.protocol === "https:";
return protocol === "http:" || protocol === "https:";
} catch {
return false; // `new URL()` will throw on incorrect data.
}
} }
/** /**

View File

@ -33,13 +33,8 @@ function createHeaders(isHttp, httpHeaders) {
} }
function getResponseOrigin(url) { 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). // Notably, null is distinct from "null" string (e.g. from file:-URLs).
return null; return URL.parse(url)?.origin ?? null;
} }
function validateRangeRequestCapabilities({ function validateRangeRequestCapabilities({

View File

@ -412,35 +412,28 @@ function createValidAbsoluteUrl(url, baseUrl = null, options = null) {
if (!url) { if (!url) {
return null; return null;
} }
try { if (options && typeof url === "string") {
if (options && typeof url === "string") { // Let URLs beginning with "www." default to using the "http://" protocol.
// Let URLs beginning with "www." default to using the "http://" protocol. if (options.addDefaultProtocol && url.startsWith("www.")) {
if (options.addDefaultProtocol && url.startsWith("www.")) { const dots = url.match(/\./g);
const dots = url.match(/\./g); // Avoid accidentally matching a *relative* URL pointing to a file named
// Avoid accidentally matching a *relative* URL pointing to a file named // e.g. "www.pdf" or similar.
// e.g. "www.pdf" or similar. if (dots?.length >= 2) {
if (dots?.length >= 2) { url = `http://${url}`;
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 {}
} }
} }
const absoluteUrl = baseUrl ? new URL(url, baseUrl) : new URL(url); // According to ISO 32000-1:2008, section 12.6.4.7, URIs should be encoded
if (_isValidProtocol(absoluteUrl)) { // in 7-bit ASCII. Some bad PDFs use UTF-8 encoding; see bug 1122280.
return absoluteUrl; 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) { function shadow(obj, prop, value, nonSerializable = false) {

View File

@ -2274,35 +2274,34 @@ if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("MOZCENTRAL")) {
} }
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) { if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
const HOSTED_VIEWER_ORIGINS = [ const HOSTED_VIEWER_ORIGINS = new Set([
"null", "null",
"http://mozilla.github.io", "http://mozilla.github.io",
"https://mozilla.github.io", "https://mozilla.github.io",
]; ]);
// eslint-disable-next-line no-var // eslint-disable-next-line no-var
var validateFileURL = function (file) { var validateFileURL = function (file) {
if (!file) { if (!file) {
return; return;
} }
try { const viewerOrigin = URL.parse(window.location)?.origin || "null";
const viewerOrigin = new URL(window.location.href).origin || "null"; if (HOSTED_VIEWER_ORIGINS.has(viewerOrigin)) {
if (HOSTED_VIEWER_ORIGINS.includes(viewerOrigin)) { // Hosted or local viewer, allow for any file locations
// Hosted or local viewer, allow for any file locations return;
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 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 // eslint-disable-next-line no-var