Bug 536567 - Store the value of the per-site last file upload directories inside the memory while private browsing is active. r=ehsan
authorGeoff Lankow <geoff@darktrojan.net>
Thu, 11 Feb 2010 09:35:49 +0100
changeset 38054 cbb7edcc6d77e0fab67e9fc2b4b85e8074c02907
parent 38053 5f1d4b1baffbd45f0741d422bdbf8fc557360996
child 38055 a2437223853ffbb5b6f74ca7680ad5e7f6020f4d
push idunknown
push userunknown
push dateunknown
reviewersehsan
bugs536567
milestone1.9.3a2pre
Bug 536567 - Store the value of the per-site last file upload directories inside the memory while private browsing is active. r=ehsan
dom/interfaces/base/Makefile.in
dom/interfaces/base/nsIContentURIGrouper.idl
layout/build/nsLayoutStatics.cpp
layout/forms/nsFileControlFrame.cpp
layout/forms/nsFileControlFrame.h
layout/forms/test/Makefile.in
layout/forms/test/bug536567_subframe.html
layout/forms/test/test_bug536567.html
toolkit/components/contentprefs/Makefile.in
toolkit/components/contentprefs/public/Makefile.in
toolkit/components/contentprefs/public/nsIContentURIGrouper.idl
toolkit/toolkit-makefiles.sh
--- a/dom/interfaces/base/Makefile.in
+++ b/dom/interfaces/base/Makefile.in
@@ -53,16 +53,17 @@ SDK_XPIDLSRCS =                         
 	nsIDOMWindow2.idl			\
 	nsIDOMWindowCollection.idl		\
 	nsIDOMWindowUtils.idl			\
 	$(NULL)
 
 XPIDLSRCS =					\
 	nsIBrowserDOMWindow.idl			\
 	nsIContentPrefService.idl		\
+	nsIContentURIGrouper.idl    \
 	nsIDOMClientInformation.idl		\
 	nsIDOMConstructor.idl			\
 	nsIDOMCRMFObject.idl			\
 	nsIDOMCrypto.idl			\
 	nsIDOMHistory.idl			\
 	nsIDOMLocation.idl			\
 	nsIDOMMimeType.idl			\
 	nsIDOMMimeTypeArray.idl			\
rename from toolkit/components/contentprefs/public/nsIContentURIGrouper.idl
rename to dom/interfaces/base/nsIContentURIGrouper.idl
--- a/toolkit/components/contentprefs/public/nsIContentURIGrouper.idl
+++ b/dom/interfaces/base/nsIContentURIGrouper.idl
@@ -43,8 +43,13 @@ interface nsIContentURIGrouper : nsISupp
      * Determine the group to which the URI belongs.
      *
      * @param    aURI       the URI to group
      *
      * @returns  the group to which the URI belongs
      */
     AString group(in nsIURI aURI);
 };
+
+%{C++
+// The contractID for the generic implementation built in to xpcom.
+#define NS_HOSTNAME_GROUPER_SERVICE_CONTRACTID "@mozilla.org/content-pref/hostname-grouper;1"
+%}
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -83,16 +83,17 @@
 #include "nsXMLHttpRequest.h"
 #include "nsDOMThreadService.h"
 #include "nsHTMLDNSPrefetch.h"
 #include "nsHtml5Module.h"
 #include "nsCrossSiteListenerProxy.h"
 #include "nsFocusManager.h"
 #include "nsFrameList.h"
 #include "nsListControlFrame.h"
+#include "nsFileControlFrame.h"
 
 #ifdef MOZ_XUL
 #include "nsXULPopupManager.h"
 #include "nsXULContentUtils.h"
 #include "nsXULElement.h"
 #include "nsXULPrototypeCache.h"
 #include "nsXULTooltipListener.h"
 
@@ -285,16 +286,18 @@ nsLayoutStatics::Initialize()
   rv = nsFrameList::Init();
   if (NS_FAILED(rv)) {
     NS_ERROR("Could not initialize nsFrameList");
     return rv;
   }
 
   NS_SealStaticAtomTable();
 
+  nsFileControlFrame::InitUploadLastDir();
+
   return NS_OK;
 }
 
 void
 nsLayoutStatics::Shutdown()
 {
   nsFocusManager::Shutdown();
 #ifdef MOZ_XUL
@@ -379,16 +382,18 @@ nsLayoutStatics::Shutdown()
   
   nsHtml5Module::ReleaseStatics();
 
   nsRegion::ShutdownStatic();
 
   NS_ShutdownChainItemPool();
 
   nsFrameList::Shutdown();
+
+  nsFileControlFrame::DestroyUploadLastDir();
 }
 
 void
 nsLayoutStatics::AddRef()
 {
   NS_ASSERTION(sLayoutStaticRefcnt,
                "nsLayoutStatics already dropped to zero!");
 
--- a/layout/forms/nsFileControlFrame.cpp
+++ b/layout/forms/nsFileControlFrame.cpp
@@ -16,16 +16,17 @@
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Mats Palmgren <mats.palmgren@bredband.net>
+ *   Geoff Lankow <geoff@darktrojan.net>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -72,23 +73,68 @@
 #include "nsDisplayList.h"
 #include "nsIDOMNSUIEvent.h"
 #include "nsIDOMEventGroup.h"
 #include "nsIDOM3EventTarget.h"
 #include "nsIDOMNSHTMLInputElement.h"
 #ifdef ACCESSIBILITY
 #include "nsIAccessibilityService.h"
 #endif
+
+#include "nsInterfaceHashtable.h"
+#include "nsURIHashKey.h"
+#include "nsILocalFile.h"
+#include "nsIPrivateBrowsingService.h"
+#include "nsNetCID.h"
+#include "nsIObserver.h"
+#include "nsIObserverService.h"
+#include "nsWeakReference.h"
 #include "nsIVariant.h"
 #include "nsIContentPrefService.h"
+#include "nsIContentURIGrouper.h"
 
 #define SYNC_TEXT 0x1
 #define SYNC_BUTTON 0x2
 #define SYNC_BOTH 0x3
 
+#define CPS_PREF_NAME NS_LITERAL_STRING("browser.upload.lastDir")
+
+class UploadLastDir : public nsIObserver, public nsSupportsWeakReference {
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+
+  UploadLastDir();
+
+  /**
+   * Fetch the last used directory for this location from the content
+   * pref service, if it is available.
+   *
+   * @param aURI URI of the current page
+   * @param aFile path to the last used directory
+   */
+  nsresult FetchLastUsedDirectory(nsIURI* aURI, nsILocalFile** aFile);
+
+  /**
+   * Store the last used directory for this location using the
+   * content pref service, if it is available
+   * @param aURI URI of the current page
+   * @param aFile file chosen by the user - the path to the parent of this
+   *        file will be stored
+   */
+  nsresult StoreLastUsedDirectory(nsIURI* aURI, nsILocalFile* aFile);
+private:
+  // Directories are stored here during private browsing mode
+  nsInterfaceHashtable<nsStringHashKey, nsILocalFile> mUploadLastDirStore;
+  PRBool mInPrivateBrowsing;
+};
+
+NS_IMPL_ISUPPORTS2(UploadLastDir, nsIObserver, nsISupportsWeakReference)
+UploadLastDir* gUploadLastDir = nsnull;
+
 nsIFrame*
 NS_NewFileControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsFileControlFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsFileControlFrame)
 
@@ -342,20 +388,19 @@ nsFileControlFrame::MouseListener::Mouse
       nsAutoString leafName;
       oldFiles[0]->GetLeafName(leafName);
       if (!leafName.IsEmpty()) {
         filePicker->SetDefaultString(leafName);
       }
     }
   } else {
     // Attempt to retrieve the last used directory from the content pref service
-    nsCOMPtr<nsILocalFile> localFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
-    if (!localFile)
-      return NS_ERROR_OUT_OF_MEMORY;
-    if (NS_SUCCEEDED(FetchLastUsedDirectory(doc->GetDocumentURI(), localFile)))
+    nsCOMPtr<nsILocalFile> localFile;
+    if (NS_SUCCEEDED(gUploadLastDir->FetchLastUsedDirectory(
+                     doc->GetDocumentURI(), getter_AddRefs(localFile))))
       filePicker->SetDisplayDirectory(localFile);
   }
 
   // Tell our textframe to remember the currently focused value
   mFrame->mTextFrame->InitFocusedValue();
 
   // Open dialog
   PRInt16 mode;
@@ -378,42 +423,46 @@ nsFileControlFrame::MouseListener::Mouse
   if (multi) {
     nsCOMPtr<nsISimpleEnumerator> iter;
     result = filePicker->GetFiles(getter_AddRefs(iter));
     NS_ENSURE_SUCCESS(result, result);
 
     nsCOMPtr<nsISupports> tmp;
     PRBool prefSaved = PR_FALSE;
     while (NS_SUCCEEDED(iter->GetNext(getter_AddRefs(tmp)))) {
-      nsCOMPtr<nsIFile> file = do_QueryInterface(tmp);
-      if (file) {
+      nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(tmp);
+      if (localFile) {
         nsString unicodePath;
-        result = file->GetPath(unicodePath);
+        result = localFile->GetPath(unicodePath);
         if (!unicodePath.IsEmpty()) {
           newFileNames.AppendElement(unicodePath);
         }
         if (!prefSaved) {
           // Store the last used directory using the content pref service
-          StoreLastUsedDirectory(doc->GetDocumentURI(), file);
+          result = gUploadLastDir->StoreLastUsedDirectory(doc->GetDocumentURI(), 
+                                                          localFile);
+          NS_ENSURE_SUCCESS(result, result);
           prefSaved = PR_TRUE;
         }
       }
     }
   }
   else {
     nsCOMPtr<nsILocalFile> localFile;
     result = filePicker->GetFile(getter_AddRefs(localFile));
     if (localFile) {
       nsString unicodePath;
       result = localFile->GetPath(unicodePath);
       if (!unicodePath.IsEmpty()) {
         newFileNames.AppendElement(unicodePath);
       }
       // Store the last used directory using the content pref service
-      StoreLastUsedDirectory(doc->GetDocumentURI(), localFile);
+      result = gUploadLastDir->StoreLastUsedDirectory(doc->GetDocumentURI(),
+                                                      localFile);
+      NS_ENSURE_SUCCESS(result, result);
     }
   }
 
   // Set new selected files
   if (!newFileNames.IsEmpty()) {
     // Tell mTextFrame that this update of the value is a user initiated
     // change. Otherwise it'll think that the value is being set by a script
     // and not fire onchange when it should.
@@ -424,68 +473,158 @@ nsFileControlFrame::MouseListener::Mouse
     mFrame->mTextFrame->SetFireChangeEventState(oldState);
     // May need to fire an onchange here
     mFrame->mTextFrame->CheckFireOnChange();
   }
 
   return NS_OK;
 }
 
+void nsFileControlFrame::InitUploadLastDir() {
+  gUploadLastDir = new UploadLastDir();
+  NS_IF_ADDREF(gUploadLastDir);
+
+  nsCOMPtr<nsIObserverService> observerService =
+    do_GetService("@mozilla.org/observer-service;1");
+  if (observerService && gUploadLastDir) {
+    observerService->AddObserver(gUploadLastDir, NS_PRIVATE_BROWSING_SWITCH_TOPIC, PR_TRUE);
+    observerService->AddObserver(gUploadLastDir, "browser:purge-session-history", PR_TRUE);
+  }
+}
+
+void nsFileControlFrame::DestroyUploadLastDir() {
+  NS_RELEASE(gUploadLastDir);
+}
+
+UploadLastDir::UploadLastDir():
+  mInPrivateBrowsing(PR_FALSE)
+{
+  nsCOMPtr<nsIPrivateBrowsingService> pbService =
+    do_GetService(NS_PRIVATE_BROWSING_SERVICE_CONTRACTID);
+  if (pbService) {
+    pbService->GetPrivateBrowsingEnabled(&mInPrivateBrowsing);
+  }
+
+  mUploadLastDirStore.Init();
+}
+
 nsresult
-nsFileControlFrame::FetchLastUsedDirectory(nsIURI* aURI, nsILocalFile* aFile)
+UploadLastDir::FetchLastUsedDirectory(nsIURI* aURI, nsILocalFile** aFile)
 {
+  NS_PRECONDITION(aURI, "aURI is null");
+  NS_PRECONDITION(aFile, "aFile is null");
+  // Retrieve the data from memory if it's present during private browsing mode,
+  // otherwise fall through to check the CPS
+  if (mInPrivateBrowsing) {
+    nsCOMPtr<nsIContentURIGrouper> hostnameGrouperService =
+      do_GetService(NS_HOSTNAME_GROUPER_SERVICE_CONTRACTID);
+    if (!hostnameGrouperService)
+      return NS_ERROR_NOT_AVAILABLE;
+    nsString group;
+    hostnameGrouperService->Group(aURI, group);
+
+    if (mUploadLastDirStore.Get(group, aFile)) {
+      return NS_OK;
+    }
+  }
+
   // Attempt to get the CPS, if it's not present we'll just return
   nsCOMPtr<nsIContentPrefService> contentPrefService =
     do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
   if (!contentPrefService)
     return NS_ERROR_NOT_AVAILABLE;
   nsCOMPtr<nsIWritableVariant> uri = do_CreateInstance(NS_VARIANT_CONTRACTID);
   if (!uri)
     return NS_ERROR_OUT_OF_MEMORY;
   uri->SetAsISupports(aURI);
-  NS_NAMED_LITERAL_STRING(prefName, "lastUploadDirectory");
 
   // Get the last used directory, if it is stored
   PRBool hasPref;
-  if (NS_SUCCEEDED(contentPrefService->HasPref(uri, prefName, &hasPref)) && hasPref) {
+  if (NS_SUCCEEDED(contentPrefService->HasPref(uri, CPS_PREF_NAME, &hasPref)) && hasPref) {
     nsCOMPtr<nsIVariant> pref;
-    contentPrefService->GetPref(uri, prefName, nsnull, getter_AddRefs(pref));
+    contentPrefService->GetPref(uri, CPS_PREF_NAME, nsnull, getter_AddRefs(pref));
     nsString prefStr;
     pref->GetAsAString(prefStr);
-    return aFile->InitWithPath(prefStr);
+
+    nsCOMPtr<nsILocalFile> localFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
+    if (!localFile)
+      return NS_ERROR_OUT_OF_MEMORY;
+    localFile->InitWithPath(prefStr);
+
+    *aFile = localFile;
+    NS_ADDREF(*aFile);
   }
   return NS_OK;
 }
 
-void
-nsFileControlFrame::StoreLastUsedDirectory(nsIURI* aURI, nsIFile* aFile)
+nsresult
+UploadLastDir::StoreLastUsedDirectory(nsIURI* aURI, nsILocalFile* aFile)
 {
+  NS_PRECONDITION(aURI, "aURI is null");
+  NS_PRECONDITION(aFile, "aFile is null");
+  nsCOMPtr<nsIFile> parentFile;
+  aFile->GetParent(getter_AddRefs(parentFile));
+  nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(parentFile);
+
+  // Store the data in memory instead of the CPS during private browsing mode
+  if (mInPrivateBrowsing) {
+    nsCOMPtr<nsIContentURIGrouper> hostnameGrouperService =
+      do_GetService(NS_HOSTNAME_GROUPER_SERVICE_CONTRACTID);
+    if (!hostnameGrouperService)
+      return NS_ERROR_NOT_AVAILABLE;
+    nsString group;
+    hostnameGrouperService->Group(aURI, group);
+
+    return mUploadLastDirStore.Put(group, localFile);
+  }
+
   // Attempt to get the CPS, if it's not present we'll just return
   nsCOMPtr<nsIContentPrefService> contentPrefService =
     do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
   if (!contentPrefService)
-    return;
+    return NS_ERROR_NOT_AVAILABLE;
   nsCOMPtr<nsIWritableVariant> uri = do_CreateInstance(NS_VARIANT_CONTRACTID);
   if (!uri)
-    return;
+    return NS_ERROR_OUT_OF_MEMORY;
   uri->SetAsISupports(aURI);
-  NS_NAMED_LITERAL_STRING(prefName, "lastUploadDirectory");
-
+ 
   // Find the parent of aFile, and store it
-  nsCOMPtr<nsIFile> parentFile;
   nsString unicodePath;
-  aFile->GetParent(getter_AddRefs(parentFile));
   parentFile->GetPath(unicodePath);
-  if (!unicodePath.IsEmpty()) {
-    nsCOMPtr<nsIWritableVariant> prefValue = do_CreateInstance(NS_VARIANT_CONTRACTID);
-    if (!prefValue)
-      return;
-    prefValue->SetAsAString(unicodePath);
-    contentPrefService->SetPref(uri, prefName, prefValue);
+  if (unicodePath.IsEmpty()) // nothing to do
+    return NS_OK;
+  nsCOMPtr<nsIWritableVariant> prefValue = do_CreateInstance(NS_VARIANT_CONTRACTID);
+  if (!prefValue)
+    return NS_ERROR_OUT_OF_MEMORY;
+  prefValue->SetAsAString(unicodePath);
+  return contentPrefService->SetPref(uri, CPS_PREF_NAME, prefValue);
+}
+
+NS_IMETHODIMP
+UploadLastDir::Observe(nsISupports *aSubject, char const *aTopic, PRUnichar const *aData)
+{
+  if (strcmp(aTopic, NS_PRIVATE_BROWSING_SWITCH_TOPIC) == 0) {
+    if (NS_LITERAL_STRING(NS_PRIVATE_BROWSING_ENTER).Equals(aData)) {
+      mInPrivateBrowsing = PR_TRUE;
+    } else if (NS_LITERAL_STRING(NS_PRIVATE_BROWSING_LEAVE).Equals(aData)) {
+      mInPrivateBrowsing = PR_FALSE;
+      if (mUploadLastDirStore.IsInitialized()) {
+        mUploadLastDirStore.Clear();
+      }
+    }
+  } else if (strcmp(aTopic, "browser:purge-session-history") == 0) {
+    if (mUploadLastDirStore.IsInitialized()) {
+      mUploadLastDirStore.Clear();
+    }
+    nsCOMPtr<nsIContentPrefService> contentPrefService =
+      do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
+    if (contentPrefService)
+      contentPrefService->RemovePrefsByName(CPS_PREF_NAME);
   }
+  return NS_OK;
 }
 
 nscoord
 nsFileControlFrame::GetMinWidth(nsIRenderingContext *aRenderingContext)
 {
   nscoord result;
   DISPLAY_MIN_WIDTH(this, result);
 
--- a/layout/forms/nsFileControlFrame.h
+++ b/layout/forms/nsFileControlFrame.h
@@ -93,16 +93,20 @@ public:
 
   // nsIAnonymousContentCreator
   virtual nsresult CreateAnonymousContent(nsTArray<nsIContent*>& aElements);
 
 #ifdef ACCESSIBILITY
   NS_IMETHOD GetAccessible(nsIAccessible** aAccessible);
 #endif
 
+  // create and destroy the static UploadLastDir object for remembering
+  // which directory was last used on a site-by-site basis
+  static void InitUploadLastDir();
+  static void DestroyUploadLastDir();
 protected:
   class MouseListener;
   friend class MouseListener;
   class MouseListener : public nsIDOMMouseListener {
   public:
     NS_DECL_ISUPPORTS
     
     MouseListener(nsFileControlFrame* aFrame) :
@@ -179,35 +183,13 @@ private:
    * Copy an attribute from file content to text and button content.
    * @param aNameSpaceID namespace of attr
    * @param aAttribute attribute atom
    * @param aWhichControls which controls to apply to (SYNC_TEXT or SYNC_FILE
    *        or SYNC_BOTH)
    */
   void SyncAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
                 PRInt32 aWhichControls);
-
-  /**
-   * Fetch the last used directory for this location from the content
-   * pref service, if it is available.  The caller must pass in an
-   * already-created nsILocalFile, and this function will initialize
-   * it to point to the right directory.
-   *
-   * @param aURI URI of the current page
-   * @param aFile path to the last used directory
-   */
-  static nsresult FetchLastUsedDirectory(nsIURI* aURI,
-                                         nsILocalFile* aFile);
-
-  /**
-   * Store the last used directory for this location using the
-   * content pref service, if it is available
-   * @param aURI URI of the current page
-   * @param aFile file chosen by the user - the path to the parent of this
-   *        file will be stored
-   */
-  static void StoreLastUsedDirectory(nsIURI* aURI,
-                                     nsIFile* aFile);
 };
 
 #endif
 
 
--- a/layout/forms/test/Makefile.in
+++ b/layout/forms/test/Makefile.in
@@ -53,12 +53,14 @@ include $(topsrcdir)/config/rules.mk
 		test_bug411236.html \
 		test_bug446663.html \
 		test_bug476308.html \
 		test_bug477531.html \
 		test_bug477700.html \
 		test_bug478219.xhtml \
 		test_bug542914.html \
 		bug477700_subframe.html \
+		test_bug536567.html \
+		bug536567_subframe.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $^ $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/layout/forms/test/bug536567_subframe.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  </head>
+<body>
+<input id="target" type="file" />
+<script type="text/javascript">
+
+netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+const Cm = Components.manager;
+
+Cc["@mozilla.org/moz/jssubscript-loader;1"]
+  .getService(Ci.mozIJSSubScriptLoader)
+  .loadSubScript("chrome://mochikit/content/browser/toolkit/content/tests/browser/common/mockObjects.js", this);
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+function MockFilePicker() { };
+MockFilePicker.prototype = {
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIFilePicker]),
+  init: function(aParent, aTitle, aMode) { },
+  appendFilters: function(aFilterMask) { },
+  appendFilter: function(aTitle, aFilter) { },
+  defaultString: "",
+  defaultExtension: "",
+  filterIndex: 0,
+  displayDirectory: null,
+  get file() {
+    var f = window.parent.dirs[window.parent.index].clone();
+    f.append("aFile.txt");
+    return f;
+  },
+  get fileURL() {
+    throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+  },
+  get files() {
+    throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+  },
+  show: function MFP_show() {
+    if (this.displayDirectory)
+      window.parent.postMessage(this.displayDirectory.path, "*");
+    else
+      window.parent.postMessage("", "*");
+    return Ci.nsIFilePicker.returnOK;
+  }
+};
+
+var mockFilePickerRegisterer =
+  new MockObjectRegisterer("@mozilla.org/filepicker;1",MockFilePicker);
+
+function test() {
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+  var wu = window.QueryInterface(Ci.nsIInterfaceRequestor)
+                 .getInterface(Ci.nsIDOMWindowUtils);
+
+  var fileInput = document.getElementById("target");
+  var rect = fileInput.getBoundingClientRect();
+
+  mockFilePickerRegisterer.register();
+  try {
+    wu.sendMouseEvent("mousedown", rect.left + 5, rect.top + 5, 0, 1, 0);
+    wu.sendMouseEvent("mouseup", rect.left + 5, rect.top + 5, 0, 1, 0);
+  } catch (e) {
+    Cu.reportError(e);
+  } finally {
+    mockFilePickerRegisterer.unregister();
+  }
+}
+
+window.onload = function() {
+  setTimeout(test, 0);
+};
+
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/forms/test/test_bug536567.html
@@ -0,0 +1,167 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=536567
+-->
+<head>
+  <title>Test for Bug 536567</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=536567">Mozilla Bug 536567</a>
+<p id="display"></p>
+<iframe id="content"></iframe>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 536567 **/
+
+netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+const Cm = Components.manager;
+
+var ioSvc = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
+var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
+var prefSvc = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
+var obSvc = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
+if ("@mozilla.org/privatebrowsing;1" in Cc) {
+  var pbSvc = Cc["@mozilla.org/privatebrowsing;1"].getService(Ci.nsIPrivateBrowsingService);
+}
+
+var tmpDir = dirSvc.get("TmpD", Ci.nsILocalFile);
+prefSvc.setBoolPref("browser.privatebrowsing.keep_current_session", true);
+
+function newDir() {
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+  var dir = tmpDir.clone();
+  dir.append("testdir" + Math.floor(Math.random() * 10000));
+  dir.QueryInterface(Ci.nsILocalFile);
+  dir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0700);
+  return dir;
+}
+
+var dirs = [];
+for(var i = 0; i < 6; i++) {
+  dirs.push(newDir());
+}
+var domains = ['http://localhost:8888', 'http://example.org:80', 'http://example.com:80'];
+/*
+ * These tests take 3 args each:
+ * - which domain to load
+ * - the filePicker displayDirectory we expect to be set
+ * - the file to pick (in most cases this will show up in the next test,
+ *   as indicated by the comments)
+ */
+var tests = [
+  [0, -1, 0],//-> 3
+  [1, -1, 1],//-> 4
+  [2, -1, 2],//-> 5
+  [0, 0, 3], //-> 6
+  [1, 1, 1], //-> 8
+  [2, 2, 2], //-> 9
+  [0, 3, 1], //-> 7
+  [0, 1, 0], //-> x
+  [1, 1, 1], //-> x
+  [2, 2, 2], //-> x
+  "clear history",
+  [0, -1, 0],//->15
+  [1, -1, 1],//->16
+  [2, -1, 2],//->17
+  "pb on",
+  [0, 0, 3], //-> 18
+  [1, 1, 4], //-> 19
+  [2, 2, 5], //-> 20
+  [0, 3, 3], //-> x
+  [1, 4, 4], //-> x
+  [2, 5, 5], //-> x
+  "pb off",
+  [0, 0, 5], //-> 26
+  [1, 1, 4], //-> 27
+  [2, 2, 3], //-> 28
+  "pb on",
+  [0, 5, 5], //-> x
+  [1, 4, 4], //-> x
+  [2, 3, 3], //-> x
+  "clear history",
+  [0, -1, 0],
+  [1, -1, 1],
+  [2, -1, 2],
+  "pb off"
+];
+
+var index;
+var testIndex = 0;
+var content = document.getElementById('content');
+
+function runTest() {
+  var test = tests[testIndex];
+  if (test == undefined) {
+    endTest();
+  } else if (test == "pb on") {
+    if (!pbSvc) {
+      // private browsing service not available, finish test
+      endTest();
+      return;
+    }
+    pbSvc.privateBrowsingEnabled = true;
+    testIndex++;
+    runTest();
+  } else if (test == "pb off") {
+    pbSvc.privateBrowsingEnabled = false;
+    testIndex++;
+    runTest();
+  } else if (test == "clear history") {
+    obSvc.notifyObservers(null, "browser:purge-session-history", "");
+    testIndex++;
+    runTest();
+  } else {
+    index = test[2];
+    content.setAttribute ('src', domains[test[0]] + '/tests/layout/forms/test/bug536567_subframe.html');
+  }
+}
+
+function endTest() {
+    prefSvc.clearUserPref("browser.privatebrowsing.keep_current_session");
+    for(var i = 0; i < dirs.length; i++) {
+      dirs[i].remove(true);
+    }
+
+    SimpleTest.finish();
+}
+
+window.addEventListener("message", function(event) {
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+  var test = tests[testIndex];
+  var returned = -1;
+  for (var i = 0; i < dirs.length; i++) {
+    if (dirs[i].path == event.data) {
+      returned = i;
+      break;
+    }
+  }
+  if (test[1] == -1) {
+    is(event.data, '', 'test ' + testIndex + ' should be empty');
+  } else {
+    is(returned, test[1], 'test ' + testIndex);
+  }
+  
+  testIndex++;
+  runTest();
+}, false);
+
+window.onload = function() {
+  SimpleTest.waitForExplicitFinish();
+  setTimeout(runTest, 0);
+};
+
+</script>
+</pre>
+</body>
+</html>
--- a/toolkit/components/contentprefs/Makefile.in
+++ b/toolkit/components/contentprefs/Makefile.in
@@ -36,15 +36,15 @@
 
 DEPTH		= ../../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
-DIRS = public src
+DIRS = src
 
 ifdef ENABLE_TESTS
 	DIRS += tests
 endif
 
 include $(topsrcdir)/config/rules.mk
deleted file mode 100644
--- a/toolkit/components/contentprefs/public/Makefile.in
+++ /dev/null
@@ -1,49 +0,0 @@
-# ***** BEGIN LICENSE BLOCK *****
-# Version: MPL 1.1/GPL 2.0/LGPL 2.1
-#
-# The contents of this file are subject to the Mozilla Public License Version
-# 1.1 (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-# http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an "AS IS" basis,
-# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-# for the specific language governing rights and limitations under the
-# License.
-#
-# The Original Code is Content Prefs (cpref).
-#
-# The Initial Developer of the Original Code is Mozilla.
-# Portions created by the Initial Developer are Copyright (C) 2006
-# the Initial Developer. All Rights Reserved.
-#
-# Contributor(s):
-#   Myk Melez <myk@mozilla.org>
-#
-# Alternatively, the contents of this file may be used under the terms of
-# either the GNU General Public License Version 2 or later (the "GPL"), or
-# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
-# in which case the provisions of the GPL or the LGPL are applicable instead
-# of those above. If you wish to allow use of your version of this file only
-# under the terms of either the GPL or the LGPL, and not to allow others to
-# use your version of this file under the terms of the MPL, indicate your
-# decision by deleting the provisions above and replace them with the notice
-# and other provisions required by the GPL or the LGPL. If you do not delete
-# the provisions above, a recipient may use your version of this file under
-# the terms of any one of the MPL, the GPL or the LGPL.
-#
-# ***** END LICENSE BLOCK *****
-
-DEPTH      = ../../../..
-topsrcdir  = @top_srcdir@
-srcdir     = @srcdir@
-VPATH      = @srcdir@
-
-include $(DEPTH)/config/autoconf.mk
-
-MODULE        = contentprefs
-XPIDL_MODULE  = contentprefs
-
-XPIDLSRCS = nsIContentURIGrouper.idl
-
-include $(topsrcdir)/config/rules.mk
--- a/toolkit/toolkit-makefiles.sh
+++ b/toolkit/toolkit-makefiles.sh
@@ -695,17 +695,16 @@ MAKEFILES_xulapp="
   toolkit/components/autocomplete/src/Makefile
   toolkit/components/Makefile
   toolkit/components/build/Makefile
   toolkit/components/commandlines/Makefile
   toolkit/components/commandlines/public/Makefile
   toolkit/components/commandlines/src/Makefile
   toolkit/components/console/Makefile
   toolkit/components/contentprefs/Makefile
-  toolkit/components/contentprefs/public/Makefile
   toolkit/components/contentprefs/src/Makefile
   toolkit/components/cookie/Makefile
   toolkit/components/downloads/public/Makefile
   toolkit/components/downloads/Makefile
   toolkit/components/downloads/src/Makefile
   toolkit/components/exthelper/Makefile
   toolkit/components/feeds/Makefile
   toolkit/components/feeds/public/Makefile