|
|
@@ -317,9 +317,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
// ---------
|
|
|
// Processor
|
|
|
// ---------
|
|
|
- const PREFIXES_DATA_URI_IMAGE = ["data:image/", "data:application/"];
|
|
|
- const PREFIX_DATA_URI_AUDIO = "data:audio/";
|
|
|
- const PREFIX_DATA_URI_VIDEO = "data:video/";
|
|
|
+ const PREFIXES_FORBIDDEN_DATA_URI = ["data:text/"];
|
|
|
const PREFIX_DATA_URI_IMAGE_SVG = "data:image/svg+xml";
|
|
|
const EMPTY_IMAGE = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
|
|
|
const SCRIPT_TAG_FOUND = /<script/gi;
|
|
|
@@ -923,26 +921,26 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
|
|
|
async processPageResources() {
|
|
|
const processAttributeArgs = [
|
|
|
- ["link[href][rel*=\"icon\"]", "href", ["data:"], false, true],
|
|
|
- ["object[type=\"image/svg+xml\"], object[type=\"image/svg-xml\"]", "data", [PREFIX_DATA_URI_IMAGE_SVG]],
|
|
|
- ["img[src], input[src][type=image]", "src", PREFIXES_DATA_URI_IMAGE, true],
|
|
|
- ["embed[src*=\".svg\"], embed[src*=\".pdf\"]", "src", "data:"],
|
|
|
- ["video[poster]", "poster", PREFIXES_DATA_URI_IMAGE],
|
|
|
- ["*[background]", "background", PREFIXES_DATA_URI_IMAGE],
|
|
|
- ["image", "xlink:href", PREFIXES_DATA_URI_IMAGE]
|
|
|
+ ["link[href][rel*=\"icon\"]", "href", false, true],
|
|
|
+ ["object[type=\"image/svg+xml\"], object[type=\"image/svg-xml\"]", "data"],
|
|
|
+ ["img[src], input[src][type=image]", "src", true],
|
|
|
+ ["embed[src*=\".svg\"], embed[src*=\".pdf\"]", "src"],
|
|
|
+ ["video[poster]", "poster"],
|
|
|
+ ["*[background]", "background"],
|
|
|
+ ["image", "xlink:href"]
|
|
|
];
|
|
|
- let resourcePromises = processAttributeArgs.map(([selector, attributeName, prefixDataURI, processDuplicates, removeElementIfMissing]) =>
|
|
|
- ProcessorHelper.processAttribute(this.doc.querySelectorAll(selector), attributeName, prefixDataURI, this.baseURI, this.options, this.cssVariables, this.styles, this.batchRequest, processDuplicates, removeElementIfMissing)
|
|
|
+ let resourcePromises = processAttributeArgs.map(([selector, attributeName, processDuplicates, removeElementIfMissing]) =>
|
|
|
+ ProcessorHelper.processAttribute(this.doc.querySelectorAll(selector), attributeName, this.baseURI, this.options, this.cssVariables, this.styles, this.batchRequest, processDuplicates, removeElementIfMissing)
|
|
|
);
|
|
|
resourcePromises = resourcePromises.concat([
|
|
|
ProcessorHelper.processXLinks(this.doc.querySelectorAll("use"), this.baseURI, this.options, this.batchRequest),
|
|
|
- ProcessorHelper.processSrcset(this.doc.querySelectorAll("img[srcset], source[srcset]"), "srcset", PREFIXES_DATA_URI_IMAGE, this.baseURI, this.options, this.batchRequest)
|
|
|
+ ProcessorHelper.processSrcset(this.doc.querySelectorAll("img[srcset], source[srcset]"), "srcset", this.baseURI, this.batchRequest)
|
|
|
]);
|
|
|
if (!this.options.removeAudioSrc) {
|
|
|
- resourcePromises.push(ProcessorHelper.processAttribute(this.doc.querySelectorAll("audio[src], audio > source[src]"), "src", [PREFIX_DATA_URI_AUDIO], this.baseURI, this.options, this.cssVariables, this.styles, this.batchRequest));
|
|
|
+ resourcePromises.push(ProcessorHelper.processAttribute(this.doc.querySelectorAll("audio[src], audio > source[src]"), "src", this.baseURI, this.options, this.cssVariables, this.styles, this.batchRequest));
|
|
|
}
|
|
|
if (!this.options.removeVideoSrc) {
|
|
|
- resourcePromises.push(ProcessorHelper.processAttribute(this.doc.querySelectorAll("video[src], video > source[src]"), "src", [PREFIX_DATA_URI_VIDEO], this.baseURI, this.options, this.cssVariables, this.styles, this.batchRequest));
|
|
|
+ resourcePromises.push(ProcessorHelper.processAttribute(this.doc.querySelectorAll("video[src], video > source[src]"), "src", this.baseURI, this.options, this.cssVariables, this.styles, this.batchRequest));
|
|
|
}
|
|
|
await Promise.all(resourcePromises);
|
|
|
ProcessorHelper.processShortcutIcons(this.doc);
|
|
|
@@ -1113,9 +1111,6 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
const REGEXP_START_TAG = /</g;
|
|
|
const REGEXP_END_TAG = />/g;
|
|
|
const REGEXP_URL_HASH = /(#.+?)$/;
|
|
|
- const PREFIX_DATA_URI_NO_MIMETYPE = "data:;";
|
|
|
- const PREFIX_DATA_URI_OCTET_STREAM = /^data:(application|binary)\/octet-stream/;
|
|
|
- const PREFIX_DATA_URI_NULL_STREAM = /^data:null;/;
|
|
|
const PREFIX_DATA_URI_VND = "data:application/vnd.";
|
|
|
const SINGLE_FILE_VARIABLE_NAME_PREFIX = "--sf-img-";
|
|
|
|
|
|
@@ -1404,7 +1399,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- static async processAttribute(resourceElements, attributeName, prefixesDataURI, baseURI, options, cssVariables, styles, batchRequest, processDuplicates, removeElementIfMissing) {
|
|
|
+ static async processAttribute(resourceElements, attributeName, baseURI, options, cssVariables, styles, batchRequest, processDuplicates, removeElementIfMissing) {
|
|
|
await Promise.all(Array.from(resourceElements).map(async resourceElement => {
|
|
|
let resourceURL = resourceElement.getAttribute(attributeName);
|
|
|
resourceURL = Util.normalizeURL(resourceURL);
|
|
|
@@ -1421,8 +1416,8 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
if (removeElementIfMissing && content == EMPTY_DATA_URI) {
|
|
|
resourceElement.remove();
|
|
|
} else {
|
|
|
- const prefixFound = prefixesDataURI.filter(prefixDataURI => content.startsWith(prefixDataURI)).length;
|
|
|
- if (prefixFound || content.startsWith(PREFIX_DATA_URI_NO_MIMETYPE) || content.match(PREFIX_DATA_URI_OCTET_STREAM) || content.match(PREFIX_DATA_URI_NULL_STREAM)) {
|
|
|
+ const forbiddenPrefixFound = PREFIXES_FORBIDDEN_DATA_URI.filter(prefixDataURI => content.startsWith(prefixDataURI)).length;
|
|
|
+ if (!forbiddenPrefixFound) {
|
|
|
const isSVG = content.startsWith(PREFIX_DATA_URI_IMAGE_SVG);
|
|
|
if (processDuplicates && duplicate && options.groupDuplicateImages && !isSVG) {
|
|
|
if (ProcessorHelper.replaceImageSource(resourceElement, SINGLE_FILE_VARIABLE_NAME_PREFIX + indexResource, options)) {
|
|
|
@@ -1479,7 +1474,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
}));
|
|
|
}
|
|
|
|
|
|
- static async processSrcset(resourceElements, attributeName, prefixesDataURI, baseURI, options, batchRequest) {
|
|
|
+ static async processSrcset(resourceElements, attributeName, baseURI, batchRequest) {
|
|
|
await Promise.all(Array.from(resourceElements).map(async resourceElement => {
|
|
|
const srcset = docUtil.parseSrcset(resourceElement.getAttribute(attributeName));
|
|
|
const srcsetValues = await Promise.all(srcset.map(async srcsetValue => {
|
|
|
@@ -1493,9 +1488,9 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
}
|
|
|
if (Util.testValidURL(resourceURL)) {
|
|
|
const { content } = await batchRequest.addURL(resourceURL, true);
|
|
|
- const prefixFound = prefixesDataURI.filter(prefixDataURI => content.startsWith(prefixDataURI)).length;
|
|
|
- if (prefixFound && !content.startsWith(PREFIX_DATA_URI_NO_MIMETYPE) && !content.match(PREFIX_DATA_URI_OCTET_STREAM) && !content.match(PREFIX_DATA_URI_NULL_STREAM)) {
|
|
|
- resourceElement.setAttribute(attributeName, EMPTY_IMAGE);
|
|
|
+ const forbiddenPrefixFound = PREFIXES_FORBIDDEN_DATA_URI.filter(prefixDataURI => content.startsWith(prefixDataURI)).length;
|
|
|
+ if (forbiddenPrefixFound) {
|
|
|
+ return "";
|
|
|
}
|
|
|
return content + (srcsetValue.w ? " " + srcsetValue.w + "w" : srcsetValue.d ? " " + srcsetValue.d + "x" : "");
|
|
|
} else {
|