Pārlūkot izejas kodu

add networkTimeout hidden option (see #935)

Gildas 3 gadi atpakaļ
vecāks
revīzija
ec1c88838b

+ 1 - 0
src/extension/core/bg/config.js

@@ -124,6 +124,7 @@ const DEFAULT_CONFIG = {
 		audio: "audio/webm,audio/ogg,audio/wav,audio/*;q=0.9,application/ogg;q=0.7,video/*;q=0.6,*/*;q=0.5"
 	},
 	moveStylesInHead: false,
+	networkTimeout: 0,
 	woleetKey: ""
 };
 

+ 17 - 9
src/single-file/single-file-core.js

@@ -363,7 +363,8 @@ class BatchRequest {
 					resourceReferrer: options.resourceReferrer,
 					baseURI,
 					blockMixedContent,
-					acceptHeaders: options.acceptHeaders
+					acceptHeaders: options.acceptHeaders,
+					networkTimeout: options.networkTimeout
 				});
 				onloadListener({ url: resourceURL });
 				if (!this.cancelled) {
@@ -445,7 +446,8 @@ class Processor {
 				frameId: this.options.windowId,
 				resourceReferrer: this.options.resourceReferrer,
 				expectedType: "document",
-				acceptHeaders: this.options.acceptHeaders
+				acceptHeaders: this.options.acceptHeaders,
+				networkTimeout: this.options.networkTimeout
 			});
 			pageContent = content.data;
 		}
@@ -1010,7 +1012,8 @@ class Processor {
 				resourceReferrer: this.options.resourceReferrer,
 				blockMixedContent: this.options.blockMixedContent,
 				saveOriginalURLs: this.options.saveOriginalURLs,
-				acceptHeaders: this.options.acceptHeaders
+				acceptHeaders: this.options.acceptHeaders,
+				networkTimeout: this.options.networkTimeout
 			};
 			let mediaText;
 			if (element.media) {
@@ -1323,7 +1326,8 @@ class Processor {
 					baseURI: this.options.baseURI,
 					blockMixedContent: this.options.blockMixedContent,
 					expectedType: "script",
-					acceptHeaders: this.options.acceptHeaders
+					acceptHeaders: this.options.acceptHeaders,
+					networkTimeout: this.options.networkTimeout
 				});
 				content.data = getUpdatedResourceContent(resourceURL, content, this.options);
 				if (element.tagName == "SCRIPT") {
@@ -1755,7 +1759,8 @@ class ProcessorHelper {
 				baseURI: options.baseURI,
 				blockMixedContent: options.blockMixedContent,
 				expectedType: "stylesheet",
-				acceptHeaders: options.acceptHeaders
+				acceptHeaders: options.acceptHeaders,
+				networkTimeout: options.networkTimeout
 			});
 			if (!(matchCharsetEquals(content.data, content.charset) || matchCharsetEquals(content.data, options.charset))) {
 				options = Object.assign({}, options, { charset: getCharset(content.data) });
@@ -1769,7 +1774,8 @@ class ProcessorHelper {
 					baseURI: options.baseURI,
 					blockMixedContent: options.blockMixedContent,
 					expectedType: "stylesheet",
-					acceptHeaders: options.acceptHeaders
+					acceptHeaders: options.acceptHeaders,
+					networkTimeout: options.networkTimeout
 				});
 			} else {
 				return content;
@@ -1833,7 +1839,8 @@ class ProcessorHelper {
 				baseURI: baseURI,
 				blockMixedContent: options.blockMixedContent,
 				expectedType: "stylesheet",
-				acceptHeaders: options.acceptHeaders
+				acceptHeaders: options.acceptHeaders,
+				networkTimeout: options.networkTimeout
 			});
 			if (!(matchCharsetEquals(content.data, content.charset) || matchCharsetEquals(content.data, options.charset))) {
 				options = Object.assign({}, options, { charset: getCharset(content.data) });
@@ -1980,7 +1987,7 @@ class ProcessorHelper {
 						}
 						if (testValidURL(resourceURL)) {
 							let { content, indexResource, duplicate } = await batchRequest.addURL(resourceURL,
-								{ asBinary: true, expectedType: expectedType, groupDuplicates: options.groupDuplicateImages && resourceElement.tagName == "IMG" && attributeName == "src" });
+								{ asBinary: true, expectedType, groupDuplicates: options.groupDuplicateImages && resourceElement.tagName == "IMG" && attributeName == "src" });
 							if (originURL) {
 								if (content == EMPTY_DATA_URI) {
 									try {
@@ -1997,7 +2004,8 @@ class ProcessorHelper {
 											maxResourceSizeEnabled: options.maxResourceSizeEnabled,
 											frameId: options.windowId,
 											resourceReferrer: options.resourceReferrer,
-											acceptHeaders: options.acceptHeaders
+											acceptHeaders: options.acceptHeaders,
+											networkTimeout: options.networkTimeout
 										})).data;
 									} catch (error) {
 										// ignored

+ 28 - 4
src/single-file/single-file-util.js

@@ -189,7 +189,7 @@ function getInstance(utilOptions) {
 	};
 
 	async function getContent(resourceURL, options) {
-		let response, startTime;
+		let response, startTime, networkTimeoutId, networkTimeoutPromise, resolveNetworkTimeoutPromise;
 		const fetchResource = utilOptions.fetch;
 		const fetchFrameResource = utilOptions.frameFetch;
 		if (DEBUG) {
@@ -199,19 +199,43 @@ function getInstance(utilOptions) {
 		if (options.blockMixedContent && /^https:/i.test(options.baseURI) && !/^https:/i.test(resourceURL)) {
 			return { data: options.asBinary ? "data:null;base64," : "", resourceURL };
 		}
+		if (options.networkTimeout) {
+			networkTimeoutPromise = new Promise((resolve, reject) => {
+				resolveNetworkTimeoutPromise = resolve;
+				networkTimeoutId = globalThis.setTimeout(() => reject(new Error("network timeout")), options.networkTimeout);
+			});
+		} else {
+			networkTimeoutPromise = new Promise(resolve => {
+				resolveNetworkTimeoutPromise = resolve;
+			});
+		}
 		try {
 			const accept = options.acceptHeaders ? options.acceptHeaders[options.expectedType] : "*/*";
 			if (options.frameId) {
 				try {
-					response = await fetchFrameResource(resourceURL, { frameId: options.frameId, referrer: options.resourceReferrer, headers: { accept } });
+					response = await Promise.race([
+						fetchFrameResource(resourceURL, { frameId: options.frameId, referrer: options.resourceReferrer, headers: { accept } }),
+						networkTimeoutPromise
+					]);
 				} catch (error) {
-					response = await fetchResource(resourceURL, { headers: { accept } });
+					response = await Promise.race([
+						fetchResource(resourceURL, { headers: { accept } }),
+						networkTimeoutPromise
+					]);
 				}
 			} else {
-				response = await fetchResource(resourceURL, { referrer: options.resourceReferrer, headers: { accept } });
+				response = await await Promise.race([
+					fetchResource(resourceURL, { referrer: options.resourceReferrer, headers: { accept } }),
+					networkTimeoutPromise
+				]);
 			}
 		} catch (error) {
 			return { data: options.asBinary ? "data:null;base64," : "", resourceURL };
+		} finally {
+			resolveNetworkTimeoutPromise();
+			if (options.networkTimeout) {
+				globalThis.clearTimeout(networkTimeoutId);
+			}
 		}
 		let buffer;
 		try {