зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1576333 - Part 2: Make WE downloads API cancel on HTTP errors r=zombie
Differential Revision: https://phabricator.services.mozilla.com/D43343 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
37528b94d0
Коммит
f28d2b02a0
|
@ -97,6 +97,7 @@ class DownloadItem {
|
|||
this.download = download;
|
||||
this.extension = extension;
|
||||
this.prechange = {};
|
||||
this._error = null;
|
||||
}
|
||||
|
||||
get url() {
|
||||
|
@ -137,7 +138,7 @@ class DownloadItem {
|
|||
if (this.download.succeeded) {
|
||||
return "complete";
|
||||
}
|
||||
if (this.download.canceled) {
|
||||
if (this.download.canceled || this.error) {
|
||||
return "interrupted";
|
||||
}
|
||||
return "in_progress";
|
||||
|
@ -157,6 +158,9 @@ class DownloadItem {
|
|||
);
|
||||
}
|
||||
get error() {
|
||||
if (this._error) {
|
||||
return this._error;
|
||||
}
|
||||
if (
|
||||
!this.download.startTime ||
|
||||
!this.download.stopped ||
|
||||
|
@ -177,6 +181,9 @@ class DownloadItem {
|
|||
}
|
||||
return "USER_CANCELED";
|
||||
}
|
||||
set error(value) {
|
||||
this._error = value && value.toString();
|
||||
}
|
||||
get bytesReceived() {
|
||||
return this.download.currentBytes;
|
||||
}
|
||||
|
@ -636,6 +643,33 @@ this.downloads = class extends ExtensionAPI {
|
|||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function allowHttpStatus(download, status) {
|
||||
if (status < 400) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const item = DownloadMap.byDownload.get(download);
|
||||
if (item === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (status === 404) {
|
||||
item.error = "SERVER_BAD_CONTENT";
|
||||
return false;
|
||||
}
|
||||
if (status === 403) {
|
||||
item.error = "SERVER_FORBIDDEN";
|
||||
return false;
|
||||
}
|
||||
// Unauthorized and proxy authorization required
|
||||
if (status === 402 || status == 407) {
|
||||
item.error = "SERVER_UNAUTHORIZED";
|
||||
return false;
|
||||
}
|
||||
item.error = "SERVER_FAILED";
|
||||
return false;
|
||||
}
|
||||
|
||||
async function createTarget(downloadsDir) {
|
||||
if (!filename) {
|
||||
let uri = Services.io.newURI(options.url);
|
||||
|
@ -728,6 +762,7 @@ this.downloads = class extends ExtensionAPI {
|
|||
const source = {
|
||||
url: options.url,
|
||||
isPrivate: options.incognito,
|
||||
allowHttpStatus,
|
||||
};
|
||||
|
||||
if (options.method || options.headers || options.body) {
|
||||
|
@ -752,7 +787,12 @@ this.downloads = class extends ExtensionAPI {
|
|||
|
||||
// This is necessary to make pause/resume work.
|
||||
download.tryToKeepPartialData = true;
|
||||
download.start();
|
||||
|
||||
// Do not handle errors.
|
||||
// Extensions will use listeners to be informed about errors.
|
||||
// Just ignore any errors from |start()| to avoid spamming the
|
||||
// error console.
|
||||
download.start().catch(() => {});
|
||||
|
||||
return item.id;
|
||||
});
|
||||
|
@ -826,6 +866,7 @@ this.downloads = class extends ExtensionAPI {
|
|||
});
|
||||
}
|
||||
|
||||
item.error = null;
|
||||
return item.download.start();
|
||||
});
|
||||
},
|
||||
|
|
|
@ -415,6 +415,76 @@ add_task(async function test_downloads() {
|
|||
await extension.unload();
|
||||
});
|
||||
|
||||
add_task(async function test_download_http_errors() {
|
||||
const server = createHttpServer();
|
||||
const url = `http://localhost:${server.identity.primaryPort}/error`;
|
||||
|
||||
server.registerPathHandler("/error", (request, response) => {
|
||||
response.setStatusLine(
|
||||
"1.1",
|
||||
parseInt(request.queryString, 10),
|
||||
"Some Error"
|
||||
);
|
||||
response.setHeader("Content-Type", "text/plain", false);
|
||||
response.setHeader("Content-Length", "3");
|
||||
response.write("err");
|
||||
});
|
||||
|
||||
function background(code) {
|
||||
let dlid = 0;
|
||||
browser.test.onMessage.addListener(async options => {
|
||||
try {
|
||||
dlid = await browser.downloads.download(options);
|
||||
} catch (err) {
|
||||
browser.test.fail(`Unexpected error in downloads.download(): ${err}`);
|
||||
}
|
||||
});
|
||||
function onChanged({ id, state }) {
|
||||
if (!state || dlid !== id || state.current !== "interrupted") {
|
||||
return;
|
||||
}
|
||||
browser.downloads.search({ id }).then(([download]) => {
|
||||
browser.test.sendMessage("done", download.error);
|
||||
});
|
||||
}
|
||||
browser.downloads.onChanged.addListener(onChanged);
|
||||
}
|
||||
|
||||
const extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
permissions: ["downloads"],
|
||||
},
|
||||
background,
|
||||
});
|
||||
await extension.startup();
|
||||
|
||||
function download(code) {
|
||||
const options = {
|
||||
url: url + "?" + code,
|
||||
conflictAction: "overwrite",
|
||||
};
|
||||
extension.sendMessage(options);
|
||||
return extension.awaitMessage("done");
|
||||
}
|
||||
|
||||
let res = await download(404);
|
||||
equal(res, "SERVER_BAD_CONTENT", "error is correct");
|
||||
|
||||
res = await download(403);
|
||||
equal(res, "SERVER_FORBIDDEN", "error is correct");
|
||||
|
||||
res = await download(402);
|
||||
equal(res, "SERVER_UNAUTHORIZED", "error is correct");
|
||||
|
||||
res = await download(407);
|
||||
equal(res, "SERVER_UNAUTHORIZED", "error is correct");
|
||||
|
||||
res = await download(504);
|
||||
equal(res, "SERVER_FAILED", "error is correct");
|
||||
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
add_task(async function test_download_http_details() {
|
||||
const server = createHttpServer();
|
||||
const url = `http://localhost:${server.identity.primaryPort}/post-log`;
|
||||
|
|
Загрузка…
Ссылка в новой задаче