From e415496cf838cc6c91747b201ae250e725bf1968 Mon Sep 17 00:00:00 2001 From: Nicholas Hurley Date: Wed, 8 Apr 2015 14:42:00 +0200 Subject: [PATCH] Bug 1127618 - make push caches work in e10s. r=mcmanus r=froydnj --- netwerk/base/SchedulingContextService.cpp | 193 ++++++++++++++++++ netwerk/base/SchedulingContextService.h | 47 +++++ netwerk/base/moz.build | 2 + netwerk/base/nsILoadGroup.idl | 55 +---- netwerk/base/nsISchedulingContext.idl | 85 ++++++++ netwerk/base/nsLoadGroup.cpp | 85 ++------ netwerk/base/nsLoadGroup.h | 4 +- netwerk/build/nsNetCID.h | 11 + netwerk/build/nsNetModule.cpp | 7 + netwerk/ipc/NeckoChannelParams.ipdlh | 1 + netwerk/protocol/http/Http2Push.cpp | 2 +- netwerk/protocol/http/Http2Push.h | 5 +- netwerk/protocol/http/Http2Session.cpp | 18 +- netwerk/protocol/http/Http2Stream.cpp | 10 +- netwerk/protocol/http/Http2Stream.h | 4 +- netwerk/protocol/http/HttpBaseChannel.cpp | 46 +++++ netwerk/protocol/http/HttpBaseChannel.h | 5 + netwerk/protocol/http/HttpChannelChild.cpp | 5 + netwerk/protocol/http/HttpChannelParent.cpp | 10 +- netwerk/protocol/http/HttpChannelParent.h | 3 +- netwerk/protocol/http/NullHttpChannel.cpp | 12 ++ netwerk/protocol/http/SpdyPush31.cpp | 2 +- netwerk/protocol/http/SpdyPush31.h | 6 +- netwerk/protocol/http/SpdySession31.cpp | 12 +- netwerk/protocol/http/SpdyStream31.cpp | 6 +- netwerk/protocol/http/SpdyStream31.h | 4 +- netwerk/protocol/http/nsAHttpTransaction.h | 6 +- netwerk/protocol/http/nsHttpChannel.cpp | 32 +-- netwerk/protocol/http/nsHttpChannel.h | 2 +- netwerk/protocol/http/nsHttpConnectionMgr.cpp | 13 +- netwerk/protocol/http/nsHttpHandler.cpp | 3 + netwerk/protocol/http/nsHttpHandler.h | 8 + netwerk/protocol/http/nsHttpTransaction.cpp | 29 +-- netwerk/protocol/http/nsHttpTransaction.h | 10 +- netwerk/protocol/http/nsIHttpChannel.idl | 7 +- .../viewsource/nsViewSourceChannel.cpp | 13 ++ netwerk/test/unit/test_http2.js | 3 +- xpcom/glue/nsID.cpp | 10 + xpcom/glue/nsID.h | 5 + 39 files changed, 575 insertions(+), 206 deletions(-) create mode 100644 netwerk/base/SchedulingContextService.cpp create mode 100644 netwerk/base/SchedulingContextService.h create mode 100644 netwerk/base/nsISchedulingContext.idl diff --git a/netwerk/base/SchedulingContextService.cpp b/netwerk/base/SchedulingContextService.cpp new file mode 100644 index 00000000000..6e367a76688 --- /dev/null +++ b/netwerk/base/SchedulingContextService.cpp @@ -0,0 +1,193 @@ +/* -*- 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 "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 nsSupportsWeakReference +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSISCHEDULINGCONTEXT + + explicit SchedulingContext(const nsID& id); +private: + virtual ~SchedulingContext() {} + + nsID mID; + Atomic mBlockingTransactionCount; + nsAutoPtr mSpdyCache; +}; + +NS_IMPL_ISUPPORTS(SchedulingContext, nsISchedulingContext, nsISupportsWeakReference) + +SchedulingContext::SchedulingContext(const nsID& aID) + : mBlockingTransactionCount(0) +{ + mID = aID; +} + +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!"); + sSelf = this; +} + +SchedulingContextService::~SchedulingContextService() +{ + Shutdown(); + sSelf = nullptr; +} + +nsresult +SchedulingContextService::Init() +{ + nsCOMPtr obs = mozilla::services::GetObserverService(); + if (!obs) { + return NS_ERROR_NOT_AVAILABLE; + } + + return obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); +} + +void +SchedulingContextService::Shutdown() +{ + mTable.Clear(); +} + +/* static */ nsresult +SchedulingContextService::Create(nsISupports *aOuter, const nsIID& aIID, void **aResult) +{ + if (aOuter != nullptr) { + return NS_ERROR_NO_AGGREGATION; + } + + nsRefPtr 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) +{ + NS_ENSURE_ARG_POINTER(sc); + *sc = nullptr; + + nsWeakPtr weakSC; + nsCOMPtr strongSC; + if (mTable.Get(scID, getter_AddRefs(weakSC))) { + strongSC = do_QueryReferent(weakSC); + } + + if (!strongSC) { + // Either this wasn't in the table to begin with, or the weak reference has + // expired. Let's make a new one. + strongSC = new SchedulingContext(scID); + weakSC = do_GetWeakReference(strongSC); + if (!weakSC) { + return NS_ERROR_OUT_OF_MEMORY; + } + mTable.Put(scID, weakSC); + } + + strongSC.swap(*sc); + + return NS_OK; +} + +NS_IMETHODIMP +SchedulingContextService::NewSchedulingContextID(nsID *scID) +{ + 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::Observe(nsISupports *subject, const char *topic, + const char16_t *data_unicode) +{ + if (!strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, topic)) { + Shutdown(); + } + + return NS_OK; +} + +} // ::mozilla::net +} // ::mozilla diff --git a/netwerk/base/SchedulingContextService.h b/netwerk/base/SchedulingContextService.h new file mode 100644 index 00000000000..cd2e61fc236 --- /dev/null +++ b/netwerk/base/SchedulingContextService.h @@ -0,0 +1,47 @@ +/* -*- 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" +#include "nsWeakReference.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 mTable; + nsCOMPtr mUUIDGen; +}; + +} // ::mozilla::net +} // ::mozilla + +#endif // mozilla__net__SchedulingContextService_h diff --git a/netwerk/base/moz.build b/netwerk/base/moz.build index 0781cb18683..b026b975873 100644 --- a/netwerk/base/moz.build +++ b/netwerk/base/moz.build @@ -91,6 +91,7 @@ XPIDL_SOURCES += [ 'nsIRequestObserverProxy.idl', 'nsIResponseHeadProvider.idl', 'nsIResumableChannel.idl', + 'nsISchedulingContext.idl', 'nsISecretDecoderRing.idl', 'nsISecureBrowserUI.idl', 'nsISecurityEventSink.idl', @@ -237,6 +238,7 @@ UNIFIED_SOURCES += [ 'Predictor.cpp', 'ProxyAutoConfig.cpp', 'RedirectChannelRegistrar.cpp', + 'SchedulingContextService.cpp', 'StreamingProtocolService.cpp', 'Tickler.cpp', 'TLSServerSocket.cpp', diff --git a/netwerk/base/nsILoadGroup.idl b/netwerk/base/nsILoadGroup.idl index 72439ebf55a..a5768111c02 100644 --- a/netwerk/base/nsILoadGroup.idl +++ b/netwerk/base/nsILoadGroup.idl @@ -8,14 +8,14 @@ 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 { /** @@ -76,10 +76,10 @@ interface nsILoadGroup : nsIRequest 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 @@ -94,48 +94,3 @@ interface nsILoadGroup : nsIRequest */ 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; -}; diff --git a/netwerk/base/nsISchedulingContext.idl b/netwerk/base/nsISchedulingContext.idl new file mode 100644 index 00000000000..ad473e20e1d --- /dev/null +++ b/netwerk/base/nsISchedulingContext.idl @@ -0,0 +1,85 @@ +/* -*- 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(); +}; diff --git a/netwerk/base/nsLoadGroup.cpp b/netwerk/base/nsLoadGroup.cpp index 8047f6407da..51c70d5188d 100644 --- a/netwerk/base/nsLoadGroup.cpp +++ b/netwerk/base/nsLoadGroup.cpp @@ -14,13 +14,11 @@ #include "prlog.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" @@ -741,12 +739,12 @@ nsLoadGroup::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks) } 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); } //////////////////////////////////////////////////////////////////////////////// @@ -1068,68 +1066,6 @@ nsresult nsLoadGroup::MergeLoadFlags(nsIRequest *aRequest, nsLoadFlags& outFlags return rv; } -// nsLoadGroupConnectionInfo - -class nsLoadGroupConnectionInfo final : public nsILoadGroupConnectionInfo -{ - ~nsLoadGroupConnectionInfo() {} - -public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSILOADGROUPCONNECTIONINFO - - nsLoadGroupConnectionInfo(); -private: - Atomic mBlockingTransactionCount; - nsAutoPtr 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; -} - nsresult nsLoadGroup::Init() { static const PLDHashTableOps hash_table_ops = @@ -1144,7 +1080,14 @@ nsresult nsLoadGroup::Init() PL_DHashTableInit(&mRequests, &hash_table_ops, sizeof(RequestMapEntry)); - mConnectionInfo = new nsLoadGroupConnectionInfo(); + nsCOMPtr scsvc = do_GetService("@mozilla.org/network/scheduling-context-service;1"); + if (scsvc) { + nsID schedulingContextID; + if (NS_SUCCEEDED(scsvc->NewSchedulingContextID(&schedulingContextID))) { + scsvc->GetSchedulingContext(schedulingContextID, + getter_AddRefs(mSchedulingContext)); + } + } return NS_OK; } diff --git a/netwerk/base/nsLoadGroup.h b/netwerk/base/nsLoadGroup.h index 28d4c29a9c5..7664814c114 100644 --- a/netwerk/base/nsLoadGroup.h +++ b/netwerk/base/nsLoadGroup.h @@ -17,7 +17,7 @@ #include "pldhash.h" #include "mozilla/TimeStamp.h" -class nsILoadGroupConnectionInfo; +class nsISchedulingContext; class nsITimedChannel; class nsLoadGroup : public nsILoadGroup, @@ -70,7 +70,7 @@ protected: nsCOMPtr mLoadGroup; // load groups can contain load groups nsCOMPtr mCallbacks; - nsCOMPtr mConnectionInfo; + nsCOMPtr mSchedulingContext; nsCOMPtr mDefaultLoadRequest; PLDHashTable mRequests; diff --git a/netwerk/build/nsNetCID.h b/netwerk/build/nsNetCID.h index ac39fb8e816..ea14941aec9 100644 --- a/netwerk/build/nsNetCID.h +++ b/netwerk/build/nsNetCID.h @@ -468,6 +468,17 @@ { 0xae, 0xcf, 0x05, 0xf8, 0xfa, 0xf0, 0x0c, 0x9b } \ } +// 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 */ diff --git a/netwerk/build/nsNetModule.cpp b/netwerk/build/nsNetModule.cpp index af6a3b827fa..f6f9d07d7b3 100644 --- a/netwerk/build/nsNetModule.cpp +++ b/netwerk/build/nsNetModule.cpp @@ -132,6 +132,10 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(RedirectChannelRegistrar) typedef mozilla::net::CacheStorageService CacheStorageService; NS_GENERIC_FACTORY_CONSTRUCTOR(CacheStorageService) +#include "SchedulingContextService.h" +typedef mozilla::net::SchedulingContextService SchedulingContextService; +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(SchedulingContextService, Init) + /////////////////////////////////////////////////////////////////////////////// extern nsresult @@ -801,6 +805,7 @@ 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_SCHEDULINGCONTEXTSERVICE_CID); static const mozilla::Module::CIDEntry kNeckoCIDs[] = { { &kNS_IOSERVICE_CID, false, nullptr, nsIOServiceConstructor }, @@ -947,6 +952,7 @@ static const mozilla::Module::CIDEntry kNeckoCIDs[] = { { &kNS_REDIRECTCHANNELREGISTRAR_CID, false, nullptr, RedirectChannelRegistrarConstructor }, { &kNS_CACHE_STORAGE_SERVICE_CID, false, nullptr, CacheStorageServiceConstructor }, { &kNS_NETWORKPREDICTOR_CID, false, nullptr, mozilla::net::Predictor::Create }, + { &kNS_SCHEDULINGCONTEXTSERVICE_CID, false, nullptr, SchedulingContextServiceConstructor }, { nullptr } }; @@ -1097,6 +1103,7 @@ static const mozilla::Module::ContractIDEntry kNeckoContracts[] = { { 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_SCHEDULINGCONTEXTSERVICE_CONTRACTID, &kNS_SCHEDULINGCONTEXTSERVICE_CID }, { nullptr } }; diff --git a/netwerk/ipc/NeckoChannelParams.ipdlh b/netwerk/ipc/NeckoChannelParams.ipdlh index 5da32e617e1..be9d032c18c 100644 --- a/netwerk/ipc/NeckoChannelParams.ipdlh +++ b/netwerk/ipc/NeckoChannelParams.ipdlh @@ -58,6 +58,7 @@ struct HttpChannelOpenArgs uint32_t securityFlags; uint32_t contentPolicyType; uint32_t innerWindowID; + nsCString schedulingContextID; }; struct HttpChannelConnectArgs diff --git a/netwerk/protocol/http/Http2Push.cpp b/netwerk/protocol/http/Http2Push.cpp index 1446ca964d5..cbde653ae6d 100644 --- a/netwerk/protocol/http/Http2Push.cpp +++ b/netwerk/protocol/http/Http2Push.cpp @@ -77,7 +77,7 @@ Http2PushedStream::Http2PushedStream(Http2PushTransactionBuffer *aTransaction, 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); } diff --git a/netwerk/protocol/http/Http2Push.h b/netwerk/protocol/http/Http2Push.h index 071823c6adc..16edf889234 100644 --- a/netwerk/protocol/http/Http2Push.h +++ b/netwerk/protocol/http/Http2Push.h @@ -13,6 +13,7 @@ #include "mozilla/TimeStamp.h" #include "nsHttpRequestHead.h" #include "nsILoadGroup.h" +#include "nsISchedulingContext.h" #include "nsString.h" #include "PSpdyPush.h" @@ -42,7 +43,7 @@ public: 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(); @@ -65,7 +66,7 @@ private: Http2Stream *mConsumerStream; // paired request stream that consumes from // real http/2 one.. null until a match is made. - nsCOMPtr mLoadGroupCI; + nsCOMPtr mSchedulingContext; nsAHttpTransaction *mAssociatedTransaction; diff --git a/netwerk/protocol/http/Http2Session.cpp b/netwerk/protocol/http/Http2Session.cpp index c8d921cc7f9..e3772ee7cd1 100644 --- a/netwerk/protocol/http/Http2Session.cpp +++ b/netwerk/protocol/http/Http2Session.cpp @@ -24,7 +24,7 @@ #include "nsHttp.h" #include "nsHttpHandler.h" #include "nsHttpConnection.h" -#include "nsILoadGroup.h" +#include "nsISchedulingContext.h" #include "nsISSLSocketControl.h" #include "nsISSLStatus.h" #include "nsISSLStatusProvider.h" @@ -1077,10 +1077,10 @@ Http2Session::CleanupStream(Http2Stream *aStream, nsresult aResult, Http2PushedStream *pushStream = static_cast(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", @@ -1638,12 +1638,12 @@ Http2Session::RecvPushPromise(Http2Session *self) 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; } @@ -1651,7 +1651,7 @@ Http2Session::RecvPushPromise(Http2Session *self) } 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; diff --git a/netwerk/protocol/http/Http2Stream.cpp b/netwerk/protocol/http/Http2Stream.cpp index 38fc025eee4..ad3f108b638 100644 --- a/netwerk/protocol/http/Http2Stream.cpp +++ b/netwerk/protocol/http/Http2Stream.cpp @@ -363,10 +363,10 @@ Http2Stream::ParseHttpRequestHeaders(const char *buf, // 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; @@ -393,8 +393,8 @@ Http2Stream::ParseHttpRequestHeaders(const char *buf, } 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", diff --git a/netwerk/protocol/http/Http2Stream.h b/netwerk/protocol/http/Http2Stream.h index 43510d58481..ef5f8220940 100644 --- a/netwerk/protocol/http/Http2Stream.h +++ b/netwerk/protocol/http/Http2Stream.h @@ -67,9 +67,9 @@ public: 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); diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index 5c6f2c3f47e..9858f36341a 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -37,6 +37,7 @@ #include "nsPerformance.h" #include "nsINetworkInterceptController.h" #include "mozIThirdPartyUtil.h" +#include "nsILoadGroupChild.h" #include @@ -95,6 +96,7 @@ HttpBaseChannel::HttpBaseChannel() #endif mSelfAddr.raw.family = PR_AF_UNSPEC; mPeerAddr.raw.family = PR_AF_UNSPEC; + mSchedulingContextID.Clear(); } HttpBaseChannel::~HttpBaseChannel() @@ -1458,6 +1460,21 @@ HttpBaseChannel::RedirectTo(nsIURI *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 //----------------------------------------------------------------------------- @@ -2671,6 +2688,35 @@ HttpBaseChannel::GetPerformance() //------------------------------------------------------------------------------ +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 childLoadGroup = do_QueryInterface(mLoadGroup); + if (!childLoadGroup) { + return false; + } + + nsCOMPtr 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 diff --git a/netwerk/protocol/http/HttpBaseChannel.h b/netwerk/protocol/http/HttpBaseChannel.h index b3b9f183a96..40c91ad608a 100644 --- a/netwerk/protocol/http/HttpBaseChannel.h +++ b/netwerk/protocol/http/HttpBaseChannel.h @@ -158,6 +158,8 @@ public: 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; @@ -433,6 +435,9 @@ protected: // 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 diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp index 897ef484a9f..fc6705b32cf 100644 --- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -1634,6 +1634,11 @@ HttpChannelChild::ContinueAsyncOpen() propagateLoadInfo(mLoadInfo, openArgs); + 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(); diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp index c514807f8c6..1ed01a64725 100644 --- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -110,7 +110,8 @@ HttpChannelParent::Init(const HttpChannelCreationArgs& aArgs) a.entityID(), a.chooseApplicationCache(), a.appCacheClientID(), a.allowSpdy(), a.fds(), a.requestingPrincipalInfo(), a.triggeringPrincipalInfo(), - a.securityFlags(), a.contentPolicyType(), a.innerWindowID()); + a.securityFlags(), a.contentPolicyType(), a.innerWindowID(), + a.schedulingContextID()); } case HttpChannelCreationArgs::THttpChannelConnectArgs: { @@ -201,7 +202,8 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI, const ipc::PrincipalInfo& aTriggeringPrincipalInfo, const uint32_t& aSecurityFlags, const uint32_t& aContentPolicyType, - const uint32_t& aInnerWindowID) + const uint32_t& aInnerWindowID, + const nsCString& aSchedulingContextID) { nsCOMPtr uri = DeserializeURI(aURI); if (!uri) { @@ -373,6 +375,10 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI, } } + nsID schedulingContextID; + schedulingContextID.Parse(aSchedulingContextID.BeginReading()); + mChannel->SetSchedulingContextID(schedulingContextID); + rv = mChannel->AsyncOpen(mParentListener, nullptr); if (NS_FAILED(rv)) return SendFailedAsyncOpen(rv); diff --git a/netwerk/protocol/http/HttpChannelParent.h b/netwerk/protocol/http/HttpChannelParent.h index 420b80298c1..2c4f1b28f3c 100644 --- a/netwerk/protocol/http/HttpChannelParent.h +++ b/netwerk/protocol/http/HttpChannelParent.h @@ -115,7 +115,8 @@ protected: const ipc::PrincipalInfo& aTriggeringPrincipalInfo, const uint32_t& aSecurityFlags, const uint32_t& aContentPolicyType, - const uint32_t& aInnerWindowID); + const uint32_t& aInnerWindowID, + const nsCString& aSchedulingContextID); virtual bool RecvSetPriority(const uint16_t& priority) override; virtual bool RecvSetClassOfService(const uint32_t& cos) override; diff --git a/netwerk/protocol/http/NullHttpChannel.cpp b/netwerk/protocol/http/NullHttpChannel.cpp index 00397d09e49..0e1584539e2 100644 --- a/netwerk/protocol/http/NullHttpChannel.cpp +++ b/netwerk/protocol/http/NullHttpChannel.cpp @@ -205,6 +205,18 @@ 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 //----------------------------------------------------------------------------- diff --git a/netwerk/protocol/http/SpdyPush31.cpp b/netwerk/protocol/http/SpdyPush31.cpp index 26b592415ef..dcdbf012f02 100644 --- a/netwerk/protocol/http/SpdyPush31.cpp +++ b/netwerk/protocol/http/SpdyPush31.cpp @@ -40,7 +40,7 @@ SpdyPushedStream31::SpdyPushedStream31(SpdyPush31TransactionBuffer *aTransaction 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(); } diff --git a/netwerk/protocol/http/SpdyPush31.h b/netwerk/protocol/http/SpdyPush31.h index 4cda1ca6b6d..4985e7f7470 100644 --- a/netwerk/protocol/http/SpdyPush31.h +++ b/netwerk/protocol/http/SpdyPush31.h @@ -11,7 +11,7 @@ #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" @@ -40,7 +40,7 @@ public: 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; } @@ -58,7 +58,7 @@ private: SpdyStream31 *mConsumerStream; // paired request stream that consumes from // real spdy one.. null until a match is made. - nsCOMPtr mLoadGroupCI; + nsCOMPtr mSchedulingContext; SpdyPush31TransactionBuffer *mBufferedPush; TimeStamp mLastRead; diff --git a/netwerk/protocol/http/SpdySession31.cpp b/netwerk/protocol/http/SpdySession31.cpp index f5084996689..7f5cceae50e 100644 --- a/netwerk/protocol/http/SpdySession31.cpp +++ b/netwerk/protocol/http/SpdySession31.cpp @@ -18,7 +18,7 @@ #include "nsHttp.h" #include "nsHttpHandler.h" #include "nsHttpConnection.h" -#include "nsILoadGroup.h" +#include "nsISchedulingContext.h" #include "nsISupportsPriority.h" #include "prprf.h" #include "prnetdb.h" @@ -1081,12 +1081,12 @@ SpdySession31::HandleSynStream(SpdySession31 *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; } @@ -1094,7 +1094,7 @@ SpdySession31::HandleSynStream(SpdySession31 *self) } 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 { diff --git a/netwerk/protocol/http/SpdyStream31.cpp b/netwerk/protocol/http/SpdyStream31.cpp index e1423847d7e..5503b423da7 100644 --- a/netwerk/protocol/http/SpdyStream31.cpp +++ b/netwerk/protocol/http/SpdyStream31.cpp @@ -316,10 +316,10 @@ SpdyStream31::ParseHttpRequestHeaders(const char *buf, // 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 diff --git a/netwerk/protocol/http/SpdyStream31.h b/netwerk/protocol/http/SpdyStream31.h index 7541b85f303..0d38aff8330 100644 --- a/netwerk/protocol/http/SpdyStream31.h +++ b/netwerk/protocol/http/SpdyStream31.h @@ -42,9 +42,9 @@ public: 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); diff --git a/netwerk/protocol/http/nsAHttpTransaction.h b/netwerk/protocol/http/nsAHttpTransaction.h index dcd2b5d3323..92bc66b0045 100644 --- a/netwerk/protocol/http/nsAHttpTransaction.h +++ b/netwerk/protocol/http/nsAHttpTransaction.h @@ -12,7 +12,7 @@ class nsIInterfaceRequestor; class nsIEventTarget; class nsITransport; -class nsILoadGroupConnectionInfo; +class nsISchedulingContext; namespace mozilla { namespace net { @@ -145,8 +145,8 @@ public: // 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; diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index 7a994dc5ca0..b4ff2ca0a81 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -604,25 +604,27 @@ nsHttpChannel::ContinueHandleAsyncFallback(nsresult rv) } void -nsHttpChannel::SetupTransactionLoadGroupInfo() +nsHttpChannel::SetupTransactionSchedulingContext() { - // 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 childLoadGroup = do_QueryInterface(mLoadGroup); - if (!childLoadGroup) + if (!EnsureSchedulingContextID()) { return; + } - nsCOMPtr rootLoadGroup; - childLoadGroup->GetRootLoadGroup(getter_AddRefs(rootLoadGroup)); - if (!rootLoadGroup) + nsISchedulingContextService *scsvc = + gHttpHandler->GetSchedulingContextService(); + if (!scsvc) { return; + } - // Set the load group connection scope on the transaction - nsCOMPtr ci; - rootLoadGroup->GetConnectionInfo(getter_AddRefs(ci)); - if (ci) - mTransaction->SetLoadGroupConnectionInfo(ci); + nsCOMPtr sc; + nsresult rv = scsvc->GetSchedulingContext(mSchedulingContextID, + getter_AddRefs(sc)); + + if (NS_FAILED(rv)) { + return; + } + + mTransaction->SetSchedulingContext(sc); } static bool @@ -839,7 +841,7 @@ nsHttpChannel::SetupTransaction() } mTransaction->SetClassOfService(mClassOfService); - SetupTransactionLoadGroupInfo(); + SetupTransactionSchedulingContext(); rv = nsInputStreamPump::Create(getter_AddRefs(mTransactionPump), responseStream); diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h index 9010e4a5c55..8d7c5080e68 100644 --- a/netwerk/protocol/http/nsHttpChannel.h +++ b/netwerk/protocol/http/nsHttpChannel.h @@ -231,7 +231,7 @@ private: nsresult Connect(); void SpeculativeConnect(); nsresult SetupTransaction(); - void SetupTransactionLoadGroupInfo(); + void SetupTransactionSchedulingContext(); nsresult CallOnStartRequest(); nsresult ProcessResponse(); nsresult ContinueProcessResponse(nsresult); diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp index d50c6e2d4cc..6369cea9c9a 100644 --- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp +++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp @@ -28,6 +28,7 @@ #include "NullHttpTransaction.h" #include "nsIDNSRecord.h" #include "nsITransport.h" +#include "nsISchedulingContext.h" #include "nsISocketTransportService.h" #include #include "Http2Compression.h" @@ -1782,20 +1783,20 @@ nsHttpConnectionMgr::TryDispatchTransaction(nsConnectionEntry *ent, } } - // 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; } } diff --git a/netwerk/protocol/http/nsHttpHandler.cpp b/netwerk/protocol/http/nsHttpHandler.cpp index 7cc666272c0..6271b1c1c77 100644 --- a/netwerk/protocol/http/nsHttpHandler.cpp +++ b/netwerk/protocol/http/nsHttpHandler.cpp @@ -321,6 +321,9 @@ nsHttpHandler::Init() 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 diff --git a/netwerk/protocol/http/nsHttpHandler.h b/netwerk/protocol/http/nsHttpHandler.h index 27e7d6d6628..d57b241ba07 100644 --- a/netwerk/protocol/http/nsHttpHandler.h +++ b/netwerk/protocol/http/nsHttpHandler.h @@ -25,6 +25,7 @@ class nsICancelable; class nsICookieService; class nsIIOService; class nsIObserverService; +class nsISchedulingContextService; class nsISiteSecurityService; class nsIStreamConverterService; class nsITimer; @@ -337,6 +338,11 @@ public: void SetCacheSkippedUntil(TimeStamp arg) { mCacheSkippedUntil = arg; } void ClearCacheSkippedUntil() { mCacheSkippedUntil = TimeStamp(); } + nsISchedulingContextService *GetSchedulingContextService() + { + return mSchedulingContextService.get(); + } + private: virtual ~nsHttpHandler(); @@ -540,6 +546,8 @@ private: // incorrect content lengths or malformed chunked encodings FrameCheckLevel mEnforceH1Framing; + nsCOMPtr mSchedulingContextService; + private: // For Rate Pacing Certain Network Events. Only assign this pointer on // socket thread. diff --git a/netwerk/protocol/http/nsHttpTransaction.cpp b/netwerk/protocol/http/nsHttpTransaction.cpp index 8340ca2cda9..bd0a02d27cd 100644 --- a/netwerk/protocol/http/nsHttpTransaction.cpp +++ b/netwerk/protocol/http/nsHttpTransaction.cpp @@ -33,6 +33,7 @@ #include "nsIInputStream.h" #include "nsITransport.h" #include "nsIOService.h" +#include "nsISchedulingContext.h" #include #ifdef MOZ_WIDGET_GONK @@ -1784,10 +1785,10 @@ nsHttpTransaction::CancelPipeline(uint32_t reason) 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 @@ -1802,32 +1803,32 @@ nsHttpTransaction::DispatchedAsBlocking() 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(); } @@ -1838,9 +1839,9 @@ 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 diff --git a/netwerk/protocol/http/nsHttpTransaction.h b/netwerk/protocol/http/nsHttpTransaction.h index 6902c8bc614..0f7ac732d7b 100644 --- a/netwerk/protocol/http/nsHttpTransaction.h +++ b/netwerk/protocol/http/nsHttpTransaction.h @@ -12,7 +12,6 @@ #include "EventTokenBucket.h" #include "nsCOMPtr.h" #include "nsThreadUtils.h" -#include "nsILoadGroup.h" #include "nsIInterfaceRequestor.h" #include "TimingStruct.h" #include "Http2Push.h" @@ -28,6 +27,7 @@ class nsIHttpActivityObserver; class nsIEventTarget; class nsIInputStream; class nsIOutputStream; +class nsISchedulingContext; namespace mozilla { namespace net { @@ -123,9 +123,9 @@ public: 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(); @@ -217,7 +217,7 @@ private: nsCOMPtr mSecurityInfo; nsCOMPtr mPipeIn; nsCOMPtr mPipeOut; - nsCOMPtr mLoadGroupCI; + nsCOMPtr mSchedulingContext; nsCOMPtr mChannel; nsCOMPtr mActivityDistributor; diff --git a/netwerk/protocol/http/nsIHttpChannel.idl b/netwerk/protocol/http/nsIHttpChannel.idl index 01bf961640a..fe582704b46 100644 --- a/netwerk/protocol/http/nsIHttpChannel.idl +++ b/netwerk/protocol/http/nsIHttpChannel.idl @@ -14,7 +14,7 @@ interface nsIHttpHeaderVisitor; * the inspection of the resulting HTTP response status and headers when they * become available. */ -[scriptable, uuid(86ad7e1f-3a64-4e0f-a104-395ebecd7d5c)] +[scriptable, uuid(fdc70825-8ae1-4f81-bd9e-f1fd3f6307ad)] interface nsIHttpChannel : nsIChannel { /************************************************************************** @@ -321,4 +321,9 @@ interface nsIHttpChannel : nsIChannel * has been opened. */ void redirectTo(in nsIURI aNewURI); + + /** + * Identifies the scheduling context for this load. + */ + [noscript] attribute nsID schedulingContextID; }; diff --git a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp index ef4e4c895a9..f49b1929111 100644 --- a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp +++ b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp @@ -798,3 +798,16 @@ nsViewSourceChannel::RedirectTo(nsIURI *uri) 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); +} diff --git a/netwerk/test/unit/test_http2.js b/netwerk/test/unit/test_http2.js index c5776a01401..b0e7f66b53b 100644 --- a/netwerk/test/unit/test_http2.js +++ b/netwerk/test/unit/test_http2.js @@ -781,8 +781,9 @@ var tests = [ test_http2_post_big , 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 diff --git a/xpcom/glue/nsID.cpp b/xpcom/glue/nsID.cpp index a6f3d5e4a5b..751ae60da15 100644 --- a/xpcom/glue/nsID.cpp +++ b/xpcom/glue/nsID.cpp @@ -8,6 +8,16 @@ #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 diff --git a/xpcom/glue/nsID.h b/xpcom/glue/nsID.h index 3d5b512d9be..9ea31609d7e 100644 --- a/xpcom/glue/nsID.h +++ b/xpcom/glue/nsID.h @@ -35,6 +35,11 @@ struct nsID */ //@{ + /** + * Ensures everything is zeroed out. + */ + void Clear(); + /** * Equivalency method. Compares this nsID with another. * @return true if they are the same, false if not.