Bug 1639606 - Downloads that are set to launchWhenSucceeded with an external application should not get handled internally, unless an attempt has already been made to launch externally. r=Gijs
☠☠ backed out by b1a3053806aa ☠ ☠
authorJared Wein <jwein@mozilla.com>
Fri, 22 May 2020 17:43:57 +0000
changeset 531697 2708f3e553cb7b327c1c4111779a309acbcdbc3c
parent 531696 e5029c564b6779ff2acff14e5df7537dc17f3190
child 531698 ab8d214e6ad8ac37d63380fe2039dfcec1080d6a
push id37442
push userncsoregi@mozilla.com
push dateSat, 23 May 2020 09:21:24 +0000
treeherdermozilla-central@bbcc193fe0f0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersGijs
bugs1639606
milestone78.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1639606 - Downloads that are set to launchWhenSucceeded with an external application should not get handled internally, unless an attempt has already been made to launch externally. r=Gijs Differential Revision: https://phabricator.services.mozilla.com/D76243
browser/components/downloads/test/browser/browser_pdfjs_preview.js
toolkit/components/downloads/DownloadIntegration.jsm
toolkit/components/downloads/DownloadUIHelper.jsm
uriloader/exthandler/tests/mochitest/browser.ini
uriloader/exthandler/tests/mochitest/browser_download_open_with_internal_handler.js
uriloader/exthandler/tests/mochitest/file_pdf_application_pdf.pdf
uriloader/exthandler/tests/mochitest/file_pdf_application_pdf.pdf^headers^
uriloader/exthandler/tests/mochitest/file_pdf_binary_octet_stream.pdf
uriloader/exthandler/tests/mochitest/file_pdf_binary_octet_stream.pdf^headers^
uriloader/exthandler/tests/mochitest/file_pdfjs_test.pdf
uriloader/exthandler/tests/mochitest/file_pdfjs_test.pdf^headers^
--- a/browser/components/downloads/test/browser/browser_pdfjs_preview.js
+++ b/browser/components/downloads/test/browser/browser_pdfjs_preview.js
@@ -207,17 +207,17 @@ async function testOpenPDFPreview({
   // Populate downloads database with the data required by this test.
   info("Adding download objects");
   let download = await addPDFDownload({
     targetFilename: "downloaded.pdf",
   });
   info("Got download pathname:" + download.target.path);
 
   let pdfFileURI = NetUtil.newURI(new FileUtils.File(download.target.path));
-  info("pdfFileURI:" + pdfFileURI);
+  info("pdfFileURI:" + pdfFileURI.spec);
 
   let uiWindow = window;
   let initialTab = gBrowser.selectedTab;
   let previewWindow = window;
   let previewTab;
   let previewHappened;
 
   if (expected.newWindow) {
--- a/toolkit/components/downloads/DownloadIntegration.jsm
+++ b/toolkit/components/downloads/DownloadIntegration.jsm
@@ -779,75 +779,49 @@ var DownloadIntegration = {
         "@mozilla.org/uriloader/local-handler-app;1"
       ].createInstance(Ci.nsILocalHandlerApp);
       localHandlerApp.executable = new FileUtils.File(aDownload.launcherPath);
 
       mimeInfo.preferredApplicationHandler = localHandlerApp;
       mimeInfo.preferredAction = Ci.nsIMIMEInfo.useHelperApp;
 
       this.launchFile(file, mimeInfo);
+      // After an attempt has been made to launch the download, clear the
+      // launchWhenSucceeded bit so future attempts to open the download can go
+      // through Firefox when possible.
+      aDownload.launchWhenSucceeded = false;
       return;
     }
 
-    if (aDownload.handleInternally) {
-      let win = Services.wm.getMostRecentBrowserWindow();
-      let browsingContext =
-        win && win.BrowsingContext.get(aDownload.source.browsingContextId);
-      win = Services.wm.getOuterWindowWithId(
-        browsingContext &&
-          browsingContext.embedderWindowGlobal &&
-          browsingContext.embedderWindowGlobal.outerWindowId
-      );
-      let fileURI = Services.io.newFileURI(file);
-      if (win) {
-        // TODO: Replace openTrustedLinkIn with openUILink once
-        //       we have access to the event.
-        win.openTrustedLinkIn(fileURI.spec, "tab", {
-          triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
-          userContextId: aDownload.source.userContextId,
-          openerBrowser: browsingContext?.top?.embedderElement,
-        });
-        return;
-      }
-      let features = "chrome,dialog=no,all";
-      if (aDownload.source.isPrivate) {
-        features += ",private";
-      }
-      let args = Cc["@mozilla.org/supports-string;1"].createInstance(
-        Ci.nsISupportsString
-      );
-      args.data = fileURI.spec;
-      win = Services.ww.openWindow(
-        null,
-        AppConstants.BROWSER_CHROME_URL,
-        "_blank",
-        features,
-        args
-      );
+    const PDF_CONTENT_TYPE = "application/pdf";
+    if (
+      aDownload.handleInternally ||
+      (mimeInfo &&
+        mimeInfo.type == PDF_CONTENT_TYPE &&
+        !mimeInfo.alwaysAskBeforeHandling &&
+        mimeInfo.preferredAction === Ci.nsIHandlerInfo.handleInternally &&
+        !aDownload.launchWhenSucceeded)
+    ) {
+      DownloadUIHelper.loadFileIn(file, {
+        browsingContextId: aDownload.source.browsingContextId,
+        isPrivate: aDownload.source.isPrivate,
+        openWhere,
+        userContextId: aDownload.source.userContextId,
+      });
       return;
     }
 
+    // An attempt will now be made to launch the download, clear the
+    // launchWhenSucceeded bit so future attempts to open the download can go
+    // through Firefox when possible.
+    aDownload.launchWhenSucceeded = false;
+
     // No custom application chosen, let's launch the file with the default
     // handler. First, let's try to launch it through the MIME service.
     if (mimeInfo) {
-      const PDF_CONTENT_TYPE = "application/pdf";
-      // Open PDFs internally unless explicitly configured to do otherwise
-      if (
-        mimeInfo.type == PDF_CONTENT_TYPE &&
-        !mimeInfo.alwaysAskBeforeHandling &&
-        mimeInfo.preferredAction === Ci.nsIHandlerInfo.handleInternally
-        // TODO: also preview for save to disk and always ask file actions?
-      ) {
-        DownloadUIHelper.loadFileIn(file, {
-          isPrivate: aDownload.source.isPrivate,
-          openWhere,
-        });
-        return;
-      }
-
       mimeInfo.preferredAction = Ci.nsIMIMEInfo.useSystemDefault;
       try {
         this.launchFile(file, mimeInfo);
         return;
       } catch (ex) {}
     }
 
     // If it didn't work or if there was no MIME info available,
--- a/toolkit/components/downloads/DownloadUIHelper.jsm
+++ b/toolkit/components/downloads/DownloadUIHelper.jsm
@@ -67,20 +67,28 @@ var DownloadUIHelper = {
   /**
    * Open the given file as a file: URI in the active window
    *
    * @param nsIFile file         The downloaded file
    * @param options.chromeWindow Optional chrome window where we could open the file URI
    * @param options.openWhere    String indicating how to open the URI.
    *                             One of "window", "tab", "tabshifted"
    * @param options.isPrivate    Open in private window or not
+   * @param options.browsingContextId BrowsingContext ID of the initiating document
+   * @param options.userContextId UserContextID of the initiating document
    */
   loadFileIn(
     file,
-    { chromeWindow: browserWin, openWhere = "tab", isPrivate } = {}
+    {
+      chromeWindow: browserWin,
+      openWhere = "tab",
+      isPrivate,
+      userContextId = 0,
+      browsingContextId = 0,
+    } = {}
   ) {
     let fileURI = Services.io.newFileURI(file);
     let allowPrivate =
       isPrivate || PrivateBrowsingUtils.permanentPrivateBrowsing;
 
     if (
       !browserWin ||
       browserWin.document.documentElement.getAttribute("windowtype") !==
@@ -112,19 +120,22 @@ var DownloadUIHelper = {
         null,
         features,
         args
       );
       return;
     }
 
     // a browser window will have the helpers from utilityOverlay.js
+    let browsingContext = browserWin?.BrowsingContext.get(browsingContextId);
     browserWin.openTrustedLinkIn(fileURI.spec, openWhere, {
       triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
       private: isPrivate,
+      userContextId,
+      openerBrowser: browsingContext?.top?.embedderElement,
     });
   },
 };
 
 /**
  * Returns an object whose keys are the string names from the downloads string
  * bundle, and whose values are either the translated strings or functions
  * returning formatted strings.
--- a/uriloader/exthandler/tests/mochitest/browser.ini
+++ b/uriloader/exthandler/tests/mochitest/browser.ini
@@ -8,18 +8,20 @@ run-if = e10s # test relies on e10s beha
 support-files =
   download_page.html
   download.bin
   download.sjs
 [browser_download_always_ask_preferred_app.js]
 [browser_download_privatebrowsing.js]
 [browser_download_open_with_internal_handler.js]
 support-files =
-  file_pdfjs_test.pdf
-  file_pdfjs_test.pdf^headers^
+  file_pdf_binary_octet_stream.pdf
+  file_pdf_binary_octet_stream.pdf^headers^
+  file_pdf_application_pdf.pdf
+  file_pdf_application_pdf.pdf^headers^
   file_txt_attachment_test.txt
   file_txt_attachment_test.txt^headers^
 [browser_download_urlescape.js]
 support-files =
   file_with@@funny_name.png
   file_with@@funny_name.png^headers^
   file_with[funny_name.webm
   file_with[funny_name.webm^headers^
--- a/uriloader/exthandler/tests/mochitest/browser_download_open_with_internal_handler.js
+++ b/uriloader/exthandler/tests/mochitest/browser_download_open_with_internal_handler.js
@@ -32,108 +32,215 @@ async function waitForPdfJS(browser, url
     true
   );
   await SpecialPowers.spawn(browser, [url], contentUrl => {
     content.location = contentUrl;
   });
   return loadPromise;
 }
 
+add_task(async function setup() {
+  // Remove the security delay for the dialog during the test.
+  await SpecialPowers.pushPrefEnv({
+    set: [["security.dialog_enable_delay", 0]],
+  });
+});
+
 /**
  * Check that loading a PDF file with content-disposition: attachment
  * shows an option to open with the internal handler, and that the
  * internal option handler is not present when the download button
  * is clicked from pdf.js.
  */
 add_task(async function test_check_open_with_internal_handler() {
-  await SpecialPowers.pushPrefEnv({
-    set: [["browser.helperApps.showOpenOptionForPdfJS", true]],
-  });
-  let publicList = await Downloads.getList(Downloads.PUBLIC);
-  registerCleanupFunction(async () => {
-    await publicList.removeFinished();
-  });
-  let dialogWindowPromise = BrowserTestUtils.domWindowOpenedAndLoaded();
-  let loadingTab = await BrowserTestUtils.openNewForegroundTab(
-    gBrowser,
-    TEST_PATH + "file_pdfjs_test.pdf"
-  );
-  // Add an extra tab after the loading tab so we can test that
-  // pdf.js is opened in the adjacent tab and not at the end of
-  // the tab strip.
-  let extraTab = await BrowserTestUtils.addTab(gBrowser, "about:blank");
-  let dialogWindow = await dialogWindowPromise;
-  is(
-    dialogWindow.location,
-    "chrome://mozapps/content/downloads/unknownContentType.xhtml",
-    "Should have seen the unknown content dialogWindow."
-  );
-  let doc = dialogWindow.document;
-  let internalHandlerRadio = doc.querySelector("#handleInternally");
-
-  await waitForAcceptButtonToGetEnabled(doc);
-
-  ok(!internalHandlerRadio.hidden, "The option should be visible for PDF");
-  ok(internalHandlerRadio.selected, "The option should be selected");
-
-  let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser);
-  let dialog = doc.querySelector("#unknownContentType");
-  let button = dialog.getButton("accept");
-  button.disabled = false;
-  dialog.acceptDialog();
-  info("waiting for new tab to open");
-  let newTab = await newTabPromise;
-
-  is(
-    newTab._tPos - 1,
-    loadingTab._tPos,
-    "pdf.js should be opened in an adjacent tab"
+  const { DownloadIntegration } = ChromeUtils.import(
+    "resource://gre/modules/DownloadIntegration.jsm"
   );
+  for (let file of [
+    "file_pdf_application_pdf.pdf",
+    "file_pdf_binary_octet_stream.pdf",
+  ]) {
+    info("Testing with " + file);
+    await SpecialPowers.pushPrefEnv({
+      set: [["browser.helperApps.showOpenOptionForPdfJS", true]],
+    });
+    let publicList = await Downloads.getList(Downloads.PUBLIC);
+    registerCleanupFunction(async () => {
+      await publicList.removeFinished();
+    });
+    let dialogWindowPromise = BrowserTestUtils.domWindowOpenedAndLoaded();
+    let loadingTab = await BrowserTestUtils.openNewForegroundTab(
+      gBrowser,
+      TEST_PATH + file
+    );
+    // Add an extra tab after the loading tab so we can test that
+    // pdf.js is opened in the adjacent tab and not at the end of
+    // the tab strip.
+    let extraTab = await BrowserTestUtils.addTab(gBrowser, "about:blank");
+    let dialogWindow = await dialogWindowPromise;
+    is(
+      dialogWindow.location,
+      "chrome://mozapps/content/downloads/unknownContentType.xhtml",
+      "Should have seen the unknown content dialogWindow."
+    );
+    let doc = dialogWindow.document;
+    let internalHandlerRadio = doc.querySelector("#handleInternally");
 
-  await ContentTask.spawn(newTab.linkedBrowser, null, async () => {
-    await ContentTaskUtils.waitForCondition(
-      () => content.document.readyState == "complete"
-    );
-  });
+    await waitForAcceptButtonToGetEnabled(doc);
+
+    ok(!internalHandlerRadio.hidden, "The option should be visible for PDF");
+    ok(internalHandlerRadio.selected, "The option should be selected");
 
-  let publicDownloads = await publicList.getAll();
-  Assert.equal(
-    publicDownloads.length,
-    1,
-    "download should appear in publicDownloads list"
-  );
-  let subdialogPromise = BrowserTestUtils.domWindowOpenedAndLoaded();
-  await SpecialPowers.spawn(newTab.linkedBrowser, [], async () => {
-    let downloadButton;
-    await ContentTaskUtils.waitForCondition(() => {
-      downloadButton = content.document.querySelector("#download");
-      return !!downloadButton;
+    let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser);
+    let dialog = doc.querySelector("#unknownContentType");
+    let button = dialog.getButton("accept");
+    button.disabled = false;
+    dialog.acceptDialog();
+    info("waiting for new tab to open");
+    let newTab = await newTabPromise;
+
+    is(
+      newTab._tPos - 1,
+      loadingTab._tPos,
+      "pdf.js should be opened in an adjacent tab"
+    );
+
+    await ContentTask.spawn(newTab.linkedBrowser, null, async () => {
+      await ContentTaskUtils.waitForCondition(
+        () => content.document.readyState == "complete"
+      );
+    });
+
+    let publicDownloads = await publicList.getAll();
+    is(
+      publicDownloads.length,
+      1,
+      "download should appear in publicDownloads list"
+    );
+    let subdialogPromise = BrowserTestUtils.domWindowOpenedAndLoaded();
+    await SpecialPowers.spawn(newTab.linkedBrowser, [], async () => {
+      let downloadButton;
+      await ContentTaskUtils.waitForCondition(() => {
+        downloadButton = content.document.querySelector("#download");
+        return !!downloadButton;
+      });
+      ok(downloadButton, "Download button should be present in pdf.js");
+      downloadButton.click();
     });
-    ok(downloadButton, "Download button should be present in pdf.js");
-    downloadButton.click();
-  });
-  info(
-    "Waiting for unknown content type dialog to appear from pdf.js download button click"
+    info(
+      "Waiting for unknown content type dialog to appear from pdf.js download button click"
+    );
+    let subDialogWindow = await subdialogPromise;
+    let subDoc = subDialogWindow.document;
+    // 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);
+    let 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 'Save' chosen"
+      );
+    };
+    gBrowser.tabContainer.addEventListener("TabOpen", tabOpenListener);
+
+    let oldLaunchFile = DownloadIntegration.launchFile;
+    let waitForLaunchFileCalled = new Promise(resolve => {
+      DownloadIntegration.launchFile = async () => {
+        ok(true, "The file should be launched with an external application");
+        resolve();
+      };
+    });
+
+    info("Accepting the dialog");
+    subDoc.querySelector("#unknownContentType").acceptDialog();
+    info("Waiting until DownloadIntegration.launchFile is called");
+    await waitForLaunchFileCalled;
+    DownloadIntegration.launchFile = oldLaunchFile;
+
+    gBrowser.tabContainer.removeEventListener("TabOpen", tabOpenListener);
+    BrowserTestUtils.removeTab(loadingTab);
+    BrowserTestUtils.removeTab(newTab);
+    BrowserTestUtils.removeTab(extraTab);
+    await publicList.removeFinished();
+  }
+});
+
+/**
+ * Test that choosing to open in an external application doesn't
+ * open the PDF into pdf.js
+ */
+add_task(async function test_check_open_with_external_application() {
+  const { DownloadIntegration } = ChromeUtils.import(
+    "resource://gre/modules/DownloadIntegration.jsm"
   );
-  let subDialogWindow = await subdialogPromise;
-  let subDoc = subDialogWindow.document;
-  // 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);
-  let subInternalHandlerRadio = subDoc.querySelector("#handleInternally");
-  ok(
-    subInternalHandlerRadio.hidden,
-    "The option should be hidden when the dialog is opened from pdf.js"
-  );
+  for (let file of [
+    "file_pdf_application_pdf.pdf",
+    "file_pdf_binary_octet_stream.pdf",
+  ]) {
+    info("Testing with " + file);
+    await SpecialPowers.pushPrefEnv({
+      set: [["browser.helperApps.showOpenOptionForPdfJS", true]],
+    });
+    let publicList = await Downloads.getList(Downloads.PUBLIC);
+    registerCleanupFunction(async () => {
+      await publicList.removeFinished();
+    });
+    let dialogWindowPromise = BrowserTestUtils.domWindowOpenedAndLoaded();
+    let loadingTab = await BrowserTestUtils.openNewForegroundTab(
+      gBrowser,
+      TEST_PATH + file
+    );
+    let dialogWindow = await dialogWindowPromise;
+    is(
+      dialogWindow.location,
+      "chrome://mozapps/content/downloads/unknownContentType.xhtml",
+      "Should have seen the unknown content dialogWindow."
+    );
 
-  subDoc.querySelector("#unknownContentType").cancelDialog();
+    let oldLaunchFile = DownloadIntegration.launchFile;
+    let waitForLaunchFileCalled = new Promise(resolve => {
+      DownloadIntegration.launchFile = () => {
+        ok(true, "The file should be launched with an external application");
+        resolve();
+      };
+    });
 
-  BrowserTestUtils.removeTab(loadingTab);
-  BrowserTestUtils.removeTab(newTab);
-  BrowserTestUtils.removeTab(extraTab);
+    let doc = dialogWindow.document;
+    await waitForAcceptButtonToGetEnabled(doc);
+    let dialog = doc.querySelector("#unknownContentType");
+    doc.querySelector("#open").click();
+    let button = dialog.getButton("accept");
+    button.disabled = false;
+    info("Accepting the dialog");
+    dialog.acceptDialog();
+    info("Waiting until DownloadIntegration.launchFile is called");
+    await waitForLaunchFileCalled;
+    DownloadIntegration.launchFile = oldLaunchFile;
+
+    let publicDownloads = await publicList.getAll();
+    is(
+      publicDownloads.length,
+      1,
+      "download should appear in publicDownloads list"
+    );
+    ok(
+      !publicDownloads[0].launchWhenSucceeded,
+      "launchWhenSucceeded should be false after launchFile is called"
+    );
+
+    BrowserTestUtils.removeTab(loadingTab);
+    await publicList.removeFinished();
+  }
 });
 
 /**
  * Check that the "Open with internal handler" option is not presented
  * for non-PDF types.
  */
 add_task(async function test_internal_handler_hidden_with_nonpdf_type() {
   let dialogWindowPromise = BrowserTestUtils.domWindowOpenedAndLoaded();
@@ -164,37 +271,42 @@ add_task(async function test_internal_ha
   BrowserTestUtils.removeTab(loadingTab);
 });
 
 /**
  * Check that the "Open with internal handler" option is not presented
  * when the feature is disabled.
  */
 add_task(async function test_internal_handler_hidden_with_pref_disabled() {
-  await SpecialPowers.pushPrefEnv({
-    set: [["browser.helperApps.showOpenOptionForPdfJS", false]],
-  });
+  for (let file of [
+    "file_pdf_application_pdf.pdf",
+    "file_pdf_binary_octet_stream.pdf",
+  ]) {
+    await SpecialPowers.pushPrefEnv({
+      set: [["browser.helperApps.showOpenOptionForPdfJS", false]],
+    });
 
-  let dialogWindowPromise = BrowserTestUtils.domWindowOpenedAndLoaded();
-  let loadingTab = await BrowserTestUtils.openNewForegroundTab(
-    gBrowser,
-    TEST_PATH + "file_pdfjs_test.pdf"
-  );
-  let dialogWindow = await dialogWindowPromise;
-  is(
-    dialogWindow.location,
-    "chrome://mozapps/content/downloads/unknownContentType.xhtml",
-    "Should have seen the unknown content dialogWindow."
-  );
-  let doc = dialogWindow.document;
+    let dialogWindowPromise = BrowserTestUtils.domWindowOpenedAndLoaded();
+    let loadingTab = await BrowserTestUtils.openNewForegroundTab(
+      gBrowser,
+      TEST_PATH + file
+    );
+    let dialogWindow = await dialogWindowPromise;
+    is(
+      dialogWindow.location,
+      "chrome://mozapps/content/downloads/unknownContentType.xhtml",
+      "Should have seen the unknown content dialogWindow."
+    );
+    let doc = dialogWindow.document;
 
-  await waitForAcceptButtonToGetEnabled(doc);
+    await waitForAcceptButtonToGetEnabled(doc);
 
-  let internalHandlerRadio = doc.querySelector("#handleInternally");
-  ok(
-    internalHandlerRadio.hidden,
-    "The option should be hidden for PDF when the pref is false"
-  );
+    let internalHandlerRadio = doc.querySelector("#handleInternally");
+    ok(
+      internalHandlerRadio.hidden,
+      "The option should be hidden for PDF when the pref is false"
+    );
 
-  let dialog = doc.querySelector("#unknownContentType");
-  dialog.cancelDialog();
-  BrowserTestUtils.removeTab(loadingTab);
+    let dialog = doc.querySelector("#unknownContentType");
+    dialog.cancelDialog();
+    BrowserTestUtils.removeTab(loadingTab);
+  }
 });
rename from uriloader/exthandler/tests/mochitest/file_pdfjs_test.pdf
rename to uriloader/exthandler/tests/mochitest/file_pdf_application_pdf.pdf
index 7ad87e3c2e328e5e25902f1e83fbe9d7d10695b7..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
rename from uriloader/exthandler/tests/mochitest/file_pdfjs_test.pdf^headers^
rename to uriloader/exthandler/tests/mochitest/file_pdf_application_pdf.pdf^headers^
--- a/uriloader/exthandler/tests/mochitest/file_pdfjs_test.pdf^headers^
+++ b/uriloader/exthandler/tests/mochitest/file_pdf_application_pdf.pdf^headers^
@@ -1,2 +1,2 @@
-Content-Disposition: attachment; filename=file_pdfjs_test.pdf
-Content-Type: application/pdf
+content-disposition: attachment; filename=file_pdf_application_pdf.pdf; filename*=UTF-8''file_pdf_application_pdf.pdf
+content-type: application/pdf
copy from uriloader/exthandler/tests/mochitest/file_pdfjs_test.pdf
copy to uriloader/exthandler/tests/mochitest/file_pdf_binary_octet_stream.pdf
index 7ad87e3c2e328e5e25902f1e83fbe9d7d10695b7..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
copy from uriloader/exthandler/tests/mochitest/file_pdfjs_test.pdf^headers^
copy to uriloader/exthandler/tests/mochitest/file_pdf_binary_octet_stream.pdf^headers^
--- a/uriloader/exthandler/tests/mochitest/file_pdfjs_test.pdf^headers^
+++ b/uriloader/exthandler/tests/mochitest/file_pdf_binary_octet_stream.pdf^headers^
@@ -1,2 +1,2 @@
-Content-Disposition: attachment; filename=file_pdfjs_test.pdf
-Content-Type: application/pdf
+Content-Disposition: attachment; filename="file_pdf_binary_octet_stream.pdf"; filename*=UTF-8''file_pdf_binary_octet_stream.pdf
+Content-Type: binary/octet-stream