Browse Source

fixed url testing when embedding resources

Gildas 7 years ago
parent
commit
ed749d73bc
1 changed files with 38 additions and 36 deletions
  1. 38 36
      lib/single-file/single-file-core.js

+ 38 - 36
lib/single-file/single-file-core.js

@@ -653,21 +653,21 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 
 		async pageResources() {
 			const resourcePromises = [
-				DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("link[href][rel*=\"icon\"]"), "href", PREFIX_DATA_URI_IMAGE, this.baseURI, this.batchRequest, this.options, false, true),
-				DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("object[type=\"image/svg+xml\"], object[type=\"image/svg-xml\"]"), "data", PREFIX_DATA_URI_IMAGE_SVG, this.baseURI, this.batchRequest, this.options),
-				DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("img[src], input[src][type=image]"), "src", PREFIX_DATA_URI_IMAGE, this.baseURI, this.batchRequest, this.options, true),
-				DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("embed[src*=\".svg\"]"), "src", PREFIX_DATA_URI_IMAGE_SVG, this.baseURI, this.batchRequest, this.options),
-				DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("video[poster]"), "poster", PREFIX_DATA_URI_IMAGE, this.baseURI, this.batchRequest, this.options),
-				DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("*[background]"), "background", PREFIX_DATA_URI_IMAGE, this.baseURI, this.batchRequest, this.options),
-				DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("image"), "xlink:href", PREFIX_DATA_URI_IMAGE, this.baseURI, this.batchRequest, this.options),
-				DomProcessorHelper.processXLinks(this.doc, this.doc.querySelectorAll("use"), this.baseURI, this.batchRequest),
-				DomProcessorHelper.processSrcset(this.doc, this.doc.querySelectorAll("img[srcset], source[srcset]"), "srcset", PREFIX_DATA_URI_IMAGE, this.baseURI, this.batchRequest)
+				DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("link[href][rel*=\"icon\"]"), "href", PREFIX_DATA_URI_IMAGE, this.baseURI, this.options, this.batchRequest, false, true),
+				DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("object[type=\"image/svg+xml\"], object[type=\"image/svg-xml\"]"), "data", PREFIX_DATA_URI_IMAGE_SVG, this.baseURI, this.options, this.batchRequest),
+				DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("img[src], input[src][type=image]"), "src", PREFIX_DATA_URI_IMAGE, this.baseURI, this.options, this.batchRequest, true),
+				DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("embed[src*=\".svg\"]"), "src", PREFIX_DATA_URI_IMAGE_SVG, this.baseURI, this.options, this.batchRequest),
+				DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("video[poster]"), "poster", PREFIX_DATA_URI_IMAGE, this.baseURI, this.options, this.batchRequest),
+				DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("*[background]"), "background", PREFIX_DATA_URI_IMAGE, this.baseURI, this.options, this.batchRequest),
+				DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("image"), "xlink:href", PREFIX_DATA_URI_IMAGE, this.baseURI, this.options, this.batchRequest),
+				DomProcessorHelper.processXLinks(this.doc.querySelectorAll("use"), this.baseURI, this.options, this.batchRequest),
+				DomProcessorHelper.processSrcset(this.doc.querySelectorAll("img[srcset], source[srcset]"), "srcset", PREFIX_DATA_URI_IMAGE, this.baseURI, this.options, this.batchRequest)
 			];
 			if (!this.options.removeAudioSrc) {
-				resourcePromises.push(DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("audio[src], audio > source[src]"), "src", PREFIX_DATA_URI_AUDIO, this.baseURI, this.batchRequest, this.options));
+				resourcePromises.push(DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("audio[src], audio > source[src]"), "src", PREFIX_DATA_URI_AUDIO, this.baseURI, this.options, this.batchRequest));
 			}
 			if (!this.options.removeVideoSrc) {
-				resourcePromises.push(DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("video[src], video > source[src]"), "src", PREFIX_DATA_URI_VIDEO, this.baseURI, this.batchRequest, this.options));
+				resourcePromises.push(DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("video[src], video > source[src]"), "src", PREFIX_DATA_URI_VIDEO, this.baseURI, this.options, this.batchRequest));
 			}
 			await resourcePromises;
 			if (this.options.removeAlternativeImages) {
@@ -685,7 +685,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 		}
 
 		async resolveStylesheetURLs() {
-			await Promise.all(Array.from(this.doc.querySelectorAll("style")).map(async styleElement => styleElement.textContent = await DomProcessorHelper.resolveImportURLs(styleElement.textContent, this.baseURI, { maxResourceSize: this.options.maxResourceSize, maxResourceSizeEnabled: this.options.maxResourceSizeEnabled })));
+			await Promise.all(Array.from(this.doc.querySelectorAll("style")).map(async styleElement => styleElement.textContent = await DomProcessorHelper.resolveImportURLs(styleElement.textContent, this.baseURI, { url: this.options.url, maxResourceSize: this.options.maxResourceSize, maxResourceSizeEnabled: this.options.maxResourceSizeEnabled })));
 		}
 
 		async processStylesheets() {
@@ -781,7 +781,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 				options.doc = null;
 				options.win = null;
 				options.url = resourceURL;
-				if (!DomUtil.testIgnoredPath(resourceURL) && DomUtil.testValidPath(resourceURL, this.baseURI)) {
+				if (!DomUtil.testIgnoredPath(resourceURL) && DomUtil.testValidPath(resourceURL, this.baseURI, this.options.url)) {
 					const processor = new PageProcessor(options);
 					this.relImportProcessors.set(linkElement, processor);
 					await processor.loadPage();
@@ -807,7 +807,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 		}
 
 		resolveStyleAttributeURLs() {
-			Array.from(this.doc.querySelectorAll("[style]")).map(element => element.setAttribute("style", DomProcessorHelper.resolveStylesheetURLs(element.getAttribute("style"), this.baseURI)));
+			Array.from(this.doc.querySelectorAll("[style]")).map(element => element.setAttribute("style", DomProcessorHelper.resolveStylesheetURLs(element.getAttribute("style"), this.baseURI, this.options)));
 		}
 
 		async processStyleAttributes() {
@@ -965,16 +965,16 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 		}
 
 		static async resolveImportURLs(stylesheetContent, baseURI, options) {
-			stylesheetContent = DomProcessorHelper.resolveStylesheetURLs(stylesheetContent, baseURI);
+			stylesheetContent = DomProcessorHelper.resolveStylesheetURLs(stylesheetContent, baseURI, options);
 			stylesheetContent = DomUtil.removeCssComments(stylesheetContent);
 			const imports = DomUtil.getImportFunctions(stylesheetContent);
 			await Promise.all(imports.map(async cssImport => {
 				const match = DomUtil.matchImport(cssImport);
 				if (match) {
 					let resourceURL = DomUtil.normalizeURL(match.resourceURL);
-					if (!DomUtil.testIgnoredPath(resourceURL) && DomUtil.testValidPath(resourceURL)) {
+					if (!DomUtil.testIgnoredPath(resourceURL) && DomUtil.testValidPath(resourceURL, baseURI, options.url)) {
 						resourceURL = new URL(match.resourceURL, baseURI).href;
-						if (DomUtil.testValidURL(resourceURL, baseURI)) {
+						if (DomUtil.testValidURL(resourceURL, baseURI, options.url)) {
 							let importedStylesheetContent = await Download.getContent(resourceURL, { asDataURI: false, maxResourceSize: options.maxResourceSize, maxResourceSizeEnabled: options.maxResourceSizeEnabled });
 							importedStylesheetContent = DomUtil.wrapMediaQuery(importedStylesheetContent, match.media);
 							if (stylesheetContent.includes(cssImport)) {
@@ -988,15 +988,15 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 			return stylesheetContent;
 		}
 
-		static resolveStylesheetURLs(stylesheetContent, baseURI) {
+		static resolveStylesheetURLs(stylesheetContent, baseURI, options) {
 			const urlFunctions = DomUtil.getUrlFunctions(stylesheetContent);
 			urlFunctions.map(urlFunction => {
 				const originalResourceURL = DomUtil.matchURL(urlFunction);
 				const resourceURL = DomUtil.normalizeURL(originalResourceURL);
 				if (!DomUtil.testIgnoredPath(resourceURL)) {
-					if (DomUtil.testValidPath(resourceURL, baseURI)) {
+					if (DomUtil.testValidPath(resourceURL, baseURI, options.url)) {
 						const resolvedURL = new URL(resourceURL, baseURI).href;
-						if (DomUtil.testValidURL(resolvedURL, baseURI) && resourceURL != resolvedURL && stylesheetContent.includes(urlFunction)) {
+						if (DomUtil.testValidURL(resolvedURL, baseURI, options.url) && resourceURL != resolvedURL && stylesheetContent.includes(urlFunction)) {
 							stylesheetContent = stylesheetContent.replace(DomUtil.getRegExp(urlFunction), urlFunction.replace(originalResourceURL, resolvedURL));
 						}
 					}
@@ -1029,7 +1029,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 				const originalResourceURL = DomUtil.matchURL(urlFunction);
 				const resourceURL = DomUtil.normalizeURL(originalResourceURL);
 				if (!DomUtil.testIgnoredPath(resourceURL)) {
-					if (DomUtil.testValidURL(resourceURL, baseURI) && stylesheetContent.includes(urlFunction)) {
+					if (DomUtil.testValidURL(resourceURL, baseURI, options.url) && stylesheetContent.includes(urlFunction)) {
 						const { content, indexResource, duplicate } = await batchRequest.addURL(resourceURL);
 						urlFunction = "url(" + JSON.stringify(resourceURL) + ")";
 						const regExpUrlFunction = DomUtil.getRegExp(urlFunction);
@@ -1069,7 +1069,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 					const originalResourceURL = DomUtil.matchURL(urlFunction);
 					const resourceURL = DomUtil.normalizeURL(originalResourceURL);
 					if (!DomUtil.testIgnoredPath(resourceURL)) {
-						if (DomUtil.testValidURL(resourceURL, baseURI) && cssText.includes(urlFunction)) {
+						if (DomUtil.testValidURL(resourceURL, baseURI, options.url) && cssText.includes(urlFunction)) {
 							const resourceInfo = resourceInfos.get(resourceURL);
 							if (options.groupDuplicateImages && resourceInfo.variableName && !preventGrouping) {
 								cssText = cssText.replace(resourceInfo.regExpUrlFunction, resourceInfo.variableName);
@@ -1084,15 +1084,15 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 			}
 		}
 
-		static async processAttribute(doc, resourceElements, attributeName, prefixDataURI, baseURI, batchRequest, options, processDuplicates, removeElementIfMissing) {
+		static async processAttribute(doc, resourceElements, attributeName, prefixDataURI, baseURI, options, batchRequest, processDuplicates, removeElementIfMissing) {
 			await Promise.all(Array.from(resourceElements).map(async resourceElement => {
 				let resourceURL = resourceElement.getAttribute(attributeName);
 				resourceURL = DomUtil.normalizeURL(resourceURL);
 				if (!DomUtil.testIgnoredPath(resourceURL)) {
 					resourceElement.setAttribute(attributeName, EMPTY_IMAGE);
-					if (DomUtil.testValidPath(resourceURL, baseURI)) {
+					if (DomUtil.testValidPath(resourceURL, baseURI, options.url)) {
 						resourceURL = new URL(resourceURL, baseURI).href;
-						if (DomUtil.testValidURL(resourceURL, baseURI)) {
+						if (DomUtil.testValidURL(resourceURL, baseURI, options.url)) {
 							const { content, indexResource, duplicate } = await batchRequest.addURL(resourceURL);
 							if (removeElementIfMissing && content == EMPTY_DATA_URI) {
 								resourceElement.remove();
@@ -1111,20 +1111,20 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 			}));
 		}
 
-		static async processXLinks(doc, resourceElements, baseURI, batchRequest) {
+		static async processXLinks(resourceElements, baseURI, options, batchRequest) {
 			const attributeName = "xlink:href";
 			await Promise.all(Array.from(resourceElements).map(async resourceElement => {
 				const originalResourceURL = resourceElement.getAttribute(attributeName);
 				let resourceURL = DomUtil.normalizeURL(originalResourceURL);
-				if (DomUtil.testValidPath(resourceURL) && !DomUtil.testIgnoredPath(resourceURL)) {
+				if (DomUtil.testValidPath(resourceURL, baseURI, options.url) && !DomUtil.testIgnoredPath(resourceURL)) {
 					resourceElement.setAttribute(attributeName, EMPTY_IMAGE);
 					resourceURL = new URL(resourceURL, baseURI).href;
-					if (DomUtil.testValidURL(resourceURL, baseURI)) {
+					if (DomUtil.testValidURL(resourceURL, baseURI, options.url)) {
 						try {
 							const { content } = await batchRequest.addURL(resourceURL, false);
 							const DOMParser = DOM.getParser();
 							if (DOMParser) {
-								const svgDoc = new DOMParser().parseFromString(content, "image/svg+xml");
+								let svgDoc = new DOMParser().parseFromString(content, "image/svg+xml");
 								const hashMatch = originalResourceURL.match(REGEXP_URL_HASH);
 								if (hashMatch && hashMatch[0]) {
 									const symbolElement = svgDoc.querySelector(hashMatch[0]);
@@ -1142,19 +1142,21 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 							/* ignored */
 						}
 					}
+				} else if (resourceURL == options.url) {
+					resourceElement.setAttribute(attributeName, originalResourceURL.substring(resourceURL.length));
 				}
 			}));
 		}
 
-		static async processSrcset(doc, resourceElements, attributeName, prefixDataURI, baseURI, batchRequest) {
+		static async processSrcset(resourceElements, attributeName, prefixDataURI, baseURI, options, 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 => {
 					let resourceURL = DomUtil.normalizeURL(srcsetValue.url);
 					if (!DomUtil.testIgnoredPath(resourceURL)) {
-						if (DomUtil.testValidPath(resourceURL)) {
+						if (DomUtil.testValidPath(resourceURL, baseURI, options.url)) {
 							resourceURL = new URL(resourceURL, baseURI).href;
-							if (DomUtil.testValidURL(resourceURL, baseURI)) {
+							if (DomUtil.testValidURL(resourceURL, baseURI, options.url)) {
 								const { content } = await batchRequest.addURL(resourceURL);
 								if (!content.startsWith(prefixDataURI) && !content.startsWith(PREFIX_DATA_URI_NO_MIMETYPE) && !content.startsWith(PREFIX_DATA_URI_OCTET_STREAM)) {
 									resourceElement.setAttribute(attributeName, EMPTY_IMAGE);
@@ -1258,12 +1260,12 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 			return resourceURL && (resourceURL.startsWith(DATA_URI_PREFIX) || resourceURL.startsWith(BLOB_URI_PREFIX) || resourceURL == ABOUT_BLANK_URI);
 		}
 
-		static testValidPath(resourceURL, baseURI) {
-			return resourceURL && resourceURL != baseURI && !resourceURL.match(EMPTY_URL);
+		static testValidPath(resourceURL, baseURI, docURL) {
+			return resourceURL && resourceURL != baseURI && resourceURL != docURL && !resourceURL.match(EMPTY_URL);
 		}
 
-		static testValidURL(resourceURL, baseURI) {
-			return DomUtil.testValidPath(resourceURL, baseURI) && (resourceURL.match(HTTP_URI_PREFIX) || resourceURL.match(FILE_URI_PREFIX)) && resourceURL.match(NOT_EMPTY_URL);
+		static testValidURL(resourceURL, baseURI, docURL) {
+			return DomUtil.testValidPath(resourceURL, baseURI, docURL) && (resourceURL.match(HTTP_URI_PREFIX) || resourceURL.match(FILE_URI_PREFIX)) && resourceURL.match(NOT_EMPTY_URL);
 		}
 
 		static matchImport(stylesheetContent) {