summaryrefslogtreecommitdiffstats
path: root/dom/ipc/TabContext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/ipc/TabContext.cpp')
-rw-r--r--dom/ipc/TabContext.cpp434
1 files changed, 434 insertions, 0 deletions
diff --git a/dom/ipc/TabContext.cpp b/dom/ipc/TabContext.cpp
new file mode 100644
index 000000000..b36dbc5eb
--- /dev/null
+++ b/dom/ipc/TabContext.cpp
@@ -0,0 +1,434 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/TabContext.h"
+#include "mozilla/dom/PTabContext.h"
+#include "mozilla/dom/TabParent.h"
+#include "mozilla/dom/TabChild.h"
+#include "nsIAppsService.h"
+#include "nsIScriptSecurityManager.h"
+#include "nsServiceManagerUtils.h"
+
+#define NO_APP_ID (nsIScriptSecurityManager::NO_APP_ID)
+
+using namespace mozilla::dom::ipc;
+using namespace mozilla::layout;
+
+namespace mozilla {
+namespace dom {
+
+TabContext::TabContext()
+ : mIsPrerendered(false)
+ , mInitialized(false)
+ , mIsMozBrowserElement(false)
+ , mContainingAppId(NO_APP_ID)
+ , mShowAccelerators(UIStateChangeType_NoChange)
+ , mShowFocusRings(UIStateChangeType_NoChange)
+{
+}
+
+bool
+TabContext::IsMozBrowserElement() const
+{
+ return mIsMozBrowserElement;
+}
+
+bool
+TabContext::IsIsolatedMozBrowserElement() const
+{
+ return mOriginAttributes.mInIsolatedMozBrowser;
+}
+
+bool
+TabContext::IsMozBrowserOrApp() const
+{
+ return HasOwnApp() || IsMozBrowserElement();
+}
+
+uint32_t
+TabContext::OwnAppId() const
+{
+ return mOriginAttributes.mAppId;
+}
+
+already_AddRefed<mozIApplication>
+TabContext::GetOwnApp() const
+{
+ nsCOMPtr<mozIApplication> ownApp = mOwnApp;
+ return ownApp.forget();
+}
+
+bool
+TabContext::HasOwnApp() const
+{
+ nsCOMPtr<mozIApplication> ownApp = GetOwnApp();
+ return !!ownApp;
+}
+
+uint32_t
+TabContext::BrowserOwnerAppId() const
+{
+ if (IsMozBrowserElement()) {
+ return mContainingAppId;
+ }
+ return NO_APP_ID;
+}
+
+already_AddRefed<mozIApplication>
+TabContext::GetBrowserOwnerApp() const
+{
+ nsCOMPtr<mozIApplication> ownerApp;
+ if (IsMozBrowserElement()) {
+ ownerApp = mContainingApp;
+ }
+ return ownerApp.forget();
+}
+
+bool
+TabContext::HasBrowserOwnerApp() const
+{
+ nsCOMPtr<mozIApplication> ownerApp = GetBrowserOwnerApp();
+ return !!ownerApp;
+}
+
+uint32_t
+TabContext::AppOwnerAppId() const
+{
+ if (HasOwnApp()) {
+ return mContainingAppId;
+ }
+ return NO_APP_ID;
+}
+
+already_AddRefed<mozIApplication>
+TabContext::GetAppOwnerApp() const
+{
+ nsCOMPtr<mozIApplication> ownerApp;
+ if (HasOwnApp()) {
+ ownerApp = mContainingApp;
+ }
+ return ownerApp.forget();
+}
+
+bool
+TabContext::HasAppOwnerApp() const
+{
+ nsCOMPtr<mozIApplication> ownerApp = GetAppOwnerApp();
+ return !!ownerApp;
+}
+
+uint32_t
+TabContext::OwnOrContainingAppId() const
+{
+ if (HasOwnApp()) {
+ return mOriginAttributes.mAppId;
+ }
+
+ return mContainingAppId;
+}
+
+already_AddRefed<mozIApplication>
+TabContext::GetOwnOrContainingApp() const
+{
+ nsCOMPtr<mozIApplication> ownOrContainingApp;
+ if (HasOwnApp()) {
+ ownOrContainingApp = mOwnApp;
+ } else {
+ ownOrContainingApp = mContainingApp;
+ }
+
+ return ownOrContainingApp.forget();
+}
+
+bool
+TabContext::HasOwnOrContainingApp() const
+{
+ nsCOMPtr<mozIApplication> ownOrContainingApp = GetOwnOrContainingApp();
+ return !!ownOrContainingApp;
+}
+
+bool
+TabContext::SetTabContext(const TabContext& aContext)
+{
+ NS_ENSURE_FALSE(mInitialized, false);
+
+ *this = aContext;
+ mInitialized = true;
+
+ return true;
+}
+
+void
+TabContext::SetPrivateBrowsingAttributes(bool aIsPrivateBrowsing)
+{
+ mOriginAttributes.SyncAttributesWithPrivateBrowsing(aIsPrivateBrowsing);
+}
+
+bool
+TabContext::UpdateTabContextAfterSwap(const TabContext& aContext)
+{
+ // This is only used after already initialized.
+ MOZ_ASSERT(mInitialized);
+
+ // The only permissable change is to `mIsMozBrowserElement`. All other fields
+ // must match for the change to be accepted.
+ if (aContext.OwnAppId() != OwnAppId() ||
+ aContext.mContainingAppId != mContainingAppId ||
+ aContext.mOriginAttributes != mOriginAttributes) {
+ return false;
+ }
+
+ mIsMozBrowserElement = aContext.mIsMozBrowserElement;
+ return true;
+}
+
+const DocShellOriginAttributes&
+TabContext::OriginAttributesRef() const
+{
+ return mOriginAttributes;
+}
+
+const nsAString&
+TabContext::PresentationURL() const
+{
+ return mPresentationURL;
+}
+
+UIStateChangeType
+TabContext::ShowAccelerators() const
+{
+ return mShowAccelerators;
+}
+
+UIStateChangeType
+TabContext::ShowFocusRings() const
+{
+ return mShowFocusRings;
+}
+
+bool
+TabContext::SetTabContext(bool aIsMozBrowserElement,
+ bool aIsPrerendered,
+ mozIApplication* aOwnApp,
+ mozIApplication* aAppFrameOwnerApp,
+ UIStateChangeType aShowAccelerators,
+ UIStateChangeType aShowFocusRings,
+ const DocShellOriginAttributes& aOriginAttributes,
+ const nsAString& aPresentationURL)
+{
+ NS_ENSURE_FALSE(mInitialized, false);
+
+ // Get ids for both apps and only write to our member variables after we've
+ // verified that this worked.
+ uint32_t ownAppId = NO_APP_ID;
+ if (aOwnApp) {
+ nsresult rv = aOwnApp->GetLocalId(&ownAppId);
+ NS_ENSURE_SUCCESS(rv, false);
+ NS_ENSURE_TRUE(ownAppId != NO_APP_ID, false);
+ }
+
+ uint32_t containingAppId = NO_APP_ID;
+ if (aAppFrameOwnerApp) {
+ nsresult rv = aAppFrameOwnerApp->GetLocalId(&containingAppId);
+ NS_ENSURE_SUCCESS(rv, false);
+ NS_ENSURE_TRUE(containingAppId != NO_APP_ID, false);
+ }
+
+ // Veryify that app id matches mAppId passed in originAttributes
+ MOZ_RELEASE_ASSERT((aOwnApp && aOriginAttributes.mAppId == ownAppId) ||
+ (aAppFrameOwnerApp && aOriginAttributes.mAppId == containingAppId) ||
+ aOriginAttributes.mAppId == NO_APP_ID);
+
+ mInitialized = true;
+ mIsMozBrowserElement = aIsMozBrowserElement;
+ mIsPrerendered = aIsPrerendered;
+ mOriginAttributes = aOriginAttributes;
+ mContainingAppId = containingAppId;
+ mOwnApp = aOwnApp;
+ mContainingApp = aAppFrameOwnerApp;
+ mPresentationURL = aPresentationURL;
+ mShowAccelerators = aShowAccelerators;
+ mShowFocusRings = aShowFocusRings;
+ return true;
+}
+
+IPCTabContext
+TabContext::AsIPCTabContext() const
+{
+ return IPCTabContext(FrameIPCTabContext(mOriginAttributes,
+ mContainingAppId,
+ mIsMozBrowserElement,
+ mIsPrerendered,
+ mPresentationURL,
+ mShowAccelerators,
+ mShowFocusRings));
+}
+
+static already_AddRefed<mozIApplication>
+GetAppForId(uint32_t aAppId)
+{
+ nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
+ NS_ENSURE_TRUE(appsService, nullptr);
+
+ nsCOMPtr<mozIApplication> app;
+ appsService->GetAppByLocalId(aAppId, getter_AddRefs(app));
+
+ return app.forget();
+}
+
+MaybeInvalidTabContext::MaybeInvalidTabContext(const IPCTabContext& aParams)
+ : mInvalidReason(nullptr)
+{
+ bool isMozBrowserElement = false;
+ bool isPrerendered = false;
+ uint32_t containingAppId = NO_APP_ID;
+ DocShellOriginAttributes originAttributes;
+ nsAutoString presentationURL;
+ UIStateChangeType showAccelerators = UIStateChangeType_NoChange;
+ UIStateChangeType showFocusRings = UIStateChangeType_NoChange;
+
+ switch(aParams.type()) {
+ case IPCTabContext::TPopupIPCTabContext: {
+ const PopupIPCTabContext &ipcContext = aParams.get_PopupIPCTabContext();
+
+ TabContext *context;
+ if (ipcContext.opener().type() == PBrowserOrId::TPBrowserParent) {
+ context = TabParent::GetFrom(ipcContext.opener().get_PBrowserParent());
+ if (!context) {
+ mInvalidReason = "Child is-browser process tried to "
+ "open a null tab.";
+ return;
+ }
+ if (context->IsMozBrowserElement() &&
+ !ipcContext.isMozBrowserElement()) {
+ // If the TabParent corresponds to a browser element, then it can only
+ // open other browser elements, for security reasons. We should have
+ // checked this before calling the TabContext constructor, so this is
+ // a fatal error.
+ mInvalidReason = "Child is-browser process tried to "
+ "open a non-browser tab.";
+ return;
+ }
+ } else if (ipcContext.opener().type() == PBrowserOrId::TPBrowserChild) {
+ context = static_cast<TabChild*>(ipcContext.opener().get_PBrowserChild());
+ } else if (ipcContext.opener().type() == PBrowserOrId::TTabId) {
+ // We should never get here because this PopupIPCTabContext is only
+ // used for allocating a new tab id, not for allocating a PBrowser.
+ mInvalidReason = "Child process tried to open an tab without the opener information.";
+ return;
+ } else {
+ // This should be unreachable because PopupIPCTabContext::opener is not a
+ // nullable field.
+ mInvalidReason = "PopupIPCTabContext::opener was null (?!).";
+ return;
+ }
+
+ // Browser elements can't nest other browser elements. So if
+ // our opener is browser element, we must be a new DOM window
+ // opened by it. In that case we inherit our containing app ID
+ // (if any).
+ //
+ // Otherwise, we're a new app window and we inherit from our
+ // opener app.
+ isMozBrowserElement = ipcContext.isMozBrowserElement();
+ originAttributes = context->mOriginAttributes;
+ if (isMozBrowserElement) {
+ containingAppId = context->OwnOrContainingAppId();
+ } else {
+ containingAppId = context->mContainingAppId;
+ }
+ break;
+ }
+ case IPCTabContext::TFrameIPCTabContext: {
+ const FrameIPCTabContext &ipcContext =
+ aParams.get_FrameIPCTabContext();
+
+ isMozBrowserElement = ipcContext.isMozBrowserElement();
+ isPrerendered = ipcContext.isPrerendered();
+ containingAppId = ipcContext.frameOwnerAppId();
+ presentationURL = ipcContext.presentationURL();
+ showAccelerators = ipcContext.showAccelerators();
+ showFocusRings = ipcContext.showFocusRings();
+ originAttributes = ipcContext.originAttributes();
+ break;
+ }
+ case IPCTabContext::TUnsafeIPCTabContext: {
+ // XXXcatalinb: This used *only* by ServiceWorkerClients::OpenWindow.
+ // It is meant as a temporary solution until service workers can
+ // provide a TabChild equivalent. Don't allow this on b2g since
+ // it might be used to escalate privileges.
+#ifdef MOZ_B2G
+ mInvalidReason = "ServiceWorkerClients::OpenWindow is not supported.";
+ return;
+#endif
+ if (!Preferences::GetBool("dom.serviceWorkers.enabled", false)) {
+ mInvalidReason = "ServiceWorkers should be enabled.";
+ return;
+ }
+
+ containingAppId = NO_APP_ID;
+ break;
+ }
+ default: {
+ MOZ_CRASH();
+ }
+ }
+
+ nsCOMPtr<mozIApplication> ownApp;
+ if (!isMozBrowserElement) {
+ // mAppId corresponds to OwnOrContainingAppId; if isMozBrowserElement is
+ // false then it's ownApp otherwise it's containingApp
+ ownApp = GetAppForId(originAttributes.mAppId);
+ if ((ownApp == nullptr) != (originAttributes.mAppId == NO_APP_ID)) {
+ mInvalidReason = "Got an ownAppId that didn't correspond to an app.";
+ return;
+ }
+ }
+
+ nsCOMPtr<mozIApplication> containingApp = GetAppForId(containingAppId);
+ if ((containingApp == nullptr) != (containingAppId == NO_APP_ID)) {
+ mInvalidReason = "Got a containingAppId that didn't correspond to an app.";
+ return;
+ }
+
+ bool rv;
+ rv = mTabContext.SetTabContext(isMozBrowserElement,
+ isPrerendered,
+ ownApp,
+ containingApp,
+ showAccelerators,
+ showFocusRings,
+ originAttributes,
+ presentationURL);
+ if (!rv) {
+ mInvalidReason = "Couldn't initialize TabContext.";
+ }
+}
+
+bool
+MaybeInvalidTabContext::IsValid()
+{
+ return mInvalidReason == nullptr;
+}
+
+const char*
+MaybeInvalidTabContext::GetInvalidReason()
+{
+ return mInvalidReason;
+}
+
+const TabContext&
+MaybeInvalidTabContext::GetTabContext()
+{
+ if (!IsValid()) {
+ MOZ_CRASH("Can't GetTabContext() if !IsValid().");
+ }
+
+ return mTabContext;
+}
+
+} // namespace dom
+} // namespace mozilla