From 43f6bdf4ed54446f372187a2e1c77d2575a795f7 Mon Sep 17 00:00:00 2001 From: tophf Date: Sat, 16 May 2020 22:50:04 +0300 Subject: [PATCH] use a separate loadTimeout for the actual data transfer (#931) --- js/messaging.js | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/js/messaging.js b/js/messaging.js index 93a4e5a7..cb8454e5 100644 --- a/js/messaging.js +++ b/js/messaging.js @@ -381,7 +381,8 @@ function download(url, { body, responseType = 'text', requiredStatusCode = 200, - timeout = 10e3, + timeout = 10e3, // connection timeout + loadTimeout = 2 * 60e3, // data transfer timeout (counted from the first remote response) headers = { 'Content-type': 'application/x-www-form-urlencoded', }, @@ -398,23 +399,41 @@ function download(url, { const usoVars = []; return new Promise((resolve, reject) => { + let xhr; const u = new URL(collapseUsoVars(url)); - if (u.protocol === 'file:' && FIREFOX) { + const onTimeout = () => { + if (xhr) xhr.abort(); + reject(new Error('Timeout fetching ' + u.href)); + }; + let timer = setTimeout(onTimeout, timeout); + const switchTimer = () => { + clearTimeout(timer); + timer = loadTimeout && setTimeout(onTimeout, loadTimeout); + }; + if (u.protocol === 'file:' && FIREFOX) { // TODO: maybe remove this since FF68+ can't do it anymore // https://stackoverflow.com/questions/42108782/firefox-webextensions-get-local-files-content-by-path // FIXME: add FetchController when it is available. - const timer = setTimeout(reject, timeout, new Error('Timeout fetching ' + u.href)); fetch(u.href, {mode: 'same-origin'}) .then(r => { - clearTimeout(timer); + switchTimer(); return r.status === 200 ? r.text() : Promise.reject(r.status); }) .catch(reject) - .then(resolve); + .then(text => { + clearTimeout(timer); + resolve(text); + }); return; } - const xhr = new XMLHttpRequest(); - xhr.timeout = timeout; + xhr = new XMLHttpRequest(); + xhr.onreadystatechange = () => { + if (xhr.readyState >= XMLHttpRequest.HEADERS_RECEIVED) { + xhr.onreadystatechange = null; + switchTimer(); + } + }; xhr.onloadend = event => { + clearTimeout(timer); if (event.type !== 'error' && ( xhr.status === requiredStatusCode || !requiredStatusCode || u.protocol === 'file:')) {