Bug 1253307 - Use a better function to load web handler apps in e10s. r=billm r=mconley, a=ritu
authorBlake Kaplan <mrbkap@gmail.com>
Fri, 11 Mar 2016 14:31:55 -0800
changeset 323902 0f7a5afcc4079532f435326762a6d77a6834e38b
parent 323901 71affd40d13fbb376bba363562cbf65524e11f0a
child 323903 ad52021053bf4933b36fde59be3954597f06ac3e
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm, mconley, ritu
bugs1253307
milestone47.0a2
Bug 1253307 - Use a better function to load web handler apps in e10s. r=billm r=mconley, a=ritu
dom/base/nsIRemoteWindowContext.idl
dom/ipc/ContentParent.cpp
dom/ipc/PBrowser.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
uriloader/exthandler/nsWebHandlerApp.js
uriloader/exthandler/tests/mochitest/browser_web_protocol_handlers.js
--- a/dom/base/nsIRemoteWindowContext.idl
+++ b/dom/base/nsIRemoteWindowContext.idl
@@ -6,10 +6,10 @@
 
 #include "nsISupports.idl"
 
 interface nsIURI;
 
 [scriptable, builtinclass, uuid(94f4a92b-752e-4fd9-8345-11b069ca19f3)]
 interface nsIRemoteWindowContext : nsISupports
 {
-  void openURI(in nsIURI aURI, in uint32_t aFlags);
+  void openURI(in nsIURI aURI);
 };
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1601,22 +1601,19 @@ RemoteWindowContext::~RemoteWindowContex
 
 NS_IMETHODIMP
 RemoteWindowContext::GetInterface(const nsIID& aIID, void** aSink)
 {
   return QueryInterface(aIID, aSink);
 }
 
 NS_IMETHODIMP
-RemoteWindowContext::OpenURI(nsIURI* aURI, uint32_t aFlags)
-{
-  URIParams uri;
-  SerializeURI(aURI, uri);
-
-  Unused << mTabParent->SendOpenURI(uri, aFlags);
+RemoteWindowContext::OpenURI(nsIURI* aURI)
+{
+  mTabParent->LoadURL(aURI);
   return NS_OK;
 }
 
 } // namespace
 
 void
 ContentParent::MaybeTakeCPUWakeLock(Element* aFrameElement)
 {
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -520,18 +520,16 @@ child:
                TextureFactoryIdentifier textureFactoryIdentifier,
                uint64_t layersId,
                nullable PRenderFrame renderFrame,
                bool parentIsActive,
                nsSizeMode sizeMode);
 
     async LoadURL(nsCString uri, BrowserConfiguration config, ShowInfo info);
 
-    async OpenURI(URIParams uri, uint32_t flags);
-
     async CacheFileDescriptor(nsString path, FileDescriptor fd);
 
     async UpdateDimensions(CSSRect rect, CSSSize size,
                            ScreenOrientationInternal orientation,
                            LayoutDeviceIntPoint clientOffset,
                            LayoutDeviceIntPoint chromeDisp) compressall;
 
     async SizeModeChanged(nsSizeMode sizeMode);
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -588,16 +588,17 @@ TabChild::TabChild(nsIContentChild* aMan
   , mHasValidInnerSize(false)
   , mDestroyed(false)
   , mUniqueId(aTabId)
   , mDPI(0)
   , mDefaultScale(0)
   , mIPCOpen(true)
   , mParentIsActive(false)
   , mDidSetRealShowInfo(false)
+  , mDidLoadURLInit(false)
   , mAPZChild(nullptr)
 {
   // In the general case having the TabParent tell us if APZ is enabled or not
   // doesn't really work because the TabParent itself may not have a reference
   // to the owning widget during initialization. Instead we assume that this
   // TabChild corresponds to a widget type that would have APZ enabled, and just
   // check the other conditions necessary for enabling APZ.
   mAsyncPanZoomEnabled = gfxPlatform::AsyncPanZoomEnabled();
@@ -1273,65 +1274,44 @@ TabChild::IsRootContentDocument() const
     return !HasAppOwnerApp();
 }
 
 bool
 TabChild::RecvLoadURL(const nsCString& aURI,
                       const BrowserConfiguration& aConfiguration,
                       const ShowInfo& aInfo)
 {
+  if (!mDidLoadURLInit) {
+    mDidLoadURLInit = true;
     if (!InitTabChildGlobal()) {
       return false;
     }
 
     ApplyShowInfo(aInfo);
 
     SetProcessNameToAppName();
 
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     MOZ_ASSERT(swm);
     swm->LoadRegistrations(aConfiguration.serviceWorkerRegistrations());
-
-    nsresult rv = WebNavigation()->LoadURI(NS_ConvertUTF8toUTF16(aURI).get(),
-                                           nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
-                                           nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_OWNER,
-                                           nullptr, nullptr, nullptr);
-    if (NS_FAILED(rv)) {
-        NS_WARNING("WebNavigation()->LoadURI failed. Eating exception, what else can I do?");
-    }
+  }
+
+  nsresult rv =
+    WebNavigation()->LoadURI(NS_ConvertUTF8toUTF16(aURI).get(),
+                             nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
+                             nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_OWNER,
+                             nullptr, nullptr, nullptr);
+  if (NS_FAILED(rv)) {
+      NS_WARNING("WebNavigation()->LoadURI failed. Eating exception, what else can I do?");
+  }
 
 #ifdef MOZ_CRASHREPORTER
-    CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("URL"), aURI);
+  CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("URL"), aURI);
 #endif
 
-    return true;
-}
-
-bool
-TabChild::RecvOpenURI(const URIParams& aURI, const uint32_t& aFlags)
-{
-  nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
-  nsCOMPtr<nsIChannel> channel;
-  nsresult rv =
-    NS_NewChannel(getter_AddRefs(channel),
-                  uri,
-                  nsContentUtils::GetSystemPrincipal(),
-                  nsILoadInfo::SEC_NORMAL,
-                  nsIContentPolicy::TYPE_DOCUMENT);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return true;
-  }
-
-  nsCOMPtr<nsIURILoader> loader = do_GetService("@mozilla.org/uriloader;1");
-  if (NS_WARN_IF(!loader)) {
-    return true;
-  }
-
-  nsCOMPtr<nsIInterfaceRequestor> context(do_QueryInterface(WebNavigation()));
-  loader->OpenURI(channel, aFlags, context);
   return true;
 }
 
 bool
 TabChild::RecvCacheFileDescriptor(const nsString& aPath,
                                   const FileDescriptor& aFileDescriptor)
 {
     MOZ_ASSERT(NS_IsMainThread());
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -308,19 +308,16 @@ public:
   DoUpdateZoomConstraints(const uint32_t& aPresShellId,
                           const ViewID& aViewId,
                           const Maybe<ZoomConstraints>& aConstraints) override;
 
   virtual bool RecvLoadURL(const nsCString& aURI,
                            const BrowserConfiguration& aConfiguration,
                            const ShowInfo& aInfo) override;
 
-  virtual bool RecvOpenURI(const URIParams& aURI,
-                           const uint32_t& aFlags) override;
-
   virtual bool RecvCacheFileDescriptor(const nsString& aPath,
                                        const FileDescriptor& aFileDescriptor)
                                        override;
 
   virtual bool
   RecvShow(const ScreenIntSize& aSize,
            const ShowInfo& aInfo,
            const TextureFactoryIdentifier& aTextureFactoryIdentifier,
@@ -741,16 +738,17 @@ private:
   float mDPI;
   double mDefaultScale;
 
   bool mIPCOpen;
   bool mParentIsActive;
   bool mAsyncPanZoomEnabled;
   CSSSize mUnscaledInnerSize;
   bool mDidSetRealShowInfo;
+  bool mDidLoadURLInit;
 
   AutoTArray<bool, NUMBER_OF_AUDIO_CHANNELS> mAudioChannelsActive;
 
   // APZChild clears this pointer from its destructor, so it shouldn't be a
   // dangling pointer.
   layers::APZChild* mAPZChild;
 
   DISALLOW_EVIL_CONSTRUCTORS(TabChild);
--- a/uriloader/exthandler/nsWebHandlerApp.js
+++ b/uriloader/exthandler/nsWebHandlerApp.js
@@ -81,17 +81,17 @@ nsWebHandlerApp.prototype = {
     // if we have a window context, use the URI loader to load there
     if (aWindowContext) {
       try {
         // getInterface throws if the object doesn't implement the given
         // interface, so this try/catch statement is more of an if.
         // If aWindowContext refers to a remote docshell, send the load
         // request to the correct process.
         aWindowContext.getInterface(Ci.nsIRemoteWindowContext)
-                      .openURI(uriToSend, Ci.nsIURILoader.IS_CONTENT_PREFERRED);
+                      .openURI(uriToSend);
         return;
       } catch (e) {
         if (e.result != Cr.NS_NOINTERFACE) {
           throw e;
         }
       }
 
       // create a channel from this URI
new file mode 100644
--- /dev/null
+++ b/uriloader/exthandler/tests/mochitest/browser_web_protocol_handlers.js
@@ -0,0 +1,76 @@
+let testURL = "http://example.com/browser/" +
+  "uriloader/exthandler/tests/mochitest/protocolHandler.html";
+
+add_task(function*() {
+  // Load a page registering a protocol handler.
+  let browser = gBrowser.selectedBrowser;
+  browser.loadURI(testURL);
+  yield BrowserTestUtils.browserLoaded(browser, testURL);
+
+  // Register the protocol handler by clicking the notificationbar button.
+  let notificationValue = "Protocol Registration: testprotocol";
+  let getNotification = () =>
+    gBrowser.getNotificationBox().getNotificationWithValue(notificationValue);
+  yield BrowserTestUtils.waitForCondition(getNotification);
+  let notification = getNotification();
+  let button =
+    notification.getElementsByClassName("notification-button-default")[0];
+  ok(button, "got registration button");
+  button.click();
+
+  // Set the new handler as default.
+  const protoSvc = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
+                     getService(Ci.nsIExternalProtocolService);
+  let protoInfo = protoSvc.getProtocolHandlerInfo("testprotocol");
+  is(protoInfo.preferredAction, protoInfo.useHelperApp,
+     "using a helper application is the preferred action");
+  ok(!protoInfo.preferredApplicationHandler, "no preferred handler is set");
+  let handlers = protoInfo.possibleApplicationHandlers;
+  is(1, handlers.length, "only one handler registered for testprotocol");
+  let handler = handlers.queryElementAt(0, Ci.nsIHandlerApp);
+  ok(handler instanceof Ci.nsIWebHandlerApp, "the handler is a web handler");
+  is(handler.uriTemplate, "https://example.com/foobar?uri=%s",
+     "correct url template")
+  protoInfo.preferredApplicationHandler = handler;
+  protoInfo.alwaysAskBeforeHandling = false;
+  const handlerSvc = Cc["@mozilla.org/uriloader/handler-service;1"].
+                       getService(Ci.nsIHandlerService);
+  handlerSvc.store(protoInfo);
+
+  // Middle-click a testprotocol link and check the new tab is correct
+  let link = browser.contentDocument.getElementById("link");
+  const expectedURL = "https://example.com/foobar?uri=testprotocol%3Atest";
+
+  let promiseTabOpened =
+    BrowserTestUtils.waitForNewTab(gBrowser, expectedURL);
+  yield BrowserTestUtils.synthesizeMouseAtCenter(link, {button: 1}, browser);
+  let tab = yield promiseTabOpened;
+  gBrowser.selectedTab = tab;
+  is(gURLBar.value, expectedURL,
+     "the expected URL is displayed in the location bar");
+  yield BrowserTestUtils.removeTab(tab);
+
+  // Shift-click the testprotocol link and check the new window.
+  let newWindowPromise = BrowserTestUtils.waitForNewWindow();
+  yield BrowserTestUtils.synthesizeMouseAtCenter(link, {shiftKey: true},
+                                                 browser);
+  let win = yield newWindowPromise;
+  yield BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
+  yield BrowserTestUtils.waitForCondition(() => win.gBrowser.currentURI.spec == expectedURL);
+  is(win.gURLBar.value, expectedURL,
+     "the expected URL is displayed in the location bar");
+  yield BrowserTestUtils.closeWindow(win);
+
+  // Click the testprotocol link and check the url in the current tab.
+  let loadPromise = BrowserTestUtils.browserLoaded(browser);
+  yield BrowserTestUtils.synthesizeMouseAtCenter(link, {}, browser);
+  yield loadPromise;
+  yield BrowserTestUtils.waitForCondition(() => gURLBar.value != testURL);
+  is(gURLBar.value, expectedURL,
+     "the expected URL is displayed in the location bar");
+
+  // Cleanup.
+  protoInfo.preferredApplicationHandler = null;
+  handlers.removeElementAt(0);
+  handlerSvc.store(protoInfo);
+});