Просмотр исходного кода

add support of the Accept HTTP header (see #822)

Gildas 4 лет назад
Родитель
Сommit
3a89acc715

+ 6 - 1
extension/core/bg/autosave.js

@@ -209,7 +209,7 @@ async function saveContent(message, tab) {
 	}
 }
 
-function fetch(url) {
+function fetch(url, options = {}) {
 	return new Promise((resolve, reject) => {
 		const xhrRequest = new XMLHttpRequest();
 		xhrRequest.withCredentials = true;
@@ -227,6 +227,11 @@ function fetch(url) {
 			}
 		};
 		xhrRequest.open("GET", url, true);
+		if (options.headers) {
+			for (const entry of Object.entries(options.headers)) {
+				xhrRequest.setRequestHeader(entry[0], entry[1]);
+			}
+		}
 		xhrRequest.send();
 	});
 }

+ 8 - 1
extension/core/bg/config.js

@@ -114,7 +114,14 @@ const DEFAULT_CONFIG = {
 	insertSingleFileComment: true,
 	blockMixedContent: false,
 	saveOriginalURLs: false,
-	woleetKey: "",	
+	acceptHeaders: {
+		font: "application/font-woff2;q=1.0,application/font-woff;q=0.9,*/*;q=0.8",
+		image: "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8",
+		stylesheet: "text/css,*/*;q=0.1",
+		script: "*/*",
+		document: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+	},
+	woleetKey: ""
 };
 
 let configStorage;

+ 7 - 2
extension/lib/single-file/fetch/bg/fetch.js

@@ -42,13 +42,13 @@ browser.runtime.onMessage.addListener((message, sender) => {
 
 function onRequest(message, sender) {
 	if (message.method == "singlefile.fetch") {
-		return fetchResource(message.url, { referrer: message.referrer });
+		return fetchResource(message.url, { referrer: message.referrer, headers: message.headers });
 	} else if (message.method == "singlefile.fetchFrame") {
 		return browser.tabs.sendMessage(sender.tab.id, message);
 	}
 }
 
-function fetchResource(url, options, includeRequestId) {
+function fetchResource(url, options = {}, includeRequestId) {
 	return new Promise((resolve, reject) => {
 		const xhrRequest = new XMLHttpRequest();
 		xhrRequest.withCredentials = true;
@@ -74,6 +74,11 @@ function fetchResource(url, options, includeRequestId) {
 			}
 		};
 		xhrRequest.open("GET", url, true);
+		if (options.headers) {
+			for (const entry of Object.entries(options.headers)) {
+				xhrRequest.setRequestHeader(entry[0], entry[1]);
+			}
+		}
 		if (includeRequestId) {
 			const randomId = String(Math.random()).substring(2);
 			setReferrer(randomId, options.referrer);

+ 5 - 5
extension/lib/single-file/fetch/content/content-fetch.js

@@ -29,7 +29,7 @@ const HOST_FETCH_MAX_DELAY = 5000;
 const addEventListener = (type, listener, options) => window.addEventListener(type, listener, options);
 const dispatchEvent = event => window.dispatchEvent(event);
 const removeEventListener = (type, listener, options) => window.removeEventListener(type, listener, options);
-const fetch = window.fetch;
+const fetch = (url, options) => window.fetch(url, options);
 
 browser.runtime.onMessage.addListener(message => {
 	if (message.method == "singlefile.fetchFrame" && window.frameId && window.frameId == message.frameId) {
@@ -39,7 +39,7 @@ browser.runtime.onMessage.addListener(message => {
 
 async function onMessage(message) {
 	try {
-		let response = await fetch(message.url, { cache: "force-cache" });
+		let response = await fetch(message.url, { cache: "force-cache", headers: message.headers });
 		if (response.status == 401 || response.status == 403 || response.status == 404) {
 			response = await Promise.race(
 				[
@@ -66,14 +66,14 @@ export {
 
 async function fetchResource(url, options = {}) {
 	try {
-		let response = await fetch(url, { cache: "force-cache" });
+		let response = await fetch(url, { cache: "force-cache", headers: options.headers });
 		if (response.status == 401 || response.status == 403 || response.status == 404) {
 			response = await hostFetch(url);
 		}
 		return response;
 	}
 	catch (error) {
-		const response = await sendMessage({ method: "singlefile.fetch", url, referrer: options.referrer });
+		const response = await sendMessage({ method: "singlefile.fetch", url, referrer: options.referrer, headers: options.headers });
 		return {
 			status: response.status,
 			headers: { get: headerName => response.headers && response.headers[headerName] },
@@ -83,7 +83,7 @@ async function fetchResource(url, options = {}) {
 }
 
 async function frameFetch(url, options) {
-	const response = await sendMessage({ method: "singlefile.fetchFrame", url, frameId: options.frameId, referrer: options.referrer });
+	const response = await sendMessage({ method: "singlefile.fetchFrame", url, frameId: options.frameId, referrer: options.referrer, headers: options.headers });
 	return {
 		status: response.status,
 		headers: new Map(response.headers),

+ 24 - 11
lib/single-file/single-file-core.js

@@ -358,7 +358,8 @@ class BatchRequest {
 					frameId: options.windowId,
 					resourceReferrer: options.resourceReferrer,
 					baseURI,
-					blockMixedContent
+					blockMixedContent,
+					acceptHeaders: options.acceptHeaders
 				});
 				onloadListener({ url: resourceURL });
 				if (!this.cancelled) {
@@ -418,7 +419,7 @@ class Processor {
 		this.options.saveDate = new Date();
 		this.options.saveUrl = this.options.url;
 		if (this.options.enableMaff) {
-			this.maffMetaDataPromise = this.batchRequest.addURL(util.resolveURL("index.rdf", this.options.baseURI || this.options.url));
+			this.maffMetaDataPromise = this.batchRequest.addURL(util.resolveURL("index.rdf", this.options.baseURI || this.options.url), { expectedType: "document" });
 		}
 		this.maxResources = this.batchRequest.getMaxResources();
 		if (!this.options.saveRawPage && !this.options.removeFrames && this.options.frames) {
@@ -438,7 +439,9 @@ class Processor {
 				maxResourceSizeEnabled: this.options.maxResourceSizeEnabled,
 				charset,
 				frameId: this.options.windowId,
-				resourceReferrer: this.options.resourceReferrer
+				resourceReferrer: this.options.resourceReferrer,
+				expectedType: "document",
+				acceptHeaders: this.options.acceptHeaders
 			});
 			pageContent = content.data;
 		}
@@ -939,7 +942,8 @@ class Processor {
 				frameId: this.options.windowId,
 				resourceReferrer: this.options.resourceReferrer,
 				blockMixedContent: this.options.blockMixedContent,
-				saveOriginalURLs: this.options.saveOriginalURLs
+				saveOriginalURLs: this.options.saveOriginalURLs,
+				acceptHeaders: this.options.acceptHeaders
 			};
 			let mediaText;
 			if (element.media) {
@@ -1249,7 +1253,9 @@ class Processor {
 					frameId: this.options.windowId,
 					resourceReferrer: this.options.resourceReferrer,
 					baseURI: this.options.baseURI,
-					blockMixedContent: this.options.blockMixedContent
+					blockMixedContent: this.options.blockMixedContent,
+					expectedType: "script",
+					acceptHeaders: this.options.acceptHeaders
 				});
 				content.data = getUpdatedResourceContent(resourceURL, content, this.options);
 				if (element.tagName == "SCRIPT") {
@@ -1679,7 +1685,9 @@ class ProcessorHelper {
 				charset: options.charset,
 				resourceReferrer: options.resourceReferrer,
 				baseURI: options.baseURI,
-				blockMixedContent: options.blockMixedContent
+				blockMixedContent: options.blockMixedContent,
+				expectedType: "stylesheet",
+				acceptHeaders: options.acceptHeaders
 			});
 			if (!matchCharsetEquals(content.data, content.charset || options.charset)) {
 				options = Object.assign({}, options, { charset: getCharset(content.data) });
@@ -1691,7 +1699,9 @@ class ProcessorHelper {
 					charset: options.charset,
 					resourceReferrer: options.resourceReferrer,
 					baseURI: options.baseURI,
-					blockMixedContent: options.blockMixedContent
+					blockMixedContent: options.blockMixedContent,
+					expectedType: "stylesheet",
+					acceptHeaders: options.acceptHeaders
 				});
 			} else {
 				return content;
@@ -1753,7 +1763,9 @@ class ProcessorHelper {
 				resourceReferrer: options.resourceReferrer,
 				validateTextContentType: true,
 				baseURI: baseURI,
-				blockMixedContent: options.blockMixedContent
+				blockMixedContent: options.blockMixedContent,
+				expectedType: "stylesheet",
+				acceptHeaders: options.acceptHeaders
 			});
 			if (!matchCharsetEquals(content.data, content.charset || options.charset)) {
 				options = Object.assign({}, options, { charset: getCharset(content.data) });
@@ -1916,7 +1928,8 @@ class ProcessorHelper {
 											maxResourceSize: options.maxResourceSize,
 											maxResourceSizeEnabled: options.maxResourceSizeEnabled,
 											frameId: options.windowId,
-											resourceReferrer: options.resourceReferrer
+											resourceReferrer: options.resourceReferrer,
+											acceptHeaders: options.acceptHeaders
 										})).data;
 									} catch (error) {
 										// ignored
@@ -1973,7 +1986,7 @@ class ProcessorHelper {
 					if (originalResourceURL.startsWith(baseURI + "#")) {
 						resourceElement.setAttribute(attributeName, hashMatch[0]);
 					} else {
-						const response = await batchRequest.addURL(resourceURL);
+						const response = await batchRequest.addURL(resourceURL, { expectedType: "image" });
 						const svgDoc = util.parseSVGContent(response.content);
 						if (hashMatch && hashMatch[0]) {
 							let symbolElement;
@@ -1987,7 +2000,7 @@ class ProcessorHelper {
 								resourceElement.parentElement.insertBefore(symbolElement, resourceElement.parentElement.firstChild);
 							}
 						} else {
-							const content = await batchRequest.addURL(resourceURL);
+							const content = await batchRequest.addURL(resourceURL, { expectedType: "image" });
 							resourceElement.setAttribute(attributeName, PREFIX_DATA_URI_IMAGE_SVG + "," + content);
 						}
 					}

+ 4 - 4
lib/single-file/single-file-util.js

@@ -37,7 +37,7 @@ const URL = globalThis.URL;
 const DOMParser = globalThis.DOMParser;
 const Blob = globalThis.Blob;
 const FileReader = globalThis.FileReader;
-const fetch = url => globalThis.fetch(url);
+const fetch = (url, options) => globalThis.fetch(url, options);
 const crypto = globalThis.crypto;
 const TextDecoder = globalThis.TextDecoder;
 const TextEncoder = globalThis.TextEncoder;
@@ -200,12 +200,12 @@ function getInstance(utilOptions) {
 		try {
 			if (options.frameId) {
 				try {
-					response = await fetchFrameResource(resourceURL, { frameId: options.frameId, referrer: options.resourceReferrer });
+					response = await fetchFrameResource(resourceURL, { frameId: options.frameId, referrer: options.resourceReferrer, headers: { accept: options.acceptHeaders[options.expectedType] } });
 				} catch (error) {
-					response = await fetchResource(resourceURL);
+					response = await fetchResource(resourceURL, { headers: { accept: options.acceptHeaders[options.expectedType] } });
 				}
 			} else {
-				response = await fetchResource(resourceURL, { referrer: options.resourceReferrer });
+				response = await fetchResource(resourceURL, { referrer: options.resourceReferrer, headers: { accept: options.acceptHeaders[options.expectedType] } });
 			}
 		} catch (error) {
 			return { data: options.asBinary ? "data:null;base64," : "", resourceURL };