Bug 794602 - Make nsWebBrowserPersist::SaveURIInternal use channels with valid privacy statuses. r=bz,mfinkle,smaug,ehsan,jwalker,roc,unfocused
authorJosh Matthews <josh@joshmatthews.net>
Thu, 04 Oct 2012 15:07:51 -0400
changeset 109307 ff5e9f36d02e62e5eccbd06b6b832def81e5f2ac
parent 109306 7f40ba56870b9aacc2c9df0c9b4071ab0c47bbcc
child 109308 0e4560cb5a35fa22948ba26474a603a5a438ae58
push id23619
push useremorley@mozilla.com
push dateFri, 05 Oct 2012 10:54:02 +0000
treeherdermozilla-central@3b458f4e0f42 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, mfinkle, smaug, ehsan, jwalker, roc, unfocused
bugs794602
milestone18.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 794602 - Make nsWebBrowserPersist::SaveURIInternal use channels with valid privacy statuses. r=bz,mfinkle,smaug,ehsan,jwalker,roc,unfocused
browser/app/profile/extensions/testpilot@labs.mozilla.com/content/experiment-page.js
browser/base/content/test/Makefile.in
browser/base/content/test/browser_save_private_link.js
browser/base/content/test/bug792517.html
browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadmonitor.js
browser/components/shell/src/nsMacShellService.cpp
browser/devtools/commandline/CmdScreenshot.jsm
content/base/src/nsContentAreaDragDrop.cpp
content/base/src/nsContentAreaDragDrop.h
embedding/browser/webBrowser/nsWebBrowser.cpp
embedding/components/webbrowserpersist/public/nsIWebBrowserPersist.idl
embedding/components/webbrowserpersist/src/nsWebBrowserPersist.cpp
embedding/components/webbrowserpersist/src/nsWebBrowserPersist.h
mobile/android/chrome/content/browser.js
mobile/android/components/SessionStore.js
toolkit/components/downloads/nsDownloadManager.cpp
toolkit/components/downloads/test/unit/head_download_manager.js
toolkit/components/downloads/test/unit/test_bug_420230.js
toolkit/components/downloads/test/unit/test_offline_support.js
toolkit/components/downloads/test/unit/test_resume.js
toolkit/components/downloads/test/unit/test_sleep_wake.js
toolkit/content/contentAreaUtils.js
toolkit/mozapps/downloads/tests/chrome/test_space_key_pauses_resumes.xul
toolkit/mozapps/downloads/tests/chrome/utils.js
toolkit/mozapps/extensions/LightweightThemeManager.jsm
widget/os2/nsDragService.cpp
--- a/browser/app/profile/extensions/testpilot@labs.mozilla.com/content/experiment-page.js
+++ b/browser/app/profile/extensions/testpilot@labs.mozilla.com/content/experiment-page.js
@@ -100,17 +100,17 @@ var stringBundle;
 
         // displays a download dialog (remove these 3 lines for silent download)
         let xfer = Components.classes["@mozilla.org/transfer;1"].
                    createInstance(Components.interfaces.nsITransfer);
         xfer.init(source, target, "", null, null, null, persist, false);
         persist.progressListener = xfer;
 
         // save the canvas data to the file
-        persist.saveURI(source, null, null, null, null, file);
+        persist.saveURI(source, null, null, null, null, file, null);
       }
     };
 
     fp.init(window, null, nsIFilePicker.modeSave);
     fp.appendFilters(nsIFilePicker.filterImages | nsIFilePicker.filterAll);
     fp.defaultString = "canvas.png";
     fp.open(fpCallback);
   }
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -189,16 +189,18 @@ endif
                  browser_clearplugindata_noage.html \
                  browser_popupUI.js \
                  browser_sanitizeDialog.js \
                  browser_save_video.js \
                  bug564387.html \
                  bug564387_video1.ogv \
                  bug564387_video1.ogv^headers^ \
                  browser_save_link.js \
+                 browser_save_private_link.js \
+                 bug792517.html \
                  bug792517-2.html \
                  bug792517.sjs \
                  browser_scope.js \
                  browser_selectTabAtIndex.js \
                  browser_tab_dragdrop.js \
                  browser_tab_dragdrop2.js \
                  browser_tab_dragdrop2_frame1.xul \
                  browser_tabfocus.js \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_save_private_link.js
@@ -0,0 +1,116 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+var MockFilePicker = SpecialPowers.MockFilePicker;
+MockFilePicker.init();
+
+function checkDiskCacheFor(filename) {
+  let visitor = {
+    visitDevice: function(deviceID, deviceInfo) {
+      if (deviceID == "disk")
+        info(deviceID + " device contains " + deviceInfo.entryCount + " entries");
+      return deviceID == "disk";
+    },
+    
+    visitEntry: function(deviceID, entryInfo) {
+      info(entryInfo.key);
+      is(entryInfo.key.contains(filename), false, "web content present in disk cache");
+    }
+  };
+  cache.visitEntries(visitor);
+}
+
+var cache = Cc["@mozilla.org/network/cache-service;1"]
+              .getService(Ci.nsICacheService);
+
+function test() {
+  waitForExplicitFinish();
+  var fileName;
+
+  gPrefService.setBoolPref("browser.privatebrowsing.keep_current_session", true);
+  let pb = Cc["@mozilla.org/privatebrowsing;1"].
+           getService(Ci.nsIPrivateBrowsingService);
+  pb.privateBrowsingEnabled = true;
+
+  gBrowser.loadURI("http://mochi.test:8888/browser/browser/base/content/test/bug792517.html");
+
+  registerCleanupFunction(function () {
+    pb.privateBrowsingEnabled = false;
+    gPrefService.clearUserPref("browser.privatebrowsing.keep_current_session");
+    gBrowser.addTab();
+    gBrowser.removeCurrentTab();
+  });
+
+  gBrowser.addEventListener("pageshow", function pageShown(event) {
+    if (event.target.location == "about:blank")
+      return;
+    gBrowser.removeEventListener("pageshow", pageShown);
+
+    executeSoon(function () {
+      document.addEventListener("popupshown", contextMenuOpened);
+
+      var img = gBrowser.contentDocument.getElementById("img");
+      EventUtils.synthesizeMouseAtCenter(img,
+                                         { type: "contextmenu", button: 2 },
+                                         gBrowser.contentWindow);
+    });
+  });
+
+  function contextMenuOpened(event) {
+    cache.evictEntries(Ci.nsICache.STORE_ANYWHERE);
+
+    event.currentTarget.removeEventListener("popupshown", contextMenuOpened);
+
+    // Create the folder the image will be saved into.
+    var destDir = createTemporarySaveDirectory();
+    var destFile = destDir.clone();
+
+    MockFilePicker.displayDirectory = destDir;
+    MockFilePicker.showCallback = function(fp) {
+      fileName = fp.defaultString;
+      destFile.append (fileName);
+      MockFilePicker.returnFiles = [destFile];
+      MockFilePicker.filterIndex = 1; // kSaveAsType_URL
+    };
+
+    mockTransferCallback = onTransferComplete;
+    mockTransferRegisterer.register();
+
+    registerCleanupFunction(function () {
+      mockTransferRegisterer.unregister();
+      MockFilePicker.cleanup();
+      destDir.remove(true);
+    });
+
+    // Select "Save Image As" option from context menu
+    var saveVideoCommand = document.getElementById("context-saveimage");
+    saveVideoCommand.doCommand();
+
+    event.target.hidePopup();
+  }
+
+  function onTransferComplete(downloadSuccess) {
+    ok(downloadSuccess, "Image file should have been downloaded successfully");
+
+    // Give the request a chance to finish and create a cache entry
+    executeSoon(function() {
+      checkDiskCacheFor(fileName);
+      finish();
+    });
+  }
+}
+
+Cc["@mozilla.org/moz/jssubscript-loader;1"]
+  .getService(Ci.mozIJSSubScriptLoader)
+  .loadSubScript("chrome://mochitests/content/browser/toolkit/content/tests/browser/common/mockTransfer.js",
+                 this);
+
+function createTemporarySaveDirectory() {
+  var saveDir = Cc["@mozilla.org/file/directory_service;1"]
+                  .getService(Ci.nsIProperties)
+                  .get("TmpD", Ci.nsIFile);
+  saveDir.append("testsavedir");
+  if (!saveDir.exists())
+    saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
+  return saveDir;
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/bug792517.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+<img src="moz.png" id="img">
+</body>
+</html>
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadmonitor.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadmonitor.js
@@ -133,19 +133,20 @@ function addDownload(dm, aParams)
                           createURI(aParams.targetFile), aParams.downloadName, null,
                           Math.round(Date.now() * 1000), null, persist, aParams.isPrivate);
 
   // This will throw if it isn't found, and that would mean test failure, so no
   // try catch block
   let test = dm.getDownload(dl.id);
 
   aParams.runBeforeStart.call(undefined, dl);
-
+  
   persist.progressListener = dl.QueryInterface(Ci.nsIWebProgressListener);
-  persist.saveURI(dl.source, null, null, null, null, dl.targetFile);
+  persist.savePrivacyAwareURI(dl.source, null, null, null, null, dl.targetFile,
+                              aParams.isPrivate);
 
   return [dl.targetFile, persist];
 }
 
 function createURI(aObj) {
   let ios = Services.io;
   return (aObj instanceof Ci.nsIFile) ? ios.newFileURI(aObj) :
                                         ios.newURI(aObj, null, null);
--- a/browser/components/shell/src/nsMacShellService.cpp
+++ b/browser/components/shell/src/nsMacShellService.cpp
@@ -188,17 +188,17 @@ nsMacShellService::SetDesktopBackground(
   uint32_t flags = nsIWebBrowserPersist::PERSIST_FLAGS_NO_CONVERSION | 
                    nsIWebBrowserPersist::PERSIST_FLAGS_REPLACE_EXISTING_FILES |
                    nsIWebBrowserPersist::PERSIST_FLAGS_FROM_CACHE;
 
   wbp->SetPersistFlags(flags);
   wbp->SetProgressListener(this);
 
   return wbp->SaveURI(imageURI, nullptr, docURI, nullptr, nullptr,
-                      mBackgroundFile);
+                      mBackgroundFile, content->OwnerDoc()->GetLoadContext());
 }
 
 NS_IMETHODIMP
 nsMacShellService::OnProgressChange(nsIWebProgress* aWebProgress,
                                     nsIRequest* aRequest,
                                     int32_t aCurSelfProgress,
                                     int32_t aMaxSelfProgress,
                                     int32_t aCurTotalProgress,
--- a/browser/devtools/commandline/CmdScreenshot.jsm
+++ b/browser/devtools/commandline/CmdScreenshot.jsm
@@ -123,16 +123,21 @@ gcli.addCommand({
     }
     canvas.width = width;
     canvas.height = height;
 
     let ctx = canvas.getContext("2d");
     ctx.drawWindow(window, left, top, width, height, "#fff");
     let data = canvas.toDataURL("image/png", "");
 
+    let loadContext = document.defaultView
+                              .QueryInterface(Ci.nsIInterfaceRequestor)
+                              .getInterface(Ci.nsIWebNavigation)
+                              .QueryInterface(Ci.nsILoadContext);
+
     try {
       if (clipboard) {
         let io = Cc["@mozilla.org/network/io-service;1"]
                    .getService(Ci.nsIIOService);
         let channel = io.newChannel(data, null, null);
         let input = channel.open();
         let imgTools = Cc["@mozilla.org/image/tools;1"]
                          .getService(Ci.imgITools);
@@ -141,20 +146,16 @@ gcli.addCommand({
         imgTools.decodeImageData(input, channel.contentType, container);
 
         let wrapped = Cc["@mozilla.org/supports-interface-pointer;1"]
                         .createInstance(Ci.nsISupportsInterfacePointer);
         wrapped.data = container.value;
 
         let trans = Cc["@mozilla.org/widget/transferable;1"]
                       .createInstance(Ci.nsITransferable);
-        let loadContext = document.defaultView
-                                  .QueryInterface(Ci.nsIInterfaceRequestor)
-                                  .getInterface(Ci.nsIWebNavigation)
-                                  .QueryInterface(Ci.nsILoadContext);
         trans.init(loadContext);
         trans.addDataFlavor(channel.contentType);
         trans.setTransferData(channel.contentType, wrapped, -1);
 
         let clipid = Ci.nsIClipboard;
         let clip = Cc["@mozilla.org/widget/clipboard;1"].getService(clipid);
         clip.setData(trans, null, clipid.kGlobalClipboard);
         div.textContent = gcli.lookup("screenshotCopied");
@@ -209,17 +210,17 @@ gcli.addCommand({
 
     let Persist = Ci.nsIWebBrowserPersist;
     let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
                     .createInstance(Persist);
     persist.persistFlags = Persist.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
                            Persist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
 
     let source = ioService.newURI(data, "UTF8", null);
-    persist.saveURI(source, null, null, null, null, file);
+    persist.saveURI(source, null, null, null, null, file, loadContext);
 
     div.textContent = gcli.lookup("screenshotSavedToFile") + " \"" + filename +
                       "\"";
     div.addEventListener("click", function openFile() {
       div.removeEventListener("click", openFile);
       file.reveal();
     });
     div.style.cursor = "pointer";
--- a/content/base/src/nsContentAreaDragDrop.cpp
+++ b/content/base/src/nsContentAreaDragDrop.cpp
@@ -125,17 +125,18 @@ nsContentAreaDragDrop::GetDragData(nsPID
 
 NS_IMPL_ISUPPORTS1(nsContentAreaDragDropDataProvider, nsIFlavorDataProvider)
 
 // SaveURIToFile
 // used on platforms where it's possible to drag items (e.g. images)
 // into the file system
 nsresult
 nsContentAreaDragDropDataProvider::SaveURIToFile(nsAString& inSourceURIString,
-                                                 nsIFile* inDestFile)
+                                                 nsIFile* inDestFile,
+                                                 bool isPrivate)
 {
   nsCOMPtr<nsIURI> sourceURI;
   nsresult rv = NS_NewURI(getter_AddRefs(sourceURI), inSourceURIString);
   if (NS_FAILED(rv)) {
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIURL> sourceURL = do_QueryInterface(sourceURI);
@@ -150,17 +151,18 @@ nsContentAreaDragDropDataProvider::SaveU
   // so we don't keep a ref to it. It will die when finished.
   nsCOMPtr<nsIWebBrowserPersist> persist =
     do_CreateInstance("@mozilla.org/embedding/browser/nsWebBrowserPersist;1",
                       &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   persist->SetPersistFlags(nsIWebBrowserPersist::PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION);
 
-  return persist->SaveURI(sourceURI, nullptr, nullptr, nullptr, nullptr, inDestFile);
+  return persist->SavePrivacyAwareURI(sourceURI, nullptr, nullptr, nullptr, nullptr,
+                                      inDestFile, isPrivate);
 }
 
 // This is our nsIFlavorDataProvider callback. There are several
 // assumptions here that make this work:
 //
 // 1. Someone put a kFilePromiseURLMime flavor into the transferable
 //    with the source URI of the file to save (as a string). We did
 //    that in AddStringsToDataTransfer.
@@ -222,17 +224,20 @@ nsContentAreaDragDropDataProvider::GetFl
       return NS_ERROR_FAILURE;
 
     nsCOMPtr<nsIFile> file;
     rv = destDirectory->Clone(getter_AddRefs(file));
     NS_ENSURE_SUCCESS(rv, rv);
 
     file->Append(targetFilename);
 
-    rv = SaveURIToFile(sourceURLString, file);
+    bool isPrivate;
+    aTransferable->GetIsPrivateData(&isPrivate);
+
+    rv = SaveURIToFile(sourceURLString, file, isPrivate);
     // send back an nsIFile
     if (NS_SUCCEEDED(rv)) {
       CallQueryInterface(file, aData);
       *aDataLen = sizeof(nsIFile*);
     }
   }
 
   return rv;
--- a/content/base/src/nsContentAreaDragDrop.h
+++ b/content/base/src/nsContentAreaDragDrop.h
@@ -66,14 +66,14 @@ class nsContentAreaDragDropDataProvider 
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIFLAVORDATAPROVIDER
 
   virtual ~nsContentAreaDragDropDataProvider() {}
 
   nsresult SaveURIToFile(nsAString& inSourceURIString,
-                         nsIFile* inDestFile);
+                         nsIFile* inDestFile, bool isPrivate);
 };
 
 
 #endif /* nsContentAreaDragDrop_h__ */
 
--- a/embedding/browser/webBrowser/nsWebBrowser.cpp
+++ b/embedding/browser/webBrowser/nsWebBrowser.cpp
@@ -911,20 +911,28 @@ NS_IMETHODIMP nsWebBrowser::GetProgressL
 NS_IMETHODIMP nsWebBrowser::SetProgressListener(nsIWebProgressListener * aProgressListener)
 {
     mProgressListener = aProgressListener;
     return NS_OK;
 }
 
 /* void saveURI (in nsIURI aURI, in nsIURI aReferrer,
    in nsISupports aCacheKey, in nsIInputStream aPostData, in wstring aExtraHeaders,
-   in nsISupports aFile); */
+   in nsISupports aFile, in nsILoadContext aPrivacyContext); */
 NS_IMETHODIMP nsWebBrowser::SaveURI(
     nsIURI *aURI, nsISupports *aCacheKey, nsIURI *aReferrer, nsIInputStream *aPostData,
-    const char *aExtraHeaders, nsISupports *aFile)
+    const char *aExtraHeaders, nsISupports *aFile, nsILoadContext* aPrivacyContext)
+{
+    return SavePrivacyAwareURI(aURI, aCacheKey, aReferrer, aPostData, aExtraHeaders,
+                               aFile, aPrivacyContext && aPrivacyContext->UsePrivateBrowsing());
+}
+
+NS_IMETHODIMP nsWebBrowser::SavePrivacyAwareURI(
+    nsIURI *aURI, nsISupports *aCacheKey, nsIURI *aReferrer, nsIInputStream *aPostData,
+    const char *aExtraHeaders, nsISupports *aFile, bool aIsPrivate)
 {
     if (mPersist)
     {
         uint32_t currentState;
         mPersist->GetCurrentState(&currentState);
         if (currentState == PERSIST_STATE_FINISHED)
         {
             mPersist = nullptr;
@@ -952,17 +960,18 @@ NS_IMETHODIMP nsWebBrowser::SaveURI(
 
     // Create a throwaway persistence object to do the work
     nsresult rv;
     mPersist = do_CreateInstance(NS_WEBBROWSERPERSIST_CONTRACTID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
     mPersist->SetProgressListener(this);
     mPersist->SetPersistFlags(mPersistFlags);
     mPersist->GetCurrentState(&mPersistCurrentState);
-    rv = mPersist->SaveURI(uri, aCacheKey, aReferrer, aPostData, aExtraHeaders, aFile);
+    rv = mPersist->SavePrivacyAwareURI(uri, aCacheKey, aReferrer, aPostData,
+                                       aExtraHeaders, aFile, aIsPrivate);
     if (NS_FAILED(rv))
     {
         mPersist = nullptr;
     }
     return rv;
 }
 
 /* void saveChannel (in nsIChannel aChannel, in nsISupports aFile); */
--- a/embedding/components/webbrowserpersist/public/nsIWebBrowserPersist.idl
+++ b/embedding/components/webbrowserpersist/public/nsIWebBrowserPersist.idl
@@ -7,21 +7,22 @@
 #include "nsICancelable.idl"
 
 interface nsIURI;
 interface nsIInputStream;
 interface nsIDOMDocument;
 interface nsIWebProgressListener;
 interface nsIFile;
 interface nsIChannel;
+interface nsILoadContext;
 
 /**
  * Interface for persisting DOM documents and URIs to local or remote storage.
  */
-[scriptable, uuid(dd4e0a6a-210f-419a-ad85-40e8543b9465)]
+[scriptable, uuid(35c1f231-582b-4315-a26c-a1227e3539b4)]
 interface nsIWebBrowserPersist : nsICancelable
 {
   /** No special persistence behaviour. */
   const unsigned long PERSIST_FLAGS_NONE = 0;
   /** Use cached data if present (skipping validation), else load from network */
   const unsigned long PERSIST_FLAGS_FROM_CACHE = 1;
   /** Bypass the cached data. */
   const unsigned long PERSIST_FLAGS_BYPASS_CACHE = 2;
@@ -125,27 +126,44 @@ interface nsIWebBrowserPersist : nsICanc
    *                   <CODE>nullptr</CODE>.
    * @param aPostData  Post data to pass with an HTTP request or
    *                   <CODE>nullptr</CODE>.
    * @param aExtraHeaders Additional headers to supply with an HTTP request
    *                   or <CODE>nullptr</CODE>.
    * @param aFile      Target file. This may be a nsIFile object or an
    *                   nsIURI object with a file scheme or a scheme that
    *                   supports uploading (e.g. ftp).
+   * @param aPrivacyContext A context from which the privacy status of this
+   *                   save operation can be determined. Must only be null
+   *                   in situations in which no such context is available
+   *                   (eg. the operation has no logical association with any
+   *                   window or document)
    *
    * @see nsIFile
    * @see nsIURI
    * @see nsIInputStream
    *
    * @return NS_OK Operation has been started.
    * @return NS_ERROR_INVALID_ARG One or more arguments was invalid.
    */
   void saveURI(in nsIURI aURI, in nsISupports aCacheKey,
       in nsIURI aReferrer, in nsIInputStream aPostData,
-      in string aExtraHeaders, in nsISupports aFile);
+      in string aExtraHeaders, in nsISupports aFile,
+      in nsILoadContext aPrivacyContext);
+
+  /**
+   * @param aIsPrivate Treat the save operation as private (ie. with
+   *                   regards to networking operations and persistence
+   *                   of intermediate data, etc.)
+   * @see saveURI for all other parameter descriptions
+   */
+  void savePrivacyAwareURI(in nsIURI aURI, in nsISupports aCacheKey,
+      in nsIURI aReferrer, in nsIInputStream aPostData,
+      in string aExtraHeaders, in nsISupports aFile,
+      in boolean aIsPrivate);
 
   /**
    * Save a channel to a file. It must not be opened yet.
    * @see saveURI
    */
   void saveChannel(in nsIChannel aChannel, in nsISupports aFile);
 
   /** Output only the current selection as opposed to the whole document. */
--- a/embedding/components/webbrowserpersist/src/nsWebBrowserPersist.cpp
+++ b/embedding/components/webbrowserpersist/src/nsWebBrowserPersist.cpp
@@ -192,16 +192,17 @@ nsWebBrowserPersist::nsWebBrowserPersist
     mCurrentThingsToPersist(0),
     mFirstAndOnlyUse(true),
     mCancel(false),
     mJustStartedLoading(true),
     mCompleted(false),
     mStartSaving(false),
     mReplaceExisting(true),
     mSerializingOutput(false),
+    mIsPrivate(false),
     mPersistFlags(kDefaultPersistFlags),
     mPersistResult(NS_OK),
     mTotalCurrentProgress(0),
     mTotalMaxProgress(0),
     mWrapColumn(72),
     mEncodingFlags(0)
 {
 }
@@ -326,31 +327,38 @@ NS_IMETHODIMP nsWebBrowserPersist::SetPr
     mProgressListener = aProgressListener;
     mProgressListener2 = do_QueryInterface(aProgressListener);
     mEventSink = do_GetInterface(aProgressListener);
     return NS_OK;
 }
 
 /* void saveURI (in nsIURI aURI, in nsISupports aCacheKey, in nsIURI aReferrer,
    in nsIInputStream aPostData, in wstring aExtraHeaders,
-   in nsISupports aFile); */
+   in nsISupports aFile, in nsILoadContext aPrivayContext); */
 NS_IMETHODIMP nsWebBrowserPersist::SaveURI(
-    nsIURI *aURI, nsISupports *aCacheKey, nsIURI *aReferrer, nsIInputStream *aPostData, const char *aExtraHeaders, nsISupports *aFile)
+    nsIURI *aURI, nsISupports *aCacheKey, nsIURI *aReferrer, nsIInputStream *aPostData, const char *aExtraHeaders, nsISupports *aFile, nsILoadContext* aPrivacyContext)
+{
+    return SavePrivacyAwareURI(aURI, aCacheKey, aReferrer, aPostData, aExtraHeaders, aFile,
+                               aPrivacyContext && aPrivacyContext->UsePrivateBrowsing());
+}
+
+NS_IMETHODIMP nsWebBrowserPersist::SavePrivacyAwareURI(
+    nsIURI *aURI, nsISupports *aCacheKey, nsIURI *aReferrer, nsIInputStream *aPostData, const char *aExtraHeaders, nsISupports *aFile, bool aIsPrivate)
 {
     NS_ENSURE_TRUE(mFirstAndOnlyUse, NS_ERROR_FAILURE);
     mFirstAndOnlyUse = false; // Stop people from reusing this object!
 
     nsCOMPtr<nsIURI> fileAsURI;
     nsresult rv;
     rv = GetValidURIFromObject(aFile, getter_AddRefs(fileAsURI));
     NS_ENSURE_SUCCESS(rv, NS_ERROR_INVALID_ARG);
 
     // SaveURI doesn't like broken uris.
     mPersistFlags |= PERSIST_FLAGS_FAIL_ON_BROKEN_LINKS;
-    rv = SaveURIInternal(aURI, aCacheKey, aReferrer, aPostData, aExtraHeaders, fileAsURI, false);
+    rv = SaveURIInternal(aURI, aCacheKey, aReferrer, aPostData, aExtraHeaders, fileAsURI, false, aIsPrivate);
     return NS_FAILED(rv) ? rv : NS_OK;
 }
 
 /* void saveChannel (in nsIChannel aChannel, in nsISupports aFile); */
 NS_IMETHODIMP nsWebBrowserPersist::SaveChannel(
     nsIChannel *aChannel, nsISupports *aFile)
 {
     NS_ENSURE_TRUE(mFirstAndOnlyUse, NS_ERROR_FAILURE);
@@ -380,16 +388,20 @@ NS_IMETHODIMP nsWebBrowserPersist::SaveD
 {
     NS_ENSURE_TRUE(mFirstAndOnlyUse, NS_ERROR_FAILURE);
     mFirstAndOnlyUse = false; // Stop people from reusing this object!
 
     nsCOMPtr<nsIURI> fileAsURI;
     nsCOMPtr<nsIURI> datapathAsURI;
     nsresult rv;
 
+    nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDocument);
+    nsCOMPtr<nsILoadContext> privacyContext = doc ? doc->GetLoadContext() : nullptr;
+    mIsPrivate = privacyContext && privacyContext->UsePrivateBrowsing();
+
     rv = GetValidURIFromObject(aFile, getter_AddRefs(fileAsURI));
     NS_ENSURE_SUCCESS(rv, NS_ERROR_INVALID_ARG);
     if (aDataPath)
     {
         rv = GetValidURIFromObject(aDataPath, getter_AddRefs(datapathAsURI));
         NS_ENSURE_SUCCESS(rv, NS_ERROR_INVALID_ARG);
     }
 
@@ -1160,17 +1172,17 @@ nsresult nsWebBrowserPersist::AppendPath
     aURI->SetPath(newPath);
 
     return NS_OK;
 }
 
 nsresult nsWebBrowserPersist::SaveURIInternal(
     nsIURI *aURI, nsISupports *aCacheKey, nsIURI *aReferrer,
     nsIInputStream *aPostData, const char *aExtraHeaders,
-    nsIURI *aFile, bool aCalcFileExt)
+    nsIURI *aFile, bool aCalcFileExt, bool aIsPrivate)
 {
     NS_ENSURE_ARG_POINTER(aURI);
     NS_ENSURE_ARG_POINTER(aFile);
 
     nsresult rv = NS_OK;
     
     mURI = aURI;
 
@@ -1214,16 +1226,22 @@ nsresult nsWebBrowserPersist::SaveURIInt
         }
     }
 
     // Open a channel to the URI
     nsCOMPtr<nsIChannel> inputChannel;
     rv = NS_NewChannel(getter_AddRefs(inputChannel), aURI,
             nullptr, nullptr, static_cast<nsIInterfaceRequestor *>(this),
             loadFlags);
+
+    nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryInterface(inputChannel);
+    if (pbChannel)
+    {
+        pbChannel->SetPrivate(aIsPrivate);
+    }
     
     if (NS_FAILED(rv) || inputChannel == nullptr)
     {
         EndDownload(NS_ERROR_FAILURE);
         return NS_ERROR_FAILURE;
     }
     
     // Disable content conversion
@@ -2506,17 +2524,18 @@ nsWebBrowserPersist::EnumPersistURIs(nsH
 
     // Make a URI to save the data to
     nsCOMPtr<nsIURI> fileAsURI;
     rv = data->mDataPath->Clone(getter_AddRefs(fileAsURI));
     NS_ENSURE_SUCCESS(rv, false);
     rv = pthis->AppendPathToURI(fileAsURI, data->mFilename);
     NS_ENSURE_SUCCESS(rv, false);
 
-    rv = pthis->SaveURIInternal(uri, nullptr, nullptr, nullptr, nullptr, fileAsURI, true);
+    rv = pthis->SaveURIInternal(uri, nullptr, nullptr, nullptr, nullptr, fileAsURI, true,
+                                pthis->mIsPrivate);
     // if SaveURIInternal fails, then it will have called EndDownload,
     // which means that |aData| is no longer valid memory.  we MUST bail.
     NS_ENSURE_SUCCESS(rv, false);
 
     if (rv == NS_OK)
     {
         // Store the actual object because once it's persisted this
         // will be fixed up with the right file extension.
--- a/embedding/components/webbrowserpersist/src/nsWebBrowserPersist.h
+++ b/embedding/components/webbrowserpersist/src/nsWebBrowserPersist.h
@@ -58,17 +58,17 @@ public:
 // Protected members
 protected:    
     virtual ~nsWebBrowserPersist();
     nsresult CloneNodeWithFixedUpAttributes(
         nsIDOMNode *aNodeIn, bool *aSerializeCloneKids, nsIDOMNode **aNodeOut);
     nsresult SaveURIInternal(
         nsIURI *aURI, nsISupports *aCacheKey, nsIURI *aReferrer,
         nsIInputStream *aPostData, const char *aExtraHeaders, nsIURI *aFile,
-        bool aCalcFileExt);
+        bool aCalcFileExt, bool aIsPrivate);
     nsresult SaveChannelInternal(
         nsIChannel *aChannel, nsIURI *aFile, bool aCalcFileExt);
     nsresult SaveDocumentInternal(
         nsIDOMDocument *aDocument, nsIURI *aFile, nsIURI *aDataPath);
     nsresult SaveDocuments();
     nsresult GetDocEncoderContentType(
         nsIDOMDocument *aDocument, const PRUnichar *aContentType,
         PRUnichar **aRealContentType);
@@ -197,16 +197,17 @@ private:
     nsTArray<nsCString>       mFilenameList;
     bool                      mFirstAndOnlyUse;
     bool                      mCancel;
     bool                      mJustStartedLoading;
     bool                      mCompleted;
     bool                      mStartSaving;
     bool                      mReplaceExisting;
     bool                      mSerializingOutput;
+    bool                      mIsPrivate;
     uint32_t                  mPersistFlags;
     nsresult                  mPersistResult;
     int64_t                   mTotalCurrentProgress;
     int64_t                   mTotalMaxProgress;
     int16_t                   mWrapColumn;
     uint32_t                  mEncodingFlags;
     nsString                  mContentType;
 };
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -6506,17 +6506,17 @@ var WebappsUI = {
             try {
               let iconFile = file.clone();
               iconFile.append("logo.png");
               let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(Ci.nsIWebBrowserPersist);
               persist.persistFlags = Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES;
               persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
   
               let source = Services.io.newURI(fullsizeIcon, "UTF8", null);
-              persist.saveURI(source, null, null, null, null, iconFile);
+              persist.saveURI(source, null, null, null, null, iconFile, null);
             } catch(ex) {
               console.log(ex);
             }
           }
           DOMApplicationRegistry.confirmInstall(aData, false, file);
         }).bind(this));
     } else {
       DOMApplicationRegistry.denyInstall(aData);
--- a/mobile/android/components/SessionStore.js
+++ b/mobile/android/components/SessionStore.js
@@ -857,17 +857,21 @@ SessionStore.prototype = {
       file.append("thumbnail-" + browser.contentWindowId);
       file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
 
       let source = Services.io.newURI(aStringValue, "UTF8", null);
       let target = Services.io.newFileURI(file)
 
       let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(Ci.nsIWebBrowserPersist);
       persist.persistFlags = Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES | Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
-      persist.saveURI(source, null, null, null, null, file);
+      let privacyContext = browser.contentWindow
+                                  .QueryInterface(Ci.nsIInterfaceRequestor)
+                                  .getInterface(Ci.nsIWebNavigation)
+                                  .QueryInterface(Ci.nsILoadContext);
+      persist.saveURI(source, null, null, null, null, file, privacyContext);
 
       aStringValue = target.spec;
     }
 
     if (!browser.__SS_extdata)
       browser.__SS_extdata = {};
     browser.__SS_extdata[aKey] = aStringValue;
     this.saveStateDelayed();
--- a/toolkit/components/downloads/nsDownloadManager.cpp
+++ b/toolkit/components/downloads/nsDownloadManager.cpp
@@ -1582,17 +1582,18 @@ nsDownloadManager::RetryDownload(uint32_
 
   rv = dl->SetState(nsIDownloadManager::DOWNLOAD_QUEUED);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Creates a cycle that will be broken when the download finishes
   dl->mCancelable = wbp;
   (void)wbp->SetProgressListener(dl);
 
-  rv = wbp->SaveURI(dl->mSource, nullptr, nullptr, nullptr, nullptr, dl->mTarget);
+  rv = wbp->SavePrivacyAwareURI(dl->mSource, nullptr, nullptr, nullptr, nullptr,
+                                dl->mTarget, dl->mPrivate);
   if (NS_FAILED(rv)) {
     dl->mCancelable = nullptr;
     (void)wbp->SetProgressListener(nullptr);
     return rv;
   }
 
   return NS_OK;
 }
--- a/toolkit/components/downloads/test/unit/head_download_manager.js
+++ b/toolkit/components/downloads/test/unit/head_download_manager.js
@@ -118,17 +118,18 @@ function addDownload(aParams)
 
   // This will throw if it isn't found, and that would mean test failure, so no
   // try catch block
   var test = dm.getDownload(dl.id);
 
   aParams.runBeforeStart.call(undefined, dl);
 
   persist.progressListener = dl.QueryInterface(Ci.nsIWebProgressListener);
-  persist.saveURI(dl.source, null, null, null, null, dl.targetFile);
+  persist.savePrivacyAwareURI(dl.source, null, null, null, null, dl.targetFile,
+                              aParams.isPrivate);
 
   return dl;
 }
 
 function getDownloadListener()
 {
   return {
     onDownloadStateChange: function(aState, aDownload)
--- a/toolkit/components/downloads/test/unit/test_bug_420230.js
+++ b/toolkit/components/downloads/test/unit/test_bug_420230.js
@@ -31,17 +31,17 @@ function run_test()
     gDownloadCount++;
 
     var dl = dm.addDownload(Ci.nsIDownloadManager.DOWNLOAD_TYPE_DOWNLOAD,
                             createURI("data:image/png;base64,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"),
                             createURI(file), null, null,
                             Math.round(Date.now() * 1000), null, persist, false);
 
     persist.progressListener = dl.QueryInterface(Ci.nsIWebProgressListener);
-    persist.saveURI(dl.source, null, null, null, null, dl.targetFile);
+    persist.saveURI(dl.source, null, null, null, null, dl.targetFile, null);
 
     return dl;
   }
 
   let listener = {
     onDownloadStateChange: function(aState, aDownload)
     {
       switch (aDownload.state) {
--- a/toolkit/components/downloads/test/unit/test_offline_support.js
+++ b/toolkit/components/downloads/test/unit/test_offline_support.js
@@ -140,13 +140,13 @@ function run_test()
   persist.persistFlags = nsIWBP.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
                          nsIWBP.PERSIST_FLAGS_BYPASS_CACHE |
                          nsIWBP.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
   let dl = dm.addDownload(nsIDM.DOWNLOAD_TYPE_DOWNLOAD,
                           createURI("http://localhost:4444/resume"),
                           createURI(destFile), null, null,
                           Math.round(Date.now() * 1000), null, persist, false);
   persist.progressListener = dl.QueryInterface(nsIWPL);
-  persist.saveURI(dl.source, null, null, null, null, dl.targetFile);
+  persist.saveURI(dl.source, null, null, null, null, dl.targetFile, null);
 
   // Mark as pending, so clear this when we actually finish the download
   do_test_pending();
 }
--- a/toolkit/components/downloads/test/unit/test_resume.js
+++ b/toolkit/components/downloads/test/unit/test_resume.js
@@ -121,13 +121,13 @@ function run_test()
   persist.persistFlags = nsIWBP.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
                          nsIWBP.PERSIST_FLAGS_BYPASS_CACHE |
                          nsIWBP.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
   var dl = dm.addDownload(nsIDM.DOWNLOAD_TYPE_DOWNLOAD,
                           createURI("http://localhost:4444/resume"),
                           createURI(destFile), null, null,
                           Math.round(Date.now() * 1000), null, persist, false);
   persist.progressListener = dl.QueryInterface(nsIWPL);
-  persist.saveURI(dl.source, null, null, null, null, dl.targetFile);
+  persist.saveURI(dl.source, null, null, null, null, dl.targetFile, null);
 
   // Mark as pending, so clear this when we actually finish the download
   do_test_pending();
 }
--- a/toolkit/components/downloads/test/unit/test_sleep_wake.js
+++ b/toolkit/components/downloads/test/unit/test_sleep_wake.js
@@ -140,13 +140,13 @@ function run_test()
   persist.persistFlags = nsIWBP.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
                          nsIWBP.PERSIST_FLAGS_BYPASS_CACHE |
                          nsIWBP.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
   let dl = dm.addDownload(nsIDM.DOWNLOAD_TYPE_DOWNLOAD,
                           createURI("http://localhost:4444/resume"),
                           createURI(destFile), null, null,
                           Math.round(Date.now() * 1000), null, persist, false);
   persist.progressListener = dl.QueryInterface(nsIWPL);
-  persist.saveURI(dl.source, null, null, null, null, dl.targetFile);
+  persist.saveURI(dl.source, null, null, null, null, dl.targetFile, null);
 
   // Mark as pending, so clear this when we actually finish the download
   do_test_pending();
 }
--- a/toolkit/content/contentAreaUtils.js
+++ b/toolkit/content/contentAreaUtils.js
@@ -428,19 +428,23 @@ function internalPersist(persistArgs)
     else {
       encodingFlags |= nsIWBP.ENCODE_FLAGS_ENCODE_BASIC_ENTITIES;
     }
 
     const kWrapColumn = 80;
     persist.saveDocument(persistArgs.sourceDocument, targetFileURL, filesFolder,
                          persistArgs.targetContentType, encodingFlags, kWrapColumn);
   } else {
+    let privacyContext = persistArgs.initiatingWindow
+                                    .QueryInterface(Ci.nsIInterfaceRequestor)
+                                    .getInterface(Ci.nsIWebNavigation)
+                                    .QueryInterface(Ci.nsILoadContext);
     persist.saveURI(persistArgs.sourceURI,
                     persistArgs.sourceCacheKey, persistArgs.sourceReferrer, persistArgs.sourcePostData, null,
-                    targetFileURL);
+                    targetFileURL, privacyContext);
   }
 }
 
 /**
  * Structure for holding info about automatically supplied parameters for
  * internalSave(...). This allows parameters to be supplied so the user does not
  * need to be prompted for file info.
  * @param aFileAutoChosen This is an nsILocalFile object that has been
--- a/toolkit/mozapps/downloads/tests/chrome/test_space_key_pauses_resumes.xul
+++ b/toolkit/mozapps/downloads/tests/chrome/test_space_key_pauses_resumes.xul
@@ -104,18 +104,22 @@ function test()
     if (destFile.exists())
       destFile.remove(false);
 
     var dl = dm.addDownload(Ci.nsIDownloadManager.DOWNLOAD_TYPE_DOWNLOAD,
                             createURI("http://example.com/httpd.js"),
                             createURI(destFile), null, null,
                             Math.round(Date.now() * 1000), null, persist, false);
 
+    var privacyContext = window.QueryInterface(Ci.nsIInterfaceRequestor)
+                               .getInterface(Ci.nsIWebNavigation)
+                               .QueryInterface(Ci.nsILoadContext);
+
     persist.progressListener = dl.QueryInterface(Ci.nsIWebProgressListener);
-    persist.saveURI(dl.source, null, null, null, null, dl.targetFile);
+    persist.saveURI(dl.source, null, null, null, null, dl.targetFile, privacyContext);
 
     return dl;
   }
 
   // First, we clear out the database
   dm.DBConnection.executeSimpleSQL("DELETE FROM moz_downloads");
 
   // See if the DM is already open, and if it is, close it!
--- a/toolkit/mozapps/downloads/tests/chrome/utils.js
+++ b/toolkit/mozapps/downloads/tests/chrome/utils.js
@@ -67,18 +67,22 @@ function addDownload(aName) {
     if (dmFile.exists())
       throw "Download file already exists";
   
     let dl = dm.addDownload(Ci.nsIDownloadManager.DOWNLOAD_TYPE_DOWNLOAD,
                             createURI("http://example.com/httpd.js"),
                             createURI(dmFile), null, null,
                             Math.round(Date.now() * 1000), null, persist, false);
 
+    let privacyContext = window.QueryInterface(Ci.nsIInterfaceRequestor)
+                               .getInterface(Ci.nsIWebNavigation)
+                               .QueryInterface(Ci.nsILoadContext);
+
     persist.progressListener = dl.QueryInterface(Ci.nsIWebProgressListener);
-    persist.saveURI(dl.source, null, null, null, null, dl.targetFile);
+    persist.saveURI(dl.source, null, null, null, null, dl.targetFile, privacyContext);
 
     return dl;
   }
 
 /**
  * Used to populate the dm with dummy download data.
  *
  * @param aDownloadData
--- a/toolkit/mozapps/extensions/LightweightThemeManager.jsm
+++ b/toolkit/mozapps/extensions/LightweightThemeManager.jsm
@@ -765,17 +765,17 @@ function _persistImage(sourceURL, localF
     Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
     Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION |
     (PERSIST_BYPASS_CACHE ?
        Ci.nsIWebBrowserPersist.PERSIST_FLAGS_BYPASS_CACHE :
        Ci.nsIWebBrowserPersist.PERSIST_FLAGS_FROM_CACHE);
 
   persist.progressListener = new _persistProgressListener(successCallback);
 
-  persist.saveURI(sourceURI, null, null, null, null, targetURI);
+  persist.saveURI(sourceURI, null, null, null, null, targetURI, null);
 }
 
 function _persistProgressListener(successCallback) {
   this.onLocationChange = function () {};
   this.onProgressChange = function () {};
   this.onStatusChange   = function () {};
   this.onSecurityChange = function () {};
   this.onStateChange    = function (aWebProgress, aRequest, aStateFlags, aStatus) {
--- a/widget/os2/nsDragService.cpp
+++ b/widget/os2/nsDragService.cpp
@@ -499,19 +499,24 @@ nsresult nsDragService::SaveAsContents(P
                         getter_AddRefs(file));
   if (!file)
     return NS_ERROR_FAILURE;
 
   FILE* fp;
   if (NS_FAILED(file->OpenANSIFileDesc("wb+", &fp)))
     return NS_ERROR_FAILURE;
 
+  nsCOMPtr<nsIDOMDocument> domDoc;
+  GetSourceDocument(getter_AddRefs(domDoc));
+  nsCOMPtr<nsIDocument> document = do_QueryInterface(domDoc);
+
   fwrite("", 0, 1, fp);
   fclose(fp);
-  webPersist->SaveURI(linkURI, nullptr, nullptr, nullptr, nullptr, file);
+  webPersist->SaveURI(linkURI, nullptr, nullptr, nullptr, nullptr, file,
+                     document->GetLoadContext());
 
   return NS_OK;
 }
 
 // --------------------------------------------------------------------------
 
 // save this URL in a file that the WPS will identify as a WPUrl object