Bläddra i källkod

check data URI mime types when replacing image/audio/video sources

Gildas 7 år sedan
förälder
incheckning
4d117d652f
1 ändrade filer med 32 tillägg och 22 borttagningar
  1. 32 22
      lib/single-file/single-file-core.js

+ 32 - 22
lib/single-file/single-file-core.js

@@ -661,25 +661,25 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 
 		async pageResources() {
 			const resourcePromises = [
-				DomProcessorHelper.processAttribute(this.doc.querySelectorAll("link[href][rel*=\"icon\"]"), "href", this.baseURI, this.batchRequest),
-				DomProcessorHelper.processAttribute(this.doc.querySelectorAll("object[type=\"image/svg+xml\"], object[type=\"image/svg-xml\"]"), "data", this.baseURI, this.batchRequest),
-				DomProcessorHelper.processAttribute(this.doc.querySelectorAll("img[src], input[src][type=image], embed[src*=\".svg\"]"), "src", this.baseURI, this.batchRequest),
-				DomProcessorHelper.processAttribute(this.doc.querySelectorAll("video[poster]"), "poster", this.baseURI, this.batchRequest),
-				DomProcessorHelper.processAttribute(this.doc.querySelectorAll("*[background]"), "background", this.baseURI, this.batchRequest),
-				DomProcessorHelper.processAttribute(this.doc.querySelectorAll("image"), "xlink:href", this.baseURI, this.batchRequest),
+				DomProcessorHelper.processAttribute(this.doc.querySelectorAll("link[href][rel*=\"icon\"]"), "href", PREFIX_DATA_URI_IMAGE, this.baseURI, this.batchRequest),
+				DomProcessorHelper.processAttribute(this.doc.querySelectorAll("object[type=\"image/svg+xml\"], object[type=\"image/svg-xml\"]"), "data", PREFIX_DATA_URI_IMAGE_SVG, this.baseURI, this.batchRequest),
+				DomProcessorHelper.processAttribute(this.doc.querySelectorAll("img[src], input[src][type=image], embed[src*=\".svg\"]"), "src", PREFIX_DATA_URI_IMAGE_SVG, this.baseURI, this.batchRequest),
+				DomProcessorHelper.processAttribute(this.doc.querySelectorAll("video[poster]"), "poster", PREFIX_DATA_URI_IMAGE, this.baseURI, this.batchRequest),
+				DomProcessorHelper.processAttribute(this.doc.querySelectorAll("*[background]"), "background", PREFIX_DATA_URI_IMAGE, this.baseURI, this.batchRequest),
+				DomProcessorHelper.processAttribute(this.doc.querySelectorAll("image"), "xlink:href", PREFIX_DATA_URI_IMAGE, this.baseURI, this.batchRequest),
 				DomProcessorHelper.processXLinks(this.doc.querySelectorAll("use"), this.baseURI, this.batchRequest),
-				DomProcessorHelper.processSrcset(this.doc.querySelectorAll("img[srcset], source[srcset]"), "srcset", this.baseURI, this.batchRequest)
+				DomProcessorHelper.processSrcset(this.doc.querySelectorAll("img[srcset], source[srcset]"), "srcset", PREFIX_DATA_URI_IMAGE, this.baseURI, this.batchRequest)
 			];
 			if (!this.options.removeAudioSrc) {
-				resourcePromises.push(DomProcessorHelper.processAttribute(this.doc.querySelectorAll("audio[src], audio > source[src]"), "src", this.baseURI, this.batchRequest));
+				resourcePromises.push(DomProcessorHelper.processAttribute(this.doc.querySelectorAll("audio[src], audio > source[src]"), "src", PREFIX_DATA_URI_AUDIO, this.baseURI, this.batchRequest));
 			}
 			if (!this.options.removeVideoSrc) {
-				resourcePromises.push(DomProcessorHelper.processAttribute(this.doc.querySelectorAll("video[src], video > source[src]"), "src", this.baseURI, this.batchRequest));
+				resourcePromises.push(DomProcessorHelper.processAttribute(this.doc.querySelectorAll("video[src], video > source[src]"), "src", PREFIX_DATA_URI_VIDEO, this.baseURI, this.batchRequest));
 			}
 			if (this.options.lazyLoadImages) {
 				const imageSelectors = DOM.lazyLoaderImageSelectors();
-				Object.keys(imageSelectors.src).forEach(selector => resourcePromises.push(DomProcessorHelper.processAttribute(this.doc.querySelectorAll(selector), imageSelectors.src[selector], this.baseURI, this.batchRequest)));
-				Object.keys(imageSelectors.srcset).forEach(selector => resourcePromises.push(DomProcessorHelper.processSrcset(this.doc.querySelectorAll(selector), imageSelectors.srcset[selector], this.baseURI, this.batchRequest)));
+				Object.keys(imageSelectors.src).forEach(selector => resourcePromises.push(DomProcessorHelper.processAttribute(this.doc.querySelectorAll(selector), imageSelectors.src[selector], PREFIX_DATA_URI_IMAGE, this.baseURI, this.batchRequest)));
+				Object.keys(imageSelectors.srcset).forEach(selector => resourcePromises.push(DomProcessorHelper.processSrcset(this.doc.querySelectorAll(selector), imageSelectors.srcset[selector], PREFIX_DATA_URI_IMAGE, this.baseURI, this.batchRequest)));
 			}
 			await resourcePromises;
 		}
@@ -826,6 +826,8 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 	const REGEXP_END_TAG = />/g;
 	const REGEXP_URL_HASH = /(#.+?)$/;
 	const PREFIX_DATA_URI_IMAGE = "data:image/";
+	const PREFIX_DATA_URI_AUDIO = "data:audio/";
+	const PREFIX_DATA_URI_VIDEO = "data:video/";
 	const PREFIX_DATA_URI_IMAGE_SVG = "data:image/svg+xml";
 
 	class DomProcessorHelper {
@@ -1011,7 +1013,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 			return stylesheetContent;
 		}
 
-		static async processAttribute(resourceElements, attributeName, baseURI, batchRequest) {
+		static async processAttribute(resourceElements, attributeName, prefixDataURI, baseURI, batchRequest) {
 			await Promise.all(Array.from(resourceElements).map(async resourceElement => {
 				let resourceURL = resourceElement.getAttribute(attributeName);
 				if (resourceURL) {
@@ -1019,9 +1021,13 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 					if (resourceURL && resourceURL != baseURI && DomUtil.testValidPath(resourceURL)) {
 						try {
 							const dataURI = await batchRequest.addURL(new URL(resourceURL, baseURI).href);
-							resourceElement.setAttribute(attributeName, dataURI);
+							if (dataURI.startsWith(prefixDataURI)) {
+								resourceElement.setAttribute(attributeName, dataURI);
+							} else {
+								resourceElement.setAttribute(attributeName, EMPTY_DATA_URI);
+							}
 						} catch (error) {
-							/* ignored */
+							resourceElement.setAttribute(attributeName, EMPTY_DATA_URI);
 						}
 					}
 				}
@@ -1029,8 +1035,9 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 		}
 
 		static async processXLinks(resourceElements, baseURI, batchRequest) {
+			const attributeName = "xlink:href";
 			await Promise.all(Array.from(resourceElements).map(async resourceElement => {
-				const originalResourceURL = resourceElement.getAttribute("xlink:href");
+				const originalResourceURL = resourceElement.getAttribute(attributeName);
 				if (originalResourceURL) {
 					const resourceURL = DomUtil.normalizeURL(originalResourceURL);
 					if (resourceURL && resourceURL != baseURI && DomUtil.testValidPath(resourceURL)) {
@@ -1043,34 +1050,37 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 								if (hashMatch && hashMatch[0]) {
 									const symbolElement = svgDoc.querySelector(hashMatch[0]);
 									if (symbolElement) {
-										resourceElement.setAttribute("xlink:href", hashMatch[0]);
+										resourceElement.setAttribute(attributeName, hashMatch[0]);
 										resourceElement.parentElement.appendChild(symbolElement);
 									}
 								} else {
-									resourceElement.setAttribute("xlink:href", "data:image/svg+xml," + content);
+									resourceElement.setAttribute(attributeName, "data:image/svg+xml," + content);
 								}
 							} else {
-								resourceElement.setAttribute("xlink:href", "data:image/svg+xml," + content);
+								resourceElement.setAttribute(attributeName, "data:image/svg+xml," + content);
 							}
 						} catch (error) {
-							/* ignored */
+							resourceElement.setAttribute(attributeName, EMPTY_DATA_URI);
 						}
 					}
 				}
 			}));
 		}
 
-		static async processSrcset(resourceElements, attributeName, baseURI, batchRequest) {
+		static async processSrcset(resourceElements, attributeName, prefixDataURI, baseURI, batchRequest) {
 			await Promise.all(Array.from(resourceElements).map(async resourceElement => {
 				const srcset = DOM.parseSrcset(resourceElement.getAttribute(attributeName));
 				const srcsetValues = await Promise.all(srcset.map(async srcsetValue => {
 					const resourceURL = DomUtil.normalizeURL(srcsetValue.url);
 					if (resourceURL && resourceURL != baseURI && DomUtil.testValidPath(resourceURL)) {
 						try {
-							const dataURI = await batchRequest.addURL(new URL(resourceURL, baseURI).href);
+							let dataURI = await batchRequest.addURL(new URL(resourceURL, baseURI).href);
+							if (!dataURI.startsWith(prefixDataURI)) {
+								resourceElement.setAttribute(attributeName, EMPTY_DATA_URI);
+							}
 							return dataURI + (srcsetValue.w ? " " + srcsetValue.w + "w" : srcsetValue.d ? " " + srcsetValue.d + "x" : "");
 						} catch (error) {
-							/* ignored */
+							resourceElement.setAttribute(attributeName, EMPTY_DATA_URI);
 						}
 					}
 				}));