Bug 1396065 - [1.3] Add nsILoadURIDelegate to handle load delegation to the window (GeckoView). r=smaug,snorp
authorEugen Sawin <esawin@mozilla.com>
Fri, 01 Sep 2017 19:43:25 +0200
changeset 659206 47b2e91b1060844712405ab8566c1cb359cd5958
parent 659205 10a488d8110e2c2fd293978e3886ebe793bec1ba
child 659207 83e6e35ab72be905a8bca44aed31e5b5fda5dffb
push id78047
push userbmo:francesco.lodolo@gmail.com
push dateTue, 05 Sep 2017 17:25:17 +0000
reviewerssmaug, snorp
bugs1396065
milestone57.0a1
Bug 1396065 - [1.3] Add nsILoadURIDelegate to handle load delegation to the window (GeckoView). r=smaug,snorp
docshell/base/nsDocShell.cpp
docshell/base/nsDocShell.h
docshell/base/nsIDocShell.idl
xpcom/base/moz.build
xpcom/base/nsILoadURIDelegate.idl
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -2911,16 +2911,30 @@ NS_IMETHODIMP
 nsDocShell::SetSecurityUI(nsISecureBrowserUI* aSecurityUI)
 {
   mSecurityUI = aSecurityUI;
   mSecurityUI->SetDocShell(this);
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsDocShell::GetLoadURIDelegate(nsILoadURIDelegate** aLoadURIDelegate)
+{
+  NS_IF_ADDREF(*aLoadURIDelegate = mLoadURIDelegate);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::SetLoadURIDelegate(nsILoadURIDelegate* aLoadURIDelegate)
+{
+  mLoadURIDelegate = aLoadURIDelegate;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsDocShell::GetUseErrorPages(bool* aUseErrorPages)
 {
   *aUseErrorPages = UseErrorPages();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::SetUseErrorPages(bool aUseErrorPages)
@@ -10093,16 +10107,41 @@ nsDocShell::InternalLoad(nsIURI* aURI,
 
         nsCOMPtr<nsIDocShellTreeItem> parent;
         treeItem->GetSameTypeParent(getter_AddRefs(parent));
         parent.swap(treeItem);
       } while (treeItem);
     }
   }
 
+  const nsIDocument* doc = mContentViewer ? mContentViewer->GetDocument()
+                                          : nullptr;
+  const bool isDocumentAuxSandboxed = doc &&
+    (doc->GetSandboxFlags() & SANDBOXED_AUXILIARY_NAVIGATION);
+
+  if (aURI && mLoadURIDelegate &&
+      (!targetDocShell || targetDocShell == static_cast<nsIDocShell*>(this))) {
+    // Dispatch only load requests for the current or a new window to the
+    // delegate, e.g., to allow for GeckoView apps to handle the load event
+    // outside of Gecko.
+    const int where = (aWindowTarget.IsEmpty() || targetDocShell)
+                      ? nsIBrowserDOMWindow::OPEN_CURRENTWINDOW
+                      : nsIBrowserDOMWindow::OPEN_NEW;
+
+    if (where == nsIBrowserDOMWindow::OPEN_NEW && isDocumentAuxSandboxed) {
+      return NS_ERROR_DOM_INVALID_ACCESS_ERR;
+    }
+
+    if (NS_SUCCEEDED(mLoadURIDelegate->LoadURI(aURI, where, aFlags,
+                                               aTriggeringPrincipal))) {
+      // The request has been handled, nothing to do here.
+      return NS_OK;
+    }
+  }
+
   //
   // Resolve the window target before going any further...
   // If the load has been targeted to another DocShell, then transfer the
   // load to it...
   //
   if (!aWindowTarget.IsEmpty()) {
     // We've already done our owner-inheriting.  Mask out that bit, so we
     // don't try inheriting an owner from the target window if we came up
@@ -10110,24 +10149,18 @@ nsDocShell::InternalLoad(nsIURI* aURI,
     aFlags = aFlags & ~INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL;
 
     bool isNewWindow = false;
     if (!targetDocShell) {
       // If the docshell's document is sandboxed, only open a new window
       // if the document's SANDBOXED_AUXILLARY_NAVIGATION flag is not set.
       // (i.e. if allow-popups is specified)
       NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE);
-      nsIDocument* doc = mContentViewer->GetDocument();
-      uint32_t sandboxFlags = 0;
-
-      if (doc) {
-        sandboxFlags = doc->GetSandboxFlags();
-        if (sandboxFlags & SANDBOXED_AUXILIARY_NAVIGATION) {
-          return NS_ERROR_DOM_INVALID_ACCESS_ERR;
-        }
+      if (isDocumentAuxSandboxed) {
+        return NS_ERROR_DOM_INVALID_ACCESS_ERR;
       }
 
       nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
       NS_ENSURE_TRUE(win, NS_ERROR_NOT_AVAILABLE);
 
       nsCOMPtr<nsPIDOMWindowOuter> newWin;
       nsAutoCString spec;
       if (aURI) {
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -56,16 +56,17 @@
 #include "nsILinkHandler.h"
 #include "nsIClipboardCommands.h"
 #include "nsITabParent.h"
 #include "nsCRT.h"
 #include "prtime.h"
 #include "nsRect.h"
 #include "Units.h"
 #include "nsIDeprecationWarner.h"
+#include "nsILoadURIDelegate.h"
 
 namespace mozilla {
 class Encoding;
 class HTMLEditor;
 enum class TaskCategory;
 namespace dom {
 class EventTarget;
 class PendingGlobalHistoryEntry;
@@ -907,16 +908,18 @@ protected:
   // Note these are intentionally not addrefd. Doing so will create a cycle.
   // For that reasons don't use nsCOMPtr.
 
   nsIDocShellTreeOwner* mTreeOwner; // Weak Reference
   mozilla::dom::EventTarget* mChromeEventHandler; // Weak Reference
 
   eCharsetReloadState mCharsetReloadState;
 
+  nsCOMPtr<nsILoadURIDelegate> mLoadURIDelegate;
+
   // Offset in the parent's child list.
   // -1 if the docshell is added dynamically to the parent shell.
   int32_t mChildOffset;
   uint32_t mBusyFlags;
   uint32_t mAppType;
   uint32_t mLoadType;
 
   int32_t mMarginWidth;
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -48,16 +48,17 @@ interface nsIPrincipal;
 interface nsIWebBrowserPrint;
 interface nsIPrivacyTransitionObserver;
 interface nsIReflowObserver;
 interface nsIScrollObserver;
 interface nsITabParent;
 interface nsITabChild;
 interface nsICommandManager;
 interface nsICommandParams;
+interface nsILoadURIDelegate;
 native TabChildRef(already_AddRefed<nsITabChild>);
 
 [scriptable, builtinclass, uuid(049234fe-da10-478b-bc5d-bc6f9a1ba63d)]
 interface nsIDocShell : nsIDocShellTreeItem
 {
   /**
    * Loads a given URI.  This will give priority to loading the requested URI
    * in the object implementing this interface.  If it can't be loaded here
@@ -459,16 +460,23 @@ interface nsIDocShell : nsIDocShellTreeI
 
   /**
    * The SecureBrowserUI object for this docshell.  This is set by XUL
    * <browser> or nsWebBrowser for their root docshell.
    */
   attribute nsISecureBrowserUI securityUI;
 
   /**
+   * Object used to delegate URI loading to an upper context.
+   * Currently only set for GeckoView to allow handling of load requests
+   * at the application level.
+   */
+  attribute nsILoadURIDelegate loadURIDelegate;
+
+  /**
    * Cancel the XPCOM timers for each meta-refresh URI in this docshell,
    * and this docshell's children, recursively. The meta-refresh timers can be
    * restarted using resumeRefreshURIs().  If the timers are already suspended,
    * this has no effect.
    */
   void suspendRefreshURIs();
 
   /**
--- a/xpcom/base/moz.build
+++ b/xpcom/base/moz.build
@@ -9,16 +9,17 @@ XPIDL_SOURCES += [
     'nsIConsoleMessage.idl',
     'nsIConsoleService.idl',
     'nsICycleCollectorListener.idl',
     'nsIDebug2.idl',
     'nsIErrorService.idl',
     'nsIException.idl',
     'nsIGZFileWriter.idl',
     'nsIInterfaceRequestor.idl',
+    'nsILoadURIDelegate.idl',
     'nsIMemory.idl',
     'nsIMemoryInfoDumper.idl',
     'nsIMemoryReporter.idl',
     'nsIMessageLoop.idl',
     'nsIMutable.idl',
     'nsISecurityConsoleMessage.idl',
     'nsIStatusReporter.idl',
     'nsISupports.idl',
new file mode 100644
--- /dev/null
+++ b/xpcom/base/nsILoadURIDelegate.idl
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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 "nsISupports.idl"
+
+interface nsIURI;
+interface nsIPrincipal;
+
+/**
+ * The nsILoadURIDelegate interface.
+ * Used for delegating URI loads to GeckoView's application, e.g., Custom Tabs
+ * or Progressive Web Apps.
+ */
+[scriptable, uuid(78e42d37-a34c-4d96-b901-25385669aba4)]
+interface nsILoadURIDelegate : nsISupports
+{
+  /**
+   * Delegates the URI load.
+   *
+   * @param aURI The URI to load.
+   * @param aWhere See possible values described in nsIBrowserDOMWindow.
+   * @param aFlags Flags which control the behavior of the load.
+   * @param aTriggeringPrincipal The principal that triggered the load of aURI.
+  */
+  void
+  loadURI(in nsIURI aURI, in short aWhere, in long aFlags,
+          in nsIPrincipal aTriggeringPrincipal);
+};