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 109302 e94dbc151121ef4fefeda5a2655238c0d6c6f065
parent 109301 e5269e137290782c7f11d98078aaf6112e1b0581
child 109303 0ea0cfc7f6f4acec3c6174828e8ecfeafac14bce
push id1145
push userpastithas@mozilla.com
push dateMon, 08 Oct 2012 14:21:16 +0000
treeherderfx-team@e7f2e2c944b7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, mfinkle, smaug, ehsan, jwalker, roc, unfocused
bugs794602
milestone18.0a1
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 () {
+    gPrefService.clearUserPref("browser.privatebrowsing.keep_current_session");
+    pb.privateBrowsingEnabled = false;
+    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
@@ -119,17 +119,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