diff --git a/dom/interfaces/base/Makefile.in b/dom/interfaces/base/Makefile.in index 38bcb4e90f9..6a4fa8fb30e 100644 --- a/dom/interfaces/base/Makefile.in +++ b/dom/interfaces/base/Makefile.in @@ -58,6 +58,7 @@ SDK_XPIDLSRCS = \ XPIDLSRCS = \ nsIBrowserDOMWindow.idl \ nsIContentPrefService.idl \ + nsIContentURIGrouper.idl \ nsIDOMClientInformation.idl \ nsIDOMConstructor.idl \ nsIDOMCRMFObject.idl \ diff --git a/toolkit/components/contentprefs/public/nsIContentURIGrouper.idl b/dom/interfaces/base/nsIContentURIGrouper.idl similarity index 92% rename from toolkit/components/contentprefs/public/nsIContentURIGrouper.idl rename to dom/interfaces/base/nsIContentURIGrouper.idl index 0fd19a7f904..c9cee93795c 100644 --- a/toolkit/components/contentprefs/public/nsIContentURIGrouper.idl +++ b/dom/interfaces/base/nsIContentURIGrouper.idl @@ -48,3 +48,8 @@ interface nsIContentURIGrouper : nsISupports */ 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" +%} diff --git a/layout/build/nsLayoutStatics.cpp b/layout/build/nsLayoutStatics.cpp index a4efa0908fd..1ec805e5500 100644 --- a/layout/build/nsLayoutStatics.cpp +++ b/layout/build/nsLayoutStatics.cpp @@ -88,6 +88,7 @@ #include "nsFocusManager.h" #include "nsFrameList.h" #include "nsListControlFrame.h" +#include "nsFileControlFrame.h" #ifdef MOZ_XUL #include "nsXULPopupManager.h" @@ -290,6 +291,8 @@ nsLayoutStatics::Initialize() NS_SealStaticAtomTable(); + nsFileControlFrame::InitUploadLastDir(); + return NS_OK; } @@ -384,6 +387,8 @@ nsLayoutStatics::Shutdown() NS_ShutdownChainItemPool(); nsFrameList::Shutdown(); + + nsFileControlFrame::DestroyUploadLastDir(); } void diff --git a/layout/forms/nsFileControlFrame.cpp b/layout/forms/nsFileControlFrame.cpp index d0368284524..7bf8b67de83 100644 --- a/layout/forms/nsFileControlFrame.cpp +++ b/layout/forms/nsFileControlFrame.cpp @@ -21,6 +21,7 @@ * * Contributor(s): * Mats Palmgren + * Geoff Lankow * * 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"), @@ -77,13 +78,58 @@ #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 mUploadLastDirStore; + PRBool mInPrivateBrowsing; +}; + +NS_IMPL_ISUPPORTS2(UploadLastDir, nsIObserver, nsISupportsWeakReference) +UploadLastDir* gUploadLastDir = nsnull; + nsIFrame* NS_NewFileControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) { @@ -347,10 +393,9 @@ nsFileControlFrame::MouseListener::MouseClick(nsIDOMEvent* aMouseEvent) } } else { // Attempt to retrieve the last used directory from the content pref service - nsCOMPtr localFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID); - if (!localFile) - return NS_ERROR_OUT_OF_MEMORY; - if (NS_SUCCEEDED(FetchLastUsedDirectory(doc->GetDocumentURI(), localFile))) + nsCOMPtr localFile; + if (NS_SUCCEEDED(gUploadLastDir->FetchLastUsedDirectory( + doc->GetDocumentURI(), getter_AddRefs(localFile)))) filePicker->SetDisplayDirectory(localFile); } @@ -383,16 +428,18 @@ nsFileControlFrame::MouseListener::MouseClick(nsIDOMEvent* aMouseEvent) nsCOMPtr tmp; PRBool prefSaved = PR_FALSE; while (NS_SUCCEEDED(iter->GetNext(getter_AddRefs(tmp)))) { - nsCOMPtr file = do_QueryInterface(tmp); - if (file) { + nsCOMPtr 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; } } @@ -408,7 +455,9 @@ nsFileControlFrame::MouseListener::MouseClick(nsIDOMEvent* aMouseEvent) 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); } } @@ -429,9 +478,54 @@ nsFileControlFrame::MouseListener::MouseClick(nsIDOMEvent* aMouseEvent) return NS_OK; } -nsresult -nsFileControlFrame::FetchLastUsedDirectory(nsIURI* aURI, nsILocalFile* aFile) +void nsFileControlFrame::InitUploadLastDir() { + gUploadLastDir = new UploadLastDir(); + NS_IF_ADDREF(gUploadLastDir); + + nsCOMPtr 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 pbService = + do_GetService(NS_PRIVATE_BROWSING_SERVICE_CONTRACTID); + if (pbService) { + pbService->GetPrivateBrowsingEnabled(&mInPrivateBrowsing); + } + + mUploadLastDirStore.Init(); +} + +nsresult +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 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 contentPrefService = do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID); @@ -441,46 +535,91 @@ nsFileControlFrame::FetchLastUsedDirectory(nsIURI* aURI, nsILocalFile* aFile) 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 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 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 parentFile; + aFile->GetParent(getter_AddRefs(parentFile)); + nsCOMPtr localFile = do_QueryInterface(parentFile); + + // Store the data in memory instead of the CPS during private browsing mode + if (mInPrivateBrowsing) { + nsCOMPtr 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 contentPrefService = do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID); if (!contentPrefService) - return; + return NS_ERROR_NOT_AVAILABLE; nsCOMPtr 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 parentFile; nsString unicodePath; - aFile->GetParent(getter_AddRefs(parentFile)); parentFile->GetPath(unicodePath); - if (!unicodePath.IsEmpty()) { - nsCOMPtr 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 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 contentPrefService = + do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID); + if (contentPrefService) + contentPrefService->RemovePrefsByName(CPS_PREF_NAME); } + return NS_OK; } nscoord diff --git a/layout/forms/nsFileControlFrame.h b/layout/forms/nsFileControlFrame.h index f9d3e156e26..9342a95335e 100644 --- a/layout/forms/nsFileControlFrame.h +++ b/layout/forms/nsFileControlFrame.h @@ -98,6 +98,10 @@ public: 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; @@ -184,28 +188,6 @@ private: */ 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 diff --git a/layout/forms/test/Makefile.in b/layout/forms/test/Makefile.in index b05ecf091b1..8e30164683c 100644 --- a/layout/forms/test/Makefile.in +++ b/layout/forms/test/Makefile.in @@ -58,6 +58,8 @@ _TEST_FILES = test_bug287446.html \ test_bug478219.xhtml \ test_bug542914.html \ bug477700_subframe.html \ + test_bug536567.html \ + bug536567_subframe.html \ $(NULL) libs:: $(_TEST_FILES) diff --git a/layout/forms/test/bug536567_subframe.html b/layout/forms/test/bug536567_subframe.html new file mode 100644 index 00000000000..f692fe9f907 --- /dev/null +++ b/layout/forms/test/bug536567_subframe.html @@ -0,0 +1,80 @@ + + + + + + + + + + diff --git a/layout/forms/test/test_bug536567.html b/layout/forms/test/test_bug536567.html new file mode 100644 index 00000000000..0bb8e04b420 --- /dev/null +++ b/layout/forms/test/test_bug536567.html @@ -0,0 +1,167 @@ + + + + + Test for Bug 536567 + + + + + + +Mozilla Bug 536567 +

+ +
+
+
+ + diff --git a/toolkit/components/contentprefs/Makefile.in b/toolkit/components/contentprefs/Makefile.in index 7d000271533..e41ed4a1925 100644 --- a/toolkit/components/contentprefs/Makefile.in +++ b/toolkit/components/contentprefs/Makefile.in @@ -41,7 +41,7 @@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk -DIRS = public src +DIRS = src ifdef ENABLE_TESTS DIRS += tests diff --git a/toolkit/components/contentprefs/public/Makefile.in b/toolkit/components/contentprefs/public/Makefile.in deleted file mode 100644 index 07d551388a3..00000000000 --- 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 -# -# 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 diff --git a/toolkit/toolkit-makefiles.sh b/toolkit/toolkit-makefiles.sh index 61645a8b53b..3d56dd6062f 100644 --- a/toolkit/toolkit-makefiles.sh +++ b/toolkit/toolkit-makefiles.sh @@ -700,7 +700,6 @@ MAKEFILES_xulapp=" 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