From 889982d7af19025925dded370eb69ed5e08f6058 Mon Sep 17 00:00:00 2001 From: Catalin Badea Date: Thu, 3 Dec 2015 23:19:29 +0200 Subject: [PATCH] Bug 1221992 - Prevent ServiceWorkerClients.OpenWindow from opening tabs in private mode windows. r=smaug --- dom/base/nsContentUtils.cpp | 18 +++++++ dom/base/nsContentUtils.h | 5 ++ dom/ipc/ContentParent.cpp | 31 +----------- dom/workers/ServiceWorkerClients.cpp | 7 ++- xpfe/appshell/nsIWindowMediator.idl | 12 +++++ xpfe/appshell/nsWindowMediator.cpp | 74 +++++++++++++++++++++------- xpfe/appshell/nsWindowMediator.h | 6 ++- 7 files changed, 98 insertions(+), 55 deletions(-) diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 72e7dc4a7b32..9f77657037cc 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -162,6 +162,7 @@ #include "nsIURIWithPrincipal.h" #include "nsIURL.h" #include "nsIWebNavigation.h" +#include "nsIWindowMediator.h" #include "nsIWordBreaker.h" #include "nsIXPConnect.h" #include "nsJSUtils.h" @@ -5167,6 +5168,23 @@ nsContentUtils::GetWindowProviderForContentProcess() return ContentChild::GetSingleton(); } +/* static */ +already_AddRefed +nsContentUtils::GetMostRecentNonPBWindow() +{ + nsCOMPtr windowMediator = + do_GetService(NS_WINDOWMEDIATOR_CONTRACTID); + nsCOMPtr wm = do_QueryInterface(windowMediator); + + nsCOMPtr window; + wm->GetMostRecentNonPBWindow(MOZ_UTF16("navigator:browser"), + getter_AddRefs(window)); + nsCOMPtr pwindow; + pwindow = do_QueryInterface(window); + + return pwindow.forget(); +} + /* static */ void nsContentUtils::WarnScriptWasIgnored(nsIDocument* aDocument) diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 18b79bcb23b7..6d043af56203 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -1666,6 +1666,11 @@ public: static nsIWindowProvider* GetWindowProviderForContentProcess(); + // Returns the browser window with the most recent time stamp that is + // not in private browsing mode. + static already_AddRefed + GetMostRecentNonPBWindow(); + /** * Call this function if !IsSafeToRunScript() and we fail to run the script * (rather than using AddScriptRunner as we usually do). |aDocument| is diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 7b5ef317de5c..42dc1f346ae9 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -147,7 +147,6 @@ #include "nsISystemMessagesInternal.h" #include "nsITimer.h" #include "nsIURIFixup.h" -#include "nsIWindowMediator.h" #include "nsIDocShellTreeOwner.h" #include "nsIXULWindow.h" #include "nsIDOMChromeWindow.h" @@ -5343,34 +5342,6 @@ ContentParent::DeallocPWebBrowserPersistDocumentParent(PWebBrowserPersistDocumen return true; } -static already_AddRefed -FindMostRecentOpenWindow() -{ - nsCOMPtr windowMediator = - do_GetService(NS_WINDOWMEDIATOR_CONTRACTID); - nsCOMPtr windowEnumerator; - windowMediator->GetEnumerator(MOZ_UTF16("navigator:browser"), - getter_AddRefs(windowEnumerator)); - - nsCOMPtr latest; - - bool hasMore = false; - MOZ_ALWAYS_TRUE(NS_SUCCEEDED(windowEnumerator->HasMoreElements(&hasMore))); - while (hasMore) { - nsCOMPtr item; - MOZ_ALWAYS_TRUE(NS_SUCCEEDED(windowEnumerator->GetNext(getter_AddRefs(item)))); - nsCOMPtr window = do_QueryInterface(item); - - if (window && !window->Closed()) { - latest = window; - } - - MOZ_ALWAYS_TRUE(NS_SUCCEEDED(windowEnumerator->HasMoreElements(&hasMore))); - } - - return latest.forget(); -} - bool ContentParent::RecvCreateWindow(PBrowserParent* aThisTab, PBrowserParent* aNewTab, @@ -5444,7 +5415,7 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab, // If we haven't found a chrome window to open in, just use the most recently // opened one. if (!parent) { - parent = FindMostRecentOpenWindow(); + parent = nsContentUtils::GetMostRecentNonPBWindow(); if (NS_WARN_IF(!parent)) { *aResult = NS_ERROR_FAILURE; return true; diff --git a/dom/workers/ServiceWorkerClients.cpp b/dom/workers/ServiceWorkerClients.cpp index b3f23217932a..1b267bb30997 100644 --- a/dom/workers/ServiceWorkerClients.cpp +++ b/dom/workers/ServiceWorkerClients.cpp @@ -615,10 +615,9 @@ private: } // Find the most recent browser window and open a new tab in it. - nsCOMPtr browserWindow; - rv = wm->GetMostRecentWindow(MOZ_UTF16("navigator:browser"), - getter_AddRefs(browserWindow)); - if (NS_WARN_IF(NS_FAILED(rv)) || !browserWindow) { + nsCOMPtr browserWindow = + nsContentUtils::GetMostRecentNonPBWindow(); + if (!browserWindow) { // It is possible to be running without a browser window on Mac OS, so // we need to open a new chrome window. // TODO(catalinb): open new chrome window. Bug 1218080 diff --git a/xpfe/appshell/nsIWindowMediator.idl b/xpfe/appshell/nsIWindowMediator.idl index d5c1946b6503..55de09e4e0be 100644 --- a/xpfe/appshell/nsIWindowMediator.idl +++ b/xpfe/appshell/nsIWindowMediator.idl @@ -191,3 +191,15 @@ interface nsIWindowMediator: nsISupports */ void removeListener(in nsIWindowMediatorListener aListener); }; + +// XXXcatalinb: This should be merged to nsIWindowMediator. Using this +// to avoid UUID change in aurora. +[scriptable, uuid(88b54988-7f3c-40d2-a625-7e42a9c196c2)] +interface nsIWindowMediator_44 : nsIWindowMediator +{ + /** + * Same as getMostRecentWindow, but ignores private browsing + * windows. + */ + nsIDOMWindow getMostRecentNonPBWindow(in wstring aWindowType); +}; diff --git a/xpfe/appshell/nsWindowMediator.cpp b/xpfe/appshell/nsWindowMediator.cpp index 263641672106..5eaa38c4c92a 100644 --- a/xpfe/appshell/nsWindowMediator.cpp +++ b/xpfe/appshell/nsWindowMediator.cpp @@ -275,7 +275,7 @@ nsWindowMediator::GetMostRecentWindow(const char16_t* inType, nsIDOMWindow** out // Find the most window with the highest time stamp that matches // the requested type - nsWindowInfo *info = MostRecentWindowInfo(inType); + nsWindowInfo* info = MostRecentWindowInfo(inType, false); if (info && info->mWindow) { nsCOMPtr DOMWindow; if (NS_SUCCEEDED(GetDOMWindow(info->mWindow, DOMWindow))) { @@ -289,31 +289,66 @@ nsWindowMediator::GetMostRecentWindow(const char16_t* inType, nsIDOMWindow** out return NS_OK; } -nsWindowInfo* -nsWindowMediator::MostRecentWindowInfo(const char16_t* inType) +NS_IMETHODIMP +nsWindowMediator::GetMostRecentNonPBWindow(const char16_t* aType, nsIDOMWindow** aWindow) { + MOZ_RELEASE_ASSERT(NS_IsMainThread()); + NS_ENSURE_ARG_POINTER(aWindow); + *aWindow = nullptr; + + nsWindowInfo *info = MostRecentWindowInfo(aType, true); + nsCOMPtr domWindow; + if (info && info->mWindow) { + GetDOMWindow(info->mWindow, domWindow); + } + + if (!domWindow) { + return NS_ERROR_FAILURE; + } + + domWindow.forget(aWindow); + return NS_OK; +} + +nsWindowInfo* +nsWindowMediator::MostRecentWindowInfo(const char16_t* inType, bool aSkipPrivateBrowsing) +{ + MOZ_ASSERT(XRE_IsParentProcess()); + int32_t lastTimeStamp = -1; nsAutoString typeString(inType); bool allWindows = !inType || typeString.IsEmpty(); - // Find the most window with the highest time stamp that matches - // the requested type - nsWindowInfo *searchInfo, - *listEnd, - *foundInfo = nullptr; - - searchInfo = mOldestWindow; - listEnd = nullptr; - while (searchInfo != listEnd) { - if ((allWindows || searchInfo->TypeEquals(typeString)) && - searchInfo->mTimeStamp >= lastTimeStamp) { - - foundInfo = searchInfo; - lastTimeStamp = searchInfo->mTimeStamp; - } - searchInfo = searchInfo->mYounger; + // Find the most recent window with the highest time stamp that matches + // the requested type and has the correct browsing mode. + nsWindowInfo* searchInfo = mOldestWindow; + nsWindowInfo* listEnd = nullptr; + nsWindowInfo* foundInfo = nullptr; + for (; searchInfo != listEnd; searchInfo = searchInfo->mYounger) { listEnd = mOldestWindow; + + if (!allWindows && !searchInfo->TypeEquals(typeString)) { + continue; + } + if (searchInfo->mTimeStamp < lastTimeStamp) { + continue; + } + if (!searchInfo->mWindow) { + continue; + } + if (aSkipPrivateBrowsing) { + nsCOMPtr docShell; + searchInfo->mWindow->GetDocShell(getter_AddRefs(docShell)); + nsCOMPtr loadContext = do_QueryInterface(docShell); + if (!loadContext || loadContext->UsePrivateBrowsing()) { + continue; + } + } + + foundInfo = searchInfo; + lastTimeStamp = searchInfo->mTimeStamp; } + return foundInfo; } @@ -741,6 +776,7 @@ nsWindowMediator::SortZOrderBackToFront() } NS_IMPL_ISUPPORTS(nsWindowMediator, + nsIWindowMediator_44, nsIWindowMediator, nsIObserver, nsISupportsWeakReference) diff --git a/xpfe/appshell/nsWindowMediator.h b/xpfe/appshell/nsWindowMediator.h index 88f90a00ab4a..6b2e4858a348 100644 --- a/xpfe/appshell/nsWindowMediator.h +++ b/xpfe/appshell/nsWindowMediator.h @@ -25,7 +25,7 @@ class nsIWindowMediatorListener; struct nsWindowInfo; class nsWindowMediator : - public nsIWindowMediator, + public nsIWindowMediator_44, public nsIObserver, public nsSupportsWeakReference { @@ -47,6 +47,7 @@ public: NS_DECL_ISUPPORTS NS_DECL_NSIWINDOWMEDIATOR + NS_DECL_NSIWINDOWMEDIATOR_44 NS_DECL_NSIOBSERVER static nsresult GetDOMWindow(nsIXULWindow* inWindow, @@ -55,7 +56,8 @@ public: private: int32_t AddEnumerator(nsAppShellWindowEnumerator* inEnumerator); int32_t RemoveEnumerator(nsAppShellWindowEnumerator* inEnumerator); - nsWindowInfo *MostRecentWindowInfo(const char16_t* inType); + nsWindowInfo* MostRecentWindowInfo(const char16_t* inType, + bool aSkipPrivateBrowsing = false); nsresult UnregisterWindow(nsWindowInfo *inInfo); nsWindowInfo *GetInfoFor(nsIXULWindow *aWindow);