Bug 1178526 - Create docshell with packageId from TabContext. r=sicking.
authorHenry <hchang@mozilla.com>
Thu, 29 Oct 2015 00:52:40 +0800
changeset 272712 e96f64e2b9d9dd3dfe9b8ba56d088834d80aea2b
parent 272711 83207d922c913c90ea7efac14dadec37fb0c1c68
child 272713 1ac9ea5105b3eff45f70972d9ac85086b764c214
push id29682
push userkwierso@gmail.com
push dateTue, 17 Nov 2015 01:21:10 +0000
treeherdermozilla-central@a2f83cbe53ac [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssicking
bugs1178526
milestone45.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1178526 - Create docshell with packageId from TabContext. r=sicking.
docshell/base/nsDocShell.cpp
docshell/base/nsDocShell.h
docshell/base/nsIDocShell.idl
dom/ipc/TabChild.cpp
netwerk/ipc/NeckoParent.cpp
netwerk/test/mochitests/mochitest.ini
netwerk/test/mochitests/test_signed_web_packaged_app_origin.html
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -13709,16 +13709,23 @@ nsDocShell::SetIsApp(uint32_t aOwnAppId)
 NS_IMETHODIMP
 nsDocShell::SetIsBrowserInsideApp(uint32_t aContainingAppId)
 {
   mOwnOrContainingAppId = aContainingAppId;
   mFrameType = eFrameTypeBrowser;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsDocShell::SetIsSignedPackage(const nsAString& aSignedPkg)
+{
+  mSignedPkg = aSignedPkg;
+  return NS_OK;
+}
+
 /* [infallible] */ NS_IMETHODIMP
 nsDocShell::GetIsBrowserElement(bool* aIsBrowser)
 {
   *aIsBrowser = (mFrameType == eFrameTypeBrowser);
   return NS_OK;
 }
 
 /* [infallible] */ NS_IMETHODIMP
@@ -13816,16 +13823,19 @@ nsDocShell::GetOriginAttributes()
   if (mOwnOrContainingAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
     attrs.mAppId = mOwnOrContainingAppId;
   }
 
   if (mFrameType == eFrameTypeBrowser) {
     attrs.mInBrowser = true;
   }
 
+  // Bug 1209162 will address the inheritance of each attributes.
+  attrs.mSignedPkg = mSignedPkg;
+
   return attrs;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetOriginAttributes(JS::MutableHandle<JS::Value> aVal)
 {
   JSContext* cx = nsContentUtils::GetCurrentJSContext();
   MOZ_ASSERT(cx);
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -1000,16 +1000,20 @@ protected:
   // containing app frame might be in another process, in which case we won't
   // find it by walking up the docshell hierarchy.)
   uint32_t mOwnOrContainingAppId;
 
   nsString mPaymentRequestId;
 
   nsString GetInheritedPaymentRequestId();
 
+  // The packageId for a signed packaged iff this docShell is created
+  // for a signed package.
+  nsString mSignedPkg;
+
 private:
   nsCString mForcedCharset;
   nsCString mParentCharset;
   int32_t mParentCharsetSource;
   nsCOMPtr<nsIPrincipal> mParentCharsetPrincipal;
   nsTObserverArray<nsWeakPtr> mPrivacyObservers;
   nsTObserverArray<nsWeakPtr> mReflowObservers;
   nsTObserverArray<nsWeakPtr> mScrollObservers;
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -38,17 +38,17 @@ interface nsIPrincipal;
 interface nsIWebBrowserPrint;
 interface nsIPrivacyTransitionObserver;
 interface nsIReflowObserver;
 interface nsIScrollObserver;
 interface nsITabParent;
 
 typedef unsigned long nsLoadFlags;
 
-[scriptable, builtinclass, uuid(41b1cf17-b37b-4a62-9df8-5f67cfecab3f)]
+[scriptable, builtinclass, uuid(63adb599-6dc9-4746-972e-c22e9018020b)]
 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
    * however, the URL dispatcher will go through its normal process of content
    * loading.
    *
@@ -819,16 +819,22 @@ interface nsIDocShell : nsIDocShellTreeI
     * the given ID.  As with setIsApp, you may pass NO_APP_ID or
     * UNKNOWN_APP_ID.
     *
     * As with setIsApp, you may call this more than once, but it's kind of a
     * hack, so be careful.
     */
    void setIsBrowserInsideApp(in unsigned long containingAppId);
 
+   /**
+    * Indicate that this docshell corresponds to a signed package with
+    * the given packageId.
+    */
+   void setIsSignedPackage(in AString packageId);
+
   /**
    * Returns the id of the app associated with this docshell.  If this docshell
    * is an <iframe mozbrowser> inside an <iframe mozapp>, we return the app's
    * appId.
    *
    * We compute this value by walking up the docshell hierarchy until we find a
    * docshell on which setIsApp(x) or setIsBrowserInsideApp(x) was called
    * (ignoring those docshells where x == UNKNOWN_APP_ID).  We return the app
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -825,16 +825,17 @@ TabChild::NotifyTabContextUpdated()
     if (docShell) {
         // nsDocShell will do the right thing if we pass NO_APP_ID or
         // UNKNOWN_APP_ID for aOwnOrContainingAppId.
         if (IsBrowserElement()) {
           docShell->SetIsBrowserInsideApp(BrowserOwnerAppId());
         } else {
           docShell->SetIsApp(OwnAppId());
         }
+        docShell->SetIsSignedPackage(OriginAttributesRef().mSignedPkg);
     }
 }
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TabChild)
   NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome)
   NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome2)
   NS_INTERFACE_MAP_ENTRY(nsIEmbeddingSiteWindow)
   NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChromeFocus)
--- a/netwerk/ipc/NeckoParent.cpp
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -139,17 +139,22 @@ NeckoParent::GetValidatedAppInfo(const S
       if (UsingNeckoIPCSecurity() && tabContext.IsBrowserElement()) {
         // <iframe mozbrowser> which doesn't have an <iframe mozapp> above it.
         // This is not supported now, and we'll need to do a code audit to make
         // sure we can handle it (i.e don't short-circuit using separate
         // namespace if just appID==0)
         continue;
       }
     }
+    if (!aSerialized.mOriginAttributes.mSignedPkg.IsEmpty() &&
+        aSerialized.mOriginAttributes.mSignedPkg != tabContext.OriginAttributesRef().mSignedPkg) {
+      continue;
+    }
     aAttrs = OriginAttributes(appId, inBrowserElement);
+    aAttrs.mSignedPkg = tabContext.OriginAttributesRef().mSignedPkg;
     return nullptr;
   }
 
   if (contextArray.Length() != 0) {
     return "App does not have permission";
   }
 
   if (!UsingNeckoIPCSecurity()) {
@@ -290,17 +295,17 @@ NeckoParent::RecvPFTPChannelConstructor(
 }
 
 PCookieServiceParent*
 NeckoParent::AllocPCookieServiceParent()
 {
   return new CookieServiceParent();
 }
 
-bool 
+bool
 NeckoParent::DeallocPCookieServiceParent(PCookieServiceParent* cs)
 {
   delete cs;
   return true;
 }
 
 PWyciwygChannelParent*
 NeckoParent::AllocPWyciwygChannelParent()
@@ -449,17 +454,17 @@ NeckoParent::DeallocPRtspChannelParent(P
 }
 
 PTCPSocketParent*
 NeckoParent::AllocPTCPSocketParent(const nsString& /* host */,
                                    const uint16_t& /* port */)
 {
   // We actually don't need host/port to construct a TCPSocketParent since
   // TCPSocketParent will maintain an internal nsIDOMTCPSocket instance which
-  // can be delegated to get the host/port. 
+  // can be delegated to get the host/port.
   TCPSocketParent* p = new TCPSocketParent();
   p->AddIPDLReference();
   return p;
 }
 
 bool
 NeckoParent::DeallocPTCPSocketParent(PTCPSocketParent* actor)
 {
--- a/netwerk/test/mochitests/mochitest.ini
+++ b/netwerk/test/mochitests/mochitest.ini
@@ -20,11 +20,13 @@ skip-if = e10s
 skip-if = e10s
 [test_user_agent_updates.html]
 skip-if = e10s
 [test_user_agent_updates_reset.html]
 [test_xhr_method_case.html]
 skip-if = e10s
 [test_signed_web_packaged_app.html]
 skip-if = e10s || buildapp != 'browser'
+[test_signed_web_packaged_app_origin.html]
+skip-if = e10s || buildapp != 'browser'
 [test_web_packaged_app.html]
 [test_loadinfo_redirectchain.html]
 skip-if = buildapp == 'b2g' #no ssl support
new file mode 100644
--- /dev/null
+++ b/netwerk/test/mochitests/test_signed_web_packaged_app_origin.html
@@ -0,0 +1,94 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title> Web packaged app </title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="application/javascript;version=1.7">
+
+// The test is mainly to verify whether the packageId is populated
+// to the child side when loading a signed packaged content.
+// Since we have to have chrome priviledge to test if the node principal
+// has the expected origin attributes, we have to load and run a script
+// in content to get the nodePrincipal and send back to the opener
+// to check the origin.
+
+var Cc = SpecialPowers.Cc;
+var Ci = SpecialPowers.Ci;
+var Cu = SpecialPowers.Cu;
+var Cr = SpecialPowers.Cr;
+
+SpecialPowers.pushPrefEnv(
+  { "set": [["network.http.enable-packaged-apps", true],
+            ["network.http.signed-packages.enabled", true],
+            ["dom.mozBrowserFramesEnabled", true]] },
+  () => SpecialPowers.pushPermissions([
+    { "type": "browser", "allow": 1, "context": document }
+  ], function() {
+    runTest();
+  }));
+
+SimpleTest.waitForExplicitFinish();
+
+function runTest() {
+  var iframe = document.createElement("iframe");
+
+  // 1. We open a remote browser and navigate to a regular content first.
+  iframe.setAttribute('mozbrowser', 'true');
+  iframe.setAttribute('remote', 'true');
+  iframe.setAttribute("src", "http://example.org:80");
+
+  iframe.addEventListener("mozbrowserloadend", function loadend(e) {
+    iframe.removeEventListener("mozbrowserloadend", loadend);
+    ok(true, "Got mozbrowserloadend");
+
+    // 2. Then we navigate to a signed packaged content.
+    iframe.setAttribute("src", "http://mochi.test:8888/tests/netwerk/test/mochitests/signed_web_packaged_app.sjs!//index.html");
+
+    iframe.addEventListener("mozbrowserloadend", function loadend(e) {
+      iframe.removeEventListener("mozbrowserloadend", loadend);
+
+        // 3. Inject a script with chrome priviledge to content to get the nodePrincipal.
+        //    We communicate via message manager with event 'my-e10s-extension-message'.
+        var mm = SpecialPowers.wrap(iframe)
+                              .QueryInterface(Ci.nsIFrameLoaderOwner)
+                              .frameLoader
+                              .messageManager;
+
+        var fsl = mm.QueryInterface(Ci.nsIFrameScriptLoader);
+
+        mm.addMessageListener("get-node-principal-origin", function(message) {
+          let contentOrigin = message.objects.origin;
+          // The expected signedPkg is defined in 'signed_web_packaged_app.sjs'.
+          let kExpectedOrigin =
+            'http://mochi.test:8888^inBrowser=1&signedPkg=09bc9714-7ab6-4320-9d20-fde4c237522c';
+          is(contentOrigin, kExpectedOrigin, 'content origin check: ' + contentOrigin);
+          SimpleTest.finish();
+        });
+
+        // The script we are going to inject to the content.
+        let frameScript =
+`
+function getNodePrincipalOrigin() {
+  sendAsyncMessage("get-node-principal-origin", {}, { origin: content.document.nodePrincipal.origin });
+}
+`;
+        fsl.loadFrameScript("data:,(" + frameScript + ")()", true);
+    });
+  });
+
+  document.body.appendChild(iframe);
+}
+
+</script>
+</pre>
+</body>
+</html>
\ No newline at end of file