[tor-commits] [tor-browser] 49/73: Bug 1761265, don't show the downloads panel when a download was started by user action that they expect will save the file, r=mhowell, kershaw a=RyanVM

gitolite role git at cupani.torproject.org
Wed Sep 21 20:17:42 UTC 2022


This is an automated email from the git hooks/post-receive script.

richard pushed a commit to branch geckoview-102.3.0esr-12.0-1
in repository tor-browser.

commit 2c8bd7596866106d17260f75a5a9480f52ddd207
Author: Neil Deakin <neil at mozilla.com>
AuthorDate: Mon Jun 6 22:23:58 2022 +0000

    Bug 1761265, don't show the downloads panel when a download was started by user action that they expect will save the file, r=mhowell,kershaw a=RyanVM
    
    The download panel should still appear when clicking on download links or those with content-disposition: attachment
    
    Differential Revision: https://phabricator.services.mozilla.com/D147875
---
 .../components/downloads/test/browser/browser.ini  |   1 +
 .../browser/browser_downloads_panel_dontshow.js    | 126 +++++++++++++++++++++
 dom/webbrowserpersist/nsWebBrowserPersist.cpp      |   3 +
 netwerk/base/LoadInfo.cpp                          |  14 +++
 netwerk/base/LoadInfo.h                            |   1 +
 netwerk/base/TRRLoadInfo.cpp                       |  10 ++
 netwerk/base/nsILoadInfo.idl                       |   6 +
 toolkit/components/downloads/DownloadCore.jsm      |   9 ++
 .../pdfjs/test/browser_pdfjs_download_button.js    |  31 +++--
 9 files changed, 190 insertions(+), 11 deletions(-)

diff --git a/browser/components/downloads/test/browser/browser.ini b/browser/components/downloads/test/browser/browser.ini
index 35d3d9a486f8b..f803f34daa988 100644
--- a/browser/components/downloads/test/browser/browser.ini
+++ b/browser/components/downloads/test/browser/browser.ini
@@ -45,6 +45,7 @@ skip-if =
 support-files =
   foo.txt
   foo.txt^headers^
+[browser_downloads_panel_dontshow.js]
 [browser_downloads_panel_height.js]
 [browser_downloads_panel_opens.js]
 [browser_downloads_autohide.js]
diff --git a/browser/components/downloads/test/browser/browser_downloads_panel_dontshow.js b/browser/components/downloads/test/browser/browser_downloads_panel_dontshow.js
new file mode 100644
index 0000000000000..b6de758723907
--- /dev/null
+++ b/browser/components/downloads/test/browser/browser_downloads_panel_dontshow.js
@@ -0,0 +1,126 @@
+// This test verifies that the download panel opens when a
+// download occurs but not when a user manually saves a page.
+
+let MockFilePicker = SpecialPowers.MockFilePicker;
+MockFilePicker.init(window);
+
+async function promiseDownloadFinished(list) {
+  return new Promise(resolve => {
+    list.addView({
+      onDownloadChanged(download) {
+        download.launchWhenSucceeded = false;
+        if (download.succeeded || download.error) {
+          list.removeView(this);
+          resolve(download);
+        }
+      },
+    });
+  });
+}
+
+function openTestPage() {
+  return BrowserTestUtils.openNewForegroundTab(
+    gBrowser,
+    `https://www.example.com/document-builder.sjs?html=
+      <html><body>
+        <a id='normallink' href='https://www.example.com'>Link1</a>
+        <a id='downloadlink' href='https://www.example.com' download='file.txt'>Link2</a>
+      </body</html>
+    `
+  );
+}
+
+add_task(async function download_saveas_file() {
+  let tab = await openTestPage();
+
+  for (let testname of ["save link", "save page"]) {
+    if (testname == "save link") {
+      let menu = document.getElementById("contentAreaContextMenu");
+      let popupShown = BrowserTestUtils.waitForEvent(menu, "popupshown");
+      BrowserTestUtils.synthesizeMouse(
+        "#normallink",
+        5,
+        5,
+        { type: "contextmenu", button: 2 },
+        gBrowser.selectedBrowser
+      );
+      await popupShown;
+    }
+
+    let list = await Downloads.getList(Downloads.PUBLIC);
+    let downloadFinishedPromise = promiseDownloadFinished(list);
+
+    let saveFile = Services.dirsvc.get("TmpD", Ci.nsIFile);
+    saveFile.append("testsavedir");
+    if (!saveFile.exists()) {
+      saveFile.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
+    }
+
+    await new Promise(resolve => {
+      MockFilePicker.showCallback = function(fp) {
+        saveFile.append("sample");
+        MockFilePicker.setFiles([saveFile]);
+        setTimeout(() => {
+          resolve(fp.defaultString);
+        }, 0);
+        return Ci.nsIFilePicker.returnOK;
+      };
+
+      if (testname == "save link") {
+        let menu = document.getElementById("contentAreaContextMenu");
+        let menuitem = document.getElementById("context-savelink");
+        menu.activateItem(menuitem);
+      } else if (testname == "save page") {
+        document.getElementById("Browser:SavePage").doCommand();
+      }
+    });
+
+    await downloadFinishedPromise;
+    is(
+      DownloadsPanel.panel.state,
+      "closed",
+      "downloads panel closed after download link after " + testname
+    );
+  }
+
+  await task_resetState();
+
+  MockFilePicker.cleanup();
+  BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function download_link() {
+  let tab = await openTestPage();
+
+  let list = await Downloads.getList(Downloads.PUBLIC);
+  let downloadFinishedPromise = promiseDownloadFinished(list);
+
+  let panelOpenedPromise = promisePanelOpened();
+
+  BrowserTestUtils.synthesizeMouse(
+    "#downloadlink",
+    5,
+    5,
+    {},
+    gBrowser.selectedBrowser
+  );
+
+  let download = await downloadFinishedPromise;
+  await panelOpenedPromise;
+
+  is(
+    DownloadsPanel.panel.state,
+    "open",
+    "downloads panel open after download link clicked"
+  );
+
+  DownloadsPanel.hidePanel();
+
+  await task_resetState();
+
+  BrowserTestUtils.removeTab(tab);
+
+  try {
+    await IOUtils.remove(download.target.path);
+  } catch (ex) {}
+});
diff --git a/dom/webbrowserpersist/nsWebBrowserPersist.cpp b/dom/webbrowserpersist/nsWebBrowserPersist.cpp
index f2c2ebf588408..7f304a77e8489 100644
--- a/dom/webbrowserpersist/nsWebBrowserPersist.cpp
+++ b/dom/webbrowserpersist/nsWebBrowserPersist.cpp
@@ -1377,6 +1377,9 @@ nsresult nsWebBrowserPersist::SaveURIInternal(
     }
   }
 
+  nsCOMPtr<nsILoadInfo> loadInfo = inputChannel->LoadInfo();
+  loadInfo->SetIsUserTriggeredSave(true);
+
   // Set the referrer, post data and headers if any
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(inputChannel));
   if (httpChannel) {
diff --git a/netwerk/base/LoadInfo.cpp b/netwerk/base/LoadInfo.cpp
index c70ae05224c37..5f5f9d0514768 100644
--- a/netwerk/base/LoadInfo.cpp
+++ b/netwerk/base/LoadInfo.cpp
@@ -1800,6 +1800,20 @@ LoadInfo::SetAllowDeprecatedSystemRequests(
   return NS_OK;
 }
 
+NS_IMETHODIMP
+LoadInfo::GetIsUserTriggeredSave(bool* aIsUserTriggeredSave) {
+  *aIsUserTriggeredSave =
+      mIsUserTriggeredSave ||
+      mInternalContentPolicyType == nsIContentPolicy::TYPE_SAVEAS_DOWNLOAD;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+LoadInfo::SetIsUserTriggeredSave(bool aIsUserTriggeredSave) {
+  mIsUserTriggeredSave = aIsUserTriggeredSave;
+  return NS_OK;
+}
+
 NS_IMETHODIMP
 LoadInfo::GetIsInDevToolsContext(bool* aIsInDevToolsContext) {
   *aIsInDevToolsContext = mIsInDevToolsContext;
diff --git a/netwerk/base/LoadInfo.h b/netwerk/base/LoadInfo.h
index 6452948b199c1..a1624592d20dc 100644
--- a/netwerk/base/LoadInfo.h
+++ b/netwerk/base/LoadInfo.h
@@ -330,6 +330,7 @@ class LoadInfo final : public nsILoadInfo {
   uint32_t mHttpsOnlyStatus = nsILoadInfo::HTTPS_ONLY_UNINITIALIZED;
   bool mHasValidUserGestureActivation = false;
   bool mAllowDeprecatedSystemRequests = false;
+  bool mIsUserTriggeredSave = false;
   bool mIsInDevToolsContext = false;
   bool mParserCreatedScript = false;
   nsILoadInfo::StoragePermissionState mStoragePermission =
diff --git a/netwerk/base/TRRLoadInfo.cpp b/netwerk/base/TRRLoadInfo.cpp
index 7ef044cb25171..05a8878a3f26a 100644
--- a/netwerk/base/TRRLoadInfo.cpp
+++ b/netwerk/base/TRRLoadInfo.cpp
@@ -698,6 +698,16 @@ TRRLoadInfo::SetAllowDeprecatedSystemRequests(
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
+NS_IMETHODIMP
+TRRLoadInfo::GetIsUserTriggeredSave(bool* aIsUserTriggeredSave) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TRRLoadInfo::SetIsUserTriggeredSave(bool aIsUserTriggeredSave) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
 NS_IMETHODIMP
 TRRLoadInfo::GetIsInDevToolsContext(bool* aIsInDevToolsContext) {
   return NS_ERROR_NOT_IMPLEMENTED;
diff --git a/netwerk/base/nsILoadInfo.idl b/netwerk/base/nsILoadInfo.idl
index 0a7d0c66fb3e5..85ba879702980 100644
--- a/netwerk/base/nsILoadInfo.idl
+++ b/netwerk/base/nsILoadInfo.idl
@@ -510,6 +510,12 @@ interface nsILoadInfo : nsISupports
    */
   [infallible] attribute boolean parserCreatedScript;
 
+  /**
+   * True if this request is known to have been triggered by a user
+   * manually requesting the URI to be saved.
+   */
+  [infallible] attribute boolean isUserTriggeredSave;
+
   /**
    * True if this request is from DevTools.
    */
diff --git a/toolkit/components/downloads/DownloadCore.jsm b/toolkit/components/downloads/DownloadCore.jsm
index 5292828f593a1..20771432cd47d 100644
--- a/toolkit/components/downloads/DownloadCore.jsm
+++ b/toolkit/components/downloads/DownloadCore.jsm
@@ -2865,6 +2865,15 @@ DownloadLegacySaver.prototype = {
       this.download.source.referrerInfo = aRequest.referrerInfo;
     }
 
+    // Don't open the download panel when the user initiated to save a
+    // link or document.
+    if (
+      aRequest instanceof Ci.nsIChannel &&
+      aRequest.loadInfo.isUserTriggeredSave
+    ) {
+      this.download.openDownloadsListOnStart = false;
+    }
+
     this.addToHistory();
   },
 
diff --git a/toolkit/components/pdfjs/test/browser_pdfjs_download_button.js b/toolkit/components/pdfjs/test/browser_pdfjs_download_button.js
index 5f21b241a223a..b0040a71941f6 100644
--- a/toolkit/components/pdfjs/test/browser_pdfjs_download_button.js
+++ b/toolkit/components/pdfjs/test/browser_pdfjs_download_button.js
@@ -12,6 +12,20 @@ MockFilePicker.returnValue = MockFilePicker.returnOK;
 
 var tempDir;
 
+async function promiseDownloadFinished(list) {
+  return new Promise(resolve => {
+    list.addView({
+      onDownloadChanged(download) {
+        download.launchWhenSucceeded = false;
+        if (download.succeeded || download.error) {
+          list.removeView(this);
+          resolve(download);
+        }
+      },
+    });
+  });
+}
+
 function createPromiseForFilePicker() {
   return new Promise(resolve => {
     MockFilePicker.showCallback = fp => {
@@ -77,10 +91,7 @@ add_task(async function test_downloading_pdf_nonprivate_window() {
 
       let filePickerShown = createPromiseForFilePicker();
 
-      let downloadsPanelPromise = BrowserTestUtils.waitForEvent(
-        DownloadsPanel.panel,
-        "popupshown"
-      );
+      let downloadFinishedPromise = promiseDownloadFinished(downloadList);
 
       info("Clicking on the download button...");
       await SpecialPowers.spawn(browser, [], () => {
@@ -89,14 +100,13 @@ add_task(async function test_downloading_pdf_nonprivate_window() {
       info("Waiting for a filename to be picked from the file picker");
       await filePickerShown;
 
-      // check that resulted in a download being added to the list
-      // and the dl panel opened
-      info("Waiting for download panel to open when the download is complete");
-      await downloadsPanelPromise;
+      // check that resulted in a download being added to the list. The
+      // download panel should not open.
+      await downloadFinishedPromise;
       is(
         DownloadsPanel.panel.state,
-        "open",
-        "Check the download panel state is 'open'"
+        "closed",
+        "Check the download panel state is 'closed'"
       );
       downloadList = await Downloads.getList(Downloads.PUBLIC);
       const allDownloads = await downloadList.getAll();
@@ -120,7 +130,6 @@ add_task(async function test_downloading_pdf_nonprivate_window() {
         tabCount,
         "No new tab was opened to view the downloaded PDF"
       );
-      await closeDownloadsPanel();
     }
   );
 });

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the tor-commits mailing list