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:
Nils Maier 2019-09-06 03:09:04 +00:00
Родитель 37528b94d0
Коммит f28d2b02a0
2 изменённых файлов: 113 добавлений и 2 удалений

Просмотреть файл

@ -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`;