Bug 1165269 - Use OriginAttributes in nsILoadContextInfo, r=michal+allstars
authorHonza Bambas <honzab.moz@firemni.cz>
Sun, 11 Oct 2015 18:13:09 +0200
changeset 267145 c08ebe9b7150d96cc3e0e8c5705675787a1b414d
parent 267144 2a93d3a102f277ed6b22c9f9f1bbdb43d3dd2243
child 267146 29e5d93f022c179607668604e19cb643eb9df3a0
push id66402
push userarchaeopteryx@coole-files.de
push dateSun, 11 Oct 2015 16:15:00 +0000
treeherdermozilla-inbound@ee4cb52e6b15 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmichal
bugs1165269
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 1165269 - Use OriginAttributes in nsILoadContextInfo, r=michal+allstars
dom/tests/mochitest/ajax/offline/offlineTests.js
netwerk/base/LoadContextInfo.cpp
netwerk/base/LoadContextInfo.h
netwerk/base/Predictor.cpp
netwerk/base/nsILoadContextInfo.idl
netwerk/build/nsNetCID.h
netwerk/build/nsNetModule.cpp
netwerk/cache/nsApplicationCacheService.cpp
netwerk/cache/nsDiskCacheDeviceSQL.cpp
netwerk/cache/nsDiskCacheDeviceSQL.h
netwerk/cache2/AppCacheStorage.cpp
netwerk/cache2/CacheFile.cpp
netwerk/cache2/CacheFileIOManager.cpp
netwerk/cache2/CacheFileMetadata.cpp
netwerk/cache2/CacheFileMetadata.h
netwerk/cache2/CacheFileUtils.cpp
netwerk/cache2/CacheIndex.cpp
netwerk/cache2/CacheIndex.h
netwerk/cache2/CacheObserver.cpp
netwerk/cache2/OldWrappers.cpp
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp
netwerk/protocol/wyciwyg/nsWyciwygChannel.h
netwerk/test/mochitests/test_web_packaged_app.html
netwerk/test/unit/test_bug248970_cache.js
netwerk/test/unit/test_cache_jar.js
netwerk/test/unit/test_predictor.js
toolkit/modules/LoadContextInfo.jsm
toolkit/modules/Services.jsm
--- a/dom/tests/mochitest/ajax/offline/offlineTests.js
+++ b/dom/tests/mochitest/ajax/offline/offlineTests.js
@@ -1,13 +1,13 @@
 // Utility functions for offline tests.
 var Cc = SpecialPowers.Cc;
 var Ci = SpecialPowers.Ci;
 var Cu = SpecialPowers.Cu;
-var LoadContextInfo = Cu.import("resource://gre/modules/LoadContextInfo.jsm", {}).LoadContextInfo;
+var LoadContextInfo = Cc["@mozilla.org/load-context-info-factory;1"].getService(Ci.nsILoadContextInfoFactory);
 var CommonUtils = Cu.import("resource://services-common/utils.js", {}).CommonUtils;
 
 const kNetBase = 2152398848; // 0x804B0000
 var NS_ERROR_CACHE_KEY_NOT_FOUND = kNetBase + 61;
 var NS_ERROR_CACHE_KEY_WAIT_FOR_VALIDATION = kNetBase + 64;
 
 // Reading the contents of multiple cache entries asynchronously
 function OfflineCacheContents(urls) {
--- a/netwerk/base/LoadContextInfo.cpp
+++ b/netwerk/base/LoadContextInfo.cpp
@@ -1,114 +1,181 @@
 /* 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 "LoadContextInfo.h"
 
 #include "nsIChannel.h"
 #include "nsILoadContext.h"
+#include "nsIWebNavigation.h"
 
 namespace mozilla {
 namespace net {
 
+// LoadContextInfo
+
 NS_IMPL_ISUPPORTS(LoadContextInfo, nsILoadContextInfo)
 
-LoadContextInfo::LoadContextInfo(bool aIsPrivate, uint32_t aAppId, bool aIsInBrowser, bool aIsAnonymous)
-  : mAppId(aAppId)
-  , mIsPrivate(aIsPrivate)
-  , mIsInBrowser(aIsInBrowser)
+LoadContextInfo::LoadContextInfo(bool aIsPrivate, bool aIsAnonymous, OriginAttributes aOriginAttributes)
+  : mIsPrivate(aIsPrivate)
   , mIsAnonymous(aIsAnonymous)
+  , mOriginAttributes(aOriginAttributes)
 {
 }
 
 LoadContextInfo::~LoadContextInfo()
 {
 }
 
 NS_IMETHODIMP LoadContextInfo::GetIsPrivate(bool *aIsPrivate)
 {
   *aIsPrivate = mIsPrivate;
   return NS_OK;
 }
 
-NS_IMETHODIMP LoadContextInfo::GetAppId(uint32_t *aAppId)
-{
-  *aAppId = mAppId;
-  return NS_OK;
-}
-
-NS_IMETHODIMP LoadContextInfo::GetIsInBrowserElement(bool *aIsInBrowser)
-{
-  *aIsInBrowser = mIsInBrowser;
-  return NS_OK;
-}
-
 NS_IMETHODIMP LoadContextInfo::GetIsAnonymous(bool *aIsAnonymous)
 {
   *aIsAnonymous = mIsAnonymous;
   return NS_OK;
 }
 
+OriginAttributes const* LoadContextInfo::OriginAttributesPtr()
+{
+  return &mOriginAttributes;
+}
+
+NS_IMETHODIMP LoadContextInfo::GetOriginAttributes(JSContext *aCx,
+                                                   JS::MutableHandle<JS::Value> aVal)
+{
+  if (NS_WARN_IF(!ToJSValue(aCx, mOriginAttributes, aVal))) {
+    return NS_ERROR_FAILURE;
+  }
+  return NS_OK;
+}
+
+// LoadContextInfoFactory
+
+NS_IMPL_ISUPPORTS(LoadContextInfoFactory, nsILoadContextInfoFactory)
+
+/* readonly attribute nsILoadContextInfo default; */
+NS_IMETHODIMP LoadContextInfoFactory::GetDefault(nsILoadContextInfo * *aDefault)
+{
+  nsCOMPtr<nsILoadContextInfo> info = GetLoadContextInfo(false, false, OriginAttributes());
+  info.forget(aDefault);
+  return NS_OK;
+}
+
+/* readonly attribute nsILoadContextInfo private; */
+NS_IMETHODIMP LoadContextInfoFactory::GetPrivate(nsILoadContextInfo * *aPrivate)
+{
+  nsCOMPtr<nsILoadContextInfo> info = GetLoadContextInfo(true, false, OriginAttributes());
+  info.forget(aPrivate);
+  return NS_OK;
+}
+
+/* readonly attribute nsILoadContextInfo anonymous; */
+NS_IMETHODIMP LoadContextInfoFactory::GetAnonymous(nsILoadContextInfo * *aAnonymous)
+{
+  nsCOMPtr<nsILoadContextInfo> info = GetLoadContextInfo(false, true, OriginAttributes());
+  info.forget(aAnonymous);
+  return NS_OK;
+}
+
+/* nsILoadContextInfo custom (in boolean aPrivate, in boolean aAnonymous, in jsval aOriginAttributes); */
+NS_IMETHODIMP LoadContextInfoFactory::Custom(bool aPrivate, bool aAnonymous,
+                                             JS::HandleValue aOriginAttributes, JSContext *cx,
+                                             nsILoadContextInfo * *_retval)
+{
+  OriginAttributes attrs;
+  bool status = attrs.Init(cx, aOriginAttributes);
+  NS_ENSURE_TRUE(status, NS_ERROR_FAILURE);
+
+  nsCOMPtr<nsILoadContextInfo> info = GetLoadContextInfo(aPrivate, aAnonymous, attrs);
+  info.forget(_retval);
+  return NS_OK;
+}
+
+/* nsILoadContextInfo fromLoadContext (in nsILoadContext aLoadContext, in boolean aAnonymous); */
+NS_IMETHODIMP LoadContextInfoFactory::FromLoadContext(nsILoadContext *aLoadContext, bool aAnonymous,
+                                                      nsILoadContextInfo * *_retval)
+{
+  nsCOMPtr<nsILoadContextInfo> info = GetLoadContextInfo(aLoadContext, aAnonymous);
+  info.forget(_retval);
+  return NS_OK;
+}
+
+/* nsILoadContextInfo fromWindow (in nsIDOMWindow aWindow, in boolean aAnonymous); */
+NS_IMETHODIMP LoadContextInfoFactory::FromWindow(nsIDOMWindow *aWindow, bool aAnonymous,
+                                                 nsILoadContextInfo * *_retval)
+{
+  nsCOMPtr<nsILoadContextInfo> info = GetLoadContextInfo(aWindow, aAnonymous);
+  info.forget(_retval);
+  return NS_OK;
+}
+
+// Helper functions
+
 LoadContextInfo *
 GetLoadContextInfo(nsIChannel * aChannel)
 {
+  nsresult rv;
+
   bool pb = NS_UsePrivateBrowsing(aChannel);
-  uint32_t appId;
-  bool ib;
-  if (!NS_GetAppInfo(aChannel, &appId, &ib)) {
-    appId = nsILoadContextInfo::NO_APP_ID;
-    ib = false;
-  }
 
   bool anon = false;
   nsLoadFlags loadFlags;
-  nsresult rv = aChannel->GetLoadFlags(&loadFlags);
-  if (NS_SUCCEEDED(rv))
+  rv = aChannel->GetLoadFlags(&loadFlags);
+  if (NS_SUCCEEDED(rv)) {
     anon = !!(loadFlags & nsIChannel::LOAD_ANONYMOUS);
+  }
 
-  return new LoadContextInfo(pb, appId, ib, anon);
+  OriginAttributes oa;
+  NS_GetOriginAttributes(aChannel, oa);
+
+  return new LoadContextInfo(pb, anon, oa);
 }
 
 LoadContextInfo *
-GetLoadContextInfo(nsILoadContext * aLoadContext, bool aIsAnonymous)
+GetLoadContextInfo(nsILoadContext *aLoadContext, bool aIsAnonymous)
 {
-  if (!aLoadContext)
-    return new LoadContextInfo(false, nsILoadContextInfo::NO_APP_ID, false, aIsAnonymous); // nullptr?
+  if (!aLoadContext) {
+    return new LoadContextInfo(false, aIsAnonymous,
+                               OriginAttributes(nsILoadContextInfo::NO_APP_ID, false));
+  }
 
   bool pb = aLoadContext->UsePrivateBrowsing();
+  OriginAttributes oa;
+  aLoadContext->GetOriginAttributes(oa);
 
-  bool ib;
-  nsresult rv = aLoadContext->GetIsInBrowserElement(&ib);
-  if (NS_FAILED(rv))
-    ib = false; // todo NS_WARNING...
+  return new LoadContextInfo(pb, aIsAnonymous, oa);
+}
 
-  uint32_t appId;
-  rv = aLoadContext->GetAppId(&appId);
-  if (NS_FAILED(rv))
-    appId = nsILoadContextInfo::NO_APP_ID;
+LoadContextInfo*
+GetLoadContextInfo(nsIDOMWindow *aWindow,
+                   bool aIsAnonymous)
+{
+  nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(aWindow);
+  nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(webNav);
 
-  return new LoadContextInfo(pb, appId, ib, aIsAnonymous);
+  return GetLoadContextInfo(loadContext, aIsAnonymous);
 }
 
 LoadContextInfo *
-GetLoadContextInfo(nsILoadContextInfo* aInfo)
+GetLoadContextInfo(nsILoadContextInfo *aInfo)
 {
   return new LoadContextInfo(aInfo->IsPrivate(),
-                             aInfo->AppId(),
-                             aInfo->IsInBrowserElement(),
-                             aInfo->IsAnonymous());
+                             aInfo->IsAnonymous(),
+                             *aInfo->OriginAttributesPtr());
 }
 
 LoadContextInfo *
 GetLoadContextInfo(bool const aIsPrivate,
-                   uint32_t const aAppId,
-                   bool const aIsInBrowserElement,
-                   bool const aIsAnonymous)
+                   bool const aIsAnonymous,
+                   OriginAttributes const &aOriginAttributes)
 {
   return new LoadContextInfo(aIsPrivate,
-                             aAppId,
-                             aIsInBrowserElement,
-                             aIsAnonymous);
+                             aIsAnonymous,
+                             aOriginAttributes);
 }
 
 } // namespace net
 } // namespace mozilla
--- a/netwerk/base/LoadContextInfo.h
+++ b/netwerk/base/LoadContextInfo.h
@@ -14,40 +14,50 @@ namespace mozilla {
 namespace net {
 
 class LoadContextInfo : public nsILoadContextInfo
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSILOADCONTEXTINFO
 
-  LoadContextInfo(bool aIsPrivate, uint32_t aAppId, bool aIsInBrowser, bool aIsAnonymous);
+  LoadContextInfo(bool aIsPrivate, bool aIsAnonymous, OriginAttributes aOriginAttributes);
 
 private:
   virtual ~LoadContextInfo();
 
 protected:
-  uint32_t mAppId;
   bool mIsPrivate : 1;
-  bool mIsInBrowser : 1;
   bool mIsAnonymous : 1;
+  OriginAttributes mOriginAttributes;
+};
+
+class LoadContextInfoFactory : public nsILoadContextInfoFactory
+{
+  virtual ~LoadContextInfoFactory() {}
+public:
+  NS_DECL_ISUPPORTS // deliberately not thread-safe
+  NS_DECL_NSILOADCONTEXTINFOFACTORY
 };
 
-LoadContextInfo *
-GetLoadContextInfo(nsIChannel * aChannel);
+LoadContextInfo*
+GetLoadContextInfo(nsIChannel *aChannel);
 
-LoadContextInfo *
-GetLoadContextInfo(nsILoadContext * aLoadContext,
-                   bool aAnonymous);
+LoadContextInfo*
+GetLoadContextInfo(nsILoadContext *aLoadContext,
+                   bool aIsAnonymous);
 
-LoadContextInfo *
-GetLoadContextInfo(nsILoadContextInfo* aInfo);
+LoadContextInfo*
+GetLoadContextInfo(nsIDOMWindow *aLoadContext,
+                   bool aIsAnonymous);
 
-LoadContextInfo *
-GetLoadContextInfo(bool const aIsPrivate = false,
-                   uint32_t const aAppId = nsILoadContextInfo::NO_APP_ID,
-                   bool const aIsInBrowserElement = false,
-                   bool const aIsAnonymous = false);
+LoadContextInfo*
+GetLoadContextInfo(nsILoadContextInfo *aInfo);
+
+LoadContextInfo*
+GetLoadContextInfo(bool const aIsPrivate,
+                   bool const aIsAnonymous,
+                   OriginAttributes const &aOriginAttributes);
 
 } // namespace net
 } // namespace mozilla
 
 #endif
--- a/netwerk/base/Predictor.cpp
+++ b/netwerk/base/Predictor.cpp
@@ -591,17 +591,17 @@ Predictor::Init()
     mDNSListener = new DNSListener();
   }
 
   nsCOMPtr<nsICacheStorageService> cacheStorageService =
     do_GetService("@mozilla.org/netwerk/cache-storage-service;1", &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsRefPtr<LoadContextInfo> lci =
-    new LoadContextInfo(false, nsILoadContextInfo::NO_APP_ID, false, false);
+    new LoadContextInfo(false, false, OriginAttributes());
 
   rv = cacheStorageService->DiskCacheStorage(lci, false,
                                              getter_AddRefs(mCacheDiskStorage));
   NS_ENSURE_SUCCESS(rv, rv);
 
   mIOService = do_GetService("@mozilla.org/network/io-service;1", &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
--- a/netwerk/base/nsILoadContextInfo.idl
+++ b/netwerk/base/nsILoadContextInfo.idl
@@ -1,79 +1,90 @@
 /* -*- Mode: C++; tab-width: 2; 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"
 
+%{ C++
+#include "mozilla/BasePrincipal.h"
+%}
+native OriginAttributesNativePtr(const mozilla::OriginAttributes*);
+
+interface nsILoadContext;
+interface nsIDOMWindow;
+
 /**
  * Helper interface to carry informatin about the load context
- * encapsulating an AppID, IsInBrowser and IsPrivite properties.
+ * encapsulating origin attributes and IsAnonymous, IsPrivite properties.
  * It shall be used where nsILoadContext cannot be used or is not
  * available.
  */
-[scriptable, uuid(1ea9cbdb-9df4-46a0-8c45-f4091aad9459)]
+
+[scriptable, builtinclass, uuid(555e2f8a-a1f6-41dd-88ca-ed4ed6b98a22)]
 interface nsILoadContextInfo : nsISupports
 {
+  const unsigned long NO_APP_ID = 0;
+  const unsigned long UNKNOWN_APP_ID = 4294967295; // UINT32_MAX
+
   /**
    * Whether the context is in a Private Browsing mode
    */
   readonly attribute boolean isPrivate;
 
   /**
-   * Whether the context belongs under an App
-   */
-  const unsigned long NO_APP_ID = 0;
-  const unsigned long UNKNOWN_APP_ID = 4294967295; // UINT32_MAX
-  readonly attribute uint32_t appId;
-
-  /**
-   * Whether the context is in a browser tag
-   */
-  readonly attribute boolean isInBrowserElement;
-
-  /**
    * Whether the load is initiated as anonymous
    */
   readonly attribute boolean isAnonymous;
 
+  /**
+   * OriginAttributes hiding all the security context attributes
+   */
+  [implicit_jscontext]
+  readonly attribute jsval originAttributes;
+  [noscript, notxpcom, nostdcall, binaryname(OriginAttributesPtr)]
+  OriginAttributesNativePtr binaryOriginAttributesPtr();
+
 %{C++
   /**
    * De-XPCOMed getters
    */
   bool IsPrivate()
   {
     bool pb;
     GetIsPrivate(&pb);
     return pb;
   }
 
-  uint32_t AppId()
-  {
-    uint32_t appId;
-    GetAppId(&appId);
-    return appId;
-  }
-
-  bool IsInBrowserElement()
-  {
-    bool ib;
-    GetIsInBrowserElement(&ib);
-    return ib;
-  }
-
   bool IsAnonymous()
   {
     bool anon;
     GetIsAnonymous(&anon);
     return anon;
   }
 
   bool Equals(nsILoadContextInfo *aOther)
   {
-    return (IsPrivate() == aOther->IsPrivate() &&
-            AppId() == aOther->AppId() &&
-            IsInBrowserElement() == aOther->IsInBrowserElement() &&
-            IsAnonymous() == aOther->IsAnonymous());
+    return IsPrivate() == aOther->IsPrivate() &&
+           IsAnonymous() == aOther->IsAnonymous() &&
+           *OriginAttributesPtr() == *aOther->OriginAttributesPtr();
   }
 %}
 };
+
+/**
+ * Since OriginAttributes struct limits the implementation of
+ * nsILoadContextInfo (that needs to be thread safe) to C++,
+ * we need a scriptable factory to create instances of that
+ * interface from JS.
+ */
+[scriptable, uuid(c1c7023d-4318-4f99-8307-b5ccf0558793)]
+interface nsILoadContextInfoFactory : nsISupports
+{
+  readonly attribute nsILoadContextInfo default;
+  readonly attribute nsILoadContextInfo private;
+  readonly attribute nsILoadContextInfo anonymous;
+  [implicit_jscontext]
+  nsILoadContextInfo custom(in boolean aPrivate, in boolean aAnonymous, in jsval aOriginAttributes);
+  nsILoadContextInfo fromLoadContext(in nsILoadContext aLoadContext, in boolean aAnonymous);
+  nsILoadContextInfo fromWindow(in nsIDOMWindow aWindow, in boolean aAnonymous);
+};
--- a/netwerk/build/nsNetCID.h
+++ b/netwerk/build/nsNetCID.h
@@ -1076,9 +1076,22 @@
  */
 #define NS_DATA_SNIFFER_CATEGORY "content-sniffing-services"
 
 /**
  * Must implement nsINSSErrorsService.
  */
 #define NS_NSS_ERRORS_SERVICE_CONTRACTID "@mozilla.org/nss_errors_service;1"
 
+/**
+ * LoadContextInfo factory
+ */
+#define NS_NSILOADCONTEXTINFOFACTORY_CONTRACTID \
+    "@mozilla.org/load-context-info-factory;1"
+#define NS_NSILOADCONTEXTINFOFACTORY_CID             \
+{ /* 62d4b190-3642-4450-b019-d1c1fba56025 */         \
+    0x62d4b190,                                      \
+    0x3642,                                          \
+    0x4450,                                          \
+    {0xb0, 0x19, 0xd1, 0xc1, 0xfb, 0xa5, 0x60, 0x25} \
+}
+
 #endif // nsNetCID_h__
--- a/netwerk/build/nsNetModule.cpp
+++ b/netwerk/build/nsNetModule.cpp
@@ -126,16 +126,20 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsSeriali
 #include "RedirectChannelRegistrar.h"
 typedef mozilla::net::RedirectChannelRegistrar RedirectChannelRegistrar;
 NS_GENERIC_FACTORY_CONSTRUCTOR(RedirectChannelRegistrar)
 
 #include "CacheStorageService.h"
 typedef mozilla::net::CacheStorageService CacheStorageService;
 NS_GENERIC_FACTORY_CONSTRUCTOR(CacheStorageService)
 
+#include "LoadContextInfo.h"
+typedef mozilla::net::LoadContextInfoFactory LoadContextInfoFactory;
+NS_GENERIC_FACTORY_CONSTRUCTOR(LoadContextInfoFactory)
+
 ///////////////////////////////////////////////////////////////////////////////
 
 #include "mozilla/net/CaptivePortalService.h"
 namespace mozilla {
 namespace net {
   NS_GENERIC_FACTORY_CONSTRUCTOR(CaptivePortalService)
 } // namespace net
 } // namespace mozilla
@@ -829,16 +833,17 @@ NS_DEFINE_NAMED_CID(NS_NETWORK_LINK_SERV
 #elif defined(MOZ_WIDGET_ANDROID)
 NS_DEFINE_NAMED_CID(NS_NETWORK_LINK_SERVICE_CID);
 #elif defined(XP_LINUX)
 NS_DEFINE_NAMED_CID(NS_NETWORK_LINK_SERVICE_CID);
 #endif
 NS_DEFINE_NAMED_CID(NS_SERIALIZATION_HELPER_CID);
 NS_DEFINE_NAMED_CID(NS_REDIRECTCHANNELREGISTRAR_CID);
 NS_DEFINE_NAMED_CID(NS_CACHE_STORAGE_SERVICE_CID);
+NS_DEFINE_NAMED_CID(NS_NSILOADCONTEXTINFOFACTORY_CID);
 NS_DEFINE_NAMED_CID(NS_NETWORKPREDICTOR_CID);
 NS_DEFINE_NAMED_CID(NS_CAPTIVEPORTAL_CID);
 NS_DEFINE_NAMED_CID(NS_SCHEDULINGCONTEXTSERVICE_CID);
 
 static const mozilla::Module::CIDEntry kNeckoCIDs[] = {
     { &kNS_IOSERVICE_CID, false, nullptr, nsIOServiceConstructor },
     { &kNS_STREAMTRANSPORTSERVICE_CID, false, nullptr, nsStreamTransportServiceConstructor },
     { &kNS_SOCKETTRANSPORTSERVICE_CID, false, nullptr, nsSocketTransportServiceConstructor },
@@ -980,16 +985,17 @@ static const mozilla::Module::CIDEntry k
 #elif defined(MOZ_WIDGET_ANDROID)
     { &kNS_NETWORK_LINK_SERVICE_CID, false, nullptr, nsAndroidNetworkLinkServiceConstructor },
 #elif defined(XP_LINUX)
     { &kNS_NETWORK_LINK_SERVICE_CID, false, nullptr, nsNotifyAddrListenerConstructor },
 #endif
     { &kNS_SERIALIZATION_HELPER_CID, false, nullptr, nsSerializationHelperConstructor },
     { &kNS_REDIRECTCHANNELREGISTRAR_CID, false, nullptr, RedirectChannelRegistrarConstructor },
     { &kNS_CACHE_STORAGE_SERVICE_CID, false, nullptr, CacheStorageServiceConstructor },
+    { &kNS_NSILOADCONTEXTINFOFACTORY_CID, false, nullptr, LoadContextInfoFactoryConstructor },
     { &kNS_NETWORKPREDICTOR_CID, false, nullptr, mozilla::net::Predictor::Create },
     { &kNS_CAPTIVEPORTAL_CID, false, nullptr, mozilla::net::CaptivePortalServiceConstructor },
     { &kNS_SCHEDULINGCONTEXTSERVICE_CID, false, nullptr, SchedulingContextServiceConstructor },
     { nullptr }
 };
 
 static const mozilla::Module::ContractIDEntry kNeckoContracts[] = {
     { NS_IOSERVICE_CONTRACTID, &kNS_IOSERVICE_CID },
@@ -1137,16 +1143,17 @@ static const mozilla::Module::ContractID
     { NS_NETWORK_LINK_SERVICE_CONTRACTID, &kNS_NETWORK_LINK_SERVICE_CID },
 #elif defined(XP_LINUX)
     { NS_NETWORK_LINK_SERVICE_CONTRACTID, &kNS_NETWORK_LINK_SERVICE_CID },
 #endif
     { NS_SERIALIZATION_HELPER_CONTRACTID, &kNS_SERIALIZATION_HELPER_CID },
     { NS_REDIRECTCHANNELREGISTRAR_CONTRACTID, &kNS_REDIRECTCHANNELREGISTRAR_CID },
     { NS_CACHE_STORAGE_SERVICE_CONTRACTID, &kNS_CACHE_STORAGE_SERVICE_CID },
     { NS_CACHE_STORAGE_SERVICE_CONTRACTID2, &kNS_CACHE_STORAGE_SERVICE_CID },
+    { NS_NSILOADCONTEXTINFOFACTORY_CONTRACTID, &kNS_NSILOADCONTEXTINFOFACTORY_CID },
     { NS_NETWORKPREDICTOR_CONTRACTID, &kNS_NETWORKPREDICTOR_CID },
     { NS_CAPTIVEPORTAL_CONTRACTID, &kNS_CAPTIVEPORTAL_CID },
     { NS_SCHEDULINGCONTEXTSERVICE_CONTRACTID, &kNS_SCHEDULINGCONTEXTSERVICE_CID },
     { nullptr }
 };
 
 static const mozilla::Module kNeckoModule = {
     mozilla::Module::kVersion,
--- a/netwerk/cache/nsApplicationCacheService.cpp
+++ b/netwerk/cache/nsApplicationCacheService.cpp
@@ -35,39 +35,38 @@ nsApplicationCacheService::~nsApplicatio
 
 NS_IMETHODIMP
 nsApplicationCacheService::BuildGroupID(nsIURI *aManifestURL,
                                         nsILoadContextInfo *aLoadContextInfo,
                                         nsACString &_result)
 {
     nsresult rv;
 
-    uint32_t appId = NECKO_NO_APP_ID;
-    bool isInBrowserElement = false;
-
-    if (aLoadContextInfo) {
-        appId = aLoadContextInfo->AppId();
-        isInBrowserElement = aLoadContextInfo->IsInBrowserElement();
-    }
+    mozilla::OriginAttributes const *oa = aLoadContextInfo
+        ? aLoadContextInfo->OriginAttributesPtr()
+        : nullptr;
 
     rv = nsOfflineCacheDevice::BuildApplicationCacheGroupID(
-        aManifestURL, appId, isInBrowserElement, _result);
+        aManifestURL, oa, _result);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsApplicationCacheService::BuildGroupIDForApp(nsIURI *aManifestURL,
                                               uint32_t aAppId,
                                               bool aIsInBrowser,
                                               nsACString &_result)
 {
+    OriginAttributes oa;
+    oa.mAppId = aAppId;
+    oa.mInBrowser = aIsInBrowser;
     nsresult rv = nsOfflineCacheDevice::BuildApplicationCacheGroupID(
-        aManifestURL, aAppId, aIsInBrowser, _result);
+        aManifestURL, &oa, _result);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsApplicationCacheService::CreateApplicationCache(const nsACString &group,
                                                   nsIApplicationCache **out)
--- a/netwerk/cache/nsDiskCacheDeviceSQL.cpp
+++ b/netwerk/cache/nsDiskCacheDeviceSQL.cpp
@@ -41,16 +41,17 @@
 
 #include "mozilla/Telemetry.h"
 
 #include "sqlite3.h"
 #include "mozilla/storage.h"
 
 using namespace mozilla;
 using namespace mozilla::storage;
+using mozilla::OriginAttributes;
 
 static const char OFFLINE_CACHE_DEVICE_ID[] = { "offline" };
 
 #define LOG(args) CACHE_LOG_DEBUG(args)
 
 static uint32_t gNextTemporaryClientID = 0;
 
 /*****************************************************************************
@@ -1294,70 +1295,45 @@ GetGroupForCache(const nsCSubstring &cli
 {
   group.Assign(clientID);
   group.Truncate(group.FindChar('|'));
   NS_UnescapeURL(group);
 
   return NS_OK;
 }
 
-nsresult
-AppendJARIdentifier(nsACString &_result, int32_t appId, bool isInBrowserElement)
+void
+AppendJARIdentifier(nsACString &_result, OriginAttributes const *aOriginAttributes)
 {
-    _result.Append('#');
-    _result.AppendInt(appId);
-    _result.Append('+');
-    _result.Append(isInBrowserElement ? 't' : 'f');
-
-    return NS_OK;
-}
-
-nsresult
-GetJARIdentifier(nsIURI *aURI,
-                 uint32_t appId, bool isInBrowserElement,
-                 nsACString &_result)
-{
-    _result.Truncate();
-
-    // These lines are here for compatibility only.  We must not fill the
-    // JAR identifier when this is no-app context, otherwise web content
-    // offline application cache loads would not be satisfied (cache would
-    // not be found).
-    if (!isInBrowserElement && appId == NECKO_NO_APP_ID)
-        return NS_OK;
-
-    // This load context has some special attributes, create a jar identifier
-    return AppendJARIdentifier(_result, appId, isInBrowserElement);
+  nsAutoCString suffix;
+  aOriginAttributes->CreateSuffix(suffix);
+  _result.Append(suffix);
 }
 
 } // namespace
 
 // static
 nsresult
 nsOfflineCacheDevice::BuildApplicationCacheGroupID(nsIURI *aManifestURL,
-                                                   uint32_t appId, bool isInBrowserElement,
+                                                   OriginAttributes const *aOriginAttributes,
                                                    nsACString &_result)
 {
   nsCOMPtr<nsIURI> newURI;
   nsresult rv = aManifestURL->CloneIgnoringRef(getter_AddRefs(newURI));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoCString manifestSpec;
   rv = newURI->GetAsciiSpec(manifestSpec);
   NS_ENSURE_SUCCESS(rv, rv);
 
   _result.Assign(manifestSpec);
 
-  nsAutoCString jarid;
-  rv = GetJARIdentifier(aManifestURL, appId, isInBrowserElement, jarid);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Include JAR ID, i.e. the extended origin if present.
-  if (!jarid.IsEmpty())
-    _result.Append(jarid);
+  if (aOriginAttributes) {
+    AppendJARIdentifier(_result, aOriginAttributes);
+  }
 
   return NS_OK;
 }
 
 nsresult
 nsOfflineCacheDevice::InitActiveCaches()
 {
   MutexAutoLock lock(mLock);
@@ -2425,19 +2401,27 @@ nsOfflineCacheDevice::DeactivateGroup(co
 }
 
 nsresult
 nsOfflineCacheDevice::DiscardByAppId(int32_t appID, bool browserEntriesOnly)
 {
   nsresult rv;
 
   nsAutoCString jaridsuffix;
+
   jaridsuffix.Append('%');
-  rv = AppendJARIdentifier(jaridsuffix, appID, browserEntriesOnly);
-  NS_ENSURE_SUCCESS(rv, rv);
+
+  // TODO - this method should accept OriginAttributes* from outside instead.
+  // If passed null, we should then delegate to
+  // nsCacheService::GlobalInstance()->EvictEntriesInternal(nsICache::STORE_OFFLINE);
+
+  OriginAttributes oa;
+  oa.mAppId = appID;
+  oa.mInBrowser = browserEntriesOnly;
+  AppendJARIdentifier(jaridsuffix, &oa);
 
   {
     AutoResetStatement statement(mStatement_EnumerateApps);
     rv = statement->BindUTF8StringByIndex(0, jaridsuffix);
     NS_ENSURE_SUCCESS(rv, rv);
 
     bool hasRows;
     rv = statement->ExecuteStep(&hasRows);
@@ -2484,48 +2468,45 @@ nsOfflineCacheDevice::CanUseCache(nsIURI
   }
 
   nsAutoCString groupID;
   nsresult rv = GetGroupForCache(clientID, groupID);
   NS_ENSURE_SUCCESS(rv, false);
 
   nsCOMPtr<nsIURI> groupURI;
   rv = NS_NewURI(getter_AddRefs(groupURI), groupID);
-  if (NS_FAILED(rv))
+  if (NS_FAILED(rv)) {
     return false;
+  }
 
   // When we are choosing an initial cache to load the top
   // level document from, the URL of that document must have
   // the same origin as the manifest, according to the spec.
   // The following check is here because explicit, fallback
   // and dynamic entries might have origin different from the
   // manifest origin.
   if (!NS_SecurityCompareURIs(keyURI, groupURI,
-                              GetStrictFileOriginPolicy()))
+                              GetStrictFileOriginPolicy())) {
     return false;
-
-  // Get extended origin attributes
-  uint32_t appId = NECKO_NO_APP_ID;
-  bool isInBrowserElement = false;
-
-  if (loadContextInfo) {
-      appId = loadContextInfo->AppId();
-      isInBrowserElement = loadContextInfo->IsInBrowserElement();
   }
 
   // Check the groupID we found is equal to groupID based
   // on the load context demanding load from app cache.
   // This is check of extended origin.
   nsAutoCString demandedGroupID;
-  rv = BuildApplicationCacheGroupID(groupURI, appId, isInBrowserElement,
-                                    demandedGroupID);
+
+  const OriginAttributes *oa = loadContextInfo
+    ? loadContextInfo->OriginAttributesPtr()
+    : nullptr;
+  rv = BuildApplicationCacheGroupID(groupURI, oa, demandedGroupID);
   NS_ENSURE_SUCCESS(rv, false);
 
-  if (groupID != demandedGroupID)
+  if (groupID != demandedGroupID) {
     return false;
+  }
 
   return true;
 }
 
 
 nsresult
 nsOfflineCacheDevice::ChooseApplicationCache(const nsACString &key,
                                              nsILoadContextInfo *loadContextInfo,
--- a/netwerk/cache/nsDiskCacheDeviceSQL.h
+++ b/netwerk/cache/nsDiskCacheDeviceSQL.h
@@ -20,16 +20,17 @@
 #include "nsClassHashtable.h"
 #include "nsWeakReference.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Mutex.h"
 
 class nsIURI;
 class nsOfflineCacheDevice;
 class mozIStorageService;
+namespace mozilla { class OriginAttributes; }
 
 class nsApplicationCacheNamespace final : public nsIApplicationCacheNamespace
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIAPPLICATIONCACHENAMESPACE
 
   nsApplicationCacheNamespace() : mItemType(0) {}
@@ -135,17 +136,17 @@ public:
                                      const nsACString &       key,
                                      bool *                 isOwned);
 
   nsresult                ClearKeysOwnedByDomain(const char *clientID,
                                                  const nsACString &ownerDomain);
   nsresult                EvictUnownedEntries(const char *clientID);
 
   static nsresult         BuildApplicationCacheGroupID(nsIURI *aManifestURL,
-                                                       uint32_t appId, bool isInBrowserElement,
+                                                       mozilla::OriginAttributes const *aOriginAttributes,
                                                        nsACString &_result);
 
   nsresult                ActivateCache(const nsCSubstring &group,
                                         const nsCSubstring &clientID);
   bool                    IsActiveCache(const nsCSubstring &group,
                                         const nsCSubstring &clientID);
   nsresult                CreateApplicationCache(const nsACString &group,
                                                  nsIApplicationCache **out);
--- a/netwerk/cache2/AppCacheStorage.cpp
+++ b/netwerk/cache2/AppCacheStorage.cpp
@@ -119,31 +119,31 @@ NS_IMETHODIMP AppCacheStorage::AsyncEvic
 
   nsresult rv;
 
   nsCOMPtr<nsIApplicationCacheService> appCacheService =
     do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!mAppCache) {
-    if (LoadInfo()->AppId() == nsILoadContextInfo::NO_APP_ID &&
-        !LoadInfo()->IsInBrowserElement()) {
-
+    // TODO - bug 1165256, have an API on nsIApplicationCacheService that takes
+    // optional OAs and decides internally what to do.
+    const OriginAttributes* oa = LoadInfo()->OriginAttributesPtr();
+    if (oa->mAppId == nsILoadContextInfo::NO_APP_ID && !oa->mInBrowser) {
       // Clear everything.
       nsCOMPtr<nsICacheService> serv =
           do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
       NS_ENSURE_SUCCESS(rv, rv);
 
       rv = nsCacheService::GlobalInstance()->EvictEntriesInternal(nsICache::STORE_OFFLINE);
       NS_ENSURE_SUCCESS(rv, rv);
     }
     else {
       // Clear app or inbrowser staff.
-      rv = appCacheService->DiscardByAppId(LoadInfo()->AppId(),
-                                           LoadInfo()->IsInBrowserElement());
+      rv = appCacheService->DiscardByAppId(oa->mAppId, oa->mInBrowser);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
   else {
     // Discard the group
     nsRefPtr<_OldStorage> old = new _OldStorage(
       LoadInfo(), WriteToDisk(), LookupAppCache(), true, mAppCache);
     rv = old->AsyncEvictStorage(aCallback);
--- a/netwerk/cache2/CacheFile.cpp
+++ b/netwerk/cache2/CacheFile.cpp
@@ -1961,20 +1961,21 @@ CacheFile::InitIndexEntry()
 {
   MOZ_ASSERT(mHandle);
 
   if (mHandle->IsDoomed())
     return NS_OK;
 
   nsresult rv;
 
+  // Bug 1201042 - will pass OriginAttributes directly.
   rv = CacheFileIOManager::InitIndexEntry(mHandle,
-                                          mMetadata->AppId(),
+                                          mMetadata->OriginAttributes().mAppId,
                                           mMetadata->IsAnonymous(),
-                                          mMetadata->IsInBrowser());
+                                          mMetadata->OriginAttributes().mInBrowser);
   NS_ENSURE_SUCCESS(rv, rv);
 
   uint32_t expTime;
   mMetadata->GetExpirationTime(&expTime);
 
   uint32_t frecency;
   mMetadata->GetFrecency(&frecency);
 
--- a/netwerk/cache2/CacheFileIOManager.cpp
+++ b/netwerk/cache2/CacheFileIOManager.cpp
@@ -2806,20 +2806,21 @@ CacheFileIOManager::EvictByContext(nsILo
   }
 
   return NS_OK;
 }
 
 nsresult
 CacheFileIOManager::EvictByContextInternal(nsILoadContextInfo *aLoadContextInfo)
 {
+  nsAutoCString suffix;
+  aLoadContextInfo->OriginAttributesPtr()->CreateSuffix(suffix);
   LOG(("CacheFileIOManager::EvictByContextInternal() [loadContextInfo=%p, "
-       "anonymous=%u, inBrowser=%u, appId=%u]", aLoadContextInfo,
-       aLoadContextInfo->IsAnonymous(), aLoadContextInfo->IsInBrowserElement(),
-       aLoadContextInfo->AppId()));
+       "anonymous=%u, suffix=%s]", aLoadContextInfo, aLoadContextInfo->IsAnonymous(),
+       suffix.get()));
 
   nsresult rv;
 
   MOZ_ASSERT(mIOThread->IsCurrentThread());
 
   MOZ_ASSERT(!aLoadContextInfo->IsPrivate());
   if (aLoadContextInfo->IsPrivate()) {
     return NS_ERROR_INVALID_ARG;
--- a/netwerk/cache2/CacheFileMetadata.cpp
+++ b/netwerk/cache2/CacheFileMetadata.cpp
@@ -49,20 +49,18 @@ CacheFileMetadata::CacheFileMetadata(Cac
   , mHashCount(0)
   , mOffset(-1)
   , mBuf(nullptr)
   , mBufSize(0)
   , mWriteBuf(nullptr)
   , mElementsSize(0)
   , mIsDirty(false)
   , mAnonymous(false)
-  , mInBrowser(false)
   , mAllocExactSize(false)
   , mFirstRead(true)
-  , mAppId(nsILoadContextInfo::NO_APP_ID)
 {
   LOG(("CacheFileMetadata::CacheFileMetadata() [this=%p, handle=%p, key=%s]",
        this, aHandle, PromiseFlatCString(aKey).get()));
 
   MOZ_COUNT_CTOR(CacheFileMetadata);
   memset(&mMetaHdr, 0, sizeof(CacheFileMetadataHeader));
   mMetaHdr.mVersion = kCacheEntryVersion;
   mMetaHdr.mExpirationTime = nsICacheEntry::NO_EXPIRATION_TIME;
@@ -81,20 +79,18 @@ CacheFileMetadata::CacheFileMetadata(boo
   , mHashCount(0)
   , mOffset(0)
   , mBuf(nullptr)
   , mBufSize(0)
   , mWriteBuf(nullptr)
   , mElementsSize(0)
   , mIsDirty(true)
   , mAnonymous(false)
-  , mInBrowser(false)
   , mAllocExactSize(false)
   , mFirstRead(true)
-  , mAppId(nsILoadContextInfo::NO_APP_ID)
 {
   LOG(("CacheFileMetadata::CacheFileMetadata() [this=%p, key=%s]",
        this, PromiseFlatCString(aKey).get()));
 
   MOZ_COUNT_CTOR(CacheFileMetadata);
   memset(&mMetaHdr, 0, sizeof(CacheFileMetadataHeader));
   mMetaHdr.mVersion = kCacheEntryVersion;
   mMetaHdr.mExpirationTime = nsICacheEntry::NO_EXPIRATION_TIME;
@@ -114,20 +110,18 @@ CacheFileMetadata::CacheFileMetadata()
   , mHashCount(0)
   , mOffset(0)
   , mBuf(nullptr)
   , mBufSize(0)
   , mWriteBuf(nullptr)
   , mElementsSize(0)
   , mIsDirty(false)
   , mAnonymous(false)
-  , mInBrowser(false)
   , mAllocExactSize(false)
   , mFirstRead(true)
-  , mAppId(nsILoadContextInfo::NO_APP_ID)
 {
   LOG(("CacheFileMetadata::CacheFileMetadata() [this=%p]", this));
 
   MOZ_COUNT_CTOR(CacheFileMetadata);
   memset(&mMetaHdr, 0, sizeof(CacheFileMetadataHeader));
 }
 
 CacheFileMetadata::~CacheFileMetadata()
@@ -1012,18 +1006,17 @@ CacheFileMetadata::EnsureBuffer(uint32_t
 
 nsresult
 CacheFileMetadata::ParseKey(const nsACString &aKey)
 {
   nsCOMPtr<nsILoadContextInfo> info = CacheFileUtils::ParseKey(aKey);
   NS_ENSURE_TRUE(info, NS_ERROR_FAILURE);
 
   mAnonymous =  info->IsAnonymous();
-  mAppId = info->AppId();
-  mInBrowser = info->IsInBrowserElement();
+  mOriginAttributes = *info->OriginAttributesPtr();
 
   return NS_OK;
 }
 
 // Memory reporting
 
 size_t
 CacheFileMetadata::SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
--- a/netwerk/cache2/CacheFileMetadata.h
+++ b/netwerk/cache2/CacheFileMetadata.h
@@ -5,16 +5,17 @@
 #ifndef CacheFileMetadata__h__
 #define CacheFileMetadata__h__
 
 #include "CacheFileIOManager.h"
 #include "CacheStorageService.h"
 #include "CacheHashUtils.h"
 #include "CacheObserver.h"
 #include "mozilla/Endian.h"
+#include "mozilla/BasePrincipal.h"
 #include "nsAutoPtr.h"
 #include "nsString.h"
 
 class nsICacheEntryMetaDataVisitor;
 
 namespace mozilla {
 namespace net {
 
@@ -122,18 +123,17 @@ public:
 
   nsresult ReadMetadata(CacheFileMetadataListener *aListener);
   uint32_t CalcMetadataSize(uint32_t aElementsSize, uint32_t aHashCount);
   nsresult WriteMetadata(uint32_t aOffset,
                          CacheFileMetadataListener *aListener);
   nsresult SyncReadMetadata(nsIFile *aFile);
 
   bool     IsAnonymous() { return mAnonymous; }
-  bool     IsInBrowser() { return mInBrowser; }
-  uint32_t AppId()       { return mAppId; }
+  mozilla::OriginAttributes const & OriginAttributes() const { return mOriginAttributes; }
 
   const char * GetElement(const char *aKey);
   nsresult     SetElement(const char *aKey, const char *aValue);
   nsresult     Visit(nsICacheEntryMetaDataVisitor *aVisitor);
 
   CacheHash::Hash16_t GetHash(uint32_t aIndex);
   nsresult            SetHash(uint32_t aIndex, CacheHash::Hash16_t aHash);
 
@@ -184,21 +184,20 @@ private:
   char                               *mBuf; // used for parsing, then points
                                             // to elements
   uint32_t                            mBufSize;
   char                               *mWriteBuf;
   CacheFileMetadataHeader             mMetaHdr;
   uint32_t                            mElementsSize;
   bool                                mIsDirty        : 1;
   bool                                mAnonymous      : 1;
-  bool                                mInBrowser      : 1;
   bool                                mAllocExactSize : 1;
   bool                                mFirstRead      : 1;
+  mozilla::OriginAttributes           mOriginAttributes;
   mozilla::TimeStamp                  mReadStart;
-  uint32_t                            mAppId;
   nsCOMPtr<CacheFileMetadataListener> mListener;
 };
 
 
 } // namespace net
 } // namespace mozilla
 
 #endif
--- a/netwerk/cache2/CacheFileUtils.cpp
+++ b/netwerk/cache2/CacheFileUtils.cpp
@@ -1,218 +1,193 @@
 /* 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 "CacheLog.h"
 #include "CacheFileUtils.h"
 #include "LoadContextInfo.h"
+#include "mozilla/Tokenizer.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "nsString.h"
 #include <algorithm>
 
 
 namespace mozilla {
 namespace net {
 namespace CacheFileUtils {
 
 namespace {
 
 /**
  * A simple recursive descent parser for the mapping key.
  */
-class KeyParser
+class KeyParser : protected Tokenizer
 {
 public:
-  KeyParser(nsACString::const_iterator aCaret, nsACString::const_iterator aEnd)
-    : caret(aCaret)
-    , end(aEnd)
+  explicit KeyParser(nsACString const& aInput)
+    : Tokenizer(aInput)
     // Initialize attributes to their default values
-    , appId(nsILoadContextInfo::NO_APP_ID)
+    , originAttribs(0, false)
     , isPrivate(false)
-    , isInBrowser(false)
     , isAnonymous(false)
     // Initialize the cache key to a zero length by default
-    , cacheKey(aEnd)
     , lastTag(0)
   {
   }
 
 private:
-  // Current character being parsed
-  nsACString::const_iterator caret;
-  // The end of the buffer
-  nsACString::const_iterator const end;
-
   // Results
-  uint32_t appId;
+  OriginAttributes originAttribs;
   bool isPrivate;
-  bool isInBrowser;
   bool isAnonymous;
   nsCString idEnhance;
-  // Position of the cache key, if present
-  nsACString::const_iterator cacheKey;
+  nsDependentCSubstring cacheKey;
 
   // Keeps the last tag name, used for alphabetical sort checking
   char lastTag;
 
+  // Classifier for the 'tag' character valid range
+  static bool TagChar(const char aChar)
+  {
+    return aChar >= ' ' && aChar <= '~';
+  }
+
   bool ParseTags()
   {
     // Expects to be at the tag name or at the end
-    if (caret == end)
+    if (CheckEOF()) {
       return true;
+    }
 
-    // 'Read' the tag name and move to the next char
-    char const tag = *caret++;
+    char tag;
+    if (!ReadChar(&TagChar, &tag)) {
+      return false;
+    }
+
     // Check the alphabetical order, hard-fail on disobedience
-    if (!(lastTag < tag || tag == ':'))
+    if (!(lastTag < tag || tag == ':')) {
       return false;
-
+    }
     lastTag = tag;
 
     switch (tag) {
     case ':':
       // last possible tag, when present there is the cacheKey following,
       // not terminated with ',' and no need to unescape.
-      cacheKey = caret;
-      caret = end;
+      cacheKey.Rebind(mCursor, mEnd - mCursor);
       return true;
+    case 'O': {
+      nsAutoCString originSuffix;
+      if (!ParseValue(&originSuffix) || !originAttribs.PopulateFromSuffix(originSuffix)) {
+        return false;
+      }
+      break;
+    }
     case 'p':
       isPrivate = true;
       break;
     case 'b':
-      isInBrowser = true;
+      // Leaving to be able to read and understand oldformatted entries
+      originAttribs.mInBrowser = true;
       break;
     case 'a':
       isAnonymous = true;
       break;
     case 'i': {
-      nsAutoCString appIdString;
-      if (!ParseValue(&appIdString))
-        return false;
-
-      nsresult rv;
-      int64_t appId64 = appIdString.ToInteger64(&rv);
-      if (NS_FAILED(rv))
-        return false; // appid value is mandatory
-      if (appId64 < 0 || appId64 > PR_UINT32_MAX)
-        return false; // not in the range
-      appId = static_cast<uint32_t>(appId64);
-
+      // Leaving to be able to read and understand oldformatted entries
+      if (!ReadInteger(&originAttribs.mAppId)) {
+        return false; // not a valid 32-bit integer
+      }
       break;
     }
     case '~':
-      if (!ParseValue(&idEnhance))
+      if (!ParseValue(&idEnhance)) {
         return false;
+      }
       break;
     default:
-      if (!ParseValue()) // skip any tag values, optional
+      if (!ParseValue()) { // skip any tag values, optional
         return false;
+      }
       break;
     }
 
+    // We expect a comma after every tag
+    if (!CheckChar(',')) {
+      return false;
+    }
+
     // Recurse to the next tag
-    return ParseNextTagOrEnd();
-  }
-
-  bool ParseNextTagOrEnd()
-  {
-    // We expect a comma after every tag
-    if (caret == end || *caret++ != ',')
-      return false;
-
-    // Go to another tag
     return ParseTags();
   }
 
-  bool ParseValue(nsACString * result = nullptr)
+  bool ParseValue(nsACString *result = nullptr)
   {
     // If at the end, fail since we expect a comma ; value may be empty tho
-    if (caret == end)
+    if (CheckEOF()) {
       return false;
+    }
 
-    // Remeber where the value starts
-    nsACString::const_iterator val = caret;
-    nsACString::const_iterator comma = end;
-    bool escape = false;
-    while (caret != end) {
-      nsACString::const_iterator at = caret;
-      ++caret; // we can safely break/continue the loop now
-
-      if (*at == ',') {
-        if (comma != end) {
-          // another comma (we have found ",," -> escape)
-          comma = end;
-          escape = true;
-        } else {
-          comma = at;
+    Token t;
+    while (Next(t)) {
+      if (!Token::Char(',').Equals(t)) {
+        if (result) {
+          result->Append(t.Fragment());
         }
         continue;
       }
 
-      if (comma != end) {
-        // after a single comma
-        break;
+      if (CheckChar(',')) {
+        // Two commas in a row, escaping
+        if (result) {
+          result->Append(',');
+        }
+        continue;
       }
+
+      // We must give the comma back since the upper calls expect it
+      Rollback();
+      return true;
     }
 
-    // At this point |comma| points to the last and lone ',' we've hit.
-    // If a lone comma was not found, |comma| is at the end of the buffer,
-    // that is not expected and we return failure.
-
-    caret = comma;
-    if (result) {
-      if (escape) {
-        // No ReplaceSubstring on nsACString..
-        nsAutoCString _result(Substring(val, caret));
-        _result.ReplaceSubstring(NS_LITERAL_CSTRING(",,"), NS_LITERAL_CSTRING(","));
-        result->Assign(_result);
-      } else {
-        result->Assign(Substring(val, caret));
-      }
-    }
-
-    return caret != end;
+    return false;
   }
 
 public:
   already_AddRefed<LoadContextInfo> Parse()
   {
     nsRefPtr<LoadContextInfo> info;
-    if (ParseTags())
-      info = GetLoadContextInfo(isPrivate, appId, isInBrowser, isAnonymous);
+    if (ParseTags()) {
+      info = GetLoadContextInfo(isPrivate, isAnonymous, originAttribs);
+    }
 
     return info.forget();
   }
 
   void URISpec(nsACString &result)
   {
-    // cacheKey is either pointing to end or the position where the cache key is.
-    result.Assign(Substring(cacheKey, end));
+    result.Assign(cacheKey);
   }
 
   void IdEnhance(nsACString &result)
   {
     result.Assign(idEnhance);
   }
 };
 
 } // namespace
 
 already_AddRefed<nsILoadContextInfo>
 ParseKey(const nsCSubstring &aKey,
          nsCSubstring *aIdEnhance,
          nsCSubstring *aURISpec)
 {
-  nsACString::const_iterator caret, end;
-  aKey.BeginReading(caret);
-  aKey.EndReading(end);
-
-  KeyParser parser(caret, end);
+  KeyParser parser(aKey);
   nsRefPtr<LoadContextInfo> info = parser.Parse();
 
   if (info) {
     if (aIdEnhance)
       parser.IdEnhance(*aIdEnhance);
     if (aURISpec)
       parser.URISpec(*aURISpec);
   }
@@ -226,28 +201,25 @@ AppendKeyPrefix(nsILoadContextInfo* aInf
   /**
    * This key is used to salt file hashes.  When form of the key is changed
    * cache entries will fail to find on disk.
    *
    * IMPORTANT NOTE:
    * Keep the attributes list sorted according their ASCII code.
    */
 
-  if (aInfo->IsAnonymous()) {
-    _retval.AppendLiteral("a,");
+  OriginAttributes const *oa = aInfo->OriginAttributesPtr();
+  nsAutoCString suffix;
+  oa->CreateSuffix(suffix);
+  if (!suffix.IsEmpty()) {
+    AppendTagWithValue(_retval, 'O', suffix);
   }
 
-  if (aInfo->IsInBrowserElement()) {
-    _retval.AppendLiteral("b,");
-  }
-
-  if (aInfo->AppId() != nsILoadContextInfo::NO_APP_ID) {
-    _retval.Append('i');
-    _retval.AppendInt(aInfo->AppId());
-    _retval.Append(',');
+  if (aInfo->IsAnonymous()) {
+    _retval.AppendLiteral("a,");
   }
 
   if (aInfo->IsPrivate()) {
     _retval.AppendLiteral("p,");
   }
 }
 
 void
--- a/netwerk/cache2/CacheIndex.cpp
+++ b/netwerk/cache2/CacheIndex.cpp
@@ -2566,18 +2566,21 @@ CacheIndex::SetupDirectoryEnumerator()
 void
 CacheIndex::InitEntryFromDiskData(CacheIndexEntry *aEntry,
                                   CacheFileMetadata *aMetaData,
                                   int64_t aFileSize)
 {
   aEntry->InitNew();
   aEntry->MarkDirty();
   aEntry->MarkFresh();
-  aEntry->Init(aMetaData->AppId(), aMetaData->IsAnonymous(),
-               aMetaData->IsInBrowser());
+
+  // Bug 1201042 - will pass OriginAttributes directly.
+  aEntry->Init(aMetaData->OriginAttributes().mAppId,
+               aMetaData->IsAnonymous(),
+               aMetaData->OriginAttributes().mInBrowser);
 
   uint32_t expirationTime;
   aMetaData->GetExpirationTime(&expirationTime);
   aEntry->SetExpirationTime(expirationTime);
 
   uint32_t frecency;
   aMetaData->GetFrecency(&frecency);
   aEntry->SetFrecency(frecency);
--- a/netwerk/cache2/CacheIndex.h
+++ b/netwerk/cache2/CacheIndex.h
@@ -254,19 +254,19 @@ public:
          IsDirty(), Anonymous(), InBrowser(), AppId(), GetFrecency(),
          GetExpirationTime(), GetFileSize()));
   }
 
   static bool RecordMatchesLoadContextInfo(CacheIndexRecord *aRec,
                                            nsILoadContextInfo *aInfo)
   {
     if (!aInfo->IsPrivate() &&
-        aInfo->AppId() == aRec->mAppId &&
+        aInfo->OriginAttributesPtr()->mAppId == aRec->mAppId &&
         aInfo->IsAnonymous() == !!(aRec->mFlags & kAnonymousMask) &&
-        aInfo->IsInBrowserElement() == !!(aRec->mFlags & kInBrowserMask)) {
+        aInfo->OriginAttributesPtr()->mInBrowser == !!(aRec->mFlags & kInBrowserMask)) {
       return true;
     }
 
     return false;
   }
 
   // Memory reporting
   size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
--- a/netwerk/cache2/CacheObserver.cpp
+++ b/netwerk/cache2/CacheObserver.cpp
@@ -4,17 +4,16 @@
 
 #include "CacheObserver.h"
 
 #include "CacheStorageService.h"
 #include "CacheFileIOManager.h"
 #include "LoadContextInfo.h"
 #include "nsICacheStorage.h"
 #include "nsIObserverService.h"
-#include "mozIApplicationClearPrivateDataParams.h"
 #include "mozilla/Services.h"
 #include "mozilla/Preferences.h"
 #include "nsServiceManagerUtils.h"
 #include "prsystem.h"
 #include <time.h>
 #include <math.h>
 
 namespace mozilla {
@@ -113,17 +112,17 @@ CacheObserver::Init()
   NS_ADDREF(sSelf);
 
   obs->AddObserver(sSelf, "prefservice:after-app-defaults", true);
   obs->AddObserver(sSelf, "profile-do-change", true);
   obs->AddObserver(sSelf, "browser-delayed-startup-finished", true);
   obs->AddObserver(sSelf, "profile-before-change", true);
   obs->AddObserver(sSelf, "xpcom-shutdown", true);
   obs->AddObserver(sSelf, "last-pb-context-exited", true);
-  obs->AddObserver(sSelf, "webapps-clear-data", true);
+  obs->AddObserver(sSelf, "clear-origin-data", true);
   obs->AddObserver(sSelf, "memory-pressure", true);
 
   return NS_OK;
 }
 
 // static
 nsresult
 CacheObserver::Shutdown()
@@ -387,65 +386,25 @@ void CacheObserver::ParentDirOverride(ns
     return;
   if (!sSelf->mCacheParentDirectoryOverride)
     return;
 
   sSelf->mCacheParentDirectoryOverride->Clone(aDir);
 }
 
 namespace {
-
-class CacheStorageEvictHelper
-{
-public:
-  nsresult Run(mozIApplicationClearPrivateDataParams* aParams);
+namespace CacheStorageEvictHelper {
 
-private:
-  uint32_t mAppId;
-  nsresult ClearStorage(bool const aPrivate,
-                        bool const aInBrowser,
-                        bool const aAnonymous);
-};
-
-nsresult
-CacheStorageEvictHelper::Run(mozIApplicationClearPrivateDataParams* aParams)
+nsresult ClearStorage(bool const aPrivate,
+                      bool const aAnonymous,
+                      OriginAttributes const &aOa)
 {
   nsresult rv;
 
-  rv = aParams->GetAppId(&mAppId);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  bool aBrowserOnly;
-  rv = aParams->GetBrowserOnly(&aBrowserOnly);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  MOZ_ASSERT(mAppId != nsILoadContextInfo::UNKNOWN_APP_ID);
-
-  // Clear all [private X anonymous] combinations
-  rv = ClearStorage(false, aBrowserOnly, false);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = ClearStorage(false, aBrowserOnly, true);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = ClearStorage(true, aBrowserOnly, false);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = ClearStorage(true, aBrowserOnly, true);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
-}
-
-nsresult
-CacheStorageEvictHelper::ClearStorage(bool const aPrivate,
-                                      bool const aInBrowser,
-                                      bool const aAnonymous)
-{
-  nsresult rv;
-
-  nsRefPtr<LoadContextInfo> info = GetLoadContextInfo(
-    aPrivate, mAppId, aInBrowser, aAnonymous);
+  nsRefPtr<LoadContextInfo> info = GetLoadContextInfo(aPrivate, aAnonymous, aOa);
 
   nsCOMPtr<nsICacheStorage> storage;
   nsRefPtr<CacheStorageService> service = CacheStorageService::Self();
   NS_ENSURE_TRUE(service, NS_ERROR_FAILURE);
 
   // Clear disk storage
   rv = service->DiskCacheStorage(info, false, getter_AddRefs(storage));
   NS_ENSURE_SUCCESS(rv, rv);
@@ -453,25 +412,38 @@ CacheStorageEvictHelper::ClearStorage(bo
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Clear memory storage
   rv = service->MemoryCacheStorage(info, getter_AddRefs(storage));
   NS_ENSURE_SUCCESS(rv, rv);
   rv = storage->AsyncEvictStorage(nullptr);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  if (!aInBrowser) {
-    rv = ClearStorage(aPrivate, true, aAnonymous);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
+  return NS_OK;
+}
+
+nsresult Run(OriginAttributes const &aOa)
+{
+  nsresult rv;
+
+  // Clear all [private X anonymous] combinations
+  rv = ClearStorage(false, false, aOa);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = ClearStorage(false, true, aOa);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = ClearStorage(true, false, aOa);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = ClearStorage(true, true, aOa);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
-} // namespace
+} // CacheStorageEvictHelper
+} // anon
 
 // static
 bool const CacheObserver::EntryIsTooBig(int64_t aSize, bool aUsingDisk)
 {
   // If custom limit is set, check it.
   int64_t preferredLimit = aUsingDisk ? sMaxDiskEntrySize : sMaxMemoryEntrySize;
 
   // do not convert to bytes when the limit is -1, which means no limit
@@ -537,26 +509,24 @@ CacheObserver::Observe(nsISupports* aSub
   if (!strcmp(aTopic, "last-pb-context-exited")) {
     nsRefPtr<CacheStorageService> service = CacheStorageService::Self();
     if (service)
       service->DropPrivateBrowsingEntries();
 
     return NS_OK;
   }
 
-  if (!strcmp(aTopic, "webapps-clear-data")) {
-    nsCOMPtr<mozIApplicationClearPrivateDataParams> params =
-            do_QueryInterface(aSubject);
-    if (!params) {
-      NS_ERROR("'webapps-clear-data' notification's subject should be a mozIApplicationClearPrivateDataParams");
-      return NS_ERROR_UNEXPECTED;
+  if (!strcmp(aTopic, "clear-origin-data")) {
+    OriginAttributes oa;
+    if (!oa.Init(nsDependentString(aData))) {
+      NS_ERROR("Could not parse OriginAttributes JSON in clear-origin-data notification");
+      return NS_OK;
     }
 
-    CacheStorageEvictHelper helper;
-    nsresult rv = helper.Run(params);
+    nsresult rv = CacheStorageEvictHelper::Run(oa);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_OK;
   }
 
   if (!strcmp(aTopic, "memory-pressure")) {
     nsRefPtr<CacheStorageService> service = CacheStorageService::Self();
     if (service)
--- a/netwerk/cache2/OldWrappers.cpp
+++ b/netwerk/cache2/OldWrappers.cpp
@@ -523,18 +523,17 @@ NS_IMETHODIMP _OldCacheEntryWrapper::Vis
 
 namespace {
 
 nsresult
 GetCacheSessionNameForStoragePolicy(
         nsCSubstring const &scheme,
         nsCacheStoragePolicy storagePolicy,
         bool isPrivate,
-        uint32_t appId,
-        bool inBrowser,
+        OriginAttributes const *originAttribs,
         nsACString& sessionName)
 {
   MOZ_ASSERT(!isPrivate || storagePolicy == nsICache::STORE_IN_MEMORY);
 
   // HTTP
   if (scheme.EqualsLiteral("http") ||
       scheme.EqualsLiteral("https")) {
     switch (storagePolicy) {
@@ -577,22 +576,19 @@ GetCacheSessionNameForStoragePolicy(
     // URL schemes.
     // Deliberately omitting |anonymous| since other session types don't
     // recognize it too.
     sessionName.AssignLiteral("other");
     if (isPrivate)
       sessionName.AppendLiteral("-private");
   }
 
-  if (appId != nsILoadContextInfo::NO_APP_ID || inBrowser) {
-    sessionName.Append('~');
-    sessionName.AppendInt(appId);
-    sessionName.Append('~');
-    sessionName.AppendInt(inBrowser);
-  }
+  nsAutoCString suffix;
+  originAttribs->CreateSuffix(suffix);
+  sessionName.Append(suffix);
 
   return NS_OK;
 }
 
 nsresult
 GetCacheSession(nsCSubstring const &aScheme,
                 bool aWriteToDisk,
                 nsILoadContextInfo* aLoadInfo,
@@ -613,18 +609,17 @@ GetCacheSession(nsCSubstring const &aSch
   if (aAppCache) {
     aAppCache->GetClientID(clientId);
   }
   else {
     rv = GetCacheSessionNameForStoragePolicy(
       aScheme,
       storagePolicy,
       aLoadInfo->IsPrivate(),
-      aLoadInfo->AppId(),
-      aLoadInfo->IsInBrowserElement(),
+      aLoadInfo->OriginAttributesPtr(),
       clientId);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   LOG(("  GetCacheSession for client=%s, policy=%d", clientId.get(), storagePolicy));
 
   nsCOMPtr<nsICacheService> serv =
       do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
@@ -995,36 +990,39 @@ NS_IMETHODIMP _OldStorage::AsyncDoomURI(
 
 NS_IMETHODIMP _OldStorage::AsyncEvictStorage(nsICacheEntryDoomCallback* aCallback)
 {
   LOG(("_OldStorage::AsyncEvictStorage"));
 
   nsresult rv;
 
   if (!mAppCache && mOfflineStorage) {
+    // TODO - bug 1165256, have an API on nsIApplicationCacheService that takes
+    // optional OAs and decides internally what to do.
+
     // Special casing for pure offline storage
-    if (mLoadInfo->AppId() == nsILoadContextInfo::NO_APP_ID &&
-        !mLoadInfo->IsInBrowserElement()) {
+    if (mLoadInfo->OriginAttributesPtr()->mAppId == nsILoadContextInfo::NO_APP_ID &&
+        !mLoadInfo->OriginAttributesPtr()->mInBrowser) {
 
       // Clear everything.
       nsCOMPtr<nsICacheService> serv =
           do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
       NS_ENSURE_SUCCESS(rv, rv);
 
       rv = nsCacheService::GlobalInstance()->EvictEntriesInternal(nsICache::STORE_OFFLINE);
       NS_ENSURE_SUCCESS(rv, rv);
     }
     else {
       // Clear app or inbrowser staff.
       nsCOMPtr<nsIApplicationCacheService> appCacheService =
         do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID, &rv);
       NS_ENSURE_SUCCESS(rv, rv);
 
-      rv = appCacheService->DiscardByAppId(mLoadInfo->AppId(),
-                                           mLoadInfo->IsInBrowserElement());
+      rv = appCacheService->DiscardByAppId(mLoadInfo->OriginAttributesPtr()->mAppId,
+                                           mLoadInfo->OriginAttributesPtr()->mInBrowser);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
   else {
     if (mAppCache) {
       nsCOMPtr<nsICacheSession> session;
       rv = GetCacheSession(EmptyCString(),
                            mWriteToDisk, mLoadInfo, mAppCache,
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -2909,17 +2909,16 @@ nsHttpChannel::OpenCacheEntry(bool isHtt
             appCacheContainer->GetApplicationCache(getter_AddRefs(mApplicationCache));
         }
     }
 
     nsCOMPtr<nsICacheStorageService> cacheStorageService =
         do_GetService("@mozilla.org/netwerk/cache-storage-service;1", &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    nsRefPtr<LoadContextInfo> info = GetLoadContextInfo(this);
     nsCOMPtr<nsICacheStorage> cacheStorage;
     nsCOMPtr<nsIURI> openURI;
     if (!mFallbackKey.IsEmpty() && mFallbackChannel) {
         // This is a fallback channel, open fallback URI instead
         rv = NS_NewURI(getter_AddRefs(openURI), mFallbackKey);
         NS_ENSURE_SUCCESS(rv, rv);
     }
     else {
@@ -2929,17 +2928,22 @@ nsHttpChannel::OpenCacheEntry(bool isHtt
         // redirect is the same.
         if (PossiblyIntercepted()) {
             openURI = mOriginalURI;
         } else {
             openURI = mURI;
         }
     }
 
-    uint32_t appId = info->AppId();
+    nsRefPtr<LoadContextInfo> info = GetLoadContextInfo(this);
+    if (!info) {
+        return NS_ERROR_FAILURE;
+    }
+
+    uint32_t appId = info->OriginAttributesPtr()->mAppId;
     bool appOffline = false;
 
     if (appId != NECKO_NO_APP_ID) {
         gIOService->IsAppOffline(appId, &appOffline);
         LOG(("nsHttpChannel::OpenCacheEntry appId: %u, offline: %d\n", appId, appOffline));
     }
 
     uint32_t cacheEntryOpenFlags;
--- a/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp
+++ b/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp
@@ -21,16 +21,17 @@
 #include "nsIEventTarget.h"
 #include "nsIInputStream.h"
 #include "nsIInputStreamPump.h"
 #include "nsIOutputStream.h"
 #include "nsIProgressEventSink.h"
 #include "nsIURI.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/unused.h"
+#include "mozilla/BasePrincipal.h"
 #include "nsProxyRelease.h"
 #include "nsContentSecurityManager.h"
 
 typedef mozilla::net::LoadContextInfo LoadContextInfo;
 
 // Must release mChannel on the main thread
 class nsWyciwygAsyncEvent : public nsRunnable {
 public:
@@ -95,19 +96,17 @@ private:
 nsWyciwygChannel::nsWyciwygChannel()
   : mMode(NONE),
     mStatus(NS_OK),
     mIsPending(false),
     mCharsetAndSourceSet(false),
     mNeedToWriteCharset(false),
     mCharsetSource(kCharsetUninitialized),
     mContentLength(-1),
-    mLoadFlags(LOAD_NORMAL),
-    mAppId(NECKO_NO_APP_ID),
-    mInBrowser(false)
+    mLoadFlags(LOAD_NORMAL)
 {
 }
 
 nsWyciwygChannel::~nsWyciwygChannel() 
 {
   if (mLoadInfo) {
     nsCOMPtr<nsIThread> mainThread;
     NS_GetMainThread(getter_AddRefs(mainThread));
@@ -228,17 +227,18 @@ nsWyciwygChannel::SetLoadGroup(nsILoadGr
   }
 
   mLoadGroup = aLoadGroup;
   NS_QueryNotificationCallbacks(mCallbacks,
                                 mLoadGroup,
                                 NS_GET_IID(nsIProgressEventSink),
                                 getter_AddRefs(mProgressSink));
   mPrivateBrowsing = NS_UsePrivateBrowsing(this);
-  NS_GetAppInfo(this, &mAppId, &mInBrowser);
+  NS_GetOriginAttributes(this, mOriginAttributes);
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWyciwygChannel::SetLoadFlags(uint32_t aLoadFlags)
 {
   mLoadFlags = aLoadFlags;
   return NS_OK;
@@ -324,17 +324,17 @@ nsWyciwygChannel::SetNotificationCallbac
 
   mCallbacks = aNotificationCallbacks;
   NS_QueryNotificationCallbacks(mCallbacks,
                                 mLoadGroup,
                                 NS_GET_IID(nsIProgressEventSink),
                                 getter_AddRefs(mProgressSink));
 
   mPrivateBrowsing = NS_UsePrivateBrowsing(this);
-  NS_GetAppInfo(this, &mAppId, &mInBrowser);
+  NS_GetOriginAttributes(this, mOriginAttributes);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP 
 nsWyciwygChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
 {
   NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
@@ -791,17 +791,17 @@ nsWyciwygChannel::OpenCacheEntry(nsIURI 
   nsresult rv;
 
   nsCOMPtr<nsICacheStorageService> cacheService =
     do_GetService("@mozilla.org/netwerk/cache-storage-service;1", &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool anonymous = mLoadFlags & LOAD_ANONYMOUS;
   nsRefPtr<LoadContextInfo> loadInfo = mozilla::net::GetLoadContextInfo(
-    mPrivateBrowsing, mAppId, mInBrowser, anonymous);
+    mPrivateBrowsing, anonymous, mOriginAttributes);
 
   nsCOMPtr<nsICacheStorage> cacheStorage;
   if (mLoadFlags & INHIBIT_PERSISTENT_CACHING)
     rv = cacheService->MemoryCacheStorage(loadInfo, getter_AddRefs(cacheStorage));
   else
     rv = cacheService->DiskCacheStorage(loadInfo, false, getter_AddRefs(cacheStorage));
   NS_ENSURE_SUCCESS(rv, rv);
 
--- a/netwerk/protocol/wyciwyg/nsWyciwygChannel.h
+++ b/netwerk/protocol/wyciwyg/nsWyciwygChannel.h
@@ -10,16 +10,17 @@
 #include "nsString.h"
 #include "nsCOMPtr.h"
 
 #include "nsILoadInfo.h"
 #include "nsIWyciwygChannel.h"
 #include "nsIStreamListener.h"
 #include "nsICacheEntryOpenCallback.h"
 #include "PrivateBrowsingChannel.h"
+#include "mozilla/BasePrincipal.h"
 
 class nsICacheEntry;
 class nsIEventTarget;
 class nsIInputStream;
 class nsIInputStreamPump;
 class nsILoadGroup;
 class nsIOutputStream;
 class nsIProgressEventSink;
@@ -81,18 +82,17 @@ protected:
     nsresult                            mStatus;
     bool                                mIsPending;
     bool                                mCharsetAndSourceSet;
     bool                                mNeedToWriteCharset;
     int32_t                             mCharsetSource;
     nsCString                           mCharset;
     int64_t                             mContentLength;
     uint32_t                            mLoadFlags;
-    uint32_t                            mAppId;
-    bool                                mInBrowser;
+    mozilla::OriginAttributes           mOriginAttributes;
     nsCOMPtr<nsIURI>                    mURI;
     nsCOMPtr<nsIURI>                    mOriginalURI;
     nsCOMPtr<nsISupports>               mOwner;
     nsCOMPtr<nsILoadInfo>               mLoadInfo;
     nsCOMPtr<nsIInterfaceRequestor>     mCallbacks;
     nsCOMPtr<nsIProgressEventSink>      mProgressSink;
     nsCOMPtr<nsILoadGroup>              mLoadGroup;
     nsCOMPtr<nsIStreamListener>         mListener;
--- a/netwerk/test/mochitests/test_web_packaged_app.html
+++ b/netwerk/test/mochitests/test_web_packaged_app.html
@@ -14,17 +14,17 @@
 </div>
 <pre id="test">
 <script class="testbody" type="application/javascript;version=1.7">
 
 var Cc = SpecialPowers.Cc;
 var Ci = SpecialPowers.Ci;
 var Cu = SpecialPowers.Cu;
 var Cr = SpecialPowers.Cr;
-var LoadContextInfo = Cu.import("resource://gre/modules/LoadContextInfo.jsm", {}).LoadContextInfo;
+var LoadContextInfo = Cc["@mozilla.org/load-context-info-factory;1"].getService(Ci.nsILoadContextInfoFactory);
 var CommonUtils = Cu.import("resource://services-common/utils.js", {}).CommonUtils;
 
 function CacheCallback(expect) {
   this.expect = expect || true;
 }
 
 CacheCallback.prototype = {
   QueryInterface: function(iid) {
@@ -38,17 +38,17 @@ CacheCallback.prototype = {
   onCacheEntryAvailable: function(entry, isnew, applicationCache, status) {
     is(status, this.expect ? Cr.NS_OK : Cr.NS_ERROR_CACHE_KEY_NOT_FOUND, "check status");
     is(!!entry, this.expect, "check if entry exists");
     SpecialPowers.executeSoon(continueTest);
   }
 };
 
 function checkCacheEntry(url, exists, appId) {
-  var loadContext = appId ? LoadContextInfo.custom(false, false, appId, false) : LoadContextInfo.default;
+  var loadContext = appId ? LoadContextInfo.custom(false, false, {appId: appId}) : LoadContextInfo.default;
   var cacheService = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
                      .getService(Ci.nsICacheStorageService);
   var cache = cacheService.diskCacheStorage(loadContext, false);
   cache.asyncOpenURI(CommonUtils.makeURI(url), "", 0, new CacheCallback(exists));
 }
 
 var gGenerator = runTest();
 
--- a/netwerk/test/unit/test_bug248970_cache.js
+++ b/netwerk/test/unit/test_bug248970_cache.js
@@ -42,17 +42,17 @@ function store_entries(cb)
   if (store_idx == entries.length) {
     do_execute_soon(store_cb);
     return;
   }
 
   asyncOpenCacheEntry(entries[store_idx][0],
                       entries[store_idx][2],
                       Ci.nsICacheStorage.OPEN_TRUNCATE,
-                      LoadContextInfo.custom(!entries[store_idx][3]),
+                      LoadContextInfo.custom(!entries[store_idx][3], false, {}),
                       store_data,
                       appCache);
 }
 
 var store_data = function(status, entry) {
   do_check_eq(status, Cr.NS_OK);
   var os = entry.openOutputStream(0);
 
@@ -82,17 +82,17 @@ function check_entries(cb, pbExited)
   if (check_idx == entries.length) {
     do_execute_soon(check_cb);
     return;
   }
 
   asyncOpenCacheEntry(entries[check_idx][0],
                       entries[check_idx][2],
                       Ci.nsICacheStorage.OPEN_READONLY,
-                      LoadContextInfo.custom(!entries[check_idx][3]),
+                      LoadContextInfo.custom(!entries[check_idx][3], false, {}),
                       check_data,
                       appCache);
 }
 
 var check_data = function (status, entry) {
   var cont = function() {
     check_idx++;
     do_execute_soon(check_entries);
--- a/netwerk/test/unit/test_cache_jar.js
+++ b/netwerk/test/unit/test_cache_jar.js
@@ -58,36 +58,30 @@ function run_all_tests() {
   }
 
   // We can't easily cause webapp data to be cleared from the child process, so skip
   // the rest of these tests.
   let procType = Cc["@mozilla.org/xre/runtime;1"].getService(Ci.nsIXULRuntime).processType;
   if (procType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT)
     return;
 
-  let subject = {
-    appId: 1,
-    browserOnly: true,
-    QueryInterface: XPCOMUtils.generateQI([Ci.mozIApplicationClearPrivateDataParams])
-  };
-  Services.obs.notifyObservers(subject, "webapps-clear-data", null);
+  let attrs_inBrowser = JSON.stringify({ appId:1, inBrowser:true });
+  let attrs_notInBrowser = JSON.stringify({ appId:1 });
+
+  Services.obs.notifyObservers(null, "clear-origin-data", attrs_inBrowser);
 
   for (let test of secondTests) {
     handlers_called = 0;
     var chan = makeChan(URL, test[0], test[1]);
     chan.asyncOpen(new ChannelListener(doneFirstLoad, test[2]), null);
     yield undefined;
   }
 
-  subject = {
-    appId: 1,
-    browserOnly: false,
-    QueryInterface: XPCOMUtils.generateQI([Ci.mozIApplicationClearPrivateDataParams])
-  };
-  Services.obs.notifyObservers(subject, "webapps-clear-data", null);
+  Services.obs.notifyObservers(null, "clear-origin-data", attrs_notInBrowser);
+  Services.obs.notifyObservers(null, "clear-origin-data", attrs_inBrowser);
 
   for (let test of thirdTests) {
     handlers_called = 0;
     var chan = makeChan(URL, test[0], test[1]);
     chan.asyncOpen(new ChannelListener(doneFirstLoad, test[2]), null);
     yield undefined;
   }
 }
--- a/netwerk/test/unit/test_predictor.js
+++ b/netwerk/test/unit/test_predictor.js
@@ -1,14 +1,15 @@
 var Cc = Components.classes;
 var Ci = Components.interfaces;
 var Cu = Components.utils;
 var Cr = Components.results;
 
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/LoadContextInfo.jsm");
 
 var running_single_process = false;
 
 var predictor = null;
 
 function is_child_process() {
   return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).processType == Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT;
 }
@@ -145,31 +146,17 @@ var prepListener = {
     this.numEntriesOpened++;
     if (this.numEntriesToOpen == this.numEntriesOpened) {
       this.continueCallback();
     }
   }
 };
 
 function open_and_continue(uris, continueCallback) {
-  var lci = {
-    QueryInterface: function (iid) {
-      if (iid.equals(Ci.nsILoadContextInfo)) {
-        return this;
-      }
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    },
-
-    isPrivate: false,
-    appId: Ci.nsILoadContextInfo.NO_APP_ID,
-    isInBrowserElement: false,
-    isAnonymous: false
-  };
-
-  var ds = Services.cache2.diskCacheStorage(lci, false);
+  var ds = Services.cache2.diskCacheStorage(LoadContextInfo.default, false);
 
   prepListener.init(uris.length, continueCallback);
   for (var i = 0; i < uris.length; ++i) {
     ds.asyncOpenURI(uris[i], "", Ci.nsICacheStorage.OPEN_NORMALLY,
                     prepListener);
   }
 }
 
--- a/toolkit/modules/LoadContextInfo.jsm
+++ b/toolkit/modules/LoadContextInfo.jsm
@@ -1,69 +1,15 @@
 /* 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/. */
 
-this.EXPORTED_SYMBOLS = ["LoadContextInfo"];
-
-const Ci = Components.interfaces;
-const Cc = Components.classes;
-const Cr = Components.results;
-
-Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
-Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
-
-this.LoadContextInfo = {};
-
-_LoadContextInfo.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsILoadContextInfo, Ci.nsISupports]),
-  get isPrivate() { return this._isPrivate },
-  get isAnonymous() { return this._isAnonymous },
-  get isInBrowserElement() { return this._isInBrowserElement },
-  get appId() { return this._appId }
-}
-
-function _LoadContextInfo(_private, _anonymous, _appId, _inBrowser) {
-  this._isPrivate = _private || false;
-  this._isAnonymous = _anonymous || false;
-  this._appId = _appId || 0;
-  this._isInBrowserElement = _inBrowser || false;
-}
-
-// LoadContextInfo.default
-
-// Non-private, non-anonymous, no app ID, not in browser
-XPCOMUtils.defineLazyGetter(LoadContextInfo, "default", function () {
-  return new _LoadContextInfo(false, false, 0, false);
-});
+/**
+ * This jsm is here only for compatibility.  Extension developers may use it
+ * to build nsILoadContextInfo to pass down to HTTP cache APIs.  Originally
+ * it was possible to implement nsILoadContextInfo in JS.  But now it turned
+ * out to be a built-in class only, so we need a component (service) as
+ * a factory to build nsILoadContextInfo in a JS code.
+ */
 
-// LoadContextInfo.private
-
-// Private, non-anonymous, no app ID, not in browser
-XPCOMUtils.defineLazyGetter(LoadContextInfo, "private", function () {
-  return new _LoadContextInfo(true, false, 0, false);
-});
-
-// LoadContextInfo.anonymous
-
-// Non-private, anonymous, no app ID, not in browser
-XPCOMUtils.defineLazyGetter(LoadContextInfo, "anonymous", function () {
-  return new _LoadContextInfo(false, true, 0, false);
-});
-
-// Fully customizable
-LoadContextInfo.custom = function(_private, _anonymous, _appId, _inBrowser) {
-  return new _LoadContextInfo(_private, _anonymous, _appId, _inBrowser);
-}
-
-// Copies info from provided nsILoadContext
-LoadContextInfo.fromLoadContext = function(_loadContext, _anonymous) {
-  return new _LoadContextInfo(_loadContext.usePrivateBrowsing,
-                              _anonymous,
-                              _loadContext.appId,
-                              _loadContext.isInBrowserElement);
-}
-
-// Copies info from provided window object
-LoadContextInfo.fromWindow = function(_window, _anonymous) {
-  var loadContext = PrivateBrowsingUtils.privacyContextFromWindow(_window);
-  return this.fromLoadContext(loadContext, _anonymous);
-}
+this.EXPORTED_SYMBOLS = ["LoadContextInfo"];
+this.LoadContextInfo = Components.classes["@mozilla.org/load-context-info-factory;1"]
+                                 .getService(Components.interfaces.nsILoadContextInfoFactory);
--- a/toolkit/modules/Services.jsm
+++ b/toolkit/modules/Services.jsm
@@ -96,16 +96,17 @@ var initTable = [
   ["startup", "@mozilla.org/toolkit/app-startup;1", "nsIAppStartup"],
   ["sysinfo", "@mozilla.org/system-info;1", "nsIPropertyBag2"],
   ["clipboard", "@mozilla.org/widget/clipboard;1", "nsIClipboard"],
   ["DOMRequest", "@mozilla.org/dom/dom-request-service;1", "nsIDOMRequestService"],
   ["focus", "@mozilla.org/focus-manager;1", "nsIFocusManager"],
   ["uriFixup", "@mozilla.org/docshell/urifixup;1", "nsIURIFixup"],
   ["blocklist", "@mozilla.org/extensions/blocklist;1", "nsIBlocklistService"],
   ["netUtils", "@mozilla.org/network/util;1", "nsINetUtil"],
+  ["loadContextInfo", "@mozilla.org/load-context-info-factory;1", "nsILoadContextInfoFactory"],
 ];
 
 initTable.forEach(([name, contract, intf, enabled = true]) => {
   if (enabled) {
     XPCOMUtils.defineLazyServiceGetter(Services, name, contract, intf);
   }
 });