Bug 1165466 - Fix up docshell and loadcontext inheriting code in nsIScriptSecurityManager. r=bholley
authorYoshi Huang <allstars.chh@mozilla.com>
Wed, 23 Sep 2015 16:10:21 +0800
changeset 297814 86a7be21dfc8ef0a3c3080d58ef508732ce2d154
parent 297813 fb6f36ba8eb1909f23e1ba5b6c1c8f3e3200bbfc
child 297815 d0e88c95f3c5abb537793b88c16a778c56050cae
push id5392
push userraliiev@mozilla.com
push dateMon, 14 Dec 2015 20:08:23 +0000
treeherdermozilla-beta@16ce8562a975 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley
bugs1165466
milestone44.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 1165466 - Fix up docshell and loadcontext inheriting code in nsIScriptSecurityManager. r=bholley
caps/BasePrincipal.cpp
caps/BasePrincipal.h
caps/moz.build
caps/nsScriptSecurityManager.cpp
caps/tests/mochitest/test_principal_jarprefix_origin_appid_appstatus.html
docshell/base/LoadContext.cpp
docshell/base/LoadContext.h
docshell/base/SerializedLoadContext.cpp
docshell/base/SerializedLoadContext.h
docshell/base/nsDocShell.cpp
docshell/base/nsDocShell.h
docshell/base/nsILoadContext.idl
dom/browser-element/BrowserElementParent.js
dom/ipc/TabParent.cpp
image/test/unit/test_private_channel.js
netwerk/cookie/CookieServiceParent.cpp
netwerk/ipc/NeckoParent.cpp
netwerk/ipc/NeckoParent.h
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/test/unit/head_channels.js
netwerk/test/unit/test_cache_jar.js
netwerk/test/unit/test_cacheflags.js
netwerk/test/unit/test_predictor.js
netwerk/test/unit_ipc/child_app_offline.js
uriloader/prefetch/OfflineCacheUpdateParent.cpp
uriloader/prefetch/OfflineCacheUpdateParent.h
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 sw=2 et 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/BasePrincipal.h"
 
+#include "nsDocShell.h"
 #include "nsIAddonPolicyService.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 
 #include "nsPrincipal.h"
 #include "nsNetUtil.h"
 #include "nsIURIWithPrincipal.h"
@@ -22,16 +23,38 @@
 #include "mozilla/dom/quota/QuotaManager.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "mozilla/dom/URLSearchParams.h"
 
 namespace mozilla {
 
 using dom::URLParams;
 
+void OriginAttributes::InheritFromDocShellParent(const OriginAttributes& aParent)
+{
+  mAppId = aParent.mAppId;
+  mInBrowser = aParent.mInBrowser;
+  mUserContextId = aParent.mUserContextId;
+  mSignedPkg = aParent.mSignedPkg;
+}
+
+bool OriginAttributes::CopyFromLoadContext(nsILoadContext* aLoadContext)
+{
+  OriginAttributes attrs;
+  bool result = aLoadContext->GetOriginAttributes(attrs);
+  NS_ENSURE_TRUE(result, false);
+
+  mAppId = attrs.mAppId;
+  mInBrowser = attrs.mInBrowser;
+  mAddonId = attrs.mAddonId;
+  mUserContextId = attrs.mUserContextId;
+  mSignedPkg = attrs.mSignedPkg;
+  return true;
+}
+
 void
 OriginAttributes::CreateSuffix(nsACString& aStr) const
 {
   MOZ_RELEASE_ASSERT(mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
 
   UniquePtr<URLParams> params(new URLParams());
   nsAutoString value;
 
--- a/caps/BasePrincipal.h
+++ b/caps/BasePrincipal.h
@@ -9,16 +9,17 @@
 
 #include "nsIPrincipal.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsJSPrincipals.h"
 
 #include "mozilla/dom/ChromeUtilsBinding.h"
 
 class nsIContentSecurityPolicy;
+class nsILoadContext;
 class nsIObjectOutputStream;
 class nsIObjectInputStream;
 
 namespace mozilla {
 
 class OriginAttributes : public dom::OriginAttributesDictionary
 {
 public:
@@ -39,16 +40,38 @@ public:
            mUserContextId == aOther.mUserContextId &&
            mSignedPkg == aOther.mSignedPkg;
   }
   bool operator!=(const OriginAttributes& aOther) const
   {
     return !(*this == aOther);
   }
 
+  // The docshell often influences the origin attributes of content loaded
+  // inside of it, and in some cases also influences the origin attributes of
+  // content loaded in child docshells. We say that a given attribute "lives on
+  // the docshell" to indicate that this attribute is specified by the docshell
+  // (if any) associated with a given content document.
+  //
+  // In practice, this usually means that we need to store a copy of those
+  // attributes on each docshell, or provide methods on the docshell to compute
+  // them on-demand.
+  // We could track each of these attributes individually, but since the
+  // majority of the existing origin attributes currently live on the docshell,
+  // it's cleaner to simply store an entire OriginAttributes struct on each
+  // docshell, and selectively copy them to child docshells and content
+  // principals in a manner that implements our desired semantics.
+  //
+  // This method is used to propagate attributes from parent to child
+  // docshells.
+  void InheritFromDocShellParent(const OriginAttributes& aParent);
+
+  // Copy from the origin attributes of the nsILoadContext.
+  bool CopyFromLoadContext(nsILoadContext* aLoadContext);
+
   // Serializes/Deserializes non-default values into the suffix format, i.e.
   // |!key1=value1&key2=value2|. If there are no non-default attributes, this
   // returns an empty string.
   void CreateSuffix(nsACString& aStr) const;
   bool PopulateFromSuffix(const nsACString& aStr);
 
   // Populates the attributes from a string like
   // |uri!key1=value1&key2=value2| and returns the uri without the suffix.
--- a/caps/moz.build
+++ b/caps/moz.build
@@ -39,15 +39,16 @@ UNIFIED_SOURCES += [
     'nsNullPrincipal.cpp',
     'nsNullPrincipalURI.cpp',
     'nsPrincipal.cpp',
     'nsScriptSecurityManager.cpp',
     'nsSystemPrincipal.cpp',
 ]
 
 LOCAL_INCLUDES += [
+    '/docshell/base',
     '/dom/base',
     '/js/xpconnect/src',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -1088,34 +1088,37 @@ nsScriptSecurityManager::GetAppCodebaseP
 }
 
 NS_IMETHODIMP
 nsScriptSecurityManager::
   GetLoadContextCodebasePrincipal(nsIURI* aURI,
                                   nsILoadContext* aLoadContext,
                                   nsIPrincipal** aPrincipal)
 {
-  // XXXbholley - Make this more general in bug 1165466.
   OriginAttributes attrs;
-  aLoadContext->GetAppId(&attrs.mAppId);
-  aLoadContext->GetIsInBrowserElement(&attrs.mInBrowser);
+  bool result = attrs.CopyFromLoadContext(aLoadContext);
+  NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
+
   nsresult rv = MaybeSetAddonIdFromURI(attrs, aURI);
   NS_ENSURE_SUCCESS(rv, rv);
   nsCOMPtr<nsIPrincipal> prin = BasePrincipal::CreateCodebasePrincipal(aURI, attrs);
   prin.forget(aPrincipal);
   return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsScriptSecurityManager::GetDocShellCodebasePrincipal(nsIURI* aURI,
                                                       nsIDocShell* aDocShell,
                                                       nsIPrincipal** aPrincipal)
 {
-  // XXXbholley - Make this more general in bug 1165466.
-  OriginAttributes attrs(aDocShell->GetAppId(), aDocShell->GetIsInBrowserElement());
+  OriginAttributes attrs;
+  nsDocShell* docShell= nsDocShell::Cast(aDocShell);
+  bool result = attrs.CopyFromLoadContext(docShell);
+  NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
+
   nsresult rv = MaybeSetAddonIdFromURI(attrs, aURI);
   NS_ENSURE_SUCCESS(rv, rv);
   nsCOMPtr<nsIPrincipal> prin = BasePrincipal::CreateCodebasePrincipal(aURI, attrs);
   prin.forget(aPrincipal);
   return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
 }
 
 // static
--- a/caps/tests/mochitest/test_principal_jarprefix_origin_appid_appstatus.html
+++ b/caps/tests/mochitest/test_principal_jarprefix_origin_appid_appstatus.html
@@ -189,28 +189,16 @@ var gData = [
     isapp: true,
     child: {
       src: "http://example.org/chrome/",
       isapp: false,
       browser: true,
     },
     test: [ "child-has-different-eo", "child-has-different-appstatus", "child-has-same-appid" ],
   },
-  // app inside a browser is an app.
-  {
-    src: "http://example.org/",
-    isapp: false,
-    browser: true,
-    child: {
-      app: "http://example.org/manifest.webapp",
-      src: "http://example.org/chrome/",
-      isapp: true,
-    },
-    test: [ "child-has-different-eo", "child-has-different-appstatus", "child-has-different-appid" ],
-  },
   // browser inside a browser are two browsers
   {
     src: "http://example.org/",
     isapp: false,
     browser: true,
     child: {
       src: "http://example.org/chrome/",
       isapp: false,
--- a/docshell/base/LoadContext.cpp
+++ b/docshell/base/LoadContext.cpp
@@ -1,15 +1,16 @@
 /* -*- 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/Assertions.h"
+#include "mozilla/BasePrincipal.h"
 #include "mozilla/LoadContext.h"
 
 namespace mozilla {
 
 NS_IMPL_ISUPPORTS(LoadContext, nsILoadContext, nsIInterfaceRequestor)
 
 LoadContext::LoadContext(nsIPrincipal* aPrincipal,
                          nsILoadContext* aOptionalBase)
@@ -17,19 +18,17 @@ LoadContext::LoadContext(nsIPrincipal* a
   , mNestedFrameId(0)
   , mIsContent(true)
   , mUsePrivateBrowsing(false)
   , mUseRemoteTabs(false)
 #ifdef DEBUG
   , mIsNotNull(true)
 #endif
 {
-  MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aPrincipal->GetAppId(&mAppId)));
-  MOZ_ALWAYS_TRUE(
-    NS_SUCCEEDED(aPrincipal->GetIsInBrowserElement(&mIsInBrowserElement)));
+  mOriginAttributes = BasePrincipal::Cast(aPrincipal)->OriginAttributesRef();
 
   if (!aOptionalBase) {
     return;
   }
 
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aOptionalBase->GetIsContent(&mIsContent)));
   MOZ_ALWAYS_TRUE(
     NS_SUCCEEDED(aOptionalBase->GetUsePrivateBrowsing(&mUsePrivateBrowsing)));
@@ -146,28 +145,39 @@ LoadContext::SetRemoteTabs(bool aUseRemo
 
 NS_IMETHODIMP
 LoadContext::GetIsInBrowserElement(bool* aIsInBrowserElement)
 {
   MOZ_ASSERT(mIsNotNull);
 
   NS_ENSURE_ARG_POINTER(aIsInBrowserElement);
 
-  *aIsInBrowserElement = mIsInBrowserElement;
+  *aIsInBrowserElement = mOriginAttributes.mInBrowser;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 LoadContext::GetAppId(uint32_t* aAppId)
 {
   MOZ_ASSERT(mIsNotNull);
 
   NS_ENSURE_ARG_POINTER(aAppId);
 
-  *aAppId = mAppId;
+  *aAppId = mOriginAttributes.mAppId;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+LoadContext::GetOriginAttributes(JS::MutableHandleValue aAttrs)
+{
+  JSContext* cx = nsContentUtils::GetCurrentJSContext();
+  MOZ_ASSERT(cx);
+
+  bool ok = ToJSValue(cx, mOriginAttributes, aAttrs);
+  NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // LoadContext::nsIInterfaceRequestor
 //-----------------------------------------------------------------------------
 NS_IMETHODIMP
 LoadContext::GetInterface(const nsIID& aIID, void** aResult)
--- a/docshell/base/LoadContext.h
+++ b/docshell/base/LoadContext.h
@@ -4,16 +4,17 @@
  * 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/. */
 
 #ifndef LoadContext_h
 #define LoadContext_h
 
 #include "SerializedLoadContext.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/BasePrincipal.h"
 #include "nsIWeakReferenceUtils.h"
 #include "mozilla/dom/Element.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsILoadContext.h"
 
 namespace mozilla {
 
 /**
@@ -37,97 +38,91 @@ public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSILOADCONTEXT
   NS_DECL_NSIINTERFACEREQUESTOR
 
   // AppId/inBrowser arguments override those in SerializedLoadContext provided
   // by child process.
   LoadContext(const IPC::SerializedLoadContext& aToCopy,
               dom::Element* aTopFrameElement,
-              uint32_t aAppId, bool aInBrowser)
+              OriginAttributes& aAttrs)
     : mTopFrameElement(do_GetWeakReference(aTopFrameElement))
     , mNestedFrameId(0)
-    , mAppId(aAppId)
     , mIsContent(aToCopy.mIsContent)
     , mUsePrivateBrowsing(aToCopy.mUsePrivateBrowsing)
     , mUseRemoteTabs(aToCopy.mUseRemoteTabs)
-    , mIsInBrowserElement(aInBrowser)
+    , mOriginAttributes(aAttrs)
 #ifdef DEBUG
     , mIsNotNull(aToCopy.mIsNotNull)
 #endif
   {
   }
 
   // AppId/inBrowser arguments override those in SerializedLoadContext provided
   // by child process.
   LoadContext(const IPC::SerializedLoadContext& aToCopy,
               uint64_t aNestedFrameId,
-              uint32_t aAppId, bool aInBrowser)
+              OriginAttributes& aAttrs)
     : mTopFrameElement(nullptr)
     , mNestedFrameId(aNestedFrameId)
-    , mAppId(aAppId)
     , mIsContent(aToCopy.mIsContent)
     , mUsePrivateBrowsing(aToCopy.mUsePrivateBrowsing)
     , mUseRemoteTabs(aToCopy.mUseRemoteTabs)
-    , mIsInBrowserElement(aInBrowser)
+    , mOriginAttributes(aAttrs)
 #ifdef DEBUG
     , mIsNotNull(aToCopy.mIsNotNull)
 #endif
   {
   }
 
   LoadContext(dom::Element* aTopFrameElement,
-              uint32_t aAppId,
               bool aIsContent,
               bool aUsePrivateBrowsing,
               bool aUseRemoteTabs,
-              bool aIsInBrowserElement)
+              OriginAttributes& aAttrs)
     : mTopFrameElement(do_GetWeakReference(aTopFrameElement))
     , mNestedFrameId(0)
-    , mAppId(aAppId)
     , mIsContent(aIsContent)
     , mUsePrivateBrowsing(aUsePrivateBrowsing)
     , mUseRemoteTabs(aUseRemoteTabs)
-    , mIsInBrowserElement(aIsInBrowserElement)
+    , mOriginAttributes(aAttrs)
 #ifdef DEBUG
     , mIsNotNull(true)
 #endif
   {
   }
 
   // Constructor taking reserved appId for the safebrowsing cookie.
   explicit LoadContext(uint32_t aAppId)
     : mTopFrameElement(nullptr)
     , mNestedFrameId(0)
-    , mAppId(aAppId)
     , mIsContent(false)
     , mUsePrivateBrowsing(false)
     , mUseRemoteTabs(false)
-    , mIsInBrowserElement(false)
+    , mOriginAttributes(aAppId, false)
 #ifdef DEBUG
     , mIsNotNull(true)
 #endif
   {
   }
 
   // Constructor for creating a LoadContext with a given principal's appId and
   // browser flag.
   explicit LoadContext(nsIPrincipal* aPrincipal,
                        nsILoadContext* aOptionalBase = nullptr);
 
 private:
   ~LoadContext() {}
 
   nsWeakPtr mTopFrameElement;
   uint64_t mNestedFrameId;
-  uint32_t mAppId;
   bool mIsContent;
   bool mUsePrivateBrowsing;
   bool mUseRemoteTabs;
-  bool mIsInBrowserElement;
+  OriginAttributes mOriginAttributes;
 #ifdef DEBUG
   bool mIsNotNull;
 #endif
 };
 
 } // namespace mozilla
 
 #endif // LoadContext_h
--- a/docshell/base/SerializedLoadContext.cpp
+++ b/docshell/base/SerializedLoadContext.cpp
@@ -57,24 +57,23 @@ void
 SerializedLoadContext::Init(nsILoadContext* aLoadContext)
 {
   if (aLoadContext) {
     mIsNotNull = true;
     mIsPrivateBitValid = true;
     aLoadContext->GetIsContent(&mIsContent);
     aLoadContext->GetUsePrivateBrowsing(&mUsePrivateBrowsing);
     aLoadContext->GetUseRemoteTabs(&mUseRemoteTabs);
-    aLoadContext->GetAppId(&mAppId);
-    aLoadContext->GetIsInBrowserElement(&mIsInBrowserElement);
+    if (!aLoadContext->GetOriginAttributes(mOriginAttributes)) {
+      NS_WARNING("GetOriginAttributes failed");
+    }
   } else {
     mIsNotNull = false;
     mIsPrivateBitValid = false;
     // none of below values really matter when mIsNotNull == false:
     // we won't be GetInterfaced to nsILoadContext
     mIsContent = true;
     mUsePrivateBrowsing = false;
     mUseRemoteTabs = false;
-    mAppId = 0;
-    mIsInBrowserElement = false;
   }
 }
 
 } // namespace IPC
--- a/docshell/base/SerializedLoadContext.h
+++ b/docshell/base/SerializedLoadContext.h
@@ -4,16 +4,17 @@
  * 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/. */
 
 #ifndef SerializedLoadContext_h
 #define SerializedLoadContext_h
 
 #include "base/basictypes.h"
 #include "ipc/IPCMessageUtils.h"
+#include "mozilla/BasePrincipal.h"
 
 class nsILoadContext;
 
 /*
  *  This file contains the IPC::SerializedLoadContext class, which is used to
  *  copy data across IPDL from Child process contexts so it is available in the
  *  Parent.
  */
@@ -43,48 +44,50 @@ public:
   // used to indicate if child-side LoadContext * was null.
   bool mIsNotNull;
   // used to indicate if child-side mUsePrivateBrowsing flag is valid, even if
   // mIsNotNull is false, i.e., child LoadContext was null.
   bool mIsPrivateBitValid;
   bool mIsContent;
   bool mUsePrivateBrowsing;
   bool mUseRemoteTabs;
-  bool mIsInBrowserElement;
-  uint32_t mAppId;
+  mozilla::OriginAttributes mOriginAttributes;
 };
 
 // Function to serialize over IPDL
 template<>
 struct ParamTraits<SerializedLoadContext>
 {
   typedef SerializedLoadContext paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
+    nsAutoCString suffix;
+    aParam.mOriginAttributes.CreateSuffix(suffix);
+
     WriteParam(aMsg, aParam.mIsNotNull);
     WriteParam(aMsg, aParam.mIsContent);
     WriteParam(aMsg, aParam.mIsPrivateBitValid);
     WriteParam(aMsg, aParam.mUsePrivateBrowsing);
     WriteParam(aMsg, aParam.mUseRemoteTabs);
-    WriteParam(aMsg, aParam.mAppId);
-    WriteParam(aMsg, aParam.mIsInBrowserElement);
+    WriteParam(aMsg, suffix);
   }
 
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
+    nsAutoCString suffix;
     if (!ReadParam(aMsg, aIter, &aResult->mIsNotNull) ||
         !ReadParam(aMsg, aIter, &aResult->mIsContent) ||
         !ReadParam(aMsg, aIter, &aResult->mIsPrivateBitValid) ||
         !ReadParam(aMsg, aIter, &aResult->mUsePrivateBrowsing) ||
         !ReadParam(aMsg, aIter, &aResult->mUseRemoteTabs) ||
-        !ReadParam(aMsg, aIter, &aResult->mAppId) ||
-        !ReadParam(aMsg, aIter, &aResult->mIsInBrowserElement)) {
+        !ReadParam(aMsg, aIter, &suffix)) {
       return false;
     }
+    aResult->mOriginAttributes.PopulateFromSuffix(suffix);
 
     return true;
   }
 };
 
 } // namespace IPC
 
 #endif // SerializedLoadContext_h
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -9383,27 +9383,17 @@ nsDocShell::JustStartedNetworkLoad()
 {
   return mDocumentRequest && mDocumentRequest != GetCurrentDocChannel();
 }
 
 nsresult
 nsDocShell::CreatePrincipalFromReferrer(nsIURI* aReferrer,
                                         nsIPrincipal** aResult)
 {
-  nsresult rv;
-
-  uint32_t appId;
-  rv = GetAppId(&appId);
-  NS_ENSURE_SUCCESS(rv, rv);
-  bool isInBrowserElement;
-  rv = GetIsInBrowserElement(&isInBrowserElement);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // TODO: Bug 1165466 - Pass mOriginAttributes directly.
-  OriginAttributes attrs(appId, isInBrowserElement);
+  OriginAttributes attrs = GetOriginAttributes();
   nsCOMPtr<nsIPrincipal> prin =
     BasePrincipal::CreateCodebasePrincipal(aReferrer, attrs);
   prin.forget(aResult);
 
   return *aResult ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
@@ -13710,16 +13700,48 @@ nsDocShell::GetAppId(uint32_t* aAppId)
   if (!parent) {
     *aAppId = nsIScriptSecurityManager::NO_APP_ID;
     return NS_OK;
   }
 
   return parent->GetAppId(aAppId);
 }
 
+OriginAttributes
+nsDocShell::GetOriginAttributes()
+{
+  OriginAttributes attrs;
+  nsRefPtr<nsDocShell> parent = GetParentDocshell();
+  if (parent) {
+    attrs.InheritFromDocShellParent(parent->GetOriginAttributes());
+  }
+
+  if (mOwnOrContainingAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
+    attrs.mAppId = mOwnOrContainingAppId;
+  }
+
+  if (mFrameType == eFrameTypeBrowser) {
+    attrs.mInBrowser = true;
+  }
+
+  return attrs;
+}
+
+NS_IMETHODIMP
+nsDocShell::GetOriginAttributes(JS::MutableHandle<JS::Value> aVal)
+{
+  JSContext* cx = nsContentUtils::GetCurrentJSContext();
+  MOZ_ASSERT(cx);
+
+  OriginAttributes attrs = GetOriginAttributes();
+  bool ok = ToJSValue(cx, attrs, aVal);
+  NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
+  return NS_OK;
+}
+
 NS_IMETHODIMP
 nsDocShell::GetAppManifestURL(nsAString& aAppManifestURL)
 {
   uint32_t appId = nsIDocShell::GetAppId();
   if (appId != nsIScriptSecurityManager::NO_APP_ID &&
       appId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
     nsCOMPtr<nsIAppsService> appsService =
       do_GetService(APPS_SERVICE_CONTRACTID);
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -13,16 +13,17 @@
 #include "nsIDocShellTreeItem.h"
 #include "nsIBaseWindow.h"
 #include "nsINetworkInterceptController.h"
 #include "nsIScrollable.h"
 #include "nsITextScroll.h"
 #include "nsIContentViewerContainer.h"
 #include "nsIDOMStorageManager.h"
 #include "nsDocLoader.h"
+#include "mozilla/BasePrincipal.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/WeakPtr.h"
 #include "mozilla/TimeStamp.h"
 #include "GeckoProfiler.h"
 #include "mozilla/dom/ProfileTimelineMarkerBinding.h"
 #include "mozilla/LinkedList.h"
 #include "jsapi.h"
 
@@ -225,16 +226,17 @@ public:
   NS_IMETHOD GetNestedFrameId(uint64_t*) override;
   NS_IMETHOD IsAppOfType(uint32_t, bool*) override;
   NS_IMETHOD GetIsContent(bool*) override;
   NS_IMETHOD GetUsePrivateBrowsing(bool*) override;
   NS_IMETHOD SetUsePrivateBrowsing(bool) override;
   NS_IMETHOD SetPrivateBrowsing(bool) override;
   NS_IMETHOD GetUseRemoteTabs(bool*) override;
   NS_IMETHOD SetRemoteTabs(bool) override;
+  NS_IMETHOD GetOriginAttributes(JS::MutableHandle<JS::Value>) override;
 
   // Restores a cached presentation from history (mLSHE).
   // This method swaps out the content viewer and simulates loads for
   // subframes. It then simulates the completion of the toplevel load.
   nsresult RestoreFromHistory();
 
   // Perform a URI load from a refresh timer. This is just like the
   // ForceRefreshURI method on nsIRefreshURI, but makes sure to take
@@ -263,16 +265,18 @@ public:
   void NotifyAsyncPanZoomStopped();
 
   void SetInFrameSwap(bool aInSwap)
   {
     mInFrameSwap = aInSwap;
   }
   bool InFrameSwap();
 
+  mozilla::OriginAttributes GetOriginAttributes();
+
 private:
   // An observed docshell wrapper is created when recording markers is enabled.
   mozilla::UniquePtr<mozilla::ObservedDocShell> mObserved;
   bool IsObserved() const { return !!mObserved; }
 
   // It is necessary to allow adding a timeline marker wherever a docshell
   // instance is available. This operation happens frequently and needs to
   // be very fast, so instead of using a Map or having to search for some
@@ -290,16 +294,21 @@ private:
     nsDocShell*, UniquePtr<AbstractTimelineMarker>&);
 
 public:
   // Tell the favicon service that aNewURI has the same favicon as aOldURI.
   static void CopyFavicon(nsIURI* aOldURI,
                           nsIURI* aNewURI,
                           bool aInPrivateBrowsing);
 
+  static nsDocShell* Cast(nsIDocShell* aDocShell)
+  {
+    return static_cast<nsDocShell*>(aDocShell);
+  }
+
 protected:
   virtual ~nsDocShell();
   virtual void DestroyChildren() override;
 
   // Content Viewer Management
   nsresult EnsureContentViewer();
   // aPrincipal can be passed in if the caller wants. If null is
   // passed in, the about:blank principal will end up being used.
--- a/docshell/base/nsILoadContext.idl
+++ b/docshell/base/nsILoadContext.idl
@@ -4,22 +4,31 @@
  * 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 nsIDOMWindow;
 interface nsIDOMElement;
 
+%{C++
+#ifdef MOZILLA_INTERNAL_API
+#include "mozilla/BasePrincipal.h" // for OriginAttributes
+#include "mozilla/dom/ScriptSettings.h" // for AutoJSAPI
+#include "xpcpublic.h" // for PrivilegedJunkScope
+#include "nsContentUtils.h" // for IsSystemPrincipal
+#endif
+%}
+
 /**
  * An nsILoadContext represents the context of a load.  This interface
  * can be queried for various information about where the load is
  * happening.
  */
-[scriptable, uuid(6ec837fa-af93-4350-bbb8-0985d54c74ca)]
+[scriptable, uuid(1220e340-b337-4c35-aaa1-f51362763621)]
 interface nsILoadContext : nsISupports
 {
   /**
    * associatedWindow is the window with which the load is associated, if any.
    * Note that the load may be triggered by a document which is different from
    * the document in associatedWindow, and in fact the source of the load need
    * not be same-origin with the document in associatedWindow.  This attribute
    * may be null if there is no associated window.
@@ -115,9 +124,44 @@ interface nsILoadContext : nsISupports
   readonly attribute boolean isInBrowserElement;
 
   /**
    * Returns the app id of the app the load is occurring is in. Returns
    * nsIScriptSecurityManager::NO_APP_ID if the load is not part of an app.
    */
   readonly attribute unsigned long appId;
 
+  /**
+   * A dictionary of the non-default origin attributes associated with this
+   * nsILoadContext.
+   */
+  readonly attribute jsval originAttributes;
+
+%{C++
+#ifdef MOZILLA_INTERNAL_API
+  /**
+   * The C++ getter for origin attributes.
+   */
+  bool GetOriginAttributes(mozilla::OriginAttributes& aAttrs)
+  {
+    mozilla::dom::AutoJSAPI jsapi;
+    bool ok = jsapi.Init(xpc::PrivilegedJunkScope());
+    NS_ENSURE_TRUE(ok, false);
+    JS::Rooted<JS::Value> v(jsapi.cx());
+    nsresult rv = GetOriginAttributes(&v);
+    NS_ENSURE_SUCCESS(rv, false);
+    MOZ_ASSERT(v.isObject());
+    JS::Rooted<JSObject*> obj(jsapi.cx(), &v.toObject());
+
+    // If we're JS-implemented, the object will be left in a different (System-Principaled)
+    // scope, so we may need to enter its compartment.
+    MOZ_ASSERT(nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(obj)));
+    JSAutoCompartment ac(jsapi.cx(), obj);
+
+    mozilla::OriginAttributes attrs;
+    ok = attrs.Init(jsapi.cx(), v);
+    NS_ENSURE_TRUE(ok, false);
+    aAttrs = attrs;
+    return true;
+  }
+#endif
+%}
 };
--- a/dom/browser-element/BrowserElementParent.js
+++ b/dom/browser-element/BrowserElementParent.js
@@ -834,25 +834,22 @@ BrowserElementParent.prototype = {
       // newURI can throw on malformed URIs.
       try {
         referrer = Services.io.newURI(_options.referrer, null, null);
       }
       catch(e) {
         debug('Malformed referrer -- ' + e);
       }
 
-      // TODO Bug 1165466: use originAttributes from nsILoadContext.
-      let attrs = {appId: this._frameLoader.loadContext.appId,
-                   inBrowser: this._frameLoader.loadContext.isInBrowserElement};
       // This simply returns null if there is no principal available
       // for the requested uri. This is an acceptable fallback when
       // calling newChannelFromURI2.
       principal =
         Services.scriptSecurityManager.createCodebasePrincipal(
-          referrer, attrs);
+          referrer, this._frameLoader.loadContext.originAttributes);
     }
 
     debug('Using principal? ' + !!principal);
 
     let channel = 
       Services.io.newChannelFromURI2(url,
                                      null,       // No document. 
                                      principal,  // Loading principal
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -2969,22 +2969,23 @@ TabParent::RecvSetAllowedTouchBehavior(c
 
 already_AddRefed<nsILoadContext>
 TabParent::GetLoadContext()
 {
   nsCOMPtr<nsILoadContext> loadContext;
   if (mLoadContext) {
     loadContext = mLoadContext;
   } else {
+    // TODO Bug 1191740 - Add OriginAttributes in TabContext
+    OriginAttributes attrs = OriginAttributes(OwnOrContainingAppId(), IsBrowserElement());
     loadContext = new LoadContext(GetOwnerElement(),
-                                  OwnOrContainingAppId(),
                                   true /* aIsContent */,
                                   mChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW,
                                   mChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW,
-                                  IsBrowserElement());
+                                  attrs);
     mLoadContext = loadContext;
   }
   return loadContext.forget();
 }
 
 NS_IMETHODIMP
 TabParent::InjectTouchEvent(const nsAString& aType,
                             uint32_t* aIdentifiers,
@@ -3343,16 +3344,17 @@ public:
   NS_IMETHOD GetNestedFrameId(uint64_t*) NO_IMPL
   NS_IMETHOD IsAppOfType(uint32_t, bool*) NO_IMPL
   NS_IMETHOD GetIsContent(bool*) NO_IMPL
   NS_IMETHOD GetUsePrivateBrowsing(bool*) NO_IMPL
   NS_IMETHOD SetUsePrivateBrowsing(bool) NO_IMPL
   NS_IMETHOD SetPrivateBrowsing(bool) NO_IMPL
   NS_IMETHOD GetIsInBrowserElement(bool*) NO_IMPL
   NS_IMETHOD GetAppId(uint32_t*) NO_IMPL
+  NS_IMETHOD GetOriginAttributes(JS::MutableHandleValue) NO_IMPL
   NS_IMETHOD GetUseRemoteTabs(bool*) NO_IMPL
   NS_IMETHOD SetRemoteTabs(bool) NO_IMPL
 #undef NO_IMPL
 
 protected:
   ~FakeChannel() {}
 
   nsCOMPtr<nsIURI> mUri;
--- a/image/test/unit/test_private_channel.js
+++ b/image/test/unit/test_private_channel.js
@@ -41,17 +41,18 @@ NotificationCallbacks.prototype = {
         iid.equals(Ci.nsILoadContext))
       return this;
     throw Cr.NS_ERROR_NO_INTERFACE;
   },
   getInterface: function(iid) {
     if (iid.equals(Ci.nsILoadContext))
       return this;
     throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  },
+  originAttributes: {}
 };
 
 var gImgPath = 'http://localhost:' + server.identity.primaryPort + '/image.png';
 
 function setup_chan(path, isPrivate, callback) {
   var uri = gIoService.newURI(gImgPath, null, null);
   var chan = gIoService.newChannelFromURI2(uri,
                                            null,      // aLoadingNode
--- a/netwerk/cookie/CookieServiceParent.cpp
+++ b/netwerk/cookie/CookieServiceParent.cpp
@@ -70,27 +70,29 @@ CookieServiceParent::GetAppInfoFromParam
                                           uint32_t& aAppId,
                                           bool& aIsInBrowserElement,
                                           bool& aIsPrivate)
 {
   aAppId = NECKO_NO_APP_ID;
   aIsInBrowserElement = false;
   aIsPrivate = false;
 
+  OriginAttributes attrs;
   const char* error = NeckoParent::GetValidatedAppInfo(aLoadContext,
                                                        Manager()->Manager(),
-                                                       &aAppId,
-                                                       &aIsInBrowserElement);
+                                                       attrs);
   if (error) {
     NS_WARNING(nsPrintfCString("CookieServiceParent: GetAppInfoFromParams: "
                                "FATAL error: %s: KILLING CHILD PROCESS\n",
                                error).get());
     return false;
   }
 
+  aAppId = attrs.mAppId;
+  aIsInBrowserElement = attrs.mInBrowser;
   if (aLoadContext.IsPrivateBitValid()) {
     aIsPrivate = aLoadContext.mUsePrivateBrowsing;
   }
   return true;
 }
 
 CookieServiceParent::CookieServiceParent()
 {
--- a/netwerk/ipc/NeckoParent.cpp
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -39,16 +39,17 @@
 #include "nsAuthInformationHolder.h"
 #include "nsIAuthPromptCallback.h"
 #include "nsPrincipal.h"
 #include "nsIOService.h"
 #include "nsINetworkPredictor.h"
 #include "mozilla/net/OfflineObserver.h"
 #include "nsISpeculativeConnect.h"
 
+using mozilla::OriginAttributes;
 using mozilla::dom::ContentParent;
 using mozilla::dom::TabContext;
 using mozilla::dom::TabParent;
 using mozilla::net::PTCPSocketParent;
 using mozilla::dom::TCPSocketParent;
 using mozilla::net::PTCPServerSocketParent;
 using mozilla::dom::TCPServerSocketParent;
 using mozilla::net::PUDPSocketParent;
@@ -104,35 +105,32 @@ PBOverrideStatusFromLoadContext(const Se
       kPBOverride_NotPrivate;
   }
   return kPBOverride_Unset;
 }
 
 const char*
 NeckoParent::GetValidatedAppInfo(const SerializedLoadContext& aSerialized,
                                  PContentParent* aContent,
-                                 uint32_t* aAppId,
-                                 bool* aInBrowserElement)
+                                 OriginAttributes& aAttrs)
 {
-  *aAppId = NECKO_UNKNOWN_APP_ID;
-  *aInBrowserElement = false;
-
   if (UsingNeckoIPCSecurity()) {
     if (!aSerialized.IsNotNull()) {
       return "SerializedLoadContext from child is null";
     }
   }
 
   nsTArray<TabContext> contextArray =
     static_cast<ContentParent*>(aContent)->GetManagedTabContext();
   for (uint32_t i = 0; i < contextArray.Length(); i++) {
     TabContext tabContext = contextArray[i];
     uint32_t appId = tabContext.OwnOrContainingAppId();
-    bool inBrowserElement = aSerialized.IsNotNull() ? aSerialized.mIsInBrowserElement
-                                                    : tabContext.IsBrowserElement();
+    bool inBrowserElement = aSerialized.IsNotNull() ?
+                              aSerialized.mOriginAttributes.mInBrowser :
+                              tabContext.IsBrowserElement();
 
     if (appId == NECKO_UNKNOWN_APP_ID) {
       continue;
     }
     // We may get appID=NO_APP if child frame is neither a browser nor an app
     if (appId == NECKO_NO_APP_ID) {
       if (tabContext.HasOwnApp()) {
         continue;
@@ -140,72 +138,67 @@ 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;
       }
     }
-    *aAppId = appId;
-    *aInBrowserElement = inBrowserElement;
+    aAttrs = OriginAttributes(appId, inBrowserElement);
     return nullptr;
   }
 
   if (contextArray.Length() != 0) {
     return "App does not have permission";
   }
 
   if (!UsingNeckoIPCSecurity()) {
     // We are running xpcshell tests
     if (aSerialized.IsNotNull()) {
-      *aAppId = aSerialized.mAppId;
-      *aInBrowserElement = aSerialized.mIsInBrowserElement;
+      aAttrs = aSerialized.mOriginAttributes;
     } else {
-      *aAppId = NECKO_NO_APP_ID;
+      aAttrs = OriginAttributes(NECKO_NO_APP_ID, false);
     }
     return nullptr;
   }
 
   return "ContentParent does not have any PBrowsers";
 }
 
 const char *
 NeckoParent::CreateChannelLoadContext(const PBrowserOrId& aBrowser,
                                       PContentParent* aContent,
                                       const SerializedLoadContext& aSerialized,
                                       nsCOMPtr<nsILoadContext> &aResult)
 {
-  uint32_t appId = NECKO_UNKNOWN_APP_ID;
-  bool inBrowser = false;
-  const char* error = GetValidatedAppInfo(aSerialized, aContent, &appId, &inBrowser);
+  OriginAttributes attrs;
+  const char* error = GetValidatedAppInfo(aSerialized, aContent, attrs);
   if (error) {
     return error;
   }
 
   // if !UsingNeckoIPCSecurity(), we may not have a LoadContext to set. This is
   // the common case for most xpcshell tests.
   if (aSerialized.IsNotNull()) {
     switch (aBrowser.type()) {
       case PBrowserOrId::TPBrowserParent:
       {
         nsRefPtr<TabParent> tabParent =
           TabParent::GetFrom(aBrowser.get_PBrowserParent());
         dom::Element* topFrameElement = nullptr;
         if (tabParent) {
           topFrameElement = tabParent->GetOwnerElement();
         }
-        aResult = new LoadContext(aSerialized, topFrameElement,
-                                  appId, inBrowser);
+        aResult = new LoadContext(aSerialized, topFrameElement, attrs);
         break;
       }
       case PBrowserOrId::TTabId:
       {
-        aResult = new LoadContext(aSerialized, aBrowser.get_TabId(),
-                                  appId, inBrowser);
+        aResult = new LoadContext(aSerialized, aBrowser.get_TabId(), attrs);
         break;
       }
       default:
         MOZ_CRASH();
     }
   }
 
   return nullptr;
@@ -561,17 +554,17 @@ NeckoParent::AllocPRemoteOpenFileParent(
     nsTArray<TabContext> contextArray =
       static_cast<ContentParent*>(Manager())->GetManagedTabContext();
     for (uint32_t i = 0; i < contextArray.Length(); i++) {
       TabContext tabContext = contextArray[i];
       uint32_t appId = tabContext.OwnOrContainingAppId();
       // Note: this enforces that SerializedLoadContext.appID is one of the apps
       // in the child process, but there's currently no way to verify the
       // request is not from a different app in that process.
-      if (appId == aSerialized.mAppId) {
+      if (appId == aSerialized.mOriginAttributes.mAppId) {
         nsresult rv = appsService->GetAppByLocalId(appId, getter_AddRefs(mozApp));
         if (NS_FAILED(rv) || !mozApp) {
           break;
         }
         rv = mozApp->HasPermission("webapps-manage", &hasManage);
         if (NS_FAILED(rv)) {
           break;
         }
@@ -873,21 +866,22 @@ NeckoParent::RecvPredPredict(const ipc::
                              const uint32_t& aReason,
                              const SerializedLoadContext& aLoadContext,
                              const bool& hasVerifier)
 {
   nsCOMPtr<nsIURI> targetURI = DeserializeURI(aTargetURI);
   nsCOMPtr<nsIURI> sourceURI = DeserializeURI(aSourceURI);
 
   // We only actually care about the loadContext.mPrivateBrowsing, so we'll just
-  // pass dummy params for nestFrameId, inBrowser and appId
+  // pass dummy params for nestFrameId, and originAttributes.
   uint64_t nestedFrameId = 0;
+  OriginAttributes attrs(NECKO_UNKNOWN_APP_ID, false);
   nsCOMPtr<nsILoadContext> loadContext;
   if (aLoadContext.IsNotNull()) {
-    loadContext = new LoadContext(aLoadContext, nestedFrameId, NECKO_UNKNOWN_APP_ID, false);
+    loadContext = new LoadContext(aLoadContext, nestedFrameId, attrs);
   }
 
   // Get the current predictor
   nsresult rv = NS_OK;
   nsCOMPtr<nsINetworkPredictor> predictor =
     do_GetService("@mozilla.org/network/predictor;1", &rv);
   NS_ENSURE_SUCCESS(rv, false);
 
@@ -904,21 +898,22 @@ NeckoParent::RecvPredLearn(const ipc::UR
                            const ipc::OptionalURIParams& aSourceURI,
                            const uint32_t& aReason,
                            const SerializedLoadContext& aLoadContext)
 {
   nsCOMPtr<nsIURI> targetURI = DeserializeURI(aTargetURI);
   nsCOMPtr<nsIURI> sourceURI = DeserializeURI(aSourceURI);
 
   // We only actually care about the loadContext.mPrivateBrowsing, so we'll just
-  // pass dummy params for nestFrameId, inBrowser and appId
+  // pass dummy params for nestFrameId, and originAttributes;
   uint64_t nestedFrameId = 0;
+  OriginAttributes attrs(NECKO_UNKNOWN_APP_ID, false);
   nsCOMPtr<nsILoadContext> loadContext;
   if (aLoadContext.IsNotNull()) {
-    loadContext = new LoadContext(aLoadContext, nestedFrameId, NECKO_UNKNOWN_APP_ID, false);
+    loadContext = new LoadContext(aLoadContext, nestedFrameId, attrs);
   }
 
   // Get the current predictor
   nsresult rv = NS_OK;
   nsCOMPtr<nsINetworkPredictor> predictor =
     do_GetService("@mozilla.org/network/predictor;1", &rv);
   NS_ENSURE_SUCCESS(rv, false);
 
--- a/netwerk/ipc/NeckoParent.h
+++ b/netwerk/ipc/NeckoParent.h
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et 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/BasePrincipal.h"
 #include "mozilla/net/PNeckoParent.h"
 #include "mozilla/net/NeckoCommon.h"
 #include "mozilla/net/OfflineObserver.h"
 #include "nsIAuthPrompt2.h"
 #include "nsINetworkPredictor.h"
 #include "nsNetUtil.h"
 
 #ifndef mozilla_net_NeckoParent_h
@@ -33,18 +34,17 @@ class NeckoParent
 public:
   NeckoParent();
   virtual ~NeckoParent();
 
   MOZ_WARN_UNUSED_RESULT
   static const char *
   GetValidatedAppInfo(const SerializedLoadContext& aSerialized,
                       PContentParent* aBrowser,
-                      uint32_t* aAppId,
-                      bool* aInBrowserElement);
+                      mozilla::OriginAttributes& aAttrs);
 
   /*
    * Creates LoadContext for parent-side of an e10s channel.
    *
    * PContentParent corresponds to the process that is requesting the load.
    *
    * Returns null if successful, or an error string if failed.
    */
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -516,23 +516,21 @@ HttpChannelParent::DoAsyncOpen(  const U
                                                 getter_AddRefs(appCache));
       if (NS_SUCCEEDED(rv)) {
         appCacheChan->SetApplicationCache(appCache);
         setChooseApplicationCache = false;
       }
     }
 
     if (setChooseApplicationCache) {
-      bool inBrowser = false;
+      OriginAttributes attrs;
       if (mLoadContext) {
-        mLoadContext->GetIsInBrowserElement(&inBrowser);
+        attrs.CopyFromLoadContext(mLoadContext);
       }
 
-      // TODO: Bug 1165466 - use originAttribute in nsILoadContext.
-      OriginAttributes attrs(appId, inBrowser);
       nsCOMPtr<nsIPrincipal> principal =
         BasePrincipal::CreateCodebasePrincipal(uri, attrs);
 
       bool chooseAppCache = false;
       // This works because we've already called SetNotificationCallbacks and
       // done mPBOverride logic by this point.
       chooseAppCache = NS_ShouldCheckAppCache(principal, NS_UsePrivateBrowsing(mChannel));
 
--- a/netwerk/test/unit/head_channels.js
+++ b/netwerk/test/unit/head_channels.js
@@ -206,16 +206,20 @@ ChannelEventSink.prototype = {
 
 /**
  * Class that implements nsILoadContext.  Use it as callbacks for channel when
  * test needs it.
  */
 function LoadContextCallback(appId, inBrowserElement, isPrivate, isContent) {
   this.appId = appId;
   this.isInBrowserElement = inBrowserElement;
+  this.originAttributes = {
+    appId: appId,
+    inBrowser: inBrowserElement
+  };
   this.usePrivateBrowsing = isPrivate;
   this.isContent = isContent;
 }
 
 LoadContextCallback.prototype = {
   associatedWindow: null,
   topWindow : null,
   isAppOfType: function(appType) {
--- a/netwerk/test/unit/test_cache_jar.js
+++ b/netwerk/test/unit/test_cache_jar.js
@@ -26,16 +26,20 @@ function makeChan(url, appId, inBrowser)
                              null,      // aLoadingNode
                              Services.scriptSecurityManager.getSystemPrincipal(),
                              null,      // aTriggeringPrincipal
                              Ci.nsILoadInfo.SEC_NORMAL,
                              Ci.nsIContentPolicy.TYPE_OTHER).QueryInterface(Ci.nsIHttpChannel);
   chan.notificationCallbacks = {
     appId: appId,
     isInBrowserElement: inBrowser,
+    originAttributes: {
+      appId: appId,
+      inBrowser: inBrowser,
+    },
     QueryInterface: function(iid) {
       if (iid.equals(Ci.nsILoadContext))
         return this;
       throw Cr.NS_ERROR_NO_INTERFACE;
     },
     getInterface: function(iid) { return this.QueryInterface(iid); }
   };
   return chan;
--- a/netwerk/test/unit/test_cacheflags.js
+++ b/netwerk/test/unit/test_cacheflags.js
@@ -28,17 +28,19 @@ LoadContext.prototype = {
       return this;
     throw Cr.NS_ERROR_NO_INTERFACE;
   },
 
   getInterface: function(iid) {
     if (iid.equals(Ci.nsILoadContext))
       return this;
     throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  },
+
+  originAttributes: {}
 };
 
 PrivateBrowsingLoadContext = new LoadContext(true);
 
 function make_channel(url, flags, usePrivateBrowsing) {
   var ios = Cc["@mozilla.org/network/io-service;1"].
     getService(Ci.nsIIOService);
   var req = ios.newChannel2(url,
--- a/netwerk/test/unit/test_predictor.js
+++ b/netwerk/test/unit/test_predictor.js
@@ -33,17 +33,19 @@ LoadContext.prototype = {
 
   QueryInterface: function loadContext_QueryInterface(iid) {
     if (iid.equals(Ci.nsINetworkPredictorVerifier) ||
         iid.equals(Ci.nsILoadContext)) {
       return this;
     }
 
     throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  },
+
+  originAttributes: {}
 };
 
 var load_context = new LoadContext();
 
 var Verifier = function _verifier(testing, expected_preconnects, expected_preresolves) {
   this.verifying = testing;
   this.expected_preconnects = expected_preconnects;
   this.expected_preresolves = expected_preresolves;
--- a/netwerk/test/unit_ipc/child_app_offline.js
+++ b/netwerk/test/unit_ipc/child_app_offline.js
@@ -14,16 +14,20 @@ function makeChan(url, appId, inBrowser)
                              null,      // aLoadingNode
                              Services.scriptSecurityManager.getSystemPrincipal(),
                              null,      // aTriggeringPrincipal
                              Ci.nsILoadInfo.SEC_NORMAL,
                              Ci.nsIContentPolicy.TYPE_OTHER).QueryInterface(Ci.nsIHttpChannel);
   chan.notificationCallbacks = {
     appId: appId,
     isInBrowserElement: inBrowser,
+    originAttributes: {
+      appId: appId,
+      inBrowser: inBrowser,
+    },
     QueryInterface: function(iid) {
       if (iid.equals(Ci.nsILoadContext))
         return this;
       throw Cr.NS_ERROR_NO_INTERFACE;
     },
     getInterface: function(iid) { return this.QueryInterface(iid); }
   };
   return chan;
--- a/uriloader/prefetch/OfflineCacheUpdateParent.cpp
+++ b/uriloader/prefetch/OfflineCacheUpdateParent.cpp
@@ -46,21 +46,21 @@ namespace docshell {
 NS_IMPL_ISUPPORTS(OfflineCacheUpdateParent,
                   nsIOfflineCacheUpdateObserver,
                   nsILoadContext)
 
 //-----------------------------------------------------------------------------
 // OfflineCacheUpdateParent <public>
 //-----------------------------------------------------------------------------
 
+// TODO: Bug 1191740 - Add OriginAttributes in TabContext
 OfflineCacheUpdateParent::OfflineCacheUpdateParent(uint32_t aAppId,
                                                    bool aIsInBrowser)
     : mIPCClosed(false)
-    , mIsInBrowserElement(aIsInBrowser)
-    , mAppId(aAppId)
+    , mOriginAttributes(aAppId, aIsInBrowser)
 {
     // Make sure the service has been initialized
     nsOfflineCacheUpdateService::EnsureService();
 
     LOG(("OfflineCacheUpdateParent::OfflineCacheUpdateParent [%p]", this));
 }
 
 OfflineCacheUpdateParent::~OfflineCacheUpdateParent()
@@ -88,44 +88,46 @@ OfflineCacheUpdateParent::Schedule(const
 
     nsOfflineCacheUpdateService* service =
         nsOfflineCacheUpdateService::EnsureService();
     if (!service)
         return NS_ERROR_FAILURE;
 
     bool offlinePermissionAllowed = false;
 
-    // TODO: Bug 1165466 - use OriginAttributes
-    OriginAttributes attrs(mAppId, mIsInBrowserElement);
     nsCOMPtr<nsIPrincipal> principal =
-      BasePrincipal::CreateCodebasePrincipal(manifestURI, attrs);
+      BasePrincipal::CreateCodebasePrincipal(manifestURI, mOriginAttributes);
 
     nsresult rv = service->OfflineAppAllowed(
         principal, nullptr, &offlinePermissionAllowed);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (!offlinePermissionAllowed)
         return NS_ERROR_DOM_SECURITY_ERR;
 
     nsCOMPtr<nsIURI> documentURI = DeserializeURI(aDocumentURI);
     if (!documentURI)
         return NS_ERROR_FAILURE;
 
     if (!NS_SecurityCompareURIs(manifestURI, documentURI, false))
         return NS_ERROR_DOM_SECURITY_ERR;
 
-    service->FindUpdate(manifestURI, mAppId, mIsInBrowserElement, nullptr,
+    // TODO: Bug 1197093 - add originAttributes to nsIOfflineCacheUpdate
+    service->FindUpdate(manifestURI,
+                        mOriginAttributes.mAppId,
+                        mOriginAttributes.mInBrowser,
+                        nullptr,
                         getter_AddRefs(update));
     if (!update) {
         update = new nsOfflineCacheUpdate();
 
         // Leave aDocument argument null. Only glues and children keep 
         // document instances.
         rv = update->Init(manifestURI, documentURI, nullptr, nullptr,
-                          mAppId, mIsInBrowserElement);
+                          mOriginAttributes.mAppId, mOriginAttributes.mInBrowser);
         NS_ENSURE_SUCCESS(rv, rv);
 
         rv = update->Schedule();
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
     update->AddObserver(this, false);
 
@@ -249,21 +251,32 @@ NS_IMETHODIMP
 OfflineCacheUpdateParent::SetRemoteTabs(bool aUseRemoteTabs)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 OfflineCacheUpdateParent::GetIsInBrowserElement(bool *aIsInBrowserElement)
 {
-    *aIsInBrowserElement = mIsInBrowserElement;
+    *aIsInBrowserElement = mOriginAttributes.mInBrowser;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 OfflineCacheUpdateParent::GetAppId(uint32_t *aAppId)
 {
-    *aAppId = mAppId;
+    *aAppId = mOriginAttributes.mAppId;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+OfflineCacheUpdateParent::GetOriginAttributes(JS::MutableHandleValue aAttrs)
+{
+    JSContext* cx = nsContentUtils::GetCurrentJSContext();
+    MOZ_ASSERT(cx);
+
+    bool ok = ToJSValue(cx, mOriginAttributes, aAttrs);
+    NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
     return NS_OK;
 }
 
 } // namespace docshell
 } // namespace mozilla
--- a/uriloader/prefetch/OfflineCacheUpdateParent.h
+++ b/uriloader/prefetch/OfflineCacheUpdateParent.h
@@ -2,16 +2,17 @@
 /* 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/. */
 
 #ifndef nsOfflineCacheUpdateParent_h
 #define nsOfflineCacheUpdateParent_h
 
 #include "mozilla/docshell/POfflineCacheUpdateParent.h"
+#include "mozilla/BasePrincipal.h"
 #include "nsIOfflineCacheUpdate.h"
 
 #include "nsString.h"
 #include "nsILoadContext.h"
 
 namespace mozilla {
 
 namespace ipc {
@@ -40,22 +41,20 @@ public:
     StopSendingMessagesToChild()
     {
       mIPCClosed = true;
     }
 
     OfflineCacheUpdateParent(uint32_t aAppId, bool aIsInBrowser);
 
     virtual void ActorDestroy(ActorDestroyReason aWhy) override;
-
 private:
     ~OfflineCacheUpdateParent();
 
     bool mIPCClosed;
 
-    bool     mIsInBrowserElement;
-    uint32_t mAppId;
+    mozilla::OriginAttributes mOriginAttributes;
 };
 
 } // namespace docshell
 } // namespace mozilla
 
 #endif