Skip to content

Commit

Permalink
Bug 1757771, always launch the save dialog when pressing the PDF View…
Browse files Browse the repository at this point in the history
…er download button, and remove test code that expected the unknown type dialog to appear, r=marco

Differential Revision: https://phabricator.services.mozilla.com/D145814
  • Loading branch information
EnnDeakin2 committed May 16, 2022
1 parent b40db53 commit b291010
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 157 deletions.
112 changes: 4 additions & 108 deletions toolkit/components/pdfjs/content/PdfStreamConverter.jsm
Original file line number Diff line number Diff line change
Expand Up @@ -340,124 +340,20 @@ class ChromeActions {
}

download(data, sendResponse) {
var self = this;
var originalUrl = data.originalUrl;
var blobUrl = data.blobUrl || originalUrl;
// The data may not be downloaded so we need just retry getting the pdf with
// the original url.
var originalUri = NetUtil.newURI(originalUrl);
var filename = data.filename;
if (
typeof filename !== "string" ||
(!/\.pdf$/i.test(filename) && !data.isAttachment)
) {
filename = "document.pdf";
}
var blobUri = NetUtil.newURI(blobUrl);

// If the download was triggered from the ctrl/cmd+s or "Save Page As"
// or the download button, launch the "Save As" dialog.
const saveOnDownload = getBoolPref(
"browser.download.improvements_to_download_panel",
false
);

if (
data.sourceEventType == "save" ||
(saveOnDownload && data.sourceEventType == "download")
) {
let actor = getActor(this.domWindow);
actor.sendAsyncMessage("PDFJS:Parent:saveURL", {
blobUrl,
filename,
});
return;
}

// The download is from the fallback bar or the download button, so trigger
// the open dialog to make it easier for users to save in the downloads
// folder or launch a different PDF viewer.
var extHelperAppSvc = Cc[
"@mozilla.org/uriloader/external-helper-app-service;1"
].getService(Ci.nsIExternalHelperAppService);

var docIsPrivate = this.isInPrivateBrowsing();
var netChannel = NetUtil.newChannel({
uri: blobUri,
loadUsingSystemPrincipal: true,
});
if (
"nsIPrivateBrowsingChannel" in Ci &&
netChannel instanceof Ci.nsIPrivateBrowsingChannel
) {
netChannel.setPrivate(docIsPrivate);
}
NetUtil.asyncFetch(netChannel, function(aInputStream, aResult) {
if (!Components.isSuccessCode(aResult)) {
if (sendResponse) {
sendResponse(true);
}
return;
}
// Create a nsIInputStreamChannel so we can set the url on the channel
// so the filename will be correct.
var channel = Cc[
"@mozilla.org/network/input-stream-channel;1"
].createInstance(Ci.nsIInputStreamChannel);
channel.QueryInterface(Ci.nsIChannel);
try {
// contentDisposition/contentDispositionFilename is readonly before FF18
channel.contentDisposition = Ci.nsIChannel.DISPOSITION_ATTACHMENT;
if (self.contentDispositionFilename && !data.isAttachment) {
channel.contentDispositionFilename = self.contentDispositionFilename;
} else {
channel.contentDispositionFilename = filename;
}
} catch (e) {}
channel.setURI(originalUri);
channel.loadInfo = netChannel.loadInfo;
channel.contentStream = aInputStream;
if (
"nsIPrivateBrowsingChannel" in Ci &&
channel instanceof Ci.nsIPrivateBrowsingChannel
) {
channel.setPrivate(docIsPrivate);
}

var listener = {
extListener: null,
onStartRequest(aRequest) {
var loadContext = self.domWindow.docShell.QueryInterface(
Ci.nsILoadContext
);
this.extListener = extHelperAppSvc.doContent(
data.isAttachment ? "application/octet-stream" : PDF_CONTENT_TYPE,
aRequest,
loadContext,
false
);
this.extListener.onStartRequest(aRequest);
},
onStopRequest(aRequest, aStatusCode) {
if (this.extListener) {
this.extListener.onStopRequest(aRequest, aStatusCode);
}
// Notify the content code we're done downloading.
if (sendResponse) {
sendResponse(false);
}
},
onDataAvailable(aRequest, aDataInputStream, aOffset, aCount) {
this.extListener.onDataAvailable(
aRequest,
aDataInputStream,
aOffset,
aCount
);
},
};

channel.asyncOpen(listener);
let actor = getActor(this.domWindow);
actor.sendAsyncMessage("PDFJS:Parent:saveURL", {
blobUrl,
filename,
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ const HandlerSvc = Cc["@mozilla.org/uriloader/handler-service;1"].getService(
Ci.nsIHandlerService
);

let MockFilePicker = SpecialPowers.MockFilePicker;
MockFilePicker.init(window);

function waitForAcceptButtonToGetEnabled(doc) {
let dialog = doc.querySelector("#unknownContentType");
let button = dialog.getButton("accept");
Expand Down Expand Up @@ -235,6 +238,15 @@ add_task(async function test_check_open_with_internal_handler() {
// Cancel dialog
subDoc.querySelector("#unknownContentType").cancelDialog();

let filepickerPromise = new Promise(resolve => {
MockFilePicker.showCallback = function(fp) {
setTimeout(() => {
resolve(fp.defaultString);
}, 0);
return Ci.nsIFilePicker.returnCancel;
};
});

subdialogPromise = BrowserTestUtils.domWindowOpenedAndLoaded();
await SpecialPowers.spawn(newTab.linkedBrowser, [], async () => {
let downloadButton;
Expand All @@ -248,54 +260,8 @@ add_task(async function test_check_open_with_internal_handler() {
info(
"Waiting for unknown content type dialog to appear from pdf.js download button click"
);
subDialogWindow = await subdialogPromise;
subDoc = subDialogWindow.document;

// There is no content type here, so the type will be 'other'.
checkTelemetry(
"open " + file + " internal from download button",
"ask",
"other",
"attachment"
);

// Prevent racing with initialization of the dialog and make sure that
// the final state of the dialog has the correct visibility of the internal-handler option.
await waitForAcceptButtonToGetEnabled(subDoc);
subInternalHandlerRadio = subDoc.querySelector("#handleInternally");
ok(
subInternalHandlerRadio.hidden,
"The option should be hidden when the dialog is opened from pdf.js"
);
subDoc.querySelector("#open").click();

let tabOpenListener = () => {
ok(
false,
"A new tab should not be opened when accepting the dialog with 'open-with-external-app' chosen"
);
};
gBrowser.tabContainer.addEventListener("TabOpen", tabOpenListener);

let openingPromise = TestUtils.topicObserved(
"test-only-opening-downloaded-file",
(subject, data) => {
subject.QueryInterface(Ci.nsISupportsPRBool);
// Block opening the file:
subject.data = false;
return true;
}
);

info("Accepting the dialog");
subDoc.querySelector("#unknownContentType").acceptDialog();
info("Waiting until we try to open the file with an external app");
let [, downloadPath] = await openingPromise;
is(
downloadPath,
download.target.path,
"Path opened with external app should be the same."
);
let filename = await filepickerPromise;
is(filename, file, "filename was set in filepicker");

// Remove the first file (can't do this sooner or the second load fails):
if (download?.target.exists) {
Expand All @@ -307,7 +273,6 @@ add_task(async function test_check_open_with_internal_handler() {
}
}

gBrowser.tabContainer.removeEventListener("TabOpen", tabOpenListener);
BrowserTestUtils.removeTab(loadingTab);
BrowserTestUtils.removeTab(newTab);
BrowserTestUtils.removeTab(extraTab);
Expand Down Expand Up @@ -930,3 +895,7 @@ add_task(async function test_check_open_with_internal_handler_noask() {
HandlerSvc.remove(mimeInfo);
}
});

add_task(async () => {
MockFilePicker.cleanup();
});

0 comments on commit b291010

Please sign in to comment.