Bug 1127618 - make push caches work in e10s. r=mcmanus r=froydnj IGNORE IDL
authorNicholas Hurley <hurley@todesschaf.org>
Fri, 31 Jul 2015 13:50:08 -0700
changeset 255988 69f2a0f7b8ad400e807a2c57424585c2b4ff9d31
parent 255987 3ace20f28dc3a891734983be30893e673774b667
child 255989 887432a3049f36070e6518157c70f6d2008c4963
push id29163
push usercbook@mozilla.com
push dateTue, 04 Aug 2015 11:01:35 +0000
treeherdermozilla-central@5cf4d2f7f2f2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmcmanus, froydnj
bugs1127618
milestone42.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 1127618 - make push caches work in e10s. r=mcmanus r=froydnj IGNORE IDL
netwerk/base/SchedulingContextService.cpp
netwerk/base/SchedulingContextService.h
netwerk/base/moz.build
netwerk/base/nsILoadGroup.idl
netwerk/base/nsISchedulingContext.idl
netwerk/base/nsLoadGroup.cpp
netwerk/base/nsLoadGroup.h
netwerk/build/nsNetCID.h
netwerk/build/nsNetModule.cpp
netwerk/ipc/NeckoChannelParams.ipdlh
netwerk/ipc/NeckoChild.cpp
netwerk/ipc/NeckoChild.h
netwerk/ipc/NeckoParent.cpp
netwerk/ipc/NeckoParent.h
netwerk/ipc/PNecko.ipdl
netwerk/protocol/http/Http2Push.cpp
netwerk/protocol/http/Http2Push.h
netwerk/protocol/http/Http2Session.cpp
netwerk/protocol/http/Http2Stream.cpp
netwerk/protocol/http/Http2Stream.h
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/protocol/http/HttpBaseChannel.h
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/protocol/http/HttpChannelParent.h
netwerk/protocol/http/NullHttpChannel.cpp
netwerk/protocol/http/SpdyPush31.cpp
netwerk/protocol/http/SpdyPush31.h
netwerk/protocol/http/SpdySession31.cpp
netwerk/protocol/http/SpdyStream31.cpp
netwerk/protocol/http/SpdyStream31.h
netwerk/protocol/http/nsAHttpTransaction.h
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/protocol/http/nsHttpChannel.h
netwerk/protocol/http/nsHttpConnectionMgr.cpp
netwerk/protocol/http/nsHttpHandler.cpp
netwerk/protocol/http/nsHttpHandler.h
netwerk/protocol/http/nsHttpTransaction.cpp
netwerk/protocol/http/nsHttpTransaction.h
netwerk/protocol/http/nsIHttpChannel.idl
netwerk/protocol/viewsource/nsViewSourceChannel.cpp
netwerk/test/unit/test_http2.js
xpcom/glue/nsID.cpp
xpcom/glue/nsID.h
new file mode 100644
--- /dev/null
+++ b/netwerk/base/SchedulingContextService.cpp
@@ -0,0 +1,203 @@
+/* -*- 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 "nsAutoPtr.h"
+#include "nsIObserverService.h"
+#include "nsIUUIDGenerator.h"
+#include "nsServiceManagerUtils.h"
+#include "nsThreadUtils.h"
+#include "SchedulingContextService.h"
+
+#include "mozilla/Atomics.h"
+#include "mozilla/Services.h"
+
+#include "mozilla/net/PSpdyPush.h"
+
+namespace mozilla {
+namespace net {
+
+// nsISchedulingContext
+class SchedulingContext final : public nsISchedulingContext
+{
+public:
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_NSISCHEDULINGCONTEXT
+
+  explicit SchedulingContext(const nsID& id);
+private:
+  virtual ~SchedulingContext();
+
+  nsID mID;
+  char mCID[NSID_LENGTH];
+  Atomic<uint32_t>       mBlockingTransactionCount;
+  nsAutoPtr<SpdyPushCache> mSpdyCache;
+};
+
+NS_IMPL_ISUPPORTS(SchedulingContext, nsISchedulingContext)
+
+SchedulingContext::SchedulingContext(const nsID& aID)
+  : mBlockingTransactionCount(0)
+{
+  mID = aID;
+  mID.ToProvidedString(mCID);
+}
+
+SchedulingContext::~SchedulingContext()
+{
+}
+
+NS_IMETHODIMP
+SchedulingContext::GetBlockingTransactionCount(uint32_t *aBlockingTransactionCount)
+{
+  NS_ENSURE_ARG_POINTER(aBlockingTransactionCount);
+  *aBlockingTransactionCount = mBlockingTransactionCount;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SchedulingContext::AddBlockingTransaction()
+{
+  mBlockingTransactionCount++;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SchedulingContext::RemoveBlockingTransaction(uint32_t *outval)
+{
+  NS_ENSURE_ARG_POINTER(outval);
+  mBlockingTransactionCount--;
+  *outval = mBlockingTransactionCount;
+  return NS_OK;
+}
+
+/* [noscript] attribute SpdyPushCachePtr spdyPushCache; */
+NS_IMETHODIMP
+SchedulingContext::GetSpdyPushCache(mozilla::net::SpdyPushCache **aSpdyPushCache)
+{
+  *aSpdyPushCache = mSpdyCache.get();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SchedulingContext::SetSpdyPushCache(mozilla::net::SpdyPushCache *aSpdyPushCache)
+{
+  mSpdyCache = aSpdyPushCache;
+  return NS_OK;
+}
+
+/* [noscript] readonly attribute nsID ID; */
+NS_IMETHODIMP
+SchedulingContext::GetID(nsID *outval)
+{
+  NS_ENSURE_ARG_POINTER(outval);
+  *outval = mID;
+  return NS_OK;
+}
+
+//nsISchedulingContextService
+SchedulingContextService *SchedulingContextService::sSelf = nullptr;
+
+NS_IMPL_ISUPPORTS(SchedulingContextService, nsISchedulingContextService, nsIObserver)
+
+SchedulingContextService::SchedulingContextService()
+{
+  MOZ_ASSERT(!sSelf, "multiple scs instances!");
+  MOZ_ASSERT(NS_IsMainThread());
+  sSelf = this;
+}
+
+SchedulingContextService::~SchedulingContextService()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  Shutdown();
+  sSelf = nullptr;
+}
+
+nsresult
+SchedulingContextService::Init()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (!obs) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  return obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
+}
+
+void
+SchedulingContextService::Shutdown()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  mTable.Clear();
+}
+
+/* static */ nsresult
+SchedulingContextService::Create(nsISupports *aOuter, const nsIID& aIID, void **aResult)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (aOuter != nullptr) {
+    return NS_ERROR_NO_AGGREGATION;
+  }
+
+  nsRefPtr<SchedulingContextService> svc = new SchedulingContextService();
+  nsresult rv = svc->Init();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return svc->QueryInterface(aIID, aResult);
+}
+
+NS_IMETHODIMP
+SchedulingContextService::GetSchedulingContext(const nsID& scID, nsISchedulingContext **sc)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  NS_ENSURE_ARG_POINTER(sc);
+  *sc = nullptr;
+
+  if (!mTable.Get(scID, sc)) {
+    nsCOMPtr<nsISchedulingContext> newSC = new SchedulingContext(scID);
+    mTable.Put(scID, newSC);
+    newSC.swap(*sc);
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SchedulingContextService::NewSchedulingContextID(nsID *scID)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (!mUUIDGen) {
+    nsresult rv;
+    mUUIDGen = do_GetService("@mozilla.org/uuid-generator;1", &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  return mUUIDGen->GenerateUUIDInPlace(scID);
+}
+
+NS_IMETHODIMP
+SchedulingContextService::RemoveSchedulingContext(const nsID& scID)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  mTable.Remove(scID);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SchedulingContextService::Observe(nsISupports *subject, const char *topic,
+                                  const char16_t *data_unicode)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (!strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, topic)) {
+    Shutdown();
+  }
+
+  return NS_OK;
+}
+
+} // ::mozilla::net
+} // ::mozilla
new file mode 100644
--- /dev/null
+++ b/netwerk/base/SchedulingContextService.h
@@ -0,0 +1,46 @@
+/* -*- 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/. */
+
+#ifndef mozilla__net__SchedulingContextService_h
+#define mozilla__net__SchedulingContextService_h
+
+#include "nsCOMPtr.h"
+#include "nsInterfaceHashtable.h"
+#include "nsIObserver.h"
+#include "nsISchedulingContext.h"
+
+class nsIUUIDGenerator;
+
+namespace mozilla {
+namespace net {
+
+class SchedulingContextService final : public nsISchedulingContextService
+                                     , public nsIObserver
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSISCHEDULINGCONTEXTSERVICE
+  NS_DECL_NSIOBSERVER
+
+  SchedulingContextService();
+
+  nsresult Init();
+  void Shutdown();
+  static nsresult Create(nsISupports *outer, const nsIID& iid, void **result);
+
+private:
+  virtual ~SchedulingContextService();
+
+  static SchedulingContextService *sSelf;
+
+  nsInterfaceHashtable<nsIDHashKey, nsISchedulingContext> mTable;
+  nsCOMPtr<nsIUUIDGenerator> mUUIDGen;
+};
+
+} // ::mozilla::net
+} // ::mozilla
+
+#endif // mozilla__net__SchedulingContextService_h
--- a/netwerk/base/moz.build
+++ b/netwerk/base/moz.build
@@ -87,16 +87,17 @@ XPIDL_SOURCES += [
     'nsIRandomGenerator.idl',
     'nsIRedirectChannelRegistrar.idl',
     'nsIRedirectResultListener.idl',
     'nsIRequest.idl',
     'nsIRequestObserver.idl',
     'nsIRequestObserverProxy.idl',
     'nsIResponseHeadProvider.idl',
     'nsIResumableChannel.idl',
+    'nsISchedulingContext.idl',
     'nsISecCheckWrapChannel.idl',
     'nsISecretDecoderRing.idl',
     'nsISecureBrowserUI.idl',
     'nsISecurityEventSink.idl',
     'nsISecurityInfoProvider.idl',
     'nsISerializationHelper.idl',
     'nsIServerSocket.idl',
     'nsISimpleStreamListener.idl',
@@ -238,16 +239,17 @@ UNIFIED_SOURCES += [
     'nsUnicharStreamLoader.cpp',
     'nsURIChecker.cpp',
     'nsURLHelper.cpp',
     'nsURLParsers.cpp',
     'OfflineObserver.cpp',
     'Predictor.cpp',
     'ProxyAutoConfig.cpp',
     'RedirectChannelRegistrar.cpp',
+    'SchedulingContextService.cpp',
     'StreamingProtocolService.cpp',
     'Tickler.cpp',
     'TLSServerSocket.cpp',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     SOURCES += [
         'nsAutodialWin.cpp',
--- a/netwerk/base/nsILoadGroup.idl
+++ b/netwerk/base/nsILoadGroup.idl
@@ -3,24 +3,24 @@
  * 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 "nsIRequest.idl"
 
 interface nsISimpleEnumerator;
 interface nsIRequestObserver;
 interface nsIInterfaceRequestor;
-interface nsILoadGroupConnectionInfo;
+interface nsISchedulingContext;
 
 typedef unsigned long nsLoadFlags;
 
 /**
  * A load group maintains a collection of nsIRequest objects. 
  */
-[scriptable, uuid(afb57ac2-bce5-4ee3-bb34-385089a9ba5c)]
+[scriptable, uuid(ff6a41f9-0bbf-44ca-9c71-f76c1da2b114)]
 interface nsILoadGroup : nsIRequest
 {
     /**
      * The group observer is notified when requests are added to and removed
      * from this load group.  The groupObserver is weak referenced.
      */
     attribute nsIRequestObserver groupObserver;
 
@@ -71,71 +71,26 @@ interface nsILoadGroup : nsIRequest
     readonly attribute unsigned long activeCount;
 
     /**
      * Notification callbacks for the load group.
      */
     attribute nsIInterfaceRequestor notificationCallbacks;
 
     /**
-     * Connection information for managing things like js/css
-     * connection blocking, and per-tab connection grouping
+     * Context for managing things like js/css connection blocking,
+     * and per-tab connection grouping.
      */
-    readonly attribute nsILoadGroupConnectionInfo connectionInfo;
+    readonly attribute nsID schedulingContextID;
 
     /**
      * The set of load flags that will be added to all new requests added to
      * this group. Any existing requests in the load group are not modified,
      * so it is expected these flags will be added before requests are added
      * to the group - typically via nsIDocShell::defaultLoadFlags on a new
      * docShell.
      * Note that these flags are *not* added to the default request for the
      * load group; it is expected the default request will already have these
      * flags (again, courtesy of setting nsIDocShell::defaultLoadFlags before
      * the docShell has created the default request.)
      */
     attribute nsLoadFlags defaultLoadFlags;
 };
-
-%{C++
-// Forward-declare mozilla::net::SpdyPushCache
-namespace mozilla {
-namespace net {
-class SpdyPushCache;
-}
-}
-%}
-
-[ptr] native SpdyPushCachePtr(mozilla::net::SpdyPushCache);
-
-/**
- * Used to maintain state about the connections of a load group and
- * how they interact with blocking items like HEAD css/js loads.
- */
-
-[uuid(fdc9659c-b597-4ac0-9c9e-14b04dbb682f)]
-interface nsILoadGroupConnectionInfo : nsISupports
-{
-    /**
-     * Number of active blocking transactions associated with this load group
-     */
-    readonly attribute unsigned long blockingTransactionCount;
-
-    /**
-     * Increase the number of active blocking transactions associated
-     * with this load group by one.
-     */
-    void addBlockingTransaction();
-
-    /**
-     * Decrease the number of active blocking transactions associated
-     * with this load group by one. The return value is the number of remaining
-     * blockers.
-     */
-    unsigned long removeBlockingTransaction();
-
-    /* reading this attribute gives out weak pointers to the push
-     * cache. The nsILoadGroupConnectionInfo implemenation owns the cache
-     * and will destroy it when overwritten or when the load group
-    *  ends.
-    */
-    [noscript]  attribute SpdyPushCachePtr spdyPushCache;
-};
new file mode 100644
--- /dev/null
+++ b/netwerk/base/nsISchedulingContext.idl
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+%{C++
+// Forward-declare mozilla::net::SpdyPushCache
+namespace mozilla {
+namespace net {
+class SpdyPushCache;
+}
+}
+%}
+
+[ptr] native SpdyPushCachePtr(mozilla::net::SpdyPushCache);
+
+/**
+ * The nsISchedulingContext is used to maintain state about connections
+ * that are in some way associated with each other (often by being part
+ * of the same load group) and how they interact with blocking items like
+ * HEAD css/js loads.
+ *
+ * This used to be known as nsILoadGroupConnectionInfo.
+ */
+[scriptable, uuid(658e3e6e-8633-4b1a-8d66-fa9f72293e63)]
+interface nsISchedulingContext : nsISupports
+{
+  /**
+   * A unique identifier for this scheduling context
+   */
+  [noscript] readonly attribute nsID ID;
+
+  /**
+   * Number of active blocking transactions associated with this context
+   */
+  readonly attribute unsigned long blockingTransactionCount;
+
+  /**
+   * Increase the number of active blocking transactions associated
+   * with this context by one.
+   */
+  void addBlockingTransaction();
+
+  /**
+   * Decrease the number of active blocking transactions associated
+   * with this context by one. The return value is the number of remaining
+   * blockers.
+   */
+  unsigned long removeBlockingTransaction();
+
+  /**
+   * This gives out a weak pointer to the push cache.
+   * The nsISchedulingContext implementation owns the cache
+   * and will destroy it when overwritten or when the context
+   * ends.
+   */
+  [noscript] attribute SpdyPushCachePtr spdyPushCache;
+};
+
+/**
+ * The nsISchedulingContextService is how anyone gets access to a scheduling
+ * context when they haven't been explicitly given a strong reference to an
+ * existing one. It is responsible for creating and handing out strong
+ * references to nsISchedulingContexts, but only keeps weak references itself.
+ * The shared scheduling context will go away once no one else is keeping a
+ * reference to it. If you ask for a scheduling context that has no one else
+ * holding a reference to it, you'll get a brand new scheduling context. Anyone
+ * who asks for the same scheduling context while you're holding a reference
+ * will get a reference to the same scheduling context you have.
+ */
+[uuid(7fcbf4da-d828-4acc-b144-e5435198f727)]
+interface nsISchedulingContextService : nsISupports
+{
+  /**
+   * Get an existing scheduling context from its ID
+   */
+  nsISchedulingContext getSchedulingContext(in nsIDRef id);
+
+  /**
+   * Create a new scheduling context identifier
+   */
+  nsID newSchedulingContextID();
+
+  /**
+   * Remove an existing scheduling context from its ID
+   */
+  void removeSchedulingContext(in nsIDRef id);
+};
--- a/netwerk/base/nsLoadGroup.cpp
+++ b/netwerk/base/nsLoadGroup.cpp
@@ -9,26 +9,26 @@
 #include "nsLoadGroup.h"
 
 #include "nsArrayEnumerator.h"
 #include "nsCOMArray.h"
 #include "nsCOMPtr.h"
 #include "mozilla/Logging.h"
 #include "nsString.h"
 #include "nsTArray.h"
-#include "mozilla/Atomics.h"
 #include "mozilla/Telemetry.h"
-#include "nsAutoPtr.h"
-#include "mozilla/net/PSpdyPush.h"
 #include "nsITimedChannel.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIRequestObserver.h"
+#include "nsISchedulingContext.h"
 #include "CacheObserver.h"
 #include "MainThreadUtils.h"
 
+#include "mozilla/net/NeckoChild.h"
+
 using namespace mozilla;
 using namespace mozilla::net;
 
 //
 // Log module for nsILoadGroup logging...
 //
 // To enable logging (see prlog.h for full details):
 //
@@ -39,79 +39,16 @@ using namespace mozilla::net;
 // the file nspr.log
 //
 static PRLogModuleInfo* gLoadGroupLog = nullptr;
 
 #undef LOG
 #define LOG(args) MOZ_LOG(gLoadGroupLog, mozilla::LogLevel::Debug, args)
 
 ////////////////////////////////////////////////////////////////////////////////
-// nsLoadGroupConnectionInfo
-
-class nsLoadGroupConnectionInfo final : public nsILoadGroupConnectionInfo
-{
-    ~nsLoadGroupConnectionInfo() {}
-
-public:
-    NS_DECL_THREADSAFE_ISUPPORTS
-    NS_DECL_NSILOADGROUPCONNECTIONINFO
-
-    nsLoadGroupConnectionInfo();
-private:
-    Atomic<uint32_t>       mBlockingTransactionCount;
-    nsAutoPtr<mozilla::net::SpdyPushCache> mSpdyCache;
-};
-
-NS_IMPL_ISUPPORTS(nsLoadGroupConnectionInfo, nsILoadGroupConnectionInfo)
-
-nsLoadGroupConnectionInfo::nsLoadGroupConnectionInfo()
-    : mBlockingTransactionCount(0)
-{
-}
-
-NS_IMETHODIMP
-nsLoadGroupConnectionInfo::GetBlockingTransactionCount(uint32_t *aBlockingTransactionCount)
-{
-    NS_ENSURE_ARG_POINTER(aBlockingTransactionCount);
-    *aBlockingTransactionCount = mBlockingTransactionCount;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsLoadGroupConnectionInfo::AddBlockingTransaction()
-{
-    mBlockingTransactionCount++;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsLoadGroupConnectionInfo::RemoveBlockingTransaction(uint32_t *_retval)
-{
-    NS_ENSURE_ARG_POINTER(_retval);
-        mBlockingTransactionCount--;
-        *_retval = mBlockingTransactionCount;
-    return NS_OK;
-}
-
-/* [noscript] attribute SpdyPushCachePtr spdyPushCache; */
-NS_IMETHODIMP
-nsLoadGroupConnectionInfo::GetSpdyPushCache(mozilla::net::SpdyPushCache **aSpdyPushCache)
-{
-    *aSpdyPushCache = mSpdyCache.get();
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsLoadGroupConnectionInfo::SetSpdyPushCache(mozilla::net::SpdyPushCache *aSpdyPushCache)
-{
-    mSpdyCache = aSpdyPushCache;
-    return NS_OK;
-}
-
-////////////////////////////////////////////////////////////////////////////////
 
 class RequestMapEntry : public PLDHashEntryHdr
 {
 public:
     explicit RequestMapEntry(nsIRequest *aRequest) :
         mKey(aRequest)
     {
     }
@@ -165,17 +102,16 @@ RescheduleRequest(nsIRequest *aRequest, 
     if (p)
         p->AdjustPriority(delta);
 }
 
 nsLoadGroup::nsLoadGroup(nsISupports* outer)
     : mForegroundCount(0)
     , mLoadFlags(LOAD_NORMAL)
     , mDefaultLoadFlags(0)
-    , mConnectionInfo(new nsLoadGroupConnectionInfo())
     , mRequests(&sRequestHashOps, sizeof(RequestMapEntry))
     , mStatus(NS_OK)
     , mPriority(PRIORITY_NORMAL)
     , mIsCanceling(false)
     , mDefaultLoadIsTimed(false)
     , mTimedRequests(0)
     , mCachedRequests(0)
     , mTimedNonCachedRequestsUntilOnEndPageLoad(0)
@@ -191,16 +127,33 @@ nsLoadGroup::nsLoadGroup(nsISupports* ou
 
 nsLoadGroup::~nsLoadGroup()
 {
     DebugOnly<nsresult> rv = Cancel(NS_BINDING_ABORTED);
     NS_ASSERTION(NS_SUCCEEDED(rv), "Cancel failed");
 
     mDefaultLoadRequest = 0;
 
+    if (mSchedulingContext) {
+        nsID scid;
+        mSchedulingContext->GetID(&scid);
+
+        if (IsNeckoChild() && gNeckoChild) {
+            char scid_str[NSID_LENGTH];
+            scid.ToProvidedString(scid_str);
+
+            nsCString scid_nscs;
+            scid_nscs.AssignASCII(scid_str);
+
+            gNeckoChild->SendRemoveSchedulingContext(scid_nscs);
+        } else {
+            mSchedulingContextService->RemoveSchedulingContext(scid);
+        }
+    }
+
     LOG(("LOADGROUP [%x]: Destroyed.\n", this));
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsISupports methods:
 
 NS_IMPL_AGGREGATED(nsLoadGroup)
@@ -753,22 +706,22 @@ nsLoadGroup::GetNotificationCallbacks(ns
 NS_IMETHODIMP
 nsLoadGroup::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks)
 {
     mCallbacks = aCallbacks;
     return NS_OK;
 }
 
 NS_IMETHODIMP
-nsLoadGroup::GetConnectionInfo(nsILoadGroupConnectionInfo **aCI)
+nsLoadGroup::GetSchedulingContextID(nsID *aSCID)
 {
-    NS_ENSURE_ARG_POINTER(aCI);
-    *aCI = mConnectionInfo;
-    NS_IF_ADDREF(*aCI);
-    return NS_OK;
+    if (!mSchedulingContext) {
+        return NS_ERROR_NOT_AVAILABLE;
+    }
+    return mSchedulingContext->GetID(aSCID);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsILoadGroupChild methods:
 
 /* attribute nsILoadGroup parentLoadGroup; */
 NS_IMETHODIMP
 nsLoadGroup::GetParentLoadGroup(nsILoadGroup * *aParentLoadGroup)
@@ -1108,9 +1061,23 @@ nsresult nsLoadGroup::MergeDefaultLoadFl
 
     if (flags != oldFlags) {
         rv = aRequest->SetLoadFlags(flags);
     }
     outFlags = flags;
     return rv;
 }
 
+nsresult nsLoadGroup::Init()
+{
+    mSchedulingContextService = do_GetService("@mozilla.org/network/scheduling-context-service;1");
+    if (mSchedulingContextService) {
+        nsID schedulingContextID;
+        if (NS_SUCCEEDED(mSchedulingContextService->NewSchedulingContextID(&schedulingContextID))) {
+            mSchedulingContextService->GetSchedulingContext(schedulingContextID,
+                                                            getter_AddRefs(mSchedulingContext));
+        }
+    }
+
+    return NS_OK;
+}
+
 #undef LOG
--- a/netwerk/base/nsLoadGroup.h
+++ b/netwerk/base/nsLoadGroup.h
@@ -12,17 +12,18 @@
 #include "nsAgg.h"
 #include "nsCOMPtr.h"
 #include "nsWeakPtr.h"
 #include "nsWeakReference.h"
 #include "nsISupportsPriority.h"
 #include "pldhash.h"
 #include "mozilla/TimeStamp.h"
 
-class nsILoadGroupConnectionInfo;
+class nsISchedulingContext;
+class nsISchedulingContextService;
 class nsITimedChannel;
 
 class nsLoadGroup : public nsILoadGroup,
                     public nsILoadGroupChild,
                     public nsISupportsPriority,
                     public nsSupportsWeakReference,
                     public nsPILoadGroupInternal
 {
@@ -47,33 +48,36 @@ public:
     NS_DECL_NSISUPPORTSPRIORITY
 
     ////////////////////////////////////////////////////////////////////////////
     // nsLoadGroup methods:
 
     explicit nsLoadGroup(nsISupports* outer);
     virtual ~nsLoadGroup();
 
+    nsresult Init();
+
 protected:
     nsresult MergeLoadFlags(nsIRequest *aRequest, nsLoadFlags& flags);
     nsresult MergeDefaultLoadFlags(nsIRequest *aRequest, nsLoadFlags& flags);
 
 private:
     void TelemetryReport();
     void TelemetryReportChannel(nsITimedChannel *timedChannel,
                                 bool defaultRequest);
 
 protected:
     uint32_t                        mForegroundCount;
     uint32_t                        mLoadFlags;
     uint32_t                        mDefaultLoadFlags;
 
     nsCOMPtr<nsILoadGroup>          mLoadGroup; // load groups can contain load groups
     nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
-    nsCOMPtr<nsILoadGroupConnectionInfo> mConnectionInfo;
+    nsCOMPtr<nsISchedulingContext>  mSchedulingContext;
+    nsCOMPtr<nsISchedulingContextService> mSchedulingContextService;
 
     nsCOMPtr<nsIRequest>            mDefaultLoadRequest;
     PLDHashTable                    mRequests;
 
     nsWeakPtr                       mObserver;
     nsWeakPtr                       mParentLoadGroup;
     
     nsresult                        mStatus;
--- a/netwerk/build/nsNetCID.h
+++ b/netwerk/build/nsNetCID.h
@@ -475,16 +475,27 @@
 #define NS_CAPTIVEPORTAL_CID \
 { /* bdbe0555-fc3d-4f7b-9205-c309ceb2d641 */ \
     0xbdbe0555, \
     0xfc3d, \
     0x4f7b, \
   { 0x92, 0x05, 0xc3, 0x09, 0xce, 0xb2, 0xd6, 0x41 } \
 }
 
+// service implementing nsISchedulingContextService
+#define NS_SCHEDULINGCONTEXTSERVICE_CONTRACTID \
+    "@mozilla.org/network/scheduling-context-service;1"
+#define NS_SCHEDULINGCONTEXTSERVICE_CID \
+{ /* d5499fa7-7ba8-49ff-9e30-1858b99ace69 */ \
+    0xd5499fa7, \
+    0x7ba8, \
+    0x49ff, \
+    {0x93, 0x30, 0x18, 0x58, 0xb9, 0x9a, 0xce, 0x69} \
+}
+
 /******************************************************************************
  * netwerk/cache/ classes
  */
 
 // service implementing nsICacheService.
 #define NS_CACHESERVICE_CONTRACTID \
     "@mozilla.org/network/cache-service;1"
 #define NS_CACHESERVICE_CID                          \
--- a/netwerk/build/nsNetModule.cpp
+++ b/netwerk/build/nsNetModule.cpp
@@ -107,17 +107,17 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(Back
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsSyncStreamListener, Init)
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsAtomicFileOutputStream)
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSafeFileOutputStream)
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsFileStream)
 
-NS_GENERIC_AGGREGATED_CONSTRUCTOR(nsLoadGroup)
+NS_GENERIC_AGGREGATED_CONSTRUCTOR_INIT(nsLoadGroup, Init)
 
 #include "ArrayBufferInputStream.h"
 NS_GENERIC_FACTORY_CONSTRUCTOR(ArrayBufferInputStream)
 
 #include "nsEffectiveTLDService.h"
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsEffectiveTLDService, Init)
 
 #include "nsSerializationHelper.h"
@@ -126,26 +126,29 @@ 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 "mozilla/net/CaptivePortalService.h"
 namespace mozilla {
 namespace net {
   NS_GENERIC_FACTORY_CONSTRUCTOR(CaptivePortalService)
 } // namespace net
 } // namespace mozilla
 
+#include "SchedulingContextService.h"
+typedef mozilla::net::SchedulingContextService SchedulingContextService;
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(SchedulingContextService, Init)
+
 ///////////////////////////////////////////////////////////////////////////////
 
 extern nsresult
 net_NewIncrementalDownload(nsISupports *, const nsIID &, void **);
 
 #define NS_INCREMENTALDOWNLOAD_CID \
 { /* a62af1ba-79b3-4896-8aaf-b148bfce4280 */         \
     0xa62af1ba,                                      \
@@ -823,16 +826,17 @@ NS_DEFINE_NAMED_CID(NS_NETWORK_LINK_SERV
 #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_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 },
     { &kNS_SERVERSOCKET_CID, false, nullptr, nsServerSocketConstructor },
     { &kNS_TLSSERVERSOCKET_CID, false, nullptr, TLSServerSocketConstructor },
     { &kNS_UDPSOCKET_CID, false, nullptr, nsUDPSocketConstructor },
@@ -972,16 +976,17 @@ static const mozilla::Module::CIDEntry k
 #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_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 },
     { NS_NETUTIL_CONTRACTID, &kNS_IOSERVICE_CID },
     { NS_STREAMTRANSPORTSERVICE_CONTRACTID, &kNS_STREAMTRANSPORTSERVICE_CID },
     { NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &kNS_SOCKETTRANSPORTSERVICE_CID },
@@ -1126,16 +1131,17 @@ static const mozilla::Module::ContractID
     { 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_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,
     kNeckoCIDs,
     kNeckoContracts,
     kNeckoCategories,
--- a/netwerk/ipc/NeckoChannelParams.ipdlh
+++ b/netwerk/ipc/NeckoChannelParams.ipdlh
@@ -87,16 +87,17 @@ struct HttpChannelOpenArgs
   bool                        chooseApplicationCache;
   nsCString                   appCacheClientID;
   bool                        allowSpdy;
   bool                        allowAltSvc;
   OptionalFileDescriptorSet   fds;
   OptionalLoadInfoArgs        loadInfo;
   OptionalHttpResponseHead    synthesizedResponseHead;
   uint32_t                    cacheKey;
+  nsCString                   schedulingContextID;
 };
 
 struct HttpChannelConnectArgs
 {
   uint32_t channelId;
   bool shouldIntercept;
 };
 
--- a/netwerk/ipc/NeckoChild.cpp
+++ b/netwerk/ipc/NeckoChild.cpp
@@ -43,46 +43,33 @@ PNeckoChild *gNeckoChild = nullptr;
 
 // C++ file contents
 NeckoChild::NeckoChild()
 {
 }
 
 NeckoChild::~NeckoChild()
 {
+  //Send__delete__(gNeckoChild);
+  gNeckoChild = nullptr;
 }
 
 void NeckoChild::InitNeckoChild()
 {
   MOZ_ASSERT(IsNeckoChild(), "InitNeckoChild called by non-child!");
 
   if (!gNeckoChild) {
     mozilla::dom::ContentChild * cpc = 
       mozilla::dom::ContentChild::GetSingleton();
     NS_ASSERTION(cpc, "Content Protocol is NULL!");
     gNeckoChild = cpc->SendPNeckoConstructor(); 
     NS_ASSERTION(gNeckoChild, "PNecko Protocol init failed!");
   }
 }
 
-// Note: not actually called; has some lifespan as child process, so
-// automatically destroyed at exit.  
-void NeckoChild::DestroyNeckoChild()
-{
-  MOZ_ASSERT(IsNeckoChild(), "DestroyNeckoChild called by non-child!");
-  static bool alreadyDestroyed = false;
-  MOZ_ASSERT(!alreadyDestroyed, "DestroyNeckoChild already called!");
-
-  if (!alreadyDestroyed) {
-    Send__delete__(gNeckoChild); 
-    gNeckoChild = nullptr;
-    alreadyDestroyed = true;
-  }
-}
-
 PHttpChannelChild*
 NeckoChild::AllocPHttpChannelChild(const PBrowserOrId& browser,
                                    const SerializedLoadContext& loadContext,
                                    const HttpChannelCreationArgs& aOpenArgs)
 {
   // We don't allocate here: instead we always use IPDL constructor that takes
   // an existing HttpChildChannel
   NS_NOTREACHED("AllocPHttpChannelChild should not be called on child");
--- a/netwerk/ipc/NeckoChild.h
+++ b/netwerk/ipc/NeckoChild.h
@@ -18,17 +18,16 @@ namespace net {
 class NeckoChild :
   public PNeckoChild
 {
 public:
   NeckoChild();
   virtual ~NeckoChild();
 
   static void InitNeckoChild();
-  static void DestroyNeckoChild();
 
 protected:
   virtual PHttpChannelChild*
     AllocPHttpChannelChild(const PBrowserOrId&, const SerializedLoadContext&,
                            const HttpChannelCreationArgs& aOpenArgs) override;
   virtual bool DeallocPHttpChannelChild(PHttpChannelChild*) override;
   virtual PCookieServiceChild* AllocPCookieServiceChild() override;
   virtual bool DeallocPCookieServiceChild(PCookieServiceChild*) override;
--- a/netwerk/ipc/NeckoParent.cpp
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -965,10 +965,26 @@ NeckoParent::OfflineNotification(nsISupp
       }
     }
 
   }
 
   return NS_OK;
 }
 
+bool
+NeckoParent::RecvRemoveSchedulingContext(const nsCString& scid)
+{
+  nsCOMPtr<nsISchedulingContextService> scsvc =
+    do_GetService("@mozilla.org/network/scheduling-context-service;1");
+  if (!scsvc) {
+    return true;
+  }
+
+  nsID id;
+  id.Parse(scid.BeginReading());
+  scsvc->RemoveSchedulingContext(id);
+
+  return true;
+}
+
 } // namespace net
 } // namespace mozilla
--- a/netwerk/ipc/NeckoParent.h
+++ b/netwerk/ipc/NeckoParent.h
@@ -219,16 +219,18 @@ protected:
                                const bool& hasVerifier) override;
 
   virtual bool RecvPredLearn(const ipc::URIParams& aTargetURI,
                              const ipc::OptionalURIParams& aSourceURI,
                              const PredictorPredictReason& aReason,
                              const IPC::SerializedLoadContext& aLoadContext) override;
   virtual bool RecvPredReset() override;
 
+  virtual bool RecvRemoveSchedulingContext(const nsCString& scid) override;
+
 private:
   nsCString mCoreAppsBasePath;
   nsCString mWebAppsBasePath;
   nsRefPtr<OfflineObserver> mObserver;
 };
 
 /**
  * Reference to the PNecko Parent protocol.
--- a/netwerk/ipc/PNecko.ipdl
+++ b/netwerk/ipc/PNecko.ipdl
@@ -103,16 +103,18 @@ parent:
    * These are called from the child with the results of the auth prompt.
    * callbackId is the id that was passed in PBrowser::AsyncAuthPrompt,
    * corresponding to an nsIAuthPromptCallback
    */
   OnAuthAvailable(uint64_t callbackId, nsString user,
                   nsString password, nsString domain);
   OnAuthCancelled(uint64_t callbackId, bool userCancel);
 
+  RemoveSchedulingContext(nsCString scid);
+
 child:
   /*
    * Bring up the http auth prompt for a nested remote mozbrowser.
    * NestedFrameId is the id corresponding to the PBrowser.  It is the same id
    * that was passed to the PBrowserOrId param in to the PHttpChannel constructor
    */
   AsyncAuthPromptForNestedFrame(TabId nestedFrameId, nsCString uri,
                                 nsString realm, uint64_t callbackId);
--- a/netwerk/protocol/http/Http2Push.cpp
+++ b/netwerk/protocol/http/Http2Push.cpp
@@ -72,17 +72,17 @@ Http2PushedStream::Http2PushedStream(Htt
   , mDeferCleanupOnSuccess(true)
   , mDeferCleanupOnPush(false)
   , mOnPushFailed(false)
 {
   LOG3(("Http2PushedStream ctor this=%p 0x%X\n", this, aID));
   mStreamID = aID;
   MOZ_ASSERT(!(aID & 1)); // must be even to be a pushed stream
   mBufferedPush->SetPushStream(this);
-  mLoadGroupCI = aAssociatedStream->LoadGroupConnectionInfo();
+  mSchedulingContext = aAssociatedStream->SchedulingContext();
   mLastRead = TimeStamp::Now();
   SetPriority(aAssociatedStream->Priority() + 1);
 }
 
 bool
 Http2PushedStream::GetPushComplete()
 {
   return mPushCompleted;
--- a/netwerk/protocol/http/Http2Push.h
+++ b/netwerk/protocol/http/Http2Push.h
@@ -11,16 +11,17 @@
 
 #include "Http2Session.h"
 #include "Http2Stream.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/TimeStamp.h"
 #include "nsHttpRequestHead.h"
 #include "nsILoadGroup.h"
+#include "nsISchedulingContext.h"
 #include "nsString.h"
 #include "PSpdyPush.h"
 
 namespace mozilla {
 namespace net {
 
 class Http2PushTransactionBuffer;
 
@@ -40,17 +41,17 @@ public:
 
   void SetConsumerStream(Http2Stream *aStream);
   bool GetHashKey(nsCString &key);
 
   // override of Http2Stream
   nsresult ReadSegments(nsAHttpSegmentReader *,  uint32_t, uint32_t *) override;
   nsresult WriteSegments(nsAHttpSegmentWriter *, uint32_t, uint32_t *) override;
 
-  nsILoadGroupConnectionInfo *LoadGroupConnectionInfo() override { return mLoadGroupCI; };
+  nsISchedulingContext *SchedulingContext() override { return mSchedulingContext; };
   void ConnectPushedStream(Http2Stream *consumer);
 
   bool TryOnPush();
 
   virtual bool DeferCleanup(nsresult status) override;
   void SetDeferCleanupOnSuccess(bool val) { mDeferCleanupOnSuccess = val; }
 
   bool IsOrphaned(TimeStamp now);
@@ -63,17 +64,17 @@ public:
 
   nsCString &GetRequestString() { return mRequestString; }
 
 private:
 
   Http2Stream *mConsumerStream; // paired request stream that consumes from
                                 // real http/2 one.. null until a match is made.
 
-  nsCOMPtr<nsILoadGroupConnectionInfo> mLoadGroupCI;
+  nsCOMPtr<nsISchedulingContext> mSchedulingContext;
 
   nsAHttpTransaction *mAssociatedTransaction;
 
   Http2PushTransactionBuffer *mBufferedPush;
   mozilla::TimeStamp mLastRead;
 
   nsCString mHashKey;
   nsresult mStatus;
--- a/netwerk/protocol/http/Http2Session.cpp
+++ b/netwerk/protocol/http/Http2Session.cpp
@@ -20,17 +20,17 @@
 #include "Http2Push.h"
 
 #include "mozilla/Endian.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/Preferences.h"
 #include "nsHttp.h"
 #include "nsHttpHandler.h"
 #include "nsHttpConnection.h"
-#include "nsILoadGroup.h"
+#include "nsISchedulingContext.h"
 #include "nsISSLSocketControl.h"
 #include "nsISSLStatus.h"
 #include "nsISSLStatusProvider.h"
 #include "nsISupportsPriority.h"
 #include "nsStandardURL.h"
 #include "nsURLHelper.h"
 #include "prprf.h"
 #include "prnetdb.h"
@@ -1042,20 +1042,20 @@ Http2Session::CleanupStream(Http2Stream 
   uint32_t id = aStream->StreamID();
   if (id > 0) {
     mStreamIDHash.Remove(id);
     if (!(id & 1)) {
       mPushedStreams.RemoveElement(aStream);
       Http2PushedStream *pushStream = static_cast<Http2PushedStream *>(aStream);
       nsAutoCString hashKey;
       pushStream->GetHashKey(hashKey);
-      nsILoadGroupConnectionInfo *loadGroupCI = aStream->LoadGroupConnectionInfo();
-      if (loadGroupCI) {
+      nsISchedulingContext *schedulingContext = aStream->SchedulingContext();
+      if (schedulingContext) {
         SpdyPushCache *cache = nullptr;
-        loadGroupCI->GetSpdyPushCache(&cache);
+        schedulingContext->GetSpdyPushCache(&cache);
         if (cache) {
           Http2PushedStream *trash = cache->RemovePushedStreamHttp2(hashKey);
           LOG3(("Http2Session::CleanupStream %p aStream=%p pushStream=%p trash=%p",
                 this, aStream, pushStream, trash));
         }
       }
     }
   }
@@ -1603,30 +1603,30 @@ Http2Session::RecvPushPromise(Http2Sessi
       LOG3(("Http2Session::RecvPushPromise sending GOAWAY"));
       RETURN_SESSION_ERROR(self, PROTOCOL_ERROR);
     }
     self->GenerateRstStream(REFUSED_STREAM_ERROR, promisedID);
   } else if (!associatedStream) {
     LOG3(("Http2Session::RecvPushPromise %p lookup associated ID failed.\n", self));
     self->GenerateRstStream(PROTOCOL_ERROR, promisedID);
   } else {
-    nsILoadGroupConnectionInfo *loadGroupCI = associatedStream->LoadGroupConnectionInfo();
-    if (loadGroupCI) {
-      loadGroupCI->GetSpdyPushCache(&cache);
+    nsISchedulingContext *schedulingContext = associatedStream->SchedulingContext();
+    if (schedulingContext) {
+      schedulingContext->GetSpdyPushCache(&cache);
       if (!cache) {
         cache = new SpdyPushCache();
-        if (!cache || NS_FAILED(loadGroupCI->SetSpdyPushCache(cache))) {
+        if (!cache || NS_FAILED(schedulingContext->SetSpdyPushCache(cache))) {
           delete cache;
           cache = nullptr;
         }
       }
     }
     if (!cache) {
       // this is unexpected, but we can handle it just by refusing the push
-      LOG3(("Http2Session::RecvPushPromise Push Recevied without loadgroup cache\n"));
+      LOG3(("Http2Session::RecvPushPromise Push Recevied without push cache\n"));
       self->GenerateRstStream(REFUSED_STREAM_ERROR, promisedID);
     } else {
       resetStream = false;
     }
   }
 
   if (resetStream) {
     // Need to decompress the headers even though we aren't using them yet in
--- a/netwerk/protocol/http/Http2Stream.cpp
+++ b/netwerk/protocol/http/Http2Stream.cpp
@@ -358,20 +358,20 @@ Http2Stream::ParseHttpRequestHeaders(con
   CreatePushHashKey(nsDependentCString(head->IsHTTPS() ? "https" : "http"),
                     authorityHeader, mSession->Serial(),
                     head->RequestURI(),
                     mOrigin, hashkey);
 
   // check the push cache for GET
   if (head->IsGet()) {
     // from :scheme, :authority, :path
-    nsILoadGroupConnectionInfo *loadGroupCI = mTransaction->LoadGroupConnectionInfo();
+    nsISchedulingContext *schedulingContext = mTransaction->SchedulingContext();
     SpdyPushCache *cache = nullptr;
-    if (loadGroupCI) {
-      loadGroupCI->GetSpdyPushCache(&cache);
+    if (schedulingContext) {
+      schedulingContext->GetSpdyPushCache(&cache);
     }
 
     Http2PushedStream *pushedStream = nullptr;
 
     // If a push stream is attached to the transaction via onPush, match only with that
     // one. This occurs when a push was made with in conjunction with a nsIHttpPushListener
     nsHttpTransaction *trans = mTransaction->QueryHttpTransaction();
     if (trans && (pushedStream = trans->TakePushedStream())) {
@@ -388,18 +388,18 @@ Http2Stream::ParseHttpRequestHeaders(con
     // we remove the pushedstream from the push cache so that
     // it will not be used for another GET. This does not destroy the
     // stream itself - that is done when the transactionhash is done with it.
     if (cache && !pushedStream){
         pushedStream = cache->RemovePushedStreamHttp2(hashkey);
     }
 
     LOG3(("Pushed Stream Lookup "
-          "session=%p key=%s loadgroupci=%p cache=%p hit=%p\n",
-          mSession, hashkey.get(), loadGroupCI, cache, pushedStream));
+          "session=%p key=%s schedulingcontext=%p cache=%p hit=%p\n",
+          mSession, hashkey.get(), schedulingContext, cache, pushedStream));
 
     if (pushedStream) {
       LOG3(("Pushed Stream Match located id=0x%X key=%s\n",
             pushedStream->StreamID(), hashkey.get()));
       pushedStream->SetConsumerStream(this);
       mPushSource = pushedStream;
       SetSentFin(true);
       AdjustPushedPriority();
--- a/netwerk/protocol/http/Http2Stream.h
+++ b/netwerk/protocol/http/Http2Stream.h
@@ -65,19 +65,19 @@ public:
   bool RequestBlockedOnRead()
   {
     return static_cast<bool>(mRequestBlockedOnRead);
   }
 
   bool HasRegisteredID() { return mStreamID != 0; }
 
   nsAHttpTransaction *Transaction() { return mTransaction; }
-  virtual nsILoadGroupConnectionInfo *LoadGroupConnectionInfo()
+  virtual nsISchedulingContext *SchedulingContext()
   {
-    return mTransaction ? mTransaction->LoadGroupConnectionInfo() : nullptr;
+    return mTransaction ? mTransaction->SchedulingContext() : nullptr;
   }
 
   void Close(nsresult reason);
 
   void SetRecvdFin(bool aStatus);
   bool RecvdFin() { return mRecvdFin; }
 
   void SetRecvdData(bool aStatus) { mReceivedData = aStatus ? 1 : 0; }
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -35,16 +35,17 @@
 #include "nsIObserverService.h"
 #include "nsProxyRelease.h"
 #include "nsPIDOMWindow.h"
 #include "nsPerformance.h"
 #include "nsINetworkInterceptController.h"
 #include "mozIThirdPartyUtil.h"
 #include "nsStreamUtils.h"
 #include "nsContentSecurityManager.h"
+#include "nsILoadGroupChild.h"
 
 #include <algorithm>
 
 namespace mozilla {
 namespace net {
 
 HttpBaseChannel::HttpBaseChannel()
   : mStartPos(UINT64_MAX)
@@ -94,16 +95,17 @@ HttpBaseChannel::HttpBaseChannel()
 #ifdef MOZ_VALGRIND
   // Zero the entire unions so that Valgrind doesn't complain when we send them
   // to another process.
   memset(&mSelfAddr, 0, sizeof(NetAddr));
   memset(&mPeerAddr, 0, sizeof(NetAddr));
 #endif
   mSelfAddr.raw.family = PR_AF_UNSPEC;
   mPeerAddr.raw.family = PR_AF_UNSPEC;
+  mSchedulingContextID.Clear();
 }
 
 HttpBaseChannel::~HttpBaseChannel()
 {
   LOG(("Destroying HttpBaseChannel @%x\n", this));
 
   NS_ReleaseOnMainThread(mLoadInfo);
 
@@ -1536,16 +1538,31 @@ HttpBaseChannel::RedirectTo(nsIURI *newU
   ENSURE_CALLED_BEFORE_CONNECT();
 
   // The redirect is stored internally for use in AsyncOpen
   mAPIRedirectToURI = newURI;
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+HttpBaseChannel::GetSchedulingContextID(nsID *aSCID)
+{
+  NS_ENSURE_ARG_POINTER(aSCID);
+  *aSCID = mSchedulingContextID;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::SetSchedulingContextID(const nsID aSCID)
+{
+  mSchedulingContextID = aSCID;
+  return NS_OK;
+}
+
 //-----------------------------------------------------------------------------
 // HttpBaseChannel::nsIHttpChannelInternal
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 HttpBaseChannel::GetTopWindowURI(nsIURI **aTopWindowURI)
 {
   nsresult rv = NS_OK;
@@ -2721,11 +2738,40 @@ HttpBaseChannel::GetPerformance()
     if (mLoadFlags & LOAD_DOCUMENT_URI) {
       return docPerformance->GetParentPerformance();
     }
     return docPerformance;
 }
 
 //------------------------------------------------------------------------------
 
+bool
+HttpBaseChannel::EnsureSchedulingContextID()
+{
+    nsID nullID;
+    nullID.Clear();
+    if (!mSchedulingContextID.Equals(nullID)) {
+        // Already have a scheduling context ID, no need to do the rest of this work
+        return true;
+    }
+
+    // Find the loadgroup at the end of the chain in order
+    // to make sure all channels derived from the load group
+    // use the same connection scope.
+    nsCOMPtr<nsILoadGroupChild> childLoadGroup = do_QueryInterface(mLoadGroup);
+    if (!childLoadGroup) {
+        return false;
+    }
+
+    nsCOMPtr<nsILoadGroup> rootLoadGroup;
+    childLoadGroup->GetRootLoadGroup(getter_AddRefs(rootLoadGroup));
+    if (!rootLoadGroup) {
+        return false;
+    }
+
+    // Set the load group connection scope on the transaction
+    rootLoadGroup->GetSchedulingContextID(&mSchedulingContextID);
+    return true;
+}
+
 } // namespace net
 } // namespace mozilla
 
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -151,16 +151,18 @@ public:
   NS_IMETHOD SetRedirectionLimit(uint32_t value) override;
   NS_IMETHOD IsNoStoreResponse(bool *value) override;
   NS_IMETHOD IsNoCacheResponse(bool *value) override;
   NS_IMETHOD IsPrivateResponse(bool *value) override;
   NS_IMETHOD GetResponseStatus(uint32_t *aValue) override;
   NS_IMETHOD GetResponseStatusText(nsACString& aValue) override;
   NS_IMETHOD GetRequestSucceeded(bool *aValue) override;
   NS_IMETHOD RedirectTo(nsIURI *newURI) override;
+  NS_IMETHOD GetSchedulingContextID(nsID *aSCID) override;
+  NS_IMETHOD SetSchedulingContextID(const nsID aSCID) override;
 
   // nsIHttpChannelInternal
   NS_IMETHOD GetDocumentURI(nsIURI **aDocumentURI) override;
   NS_IMETHOD SetDocumentURI(nsIURI *aDocumentURI) override;
   NS_IMETHOD GetRequestVersion(uint32_t *major, uint32_t *minor) override;
   NS_IMETHOD GetResponseVersion(uint32_t *major, uint32_t *minor) override;
   NS_IMETHOD SetCookie(const char *aCookieHeader) override;
   NS_IMETHOD GetThirdPartyFlags(uint32_t *aForce) override;
@@ -426,16 +428,19 @@ protected:
   uint32_t mCorsMode;
 
   // This parameter is used to ensure that we do not call OnStartRequest more
   // than once.
   bool mOnStartRequestCalled;
 
   // The network interface id that's associated with this channel.
   nsCString mNetworkInterfaceId;
+
+  nsID mSchedulingContextID;
+  bool EnsureSchedulingContextID();
 };
 
 // Share some code while working around C++'s absurd inability to handle casting
 // of member functions between base/derived types.
 // - We want to store member function pointer to call at resume time, but one
 //   such function--HandleAsyncAbort--we want to share between the
 //   nsHttpChannel/HttpChannelChild.  Can't define it in base class, because
 //   then we'd have to cast member function ptr between base/derived class
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -1688,16 +1688,21 @@ HttpChannelChild::ContinueAsyncOpen()
       return rv;
     }
   }
   openArgs.cacheKey() = cacheKey;
 
   nsresult rv = mozilla::ipc::LoadInfoToLoadInfoArgs(mLoadInfo, &openArgs.loadInfo());
   NS_ENSURE_SUCCESS(rv, rv);
 
+  EnsureSchedulingContextID();
+  char scid[NSID_LENGTH];
+  mSchedulingContextID.ToProvidedString(scid);
+  openArgs.schedulingContextID().AssignASCII(scid);
+
   // The socket transport in the chrome process now holds a logical ref to us
   // until OnStopRequest, or we do a redirect, or we hit an IPDL error.
   AddIPDLReference();
 
   PBrowserOrId browser = static_cast<ContentChild*>(gNeckoChild->Manager())
                          ->GetBrowserOrId(tabChild);
   gNeckoChild->SendPHttpChannelConstructor(this, browser,
                                            IPC::SerializedLoadContext(this),
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -115,17 +115,18 @@ HttpChannelParent::Init(const HttpChanne
                        a.referrerPolicy(), a.apiRedirectTo(), a.topWindowURI(),
                        a.loadFlags(), a.requestHeaders(),
                        a.requestMethod(), a.uploadStream(),
                        a.uploadStreamHasHeaders(), a.priority(), a.classOfService(),
                        a.redirectionLimit(), a.allowPipelining(), a.allowSTS(),
                        a.thirdPartyFlags(), a.resumeAt(), a.startPos(),
                        a.entityID(), a.chooseApplicationCache(),
                        a.appCacheClientID(), a.allowSpdy(), a.allowAltSvc(), a.fds(),
-                       a.loadInfo(), a.synthesizedResponseHead(), a.cacheKey());
+                       a.loadInfo(), a.synthesizedResponseHead(), a.cacheKey(),
+                       a.schedulingContextID());
   }
   case HttpChannelCreationArgs::THttpChannelConnectArgs:
   {
     const HttpChannelConnectArgs& cArgs = aArgs.get_HttpChannelConnectArgs();
     return ConnectChannel(cArgs.channelId(), cArgs.shouldIntercept());
   }
   default:
     NS_NOTREACHED("unknown open type");
@@ -271,17 +272,18 @@ HttpChannelParent::DoAsyncOpen(  const U
                                  const nsCString&           entityID,
                                  const bool&                chooseApplicationCache,
                                  const nsCString&           appCacheClientID,
                                  const bool&                allowSpdy,
                                  const bool&                allowAltSvc,
                                  const OptionalFileDescriptorSet& aFds,
                                  const OptionalLoadInfoArgs& aLoadInfoArgs,
                                  const OptionalHttpResponseHead& aSynthesizedResponseHead,
-                                 const uint32_t&            aCacheKey)
+                                 const uint32_t&            aCacheKey,
+                                 const nsCString&           aSchedulingContextID)
 {
   nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
   if (!uri) {
     // URIParams does MOZ_ASSERT if null, but we need to protect opt builds from
     // null deref here.
     return false;
   }
   nsCOMPtr<nsIURI> originalUri = DeserializeURI(aOriginalURI);
@@ -456,16 +458,20 @@ HttpChannelParent::DoAsyncOpen(  const U
         // done mPBOverride logic by this point.
         chooseAppCache = NS_ShouldCheckAppCache(principal, NS_UsePrivateBrowsing(mChannel));
       }
 
       appCacheChan->SetChooseApplicationCache(chooseAppCache);
     }
   }
 
+  nsID schedulingContextID;
+  schedulingContextID.Parse(aSchedulingContextID.BeginReading());
+  mChannel->SetSchedulingContextID(schedulingContextID);
+
   rv = mChannel->AsyncOpen(mParentListener, nullptr);
   if (NS_FAILED(rv))
     return SendFailedAsyncOpen(rv);
 
   return true;
 }
 
 bool
--- a/netwerk/protocol/http/HttpChannelParent.h
+++ b/netwerk/protocol/http/HttpChannelParent.h
@@ -113,17 +113,18 @@ protected:
                    const nsCString&           entityID,
                    const bool&                chooseApplicationCache,
                    const nsCString&           appCacheClientID,
                    const bool&                allowSpdy,
                    const bool&                allowAltSvc,
                    const OptionalFileDescriptorSet& aFds,
                    const OptionalLoadInfoArgs& aLoadInfoArgs,
                    const OptionalHttpResponseHead& aSynthesizedResponseHead,
-                   const uint32_t&            aCacheKey);
+                   const uint32_t&            aCacheKey,
+                   const nsCString&           aSchedulingContextID);
 
   virtual bool RecvSetPriority(const uint16_t& priority) override;
   virtual bool RecvSetClassOfService(const uint32_t& cos) override;
   virtual bool RecvSetCacheTokenCachedCharset(const nsCString& charset) override;
   virtual bool RecvSuspend() override;
   virtual bool RecvResume() override;
   virtual bool RecvCancel(const nsresult& status) override;
   virtual bool RecvRedirect2Verify(const nsresult& result,
--- a/netwerk/protocol/http/NullHttpChannel.cpp
+++ b/netwerk/protocol/http/NullHttpChannel.cpp
@@ -201,16 +201,28 @@ NullHttpChannel::IsPrivateResponse(bool 
 }
 
 NS_IMETHODIMP
 NullHttpChannel::RedirectTo(nsIURI *aNewURI)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
+NS_IMETHODIMP
+NullHttpChannel::GetSchedulingContextID(nsID *_retval)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+NullHttpChannel::SetSchedulingContextID(const nsID scID)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
 //-----------------------------------------------------------------------------
 // NullHttpChannel::nsIChannel
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 NullHttpChannel::GetOriginalURI(nsIURI * *aOriginalURI)
 {
   NS_IF_ADDREF(*aOriginalURI = mOriginalURI);
--- a/netwerk/protocol/http/SpdyPush31.cpp
+++ b/netwerk/protocol/http/SpdyPush31.cpp
@@ -35,17 +35,17 @@ SpdyPushedStream31::SpdyPushedStream31(S
   , mBufferedPush(aTransaction)
   , mStatus(NS_OK)
   , mPushCompleted(false)
   , mDeferCleanupOnSuccess(true)
 {
   LOG3(("SpdyPushedStream31 ctor this=%p id=0x%X\n", this, aID));
   mStreamID = aID;
   mBufferedPush->SetPushStream(this);
-  mLoadGroupCI = aAssociatedStream->LoadGroupConnectionInfo();
+  mSchedulingContext = aAssociatedStream->SchedulingContext();
   mLastRead = TimeStamp::Now();
 }
 
 bool
 SpdyPushedStream31::GetPushComplete()
 {
   return mPushCompleted;
 }
--- a/netwerk/protocol/http/SpdyPush31.h
+++ b/netwerk/protocol/http/SpdyPush31.h
@@ -6,17 +6,17 @@
 // spdy/3.1
 
 #ifndef mozilla_net_SpdyPush31_Internal_h
 #define mozilla_net_SpdyPush31_Internal_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/TimeStamp.h"
 #include "nsHttpRequestHead.h"
-#include "nsILoadGroup.h"
+#include "nsISchedulingContext.h"
 #include "nsString.h"
 #include "PSpdyPush.h"
 #include "SpdySession31.h"
 #include "SpdyStream31.h"
 
 namespace mozilla {
 namespace net {
 
@@ -35,17 +35,17 @@ public:
   SpdyStream31 *GetConsumerStream() { return mConsumerStream; };
   void SetConsumerStream(SpdyStream31 *aStream) { mConsumerStream = aStream; }
   bool GetHashKey(nsCString &key);
 
   // override of SpdyStream31
   nsresult ReadSegments(nsAHttpSegmentReader *,  uint32_t, uint32_t *);
   nsresult WriteSegments(nsAHttpSegmentWriter *, uint32_t, uint32_t *);
 
-  nsILoadGroupConnectionInfo *LoadGroupConnectionInfo() { return mLoadGroupCI; };
+  nsISchedulingContext *SchedulingContext() { return mSchedulingContext; };
   void ConnectPushedStream(SpdyStream31 *consumer);
 
   bool DeferCleanupOnSuccess() { return mDeferCleanupOnSuccess; }
   void SetDeferCleanupOnSuccess(bool val) { mDeferCleanupOnSuccess = val; }
 
   bool IsOrphaned(TimeStamp now);
 
   nsresult GetBufferedData(char *buf, uint32_t count, uint32_t *countWritten);
@@ -53,17 +53,17 @@ public:
   // overload of SpdyStream31
   virtual bool HasSink() { return !!mConsumerStream; }
 
 private:
 
   SpdyStream31 *mConsumerStream; // paired request stream that consumes from
   // real spdy one.. null until a match is made.
 
-  nsCOMPtr<nsILoadGroupConnectionInfo> mLoadGroupCI;
+  nsCOMPtr<nsISchedulingContext> mSchedulingContext;
 
   SpdyPush31TransactionBuffer *mBufferedPush;
   TimeStamp          mLastRead;
 
   nsCString mHashKey;
   nsresult mStatus;
   bool mPushCompleted; // server push FIN received
   bool mDeferCleanupOnSuccess;
--- a/netwerk/protocol/http/SpdySession31.cpp
+++ b/netwerk/protocol/http/SpdySession31.cpp
@@ -13,17 +13,17 @@
 #undef LOG_ENABLED
 #define LOG_ENABLED() LOG5_ENABLED()
 
 #include "mozilla/Telemetry.h"
 #include "mozilla/Preferences.h"
 #include "nsHttp.h"
 #include "nsHttpHandler.h"
 #include "nsHttpConnection.h"
-#include "nsILoadGroup.h"
+#include "nsISchedulingContext.h"
 #include "nsISupportsPriority.h"
 #include "prprf.h"
 #include "prnetdb.h"
 #include "SpdyPush31.h"
 #include "SpdySession31.h"
 #include "SpdyStream31.h"
 #include "SpdyZlibReporter.h"
 
@@ -1076,30 +1076,30 @@ SpdySession31::HandleSynStream(SpdySessi
     LOG3(("SpdySession31::HandleSynStream Push Recevied when Disabled\n"));
     self->GenerateRstStream(RST_REFUSED_STREAM, streamID);
 
   } else if (!associatedStream) {
     LOG3(("SpdySession31::HandleSynStream %p lookup associated ID failed.\n", self));
     self->GenerateRstStream(RST_INVALID_STREAM, streamID);
 
   } else {
-    nsILoadGroupConnectionInfo *loadGroupCI = associatedStream->LoadGroupConnectionInfo();
-    if (loadGroupCI) {
-      loadGroupCI->GetSpdyPushCache(&cache);
+    nsISchedulingContext *schedulingContext = associatedStream->SchedulingContext();
+    if (schedulingContext) {
+      schedulingContext->GetSpdyPushCache(&cache);
       if (!cache) {
         cache = new SpdyPushCache();
-        if (!cache || NS_FAILED(loadGroupCI->SetSpdyPushCache(cache))) {
+        if (!cache || NS_FAILED(schedulingContext->SetSpdyPushCache(cache))) {
           delete cache;
           cache = nullptr;
         }
       }
     }
     if (!cache) {
       // this is unexpected, but we can handle it just be refusing the push
-      LOG3(("SpdySession31::HandleSynStream Push Recevied without loadgroup cache\n"));
+      LOG3(("SpdySession31::HandleSynStream Push Recevied without push cache\n"));
       self->GenerateRstStream(RST_REFUSED_STREAM, streamID);
     }
     else {
       resetStream = false;
     }
   }
 
   if (resetStream) {
--- a/netwerk/protocol/http/SpdyStream31.cpp
+++ b/netwerk/protocol/http/SpdyStream31.cpp
@@ -311,20 +311,20 @@ SpdyStream31::ParseHttpRequestHeaders(co
   CreatePushHashKey(nsDependentCString(mTransaction->RequestHead()->IsHTTPS() ? "https" : "http"),
                     hostHeader, mSession->Serial(),
                     mTransaction->RequestHead()->RequestURI(),
                     mOrigin, hashkey);
 
   // check the push cache for GET
   if (mTransaction->RequestHead()->IsGet()) {
     // from :scheme, :host, :path
-    nsILoadGroupConnectionInfo *loadGroupCI = mTransaction->LoadGroupConnectionInfo();
+    nsISchedulingContext *schedulingContext = mTransaction->SchedulingContext();
     SpdyPushCache *cache = nullptr;
-    if (loadGroupCI)
-      loadGroupCI->GetSpdyPushCache(&cache);
+    if (schedulingContext)
+      schedulingContext->GetSpdyPushCache(&cache);
 
     SpdyPushedStream31 *pushedStream = nullptr;
     // we remove the pushedstream from the push cache so that
     // it will not be used for another GET. This does not destroy the
     // stream itself - that is done when the transactionhash is done with it.
     if (cache)
       pushedStream = cache->RemovePushedStreamSpdy31(hashkey);
 
--- a/netwerk/protocol/http/SpdyStream31.h
+++ b/netwerk/protocol/http/SpdyStream31.h
@@ -37,19 +37,19 @@ public:
   bool GetFullyOpen();
   // returns failure if stream cannot be made ready and stream
   // should be canceled
   nsresult SetFullyOpen();
 
   bool HasRegisteredID() { return mStreamID != 0; }
 
   nsAHttpTransaction *Transaction() { return mTransaction; }
-  virtual nsILoadGroupConnectionInfo *LoadGroupConnectionInfo()
+  virtual nsISchedulingContext *SchedulingContext()
   {
-    return mTransaction ? mTransaction->LoadGroupConnectionInfo() : nullptr;
+    return mTransaction ? mTransaction->SchedulingContext() : nullptr;
   }
 
   void Close(nsresult reason);
 
   void SetRecvdFin(bool aStatus) { mRecvdFin = aStatus ? 1 : 0; }
   bool RecvdFin() { return mRecvdFin; }
 
   void SetRecvdData(bool aStatus) { mReceivedData = aStatus ? 1 : 0; }
--- a/netwerk/protocol/http/nsAHttpTransaction.h
+++ b/netwerk/protocol/http/nsAHttpTransaction.h
@@ -6,17 +6,17 @@
 #define nsAHttpTransaction_h__
 
 #include "nsISupports.h"
 #include "nsTArray.h"
 #include "nsWeakReference.h"
 
 class nsIInterfaceRequestor;
 class nsITransport;
-class nsILoadGroupConnectionInfo;
+class nsISchedulingContext;
 
 namespace mozilla { namespace net {
 
 class nsAHttpConnection;
 class nsAHttpSegmentReader;
 class nsAHttpSegmentWriter;
 class nsHttpTransaction;
 class nsHttpPipeline;
@@ -139,18 +139,18 @@ public:
     // non nsHttpTransaction implementations of nsAHttpTransaction
     virtual nsHttpTransaction *QueryHttpTransaction() { return nullptr; }
 
     // If we used rtti this would be the result of doing
     // dynamic_cast<SpdyConnectTransaction *>(this).. i.e. it can be nullptr for
     // other types
     virtual SpdyConnectTransaction *QuerySpdyConnectTransaction() { return nullptr; }
 
-    // return the load group connection information associated with the transaction
-    virtual nsILoadGroupConnectionInfo *LoadGroupConnectionInfo() { return nullptr; }
+    // return the scheduling context associated with the transaction
+    virtual nsISchedulingContext *SchedulingContext() { return nullptr; }
 
     // return the connection information associated with the transaction
     virtual nsHttpConnectionInfo *ConnectionInfo() = 0;
 
     // The base definition of these is done in nsHttpTransaction.cpp
     virtual bool ResponseTimeoutEnabled() const;
     virtual PRIntervalTime ResponseTimeout();
 
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -679,35 +679,40 @@ nsHttpChannel::ContinueHandleAsyncFallba
 
     if (mLoadGroup)
         mLoadGroup->RemoveRequest(this, nullptr, mStatus);
 
     return rv;
 }
 
 void
-nsHttpChannel::SetupTransactionLoadGroupInfo()
-{
-    // Find the loadgroup at the end of the chain in order
-    // to make sure all channels derived from the load group
-    // use the same connection scope.
-    nsCOMPtr<nsILoadGroupChild> childLoadGroup = do_QueryInterface(mLoadGroup);
-    if (!childLoadGroup)
+nsHttpChannel::SetupTransactionSchedulingContext()
+{
+    if (!EnsureSchedulingContextID()) {
+        return;
+    }
+
+    nsISchedulingContextService *scsvc =
+        gHttpHandler->GetSchedulingContextService();
+    if (!scsvc) {
         return;
-
-    nsCOMPtr<nsILoadGroup> rootLoadGroup;
-    childLoadGroup->GetRootLoadGroup(getter_AddRefs(rootLoadGroup));
-    if (!rootLoadGroup)
+    }
+
+    nsCOMPtr<nsISchedulingContext> sc;
+    char scid[NSID_LENGTH];
+    mSchedulingContextID.ToProvidedString(scid);
+    fprintf(stderr, "NWGH: nsHttpChannel %p getting scheduling context %s\n", this, scid);
+    nsresult rv = scsvc->GetSchedulingContext(mSchedulingContextID,
+                                              getter_AddRefs(sc));
+
+    if (NS_FAILED(rv)) {
         return;
-
-    // Set the load group connection scope on the transaction
-    nsCOMPtr<nsILoadGroupConnectionInfo> ci;
-    rootLoadGroup->GetConnectionInfo(getter_AddRefs(ci));
-    if (ci)
-        mTransaction->SetLoadGroupConnectionInfo(ci);
+    }
+
+    mTransaction->SetSchedulingContext(sc);
 }
 
 static bool
 SafeForPipelining(nsHttpRequestHead::ParsedMethodType method,
                   const nsCString &methodString)
 {
     if (method == nsHttpRequestHead::kMethod_Get ||
         method == nsHttpRequestHead::kMethod_Head ||
@@ -914,17 +919,17 @@ nsHttpChannel::SetupTransaction()
                             NS_GetCurrentThread(), callbacks, this,
                             getter_AddRefs(responseStream));
     if (NS_FAILED(rv)) {
         mTransaction = nullptr;
         return rv;
     }
 
     mTransaction->SetClassOfService(mClassOfService);
-    SetupTransactionLoadGroupInfo();
+    SetupTransactionSchedulingContext();
 
     rv = nsInputStreamPump::Create(getter_AddRefs(mTransactionPump),
                                    responseStream);
     return rv;
 }
 
 // NOTE: This function duplicates code from nsBaseChannel. This will go away
 // once HTTP uses nsBaseChannel (part of bug 312760)
--- a/netwerk/protocol/http/nsHttpChannel.h
+++ b/netwerk/protocol/http/nsHttpChannel.h
@@ -243,17 +243,17 @@ private:
 
     bool     RequestIsConditional();
     nsresult BeginConnect();
     nsresult ContinueBeginConnectWithResult();
     void     ContinueBeginConnect();
     nsresult Connect();
     void     SpeculativeConnect();
     nsresult SetupTransaction();
-    void     SetupTransactionLoadGroupInfo();
+    void     SetupTransactionSchedulingContext();
     nsresult CallOnStartRequest();
     nsresult ProcessResponse();
     nsresult ContinueProcessResponse(nsresult);
     nsresult ProcessNormal();
     nsresult ContinueProcessNormal(nsresult);
     void     ProcessAltService();
     nsresult ProcessNotModified();
     nsresult AsyncProcessRedirection(uint32_t httpStatus);
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -24,16 +24,17 @@
 #include "nsISocketTransport.h"
 #include "nsISSLSocketControl.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/net/DashboardTypes.h"
 #include "NullHttpTransaction.h"
 #include "nsIDNSRecord.h"
 #include "nsITransport.h"
 #include "nsInterfaceRequestorAgg.h"
+#include "nsISchedulingContext.h"
 #include "nsISocketTransportService.h"
 #include <algorithm>
 #include "mozilla/ChaosMode.h"
 #include "mozilla/unused.h"
 
 #include "mozilla/Telemetry.h"
 
 // defined by the socket transport service while active
@@ -1776,30 +1777,30 @@ nsHttpConnectionMgr::TryDispatchTransact
                 trans->RemoveDispatchedAsBlocking();  /* just in case */
                 DispatchTransaction(ent, trans, conn);
                 return NS_OK;
             }
             unusedSpdyPersistentConnection = conn;
         }
     }
 
-    // If this is not a blocking transaction and the loadgroup for it is
+    // If this is not a blocking transaction and the scheduling context for it is
     // currently processing one or more blocking transactions then we
     // need to just leave it in the queue until those are complete unless it is
     // explicitly marked as unblocked.
     if (!(caps & NS_HTTP_LOAD_AS_BLOCKING)) {
         if (!(caps & NS_HTTP_LOAD_UNBLOCKED)) {
-            nsILoadGroupConnectionInfo *loadGroupCI = trans->LoadGroupConnectionInfo();
-            if (loadGroupCI) {
+            nsISchedulingContext *schedulingContext = trans->SchedulingContext();
+            if (schedulingContext) {
                 uint32_t blockers = 0;
-                if (NS_SUCCEEDED(loadGroupCI->GetBlockingTransactionCount(&blockers)) &&
+                if (NS_SUCCEEDED(schedulingContext->GetBlockingTransactionCount(&blockers)) &&
                     blockers) {
                     // need to wait for blockers to clear
-                    LOG(("   blocked by load group: [lgci=%p trans=%p blockers=%d]\n",
-                         loadGroupCI, trans, blockers));
+                    LOG(("   blocked by scheduling context: [sc=%p trans=%p blockers=%d]\n",
+                         schedulingContext, trans, blockers));
                     return NS_ERROR_NOT_AVAILABLE;
                 }
             }
         }
     } else {
         // Mark the transaction and its load group as blocking right now to prevent
         // other transactions from being reordered in the queue due to slow syns.
         trans->DispatchedAsBlocking();
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -321,16 +321,19 @@ nsHttpHandler::Init()
     if (NS_FAILED(rv)) return rv;
 
     rv = mPrivateAuthCache.Init();
     if (NS_FAILED(rv)) return rv;
 
     rv = InitConnectionMgr();
     if (NS_FAILED(rv)) return rv;
 
+    mSchedulingContextService =
+        do_GetService("@mozilla.org/network/scheduling-context-service;1");
+
 #ifdef ANDROID
     mProductSub.AssignLiteral(MOZILLA_UAVERSION);
 #else
     mProductSub.AssignLiteral("20100101");
 #endif
 
 #if DEBUG
     // dump user agent prefs
--- a/netwerk/protocol/http/nsHttpHandler.h
+++ b/netwerk/protocol/http/nsHttpHandler.h
@@ -19,16 +19,17 @@
 #include "nsIObserver.h"
 #include "nsISpeculativeConnect.h"
 
 class nsIHttpChannel;
 class nsIPrefBranch;
 class nsICancelable;
 class nsICookieService;
 class nsIIOService;
+class nsISchedulingContextService;
 class nsISiteSecurityService;
 class nsIStreamConverterService;
 class nsITimer;
 
 namespace mozilla {
 namespace net {
 class ATokenBucketEvent;
 class EventTokenBucket;
@@ -331,16 +332,21 @@ public:
     bool Active() { return mHandlerActive; }
 
     // When the disk cache is responding slowly its use is suppressed
     // for 1 minute for most requests. Callable from main thread only.
     TimeStamp GetCacheSkippedUntil() { return mCacheSkippedUntil; }
     void SetCacheSkippedUntil(TimeStamp arg) { mCacheSkippedUntil = arg; }
     void ClearCacheSkippedUntil() { mCacheSkippedUntil = TimeStamp(); }
 
+    nsISchedulingContextService *GetSchedulingContextService()
+    {
+        return mSchedulingContextService.get();
+    }
+
 private:
     virtual ~nsHttpHandler();
 
     //
     // Useragent/prefs helper methods
     //
     void     BuildUserAgent();
     void     InitUserAgentComponents();
@@ -538,16 +544,18 @@ private:
     bool mTCPKeepaliveLongLivedEnabled;
     // Time (secs) before first keepalive probe; between successful probes.
     int32_t mTCPKeepaliveLongLivedIdleTimeS;
 
     // if true, generate NS_ERROR_PARTIAL_TRANSFER for h1 responses with
     // incorrect content lengths or malformed chunked encodings
     FrameCheckLevel mEnforceH1Framing;
 
+    nsCOMPtr<nsISchedulingContextService> mSchedulingContextService;
+
 private:
     // For Rate Pacing Certain Network Events. Only assign this pointer on
     // socket thread.
     void MakeNewRequestTokenBucket();
     nsRefPtr<EventTokenBucket> mRequestTokenBucket;
 
 public:
     // Socket thread only
--- a/netwerk/protocol/http/nsHttpTransaction.cpp
+++ b/netwerk/protocol/http/nsHttpTransaction.cpp
@@ -30,16 +30,17 @@
 #include "nsIHttpActivityObserver.h"
 #include "nsSocketTransportService2.h"
 #include "nsICancelable.h"
 #include "nsIEventTarget.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsIInputStream.h"
 #include "nsITransport.h"
 #include "nsIOService.h"
+#include "nsISchedulingContext.h"
 #include <algorithm>
 
 #ifdef MOZ_WIDGET_GONK
 #include "NetStatistics.h"
 #endif
 
 //-----------------------------------------------------------------------------
 
@@ -1843,73 +1844,73 @@ nsHttpTransaction::CancelPipeline(uint32
     // Avoid pipelining this transaction on restart by classifying it as solo.
     // This also prevents BadUnexpectedLarge from being reported more
     // than one time per transaction.
     mClassification = CLASS_SOLO;
 }
 
 
 void
-nsHttpTransaction::SetLoadGroupConnectionInfo(nsILoadGroupConnectionInfo *aLoadGroupCI)
+nsHttpTransaction::SetSchedulingContext(nsISchedulingContext *aSchedulingContext)
 {
-    LOG(("nsHttpTransaction %p SetLoadGroupConnectionInfo %p\n", this, aLoadGroupCI));
-    mLoadGroupCI = aLoadGroupCI;
+    LOG(("nsHttpTransaction %p SetSchedulingContext %p\n", this, aSchedulingContext));
+    mSchedulingContext = aSchedulingContext;
 }
 
 // Called when the transaction marked for blocking is associated with a connection
 // (i.e. added to a new h1 conn, an idle http connection, or placed into
 // a http pipeline). It is safe to call this multiple times with it only
 // having an effect once.
 void
 nsHttpTransaction::DispatchedAsBlocking()
 {
     if (mDispatchedAsBlocking)
         return;
 
     LOG(("nsHttpTransaction %p dispatched as blocking\n", this));
 
-    if (!mLoadGroupCI)
+    if (!mSchedulingContext)
         return;
 
     LOG(("nsHttpTransaction adding blocking transaction %p from "
-         "loadgroup %p\n", this, mLoadGroupCI.get()));
+         "scheduling context %p\n", this, mSchedulingContext.get()));
 
-    mLoadGroupCI->AddBlockingTransaction();
+    mSchedulingContext->AddBlockingTransaction();
     mDispatchedAsBlocking = true;
 }
 
 void
 nsHttpTransaction::RemoveDispatchedAsBlocking()
 {
-    if (!mLoadGroupCI || !mDispatchedAsBlocking)
+    if (!mSchedulingContext || !mDispatchedAsBlocking)
         return;
 
     uint32_t blockers = 0;
-    nsresult rv = mLoadGroupCI->RemoveBlockingTransaction(&blockers);
+    nsresult rv = mSchedulingContext->RemoveBlockingTransaction(&blockers);
 
     LOG(("nsHttpTransaction removing blocking transaction %p from "
-         "loadgroup %p. %d blockers remain.\n", this,
-         mLoadGroupCI.get(), blockers));
+         "scheduling context %p. %d blockers remain.\n", this,
+         mSchedulingContext.get(), blockers));
 
     if (NS_SUCCEEDED(rv) && !blockers) {
         LOG(("nsHttpTransaction %p triggering release of blocked channels "
-             " with loadgroupci=%p\n", this, mLoadGroupCI.get()));
+             " with scheduling context=%p\n", this, mSchedulingContext.get()));
         gHttpHandler->ConnMgr()->ProcessPendingQ();
     }
 
     mDispatchedAsBlocking = false;
 }
 
 void
 nsHttpTransaction::ReleaseBlockingTransaction()
 {
     RemoveDispatchedAsBlocking();
-    LOG(("nsHttpTransaction %p loadgroupci set to null "
-         "in ReleaseBlockingTransaction() - was %p\n", this, mLoadGroupCI.get()));
-    mLoadGroupCI = nullptr;
+    LOG(("nsHttpTransaction %p scheduling context set to null "
+         "in ReleaseBlockingTransaction() - was %p\n", this, mSchedulingContext.get()));
+    mSchedulingContext = nullptr;
 }
 
 void
 nsHttpTransaction::DisableSpdy()
 {
     mCaps |= NS_HTTP_DISALLOW_SPDY;
     if (mConnInfo) {
         // This is our clone of the connection info, not the persistent one that
--- a/netwerk/protocol/http/nsHttpTransaction.h
+++ b/netwerk/protocol/http/nsHttpTransaction.h
@@ -7,33 +7,33 @@
 #define nsHttpTransaction_h__
 
 #include "nsHttp.h"
 #include "nsAHttpTransaction.h"
 #include "nsAHttpConnection.h"
 #include "EventTokenBucket.h"
 #include "nsCOMPtr.h"
 #include "nsThreadUtils.h"
-#include "nsILoadGroup.h"
 #include "nsIInterfaceRequestor.h"
 #include "TimingStruct.h"
 #include "Http2Push.h"
 #include "mozilla/net/DNS.h"
 
 #ifdef MOZ_WIDGET_GONK
 #include "nsINetworkInterface.h"
 #include "nsProxyRelease.h"
 #endif
 
 //-----------------------------------------------------------------------------
 
 class nsIHttpActivityObserver;
 class nsIEventTarget;
 class nsIInputStream;
 class nsIOutputStream;
+class nsISchedulingContext;
 
 namespace mozilla { namespace net {
 
 class nsHttpChunkedDecoder;
 class nsHttpRequestHead;
 class nsHttpResponseHead;
 
 //-----------------------------------------------------------------------------
@@ -119,19 +119,19 @@ public:
 
     void PrintDiagnostics(nsCString &log);
 
     // Sets mPendingTime to the current time stamp or to a null time stamp (if now is false)
     void SetPendingTime(bool now = true) { mPendingTime = now ? TimeStamp::Now() : TimeStamp(); }
     const TimeStamp GetPendingTime() { return mPendingTime; }
     bool UsesPipelining() const { return mCaps & NS_HTTP_ALLOW_PIPELINING; }
 
-    // overload of nsAHttpTransaction::LoadGroupConnectionInfo()
-    nsILoadGroupConnectionInfo *LoadGroupConnectionInfo() override { return mLoadGroupCI.get(); }
-    void SetLoadGroupConnectionInfo(nsILoadGroupConnectionInfo *aLoadGroupCI);
+    // overload of nsAHttpTransaction::SchedulingContext()
+    nsISchedulingContext *SchedulingContext() override { return mSchedulingContext.get(); }
+    void SetSchedulingContext(nsISchedulingContext *aSchedulingContext);
     void DispatchedAsBlocking();
     void RemoveDispatchedAsBlocking();
 
     nsHttpTransaction *QueryHttpTransaction() override { return this; }
 
     Http2PushedStream *GetPushedStream() { return mPushedStream; }
     Http2PushedStream *TakePushedStream()
     {
@@ -213,17 +213,17 @@ private:
     Mutex mLock;
 
     nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
     nsCOMPtr<nsITransportEventSink> mTransportSink;
     nsCOMPtr<nsIEventTarget>        mConsumerTarget;
     nsCOMPtr<nsISupports>           mSecurityInfo;
     nsCOMPtr<nsIAsyncInputStream>   mPipeIn;
     nsCOMPtr<nsIAsyncOutputStream>  mPipeOut;
-    nsCOMPtr<nsILoadGroupConnectionInfo> mLoadGroupCI;
+    nsCOMPtr<nsISchedulingContext>  mSchedulingContext;
 
     nsCOMPtr<nsISupports>             mChannel;
     nsCOMPtr<nsIHttpActivityObserver> mActivityDistributor;
 
     nsCString                       mReqHeaderBuf;    // flattened request headers
     nsCOMPtr<nsIInputStream>        mRequestStream;
     int64_t                         mRequestSize;
 
--- a/netwerk/protocol/http/nsIHttpChannel.idl
+++ b/netwerk/protocol/http/nsIHttpChannel.idl
@@ -9,17 +9,17 @@ interface nsIHttpHeaderVisitor;
 
 /**
  * nsIHttpChannel
  *
  * This interface allows for the modification of HTTP request parameters and
  * the inspection of the resulting HTTP response status and headers when they
  * become available.
  */
-[builtinclass, scriptable, uuid(1656b777-3045-4b74-b6c3-a2677c0ae082)]
+[builtinclass, scriptable, uuid(fdc70825-8ae1-4f81-bd9e-f1fd3f6307ad)]
 interface nsIHttpChannel : nsIChannel
 {
     /**************************************************************************
      * REQUEST CONFIGURATION
      *
      * Modifying request parameters after asyncOpen has been called is an error.
      */
 
@@ -316,9 +316,14 @@ interface nsIHttpChannel : nsIChannel
      *
      * This method provides no explicit conflict resolution. The last
      * caller to call it wins.
      *
      * @throws NS_ERROR_ALREADY_OPENED if called after the channel
      *         has been opened.
      */
     void redirectTo(in nsIURI aNewURI);
+
+    /**
+     * Identifies the scheduling context for this load.
+     */
+    [noscript] attribute nsID schedulingContextID;
 };
--- a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp
+++ b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp
@@ -841,8 +841,21 @@ nsViewSourceChannel::IsPrivateResponse(b
 
 NS_IMETHODIMP
 nsViewSourceChannel::RedirectTo(nsIURI *uri)
 {
     return !mHttpChannel ? NS_ERROR_NULL_POINTER :
         mHttpChannel->RedirectTo(uri);
 }
 
+NS_IMETHODIMP
+nsViewSourceChannel::GetSchedulingContextID(nsID *_retval)
+{
+    return !mHttpChannel ? NS_ERROR_NULL_POINTER :
+        mHttpChannel->GetSchedulingContextID(_retval);
+}
+
+NS_IMETHODIMP
+nsViewSourceChannel::SetSchedulingContextID(const nsID scid)
+{
+    return !mHttpChannel ? NS_ERROR_NULL_POINTER :
+        mHttpChannel->SetSchedulingContextID(scid);
+}
--- a/netwerk/test/unit/test_http2.js
+++ b/netwerk/test/unit/test_http2.js
@@ -776,18 +776,19 @@ var tests = [ test_http2_post_big
             , test_http2_cookie_crumbling
             , test_http2_multiplex
             , test_http2_big
             , test_http2_huge_suspended
             , test_http2_post
             , test_http2_patch
             , test_http2_pushapi_1
             , test_http2_continuations
+            // Add new tests above here - best to add new tests before h1
+            // streams get too involved
             // These next two must always come in this order
-	    // best to add new tests before h1 streams get too involved
             , test_http2_h11required_stream
             , test_http2_h11required_session
             , test_http2_retry_rst
             , test_http2_wrongsuite
 
             // cleanup
             , test_complete
             ];
--- a/xpcom/glue/nsID.cpp
+++ b/xpcom/glue/nsID.cpp
@@ -3,16 +3,26 @@
 /* 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 "nsID.h"
 #include "prprf.h"
 #include "nsMemory.h"
 
+void nsID::Clear()
+{
+  m0 = 0;
+  m1 = 0;
+  m2 = 0;
+  for (int i = 0; i < 8; ++i) {
+    m3[i] = 0;
+  }
+}
+
 /**
  * Multiplies the_int_var with 16 (0x10) and adds the value of the
  * hexadecimal digit the_char. If it fails it returns false from
  * the function it's used in.
  */
 
 #define ADD_HEX_CHAR_TO_INT_OR_RETURN_FALSE(the_char, the_int_var) \
     the_int_var = (the_int_var << 4) + the_char; \
--- a/xpcom/glue/nsID.h
+++ b/xpcom/glue/nsID.h
@@ -31,16 +31,21 @@ struct nsID
   //@}
 
   /**
    * @name Methods
    */
 
   //@{
   /**
+   * Ensures everything is zeroed out.
+   */
+  void Clear();
+
+  /**
    * Equivalency method. Compares this nsID with another.
    * @return <b>true</b> if they are the same, <b>false</b> if not.
    */
 
   inline bool Equals(const nsID& aOther) const
   {
     // Unfortunately memcmp isn't faster than this.
     return