author | Kershaw Chang <kershaw@mozilla.com> |
Thu, 30 Jan 2020 13:52:22 +0000 | |
changeset 512139 | 0925f61718bbfde97fcd4c3052696be917b73d3c |
parent 512138 | 1d7b2d12113cd3cefe79ab0cfe0a536f3b5c5946 |
child 512140 | 1d2e243f15816f932d86999b548c73512b49ca1d |
push id | 37073 |
push user | dvarga@mozilla.com |
push date | Thu, 30 Jan 2020 21:38:07 +0000 |
treeherder | mozilla-central@fc760793ad44 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | dragana |
bugs | 1600254 |
milestone | 74.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
|
--- a/netwerk/protocol/http/Http2Push.cpp +++ b/netwerk/protocol/http/Http2Push.cpp @@ -11,54 +11,22 @@ #undef LOG #define LOG(args) LOG5(args) #undef LOG_ENABLED #define LOG_ENABLED() LOG5_ENABLED() #include <algorithm> #include "Http2Push.h" -#include "nsHttpChannel.h" #include "nsIHttpPushListener.h" #include "nsString.h" namespace mozilla { namespace net { -class CallChannelOnPush final : public Runnable { - public: - CallChannelOnPush(nsIHttpChannelInternal* associatedChannel, - const nsACString& pushedURI, Http2PushedStream* pushStream) - : Runnable("net::CallChannelOnPush"), - mAssociatedChannel(associatedChannel), - mPushedURI(pushedURI) { - mPushedStreamWrapper = new Http2PushedStreamWrapper(pushStream); - } - - NS_IMETHOD Run() override { - MOZ_ASSERT(NS_IsMainThread()); - RefPtr<nsHttpChannel> channel; - CallQueryInterface(mAssociatedChannel, channel.StartAssignment()); - MOZ_ASSERT(channel); - if (channel && - NS_SUCCEEDED(channel->OnPush(mPushedURI, mPushedStreamWrapper))) { - return NS_OK; - } - - LOG3(("Http2PushedStream Orphan %p failed OnPush\n", this)); - mPushedStreamWrapper->OnPushFailed(); - return NS_OK; - } - - private: - nsCOMPtr<nsIHttpChannelInternal> mAssociatedChannel; - const nsCString mPushedURI; - RefPtr<Http2PushedStreamWrapper> mPushedStreamWrapper; -}; - // Because WeakPtr isn't thread-safe we must ensure that the object is destroyed // on the socket thread, so any Release() called on a different thread is // dispatched to the socket thread. bool Http2PushedStreamWrapper::DispatchRelease() { if (OnSocketThread()) { return false; } @@ -95,16 +63,18 @@ Http2PushedStreamWrapper::Release() { NS_INTERFACE_MAP_BEGIN(Http2PushedStreamWrapper) NS_INTERFACE_MAP_END Http2PushedStreamWrapper::Http2PushedStreamWrapper( Http2PushedStream* aPushStream) { MOZ_ASSERT(OnSocketThread(), "not on socket thread"); mStream = aPushStream; mRequestString = aPushStream->GetRequestString(); + mResourceUrl = aPushStream->GetResourceUrl(); + mStreamID = aPushStream->StreamID(); } Http2PushedStreamWrapper::~Http2PushedStreamWrapper() { MOZ_ASSERT(OnSocketThread(), "not on socket thread"); } Http2PushedStream* Http2PushedStreamWrapper::GetStream() { MOZ_ASSERT(OnSocketThread(), "not on socket thread"); @@ -212,29 +182,27 @@ bool Http2PushedStream::DeferCleanup(nsr // return true if channel implements nsIHttpPushListener bool Http2PushedStream::TryOnPush() { nsHttpTransaction* trans = mAssociatedTransaction->QueryHttpTransaction(); if (!trans) { return false; } - nsCOMPtr<nsIHttpChannelInternal> associatedChannel = - do_QueryInterface(trans->HttpChannel()); - if (!associatedChannel) { - return false; - } - if (!(trans->Caps() & NS_HTTP_ONPUSH_LISTENER)) { return false; } mDeferCleanupOnPush = true; - nsCString uri = Origin() + Path(); - NS_DispatchToMainThread(new CallChannelOnPush(associatedChannel, uri, this)); + mResourceUrl = Origin() + Path(); + RefPtr<Http2PushedStreamWrapper> stream = new Http2PushedStreamWrapper(this); + RefPtr<nsHttpTransaction> transaction = trans; + NS_DispatchToMainThread(NS_NewRunnableFunction( + "net::nsHttpTransaction::OnPush", + [transaction, stream]() { transaction->OnPush(stream); })); return true; } // side effect free static method to determine if Http2Stream implements // nsIHttpPushListener bool Http2PushedStream::TestOnPush(Http2Stream* stream) { if (!stream) { return false; @@ -242,22 +210,17 @@ bool Http2PushedStream::TestOnPush(Http2 nsAHttpTransaction* abstractTransaction = stream->Transaction(); if (!abstractTransaction) { return false; } nsHttpTransaction* trans = abstractTransaction->QueryHttpTransaction(); if (!trans) { return false; } - nsCOMPtr<nsIHttpChannelInternal> associatedChannel = - do_QueryInterface(trans->HttpChannel()); - if (!associatedChannel) { - return false; - } - return (trans->Caps() & NS_HTTP_ONPUSH_LISTENER); + return trans->Caps() & NS_HTTP_ONPUSH_LISTENER; } nsresult Http2PushedStream::ReadSegments(nsAHttpSegmentReader* reader, uint32_t, uint32_t* count) { nsresult rv = NS_OK; *count = 0; mozilla::OriginAttributes originAttributes;
--- a/netwerk/protocol/http/Http2Push.h +++ b/netwerk/protocol/http/Http2Push.h @@ -67,16 +67,17 @@ class Http2PushedStream final : public H uint32_t* countWritten); // overload of Http2Stream virtual bool HasSink() override { return !!mConsumerStream; } virtual void SetPushComplete() override { mPushCompleted = true; } virtual void TopLevelOuterContentWindowIdChanged(uint64_t) override; nsCString& GetRequestString() { return mRequestString; } + nsCString& GetResourceUrl() { return mResourceUrl; } private: Http2Stream* mConsumerStream; // paired request stream that consumes from // real http/2 one.. null until a match is made. nsCOMPtr<nsIRequestContext> mRequestContext; @@ -94,16 +95,17 @@ class Http2PushedStream final : public H // destroying the push stream on an error code during the period between // when we need to do OnPush() on another thread and the time it takes // for that event to create a synthetic pull stream attached to this // object. That synthetic pull will become mConsuemerStream. // Ths is essentially a delete protecting reference. bool mDeferCleanupOnPush; bool mOnPushFailed; nsCString mRequestString; + nsCString mResourceUrl; uint32_t mDefaultPriorityDependency; }; class Http2PushTransactionBuffer final : public nsAHttpTransaction { public: NS_DECL_ISUPPORTS NS_DECL_NSAHTTPTRANSACTION @@ -134,22 +136,26 @@ class Http2PushTransactionBuffer final : class Http2PushedStreamWrapper : public nsISupports { public: NS_DECL_THREADSAFE_ISUPPORTS bool DispatchRelease(); explicit Http2PushedStreamWrapper(Http2PushedStream* aPushStream); nsCString& GetRequestString() { return mRequestString; } + nsCString& GetResourceUrl() { return mResourceUrl; } Http2PushedStream* GetStream(); void OnPushFailed(); + uint32_t StreamID() { return mStreamID; } private: virtual ~Http2PushedStreamWrapper(); nsCString mRequestString; + nsCString mResourceUrl; + uint32_t mStreamID; WeakPtr<Http2Stream> mStream; }; } // namespace net } // namespace mozilla #endif // mozilla_net_Http2Push_Internal_h
--- a/netwerk/protocol/http/Http3Session.cpp +++ b/netwerk/protocol/http/Http3Session.cpp @@ -9,16 +9,17 @@ #include "Http3Stream.h" #include "mozilla/net/DNS.h" #include "nsHttpHandler.h" #include "mozilla/RefPtr.h" #include "ASpdySession.h" // because of SoftStreamError() #include "nsIOService.h" #include "nsISSLSocketControl.h" #include "ScopedNSSTypes.h" +#include "nsQueryObject.h" #include "nsSocketTransportService2.h" #include "nsThreadUtils.h" #include "QuicSocketControl.h" #include "SSLServerCertVerification.h" //#include "cert.h" #include "sslerr.h" namespace mozilla {
--- a/netwerk/protocol/http/HttpTransactionChild.cpp +++ b/netwerk/protocol/http/HttpTransactionChild.cpp @@ -110,31 +110,57 @@ static already_AddRefed<nsIRequestContex } nsresult HttpTransactionChild::InitInternal( uint32_t caps, const HttpConnectionInfoCloneArgs& infoArgs, nsHttpRequestHead* requestHead, nsIInputStream* requestBody, uint64_t requestContentLength, bool requestBodyHasHeaders, uint64_t topLevelOuterContentWindowId, uint8_t httpTrafficCategory, uint64_t requestContextID, uint32_t classOfService, uint32_t initialRwin, - bool responseTimeoutEnabled, uint64_t channelId) { + bool responseTimeoutEnabled, uint64_t channelId, + const Maybe<H2PushedStreamArg>& aPushedStreamArg) { LOG(("HttpTransactionChild::InitInternal [this=%p caps=%x]\n", this, caps)); RefPtr<nsHttpConnectionInfo> cinfo = DeserializeHttpConnectionInfoCloneArgs(infoArgs); nsCOMPtr<nsIRequestContext> rc = CreateRequestContext(requestContextID); + HttpTransactionShell::OnPushCallback pushCallback = nullptr; + if (caps & NS_HTTP_ONPUSH_LISTENER) { + RefPtr<HttpTransactionChild> self = this; + pushCallback = [self](uint32_t aPushedStreamId, const nsACString& aUrl, + const nsACString& aRequestString) { + bool res = false; + if (self->CanSend()) { + res = + self->SendOnH2PushStream(aPushedStreamId, PromiseFlatCString(aUrl), + PromiseFlatCString(aRequestString)); + } + return res ? NS_OK : NS_ERROR_FAILURE; + }; + } + + RefPtr<nsHttpTransaction> transWithPushedStream; + uint32_t pushedStreamId = 0; + if (aPushedStreamArg) { + HttpTransactionChild* transChild = static_cast<HttpTransactionChild*>( + aPushedStreamArg.ref().transWithPushedStreamChild()); + transWithPushedStream = transChild->GetHttpTransaction(); + pushedStreamId = aPushedStreamArg.ref().pushedStreamId(); + } + nsresult rv = mTransaction->Init( caps, cinfo, requestHead, requestBody, requestContentLength, requestBodyHasHeaders, GetCurrentThreadEventTarget(), nullptr, // TODO: security callback, fix in bug 1512479. this, topLevelOuterContentWindowId, static_cast<HttpTrafficCategory>(httpTrafficCategory), rc, classOfService, initialRwin, responseTimeoutEnabled, channelId, - std::move(mTransactionObserver)); + std::move(mTransactionObserver), std::move(pushCallback), + transWithPushedStream, pushedStreamId); if (NS_WARN_IF(NS_FAILED(rv))) { mTransaction = nullptr; return rv; } Unused << mTransaction->AsyncRead(this, getter_AddRefs(mTransactionPump)); return rv; } @@ -174,17 +200,18 @@ mozilla::ipc::IPCResult HttpTransactionC mozilla::ipc::IPCResult HttpTransactionChild::RecvInit( const uint32_t& aCaps, const HttpConnectionInfoCloneArgs& aArgs, const nsHttpRequestHead& aReqHeaders, const Maybe<IPCStream>& aRequestBody, const uint64_t& aReqContentLength, const bool& aReqBodyIncludesHeaders, const uint64_t& aTopLevelOuterContentWindowId, const uint8_t& aHttpTrafficCategory, const uint64_t& aRequestContextID, const uint32_t& aClassOfService, const uint32_t& aInitialRwin, const bool& aResponseTimeoutEnabled, const uint64_t& aChannelId, - const bool& aHasTransactionObserver) { + const bool& aHasTransactionObserver, + const Maybe<H2PushedStreamArg>& aPushedStreamArg) { mRequestHead = aReqHeaders; if (aRequestBody) { mUploadStream = mozilla::ipc::DeserializeIPCStream(aRequestBody); } mTransaction = new nsHttpTransaction(); mChannelId = aChannelId; @@ -200,17 +227,17 @@ mozilla::ipc::IPCResult HttpTransactionC } }; } nsresult rv = InitInternal( aCaps, aArgs, &mRequestHead, mUploadStream, aReqContentLength, aReqBodyIncludesHeaders, aTopLevelOuterContentWindowId, aHttpTrafficCategory, aRequestContextID, aClassOfService, aInitialRwin, - aResponseTimeoutEnabled, aChannelId); + aResponseTimeoutEnabled, aChannelId, aPushedStreamArg); if (NS_FAILED(rv)) { LOG(("HttpTransactionChild::RecvInit: [this=%p] InitInternal failed!\n", this)); mTransaction = nullptr; SendOnInitFailed(rv); } return IPC_OK(); }
--- a/netwerk/protocol/http/HttpTransactionChild.h +++ b/netwerk/protocol/http/HttpTransactionChild.h @@ -41,17 +41,18 @@ class HttpTransactionChild final : publi const uint32_t& aCaps, const HttpConnectionInfoCloneArgs& aArgs, const nsHttpRequestHead& aReqHeaders, const Maybe<IPCStream>& aRequestBody, const uint64_t& aReqContentLength, const bool& aReqBodyIncludesHeaders, const uint64_t& aTopLevelOuterContentWindowId, const uint8_t& aHttpTrafficCategory, const uint64_t& aRequestContextID, const uint32_t& aClassOfService, const uint32_t& aInitialRwin, const bool& aResponseTimeoutEnabled, const uint64_t& aChannelId, - const bool& aHasTransactionObserver); + const bool& aHasTransactionObserver, + const Maybe<H2PushedStreamArg>& aPushedStreamArg); mozilla::ipc::IPCResult RecvUpdateClassOfService( const uint32_t& classOfService); mozilla::ipc::IPCResult RecvCancelPump(const nsresult& aStatus); mozilla::ipc::IPCResult RecvSuspendPump(); mozilla::ipc::IPCResult RecvResumePump(); mozilla::ipc::IPCResult RecvSetDNSWasRefreshed(); mozilla::ipc::IPCResult RecvDontReuseConnection(); mozilla::ipc::IPCResult RecvSetH2WSConnRefTaken(); @@ -70,17 +71,18 @@ class HttpTransactionChild final : publi // for the parameters. MOZ_MUST_USE nsresult InitInternal( uint32_t caps, const HttpConnectionInfoCloneArgs& aArgs, nsHttpRequestHead* reqHeaders, nsIInputStream* reqBody, // use the trick in bug 1277681 uint64_t reqContentLength, bool reqBodyIncludesHeaders, uint64_t topLevelOuterContentWindowId, uint8_t httpTrafficCategory, uint64_t requestContextID, uint32_t classOfService, uint32_t initialRwin, - bool responseTimeoutEnabled, uint64_t channelId); + bool responseTimeoutEnabled, uint64_t channelId, + const Maybe<H2PushedStreamArg>& aPushedStreamArg); bool mCanceled; nsresult mStatus; uint64_t mChannelId; nsHttpRequestHead mRequestHead; nsCOMPtr<nsIInputStream> mUploadStream; RefPtr<nsHttpTransaction> mTransaction;
--- a/netwerk/protocol/http/HttpTransactionParent.cpp +++ b/netwerk/protocol/http/HttpTransactionParent.cpp @@ -146,48 +146,60 @@ void HttpTransactionParent::GetStructFro nsresult HttpTransactionParent::Init( uint32_t caps, nsHttpConnectionInfo* cinfo, nsHttpRequestHead* requestHead, nsIInputStream* requestBody, uint64_t requestContentLength, bool requestBodyHasHeaders, nsIEventTarget* target, nsIInterfaceRequestor* callbacks, nsITransportEventSink* eventsink, uint64_t topLevelOuterContentWindowId, HttpTrafficCategory trafficCategory, nsIRequestContext* requestContext, uint32_t classOfService, uint32_t initialRwin, bool responseTimeoutEnabled, uint64_t channelId, - TransactionObserverFunc&& transactionObserver) { + TransactionObserverFunc&& transactionObserver, + OnPushCallback&& aOnPushCallback, + HttpTransactionShell* aTransWithPushedStream, uint32_t aPushedStreamId) { LOG(("HttpTransactionParent::Init [this=%p caps=%x]\n", this, caps)); if (!CanSend()) { return NS_ERROR_FAILURE; } mEventsink = eventsink; mTargetThread = GetCurrentThreadEventTarget(); mChannelId = channelId; mTransactionObserver = std::move(transactionObserver); + mOnPushCallback = std::move(aOnPushCallback); HttpConnectionInfoCloneArgs infoArgs; GetStructFromInfo(cinfo, infoArgs); mozilla::ipc::AutoIPCStream autoStream; if (requestBody && !autoStream.Serialize(requestBody, SocketProcessParent::GetSingleton())) { return NS_ERROR_FAILURE; } uint64_t requestContextID = requestContext ? requestContext->GetID() : 0; + Maybe<H2PushedStreamArg> pushedStreamArg; + if (aTransWithPushedStream && aPushedStreamId) { + MOZ_ASSERT(aTransWithPushedStream->AsHttpTransactionParent()); + pushedStreamArg.emplace(); + pushedStreamArg.ref().transWithPushedStreamParent() = + aTransWithPushedStream->AsHttpTransactionParent(); + pushedStreamArg.ref().pushedStreamId() = aPushedStreamId; + } + // TODO: Figure out if we have to implement nsIThreadRetargetableRequest in // bug 1544378. if (!SendInit(caps, infoArgs, *requestHead, requestBody ? Some(autoStream.TakeValue()) : Nothing(), requestContentLength, requestBodyHasHeaders, topLevelOuterContentWindowId, static_cast<uint8_t>(trafficCategory), requestContextID, classOfService, initialRwin, responseTimeoutEnabled, mChannelId, - !!mTransactionObserver)) { + !!mTransactionObserver, pushedStreamArg)) { return NS_ERROR_FAILURE; } return NS_OK; } nsresult HttpTransactionParent::AsyncRead(nsIStreamListener* listener, nsIRequest** pump) { @@ -314,20 +326,16 @@ void HttpTransactionParent::SetH2WSConnR } void HttpTransactionParent::SetSecurityCallbacks( nsIInterfaceRequestor* aCallbacks) { // TODO: we might don't need to implement this. // Will figure out in bug 1512479. } -void HttpTransactionParent::SetPushedStream(Http2PushedStreamWrapper* push) { - // TODO: will be implemented later in bug 1600254. -} - void HttpTransactionParent::SetDomainLookupStart(mozilla::TimeStamp timeStamp, bool onlyIfNull) { mDomainLookupStart = timeStamp; mTimings.domainLookupStart = mDomainLookupStart; } void HttpTransactionParent::SetDomainLookupEnd(mozilla::TimeStamp timeStamp, bool onlyIfNull) { mDomainLookupEnd = timeStamp; @@ -557,16 +565,25 @@ mozilla::ipc::IPCResult HttpTransactionP const nsresult& aStatus) { nsCOMPtr<nsIRequest> request = do_QueryInterface(mEventsink); if (request) { request->Cancel(aStatus); } return IPC_OK(); } +mozilla::ipc::IPCResult HttpTransactionParent::RecvOnH2PushStream( + const uint32_t& aPushedStreamId, const nsCString& aResourceUrl, + const nsCString& aRequestString) { + MOZ_ASSERT(mOnPushCallback); + + mOnPushCallback(aPushedStreamId, aResourceUrl, aRequestString); + return IPC_OK(); +} // namespace net + //----------------------------------------------------------------------------- // HttpTransactionParent <nsIRequest> //----------------------------------------------------------------------------- NS_IMETHODIMP HttpTransactionParent::GetName(nsACString& aResult) { aResult.Truncate(); return NS_OK;
--- a/netwerk/protocol/http/HttpTransactionParent.h +++ b/netwerk/protocol/http/HttpTransactionParent.h @@ -54,16 +54,20 @@ class HttpTransactionParent final : publ const Maybe<nsHttpHeaderArray>& responseTrailers, const bool& aHasStickyConn, const Maybe<TransactionObserverResult>& aTransactionObserverResult); mozilla::ipc::IPCResult RecvOnNetAddrUpdate(const NetAddr& aSelfAddr, const NetAddr& aPeerAddr, const bool& aResolvedByTRR); mozilla::ipc::IPCResult RecvOnInitFailed(const nsresult& aStatus); + mozilla::ipc::IPCResult RecvOnH2PushStream(const uint32_t& aPushedStreamId, + const nsCString& aResourceUrl, + const nsCString& aRequestString); + already_AddRefed<nsIEventTarget> GetNeckoTarget(); private: virtual ~HttpTransactionParent(); void GetStructFromInfo(nsHttpConnectionInfo* aInfo, HttpConnectionInfoCloneArgs& aArgs); void DoOnStartRequest(const nsresult& aStatus, @@ -110,14 +114,15 @@ class HttpTransactionParent final : publ NetAddr mSelfAddr; NetAddr mPeerAddr; TimingStruct mTimings; TimeStamp mDomainLookupStart; TimeStamp mDomainLookupEnd; TransactionObserverFunc mTransactionObserver; TransactionObserverResult mTransactionObserverResult; + OnPushCallback mOnPushCallback; }; } // namespace net } // namespace mozilla #endif // nsHttpTransactionParent_h__
--- a/netwerk/protocol/http/HttpTransactionShell.h +++ b/netwerk/protocol/http/HttpTransactionShell.h @@ -41,16 +41,18 @@ class TransactionObserverResult; } \ } class HttpTransactionShell : public nsISupports { public: NS_DECLARE_STATIC_IID_ACCESSOR(HTTPTRANSACTIONSHELL_IID) using TransactionObserverFunc = std::function<void()>; + using OnPushCallback = + std::function<nsresult(uint32_t, const nsACString&, const nsACString&)>; // // called to initialize the transaction // // @param caps // the transaction capabilities (see nsHttp.h) // @param connInfo // the connection type for this transaction. @@ -71,17 +73,20 @@ class HttpTransactionShell : public nsIS uint32_t caps, nsHttpConnectionInfo* connInfo, nsHttpRequestHead* reqHeaders, nsIInputStream* reqBody, uint64_t reqContentLength, bool reqBodyIncludesHeaders, nsIEventTarget* consumerTarget, nsIInterfaceRequestor* callbacks, nsITransportEventSink* eventsink, uint64_t topLevelOuterContentWindowId, HttpTrafficCategory trafficCategory, nsIRequestContext* requestContext, uint32_t classOfService, uint32_t initialRwin, bool responseTimeoutEnabled, uint64_t channelId, - TransactionObserverFunc&& transactionObserver) = 0; + TransactionObserverFunc&& transactionObserver, + OnPushCallback&& aOnPushCallback, + HttpTransactionShell* aTransWithPushedStream, + uint32_t aPushedStreamId) = 0; // @param aListener // receives notifications. // @param pump // the pump that will contain the response data. async wait on this // input stream for data. On first notification, headers should be // available (check transaction status). virtual nsresult AsyncRead(nsIStreamListener* listener, @@ -129,17 +134,16 @@ class HttpTransactionShell : public nsIS // Called to notify that a requested DNS cache entry was refreshed. virtual void SetDNSWasRefreshed() = 0; virtual void DontReuseConnection() = 0; virtual bool HasStickyConnection() const = 0; virtual void SetH2WSConnRefTaken() = 0; - virtual void SetPushedStream(Http2PushedStreamWrapper* push) = 0; virtual bool ProxyConnectFailed() = 0; virtual int32_t GetProxyConnectResponseCode() = 0; virtual nsresult SetSniffedTypeToChannel( nsIRequest* aPump, nsIChannel* aChannel, nsInputStreamPump::PeekSegmentFun aCallTypeSniffers) = 0; @@ -157,17 +161,20 @@ NS_DEFINE_STATIC_IID_ACCESSOR(HttpTransa uint32_t caps, nsHttpConnectionInfo* connInfo, \ nsHttpRequestHead* reqHeaders, nsIInputStream* reqBody, \ uint64_t reqContentLength, bool reqBodyIncludesHeaders, \ nsIEventTarget* consumerTarget, nsIInterfaceRequestor* callbacks, \ nsITransportEventSink* eventsink, uint64_t topLevelOuterContentWindowId, \ HttpTrafficCategory trafficCategory, nsIRequestContext* requestContext, \ uint32_t classOfService, uint32_t initialRwin, \ bool responseTimeoutEnabled, uint64_t channelId, \ - TransactionObserverFunc&& transactionObserver) override; \ + TransactionObserverFunc&& transactionObserver, \ + OnPushCallback&& aOnPushCallback, \ + HttpTransactionShell* aTransWithPushedStream, uint32_t aPushedStreamId) \ + override; \ virtual nsresult AsyncRead(nsIStreamListener* listener, nsIRequest** pump) \ override; \ virtual void SetClassOfService(uint32_t classOfService) override; \ virtual nsHttpResponseHead* TakeResponseHead() override; \ virtual nsHttpHeaderArray* TakeResponseTrailers() override; \ virtual nsISupports* SecurityInfo() override; \ virtual void SetSecurityCallbacks(nsIInterfaceRequestor* aCallbacks) \ override; \ @@ -189,17 +196,16 @@ NS_DEFINE_STATIC_IID_ACCESSOR(HttpTransa virtual const TimingStruct Timings() override; \ virtual bool ResponseIsComplete() override; \ virtual int64_t GetTransferSize() override; \ virtual int64_t GetRequestSize() override; \ virtual void SetDNSWasRefreshed() override; \ virtual void DontReuseConnection() override; \ virtual bool HasStickyConnection() const override; \ virtual void SetH2WSConnRefTaken() override; \ - virtual void SetPushedStream(Http2PushedStreamWrapper* push) override; \ virtual bool ProxyConnectFailed() override; \ virtual int32_t GetProxyConnectResponseCode() override; \ virtual nsresult SetSniffedTypeToChannel( \ nsIRequest* aPump, nsIChannel* aChannel, \ nsInputStreamPump::PeekSegmentFun aCallTypeSniffers) override; \ virtual void GetTransactionObserverResult( \ TransactionObserverResult& aResult) override; \ virtual nsHttpTransaction* AsHttpTransaction() override; \
--- a/netwerk/protocol/http/PHttpTransaction.ipdl +++ b/netwerk/protocol/http/PHttpTransaction.ipdl @@ -15,16 +15,21 @@ include "mozilla/net/NeckoMessageUtils.h using class mozilla::net::nsHttpRequestHead from "nsHttpRequestHead.h"; using class nsHttpHeaderArray from "nsHttpHeaderArray.h"; using mozilla::net::NetAddr from "mozilla/net/DNS.h"; namespace mozilla { namespace net { +struct H2PushedStreamArg { + PHttpTransaction transWithPushedStream; + uint32_t pushedStreamId; +}; + refcounted protocol PHttpTransaction { manager PSocketProcess; parent: async OnStartRequest(nsresult status, nsHttpResponseHead? responseHead, nsCString securityInfoSerialization, @@ -41,33 +46,37 @@ parent: bool responseIsComplete, int64_t transferSize, TimingStructArgs timings, nsHttpHeaderArray? responseTrailers, bool hasStickyConn, TransactionObserverResult? transactionObserverResult); async OnNetAddrUpdate(NetAddr selfAddr, NetAddr peerAddr, bool resolvedByTRR); async OnInitFailed(nsresult status); + async OnH2PushStream(uint32_t pushedStreamId, + nsCString resourceUrl, + nsCString requestString); child: async __delete__(); async Init(uint32_t caps, HttpConnectionInfoCloneArgs aArgs, nsHttpRequestHead reqHeaders, IPCStream? requestBody, uint64_t reqContentLength, bool reqBodyIncludesHeaders, uint64_t topLevelOuterContentWindowId, uint8_t httpTrafficCategory, uint64_t requestContextID, uint32_t classOfService, uint32_t initialRwin, bool responseTimeoutEnabled, uint64_t channelId, - bool hasTransactionObserver); + bool hasTransactionObserver, + H2PushedStreamArg? pushedStreamArg); async UpdateClassOfService(uint32_t classOfService); async CancelPump(nsresult status); async SuspendPump(); async ResumePump(); async SetDNSWasRefreshed(); async DontReuseConnection();
--- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -332,17 +332,17 @@ nsHttpChannel::nsHttpChannel() mUsedNetwork(0), mAuthConnectionRestartable(0), mChannelClassifierCancellationPending(0), mAsyncResumePending(0), mHasBeenIsolatedChecked(0), mIsIsolated(0), mTopWindowOriginComputed(0), mHasCrossOriginOpenerPolicyMismatch(0), - mPushedStream(nullptr), + mPushedStreamId(0), mLocalBlocklist(false), mOnTailUnblock(nullptr), mWarningReporter(nullptr), mIsReadingFromCache(false), mFirstResponseSource(RESPONSE_PENDING), mRaceCacheWithNetwork(false), mRaceDelay(0), mIgnoreCacheEntry(false), @@ -1313,27 +1313,34 @@ nsresult nsHttpChannel::SetupTransaction MOZ_ASSERT(NS_SUCCEEDED(rv)); rv = mRequestHead.SetHeaderOnce(nsHttp::Connection, nsHttp::Upgrade.get(), true); MOZ_ASSERT(NS_SUCCEEDED(rv)); mCaps |= NS_HTTP_STICKY_CONNECTION; mCaps &= ~NS_HTTP_ALLOW_KEEPALIVE; } - if (mPushedStream) { - mTransaction->SetPushedStream(mPushedStream); - mPushedStream = nullptr; - } - nsCOMPtr<nsIHttpPushListener> pushListener; NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, NS_GET_IID(nsIHttpPushListener), getter_AddRefs(pushListener)); + HttpTransactionShell::OnPushCallback pushCallback = nullptr; if (pushListener) { mCaps |= NS_HTTP_ONPUSH_LISTENER; + nsWeakPtr weakPtrThis( + do_GetWeakReference(static_cast<nsIHttpChannel*>(this))); + pushCallback = [weakPtrThis](uint32_t aPushedStreamId, + const nsACString& aUrl, + const nsACString& aRequestString) { + if (nsCOMPtr<nsIHttpChannel> channel = do_QueryReferent(weakPtrThis)) { + return static_cast<nsHttpChannel*>(channel.get()) + ->OnPush(aPushedStreamId, aUrl, aRequestString); + } + return NS_ERROR_NOT_AVAILABLE; + }; } EnsureTopLevelOuterContentWindowId(); EnsureRequestContext(); HttpTrafficCategory category = CreateTrafficCategory(); std::function<void()> observer; if (mTransactionObserver) { @@ -1345,17 +1352,18 @@ nsresult nsHttpChannel::SetupTransaction transactionObserver->Complete(result.versionOk(), result.authOk(), result.closeReason()); }; } rv = mTransaction->Init( mCaps, mConnectionInfo, &mRequestHead, mUploadStream, mReqContentLength, mUploadStreamHasHeaders, GetCurrentThreadEventTarget(), callbacks, this, mTopLevelOuterContentWindowId, category, mRequestContext, mClassOfService, - mInitialRwin, mResponseTimeoutEnabled, mChannelId, std::move(observer)); + mInitialRwin, mResponseTimeoutEnabled, mChannelId, std::move(observer), + std::move(pushCallback), mTransWithPushedStream, mPushedStreamId); if (NS_FAILED(rv)) { mTransaction = nullptr; return rv; } return rv; } @@ -9475,26 +9483,32 @@ nsHttpChannel::SetNotificationCallbacks( } return rv; } bool nsHttpChannel::AwaitingCacheCallbacks() { return mCacheEntriesToWaitFor != 0; } -void nsHttpChannel::SetPushedStream(Http2PushedStreamWrapper* stream) { - MOZ_ASSERT(stream); - MOZ_ASSERT(!mPushedStream); - mPushedStream = stream; -} - -nsresult nsHttpChannel::OnPush(const nsACString& url, - Http2PushedStreamWrapper* pushedStream) { +void nsHttpChannel::SetPushedStreamTransactionAndId( + HttpTransactionShell* aTransWithPushedStream, uint32_t aPushedStreamId) { + MOZ_ASSERT(!mTransWithPushedStream); + LOG(("nsHttpChannel::SetPushedStreamTransaction [this=%p] trans=%p", this, + aTransWithPushedStream)); + + mTransWithPushedStream = aTransWithPushedStream; + mPushedStreamId = aPushedStreamId; +} + +nsresult nsHttpChannel::OnPush(uint32_t aPushedStreamId, const nsACString& aUrl, + const nsACString& aRequestString) { MOZ_ASSERT(NS_IsMainThread()); - LOG(("nsHttpChannel::OnPush [this=%p]\n", this)); + MOZ_ASSERT(mTransaction); + LOG(("nsHttpChannel::OnPush [this=%p, trans=%p]\n", this, + mTransaction.get())); MOZ_ASSERT(mCaps & NS_HTTP_ONPUSH_LISTENER); nsCOMPtr<nsIHttpPushListener> pushListener; NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, NS_GET_IID(nsIHttpPushListener), getter_AddRefs(pushListener)); if (!pushListener) { @@ -9504,17 +9518,17 @@ nsresult nsHttpChannel::OnPush(const nsA this)); return NS_ERROR_NOT_AVAILABLE; } nsCOMPtr<nsIURI> pushResource; nsresult rv; // Create a Channel for the Push Resource - rv = NS_NewURI(getter_AddRefs(pushResource), url); + rv = NS_NewURI(getter_AddRefs(pushResource), aUrl); if (NS_FAILED(rv)) { return NS_ERROR_FAILURE; } nsCOMPtr<nsIIOService> ioService; rv = gHttpHandler->GetIOService(getter_AddRefs(ioService)); NS_ENSURE_SUCCESS(rv, rv); @@ -9536,25 +9550,23 @@ nsresult nsHttpChannel::OnPush(const nsA RefPtr<nsHttpChannel> channel; CallQueryInterface(pushHttpChannel, channel.StartAssignment()); MOZ_ASSERT(channel); if (!channel) { return NS_ERROR_UNEXPECTED; } // new channel needs mrqeuesthead and headers from pushedStream - channel->mRequestHead.ParseHeaderSet( - pushedStream->GetRequestString().BeginWriting()); - + channel->mRequestHead.ParseHeaderSet(aRequestString.BeginReading()); channel->mLoadGroup = mLoadGroup; channel->mLoadInfo = mLoadInfo; channel->mCallbacks = mCallbacks; - // Link the pushed stream with the new channel and call listener - channel->SetPushedStream(pushedStream); + // Link the trans with pushed stream and the new channel and call listener + channel->SetPushedStreamTransactionAndId(mTransaction, aPushedStreamId); rv = pushListener->OnPush(this, pushHttpChannel); return rv; } // static bool nsHttpChannel::IsRedirectStatus(uint32_t status) { // 305 disabled as a security measure (see bug 187996). return status == 300 || status == 301 || status == 302 || status == 303 ||
--- a/netwerk/protocol/http/nsHttpChannel.h +++ b/netwerk/protocol/http/nsHttpChannel.h @@ -39,17 +39,16 @@ class nsIDNSRecord; class nsIHttpChannelAuthProvider; class nsInputStreamPump; class nsITransportSecurityInfo; namespace mozilla { namespace net { class nsChannelClassifier; -class Http2PushedStream; class HttpChannelSecurityWarningReporter; using DNSPromise = MozPromise<nsCOMPtr<nsIDNSRecord>, nsresult, false>; //----------------------------------------------------------------------------- // nsHttpChannel //----------------------------------------------------------------------------- @@ -131,18 +130,18 @@ class nsHttpChannel final : public HttpB nsHttpChannel(); virtual MOZ_MUST_USE nsresult Init(nsIURI* aURI, uint32_t aCaps, nsProxyInfo* aProxyInfo, uint32_t aProxyResolveFlags, nsIURI* aProxyURI, uint64_t aChannelId, nsContentPolicyType aContentPolicyType) override; - MOZ_MUST_USE nsresult OnPush(const nsACString& uri, - Http2PushedStreamWrapper* pushedStream); + MOZ_MUST_USE nsresult OnPush(uint32_t aPushedStreamId, const nsACString& aUrl, + const nsACString& aRequestString); static bool IsRedirectStatus(uint32_t status); static bool WillRedirect(nsHttpResponseHead* response); // Methods HttpBaseChannel didn't implement for us or that we override. // // nsIRequest NS_IMETHOD Cancel(nsresult status) override; @@ -547,17 +546,18 @@ class nsHttpChannel final : public HttpB bool ignoreMissingPartialLen = false); MOZ_MUST_USE nsresult SetupByteRangeRequest(int64_t partialLen); void UntieByteRangeRequest(); void UntieValidationRequest(); MOZ_MUST_USE nsresult OpenCacheInputStream(nsICacheEntry* cacheEntry, bool startBuffering, bool checkingAppCacheEntry); - void SetPushedStream(Http2PushedStreamWrapper* stream); + void SetPushedStreamTransactionAndId( + HttpTransactionShell* aTransWithPushedStream, uint32_t aPushedStreamId); void MaybeWarnAboutAppCache(); void SetOriginHeader(); void SetDoNotTrack(); bool IsIsolated(); @@ -750,17 +750,19 @@ class nsHttpChannel final : public HttpB // true. nsCString mTopWindowOrigin; nsTArray<nsContinueRedirectionFunc> mRedirectFuncStack; // Needed for accurate DNS timing RefPtr<nsDNSPrefetch> mDNSPrefetch; - RefPtr<Http2PushedStreamWrapper> mPushedStream; + uint32_t mPushedStreamId; + RefPtr<HttpTransactionShell> mTransWithPushedStream; + // True if the channel's principal was found on a phishing, malware, or // tracking (if tracking protection is enabled) blocklist bool mLocalBlocklist; MOZ_MUST_USE nsresult WaitForRedirectCallback(); void PushRedirectAsyncFunc(nsContinueRedirectionFunc func); void PopRedirectAsyncFunc(nsContinueRedirectionFunc func);
--- a/netwerk/protocol/http/nsHttpTransaction.cpp +++ b/netwerk/protocol/http/nsHttpTransaction.cpp @@ -246,28 +246,31 @@ nsHttpTransaction::~nsHttpTransaction() nsresult nsHttpTransaction::Init( uint32_t caps, nsHttpConnectionInfo* cinfo, nsHttpRequestHead* requestHead, nsIInputStream* requestBody, uint64_t requestContentLength, bool requestBodyHasHeaders, nsIEventTarget* target, nsIInterfaceRequestor* callbacks, nsITransportEventSink* eventsink, uint64_t topLevelOuterContentWindowId, HttpTrafficCategory trafficCategory, nsIRequestContext* requestContext, uint32_t classOfService, uint32_t initialRwin, bool responseTimeoutEnabled, uint64_t channelId, - TransactionObserverFunc&& transactionObserver) { + TransactionObserverFunc&& transactionObserver, + OnPushCallback&& aOnPushCallback, + HttpTransactionShell* transWithPushedStream, uint32_t aPushedStreamId) { nsresult rv; LOG1(("nsHttpTransaction::Init [this=%p caps=%x]\n", this, caps)); MOZ_ASSERT(cinfo); MOZ_ASSERT(requestHead); MOZ_ASSERT(target); MOZ_ASSERT(NS_IsMainThread()); mChannelId = channelId; mTransactionObserver = std::move(transactionObserver); + mOnPushCallback = std::move(aOnPushCallback); mTopLevelOuterContentWindowId = topLevelOuterContentWindowId; LOG((" window-id = %" PRIx64, mTopLevelOuterContentWindowId)); mTrafficCategory = trafficCategory; mActivityDistributor = services::GetActivityDistributor(); if (!mActivityDistributor) { return NS_ERROR_NOT_AVAILABLE; @@ -430,16 +433,22 @@ nsresult nsHttpTransaction::Init( : -1; // create pipe for response stream rv = NS_NewPipe2(getter_AddRefs(mPipeIn), getter_AddRefs(mPipeOut), true, true, nsIOService::gDefaultSegmentSize, nsIOService::gDefaultSegmentCount); if (NS_FAILED(rv)) return rv; + if (transWithPushedStream && aPushedStreamId) { + RefPtr<nsHttpTransaction> trans = + transWithPushedStream->AsHttpTransaction(); + MOZ_ASSERT(trans); + mPushedStream = trans->TakePushedStreamById(aPushedStreamId); + } return NS_OK; } nsresult nsHttpTransaction::AsyncRead(nsIStreamListener* listener, nsIRequest** pump) { RefPtr<nsInputStreamPump> transactionPump; nsresult rv = nsInputStreamPump::Create(getter_AddRefs(transactionPump), mPipeIn); @@ -1009,18 +1018,49 @@ bool nsHttpTransaction::HasStickyConnect } bool nsHttpTransaction::ResponseIsComplete() { return mResponseIsComplete; } int64_t nsHttpTransaction::GetTransferSize() { return mTransferSize; } int64_t nsHttpTransaction::GetRequestSize() { return mRequestSize; } -void nsHttpTransaction::SetPushedStream(Http2PushedStreamWrapper* push) { - mPushedStream = push; +already_AddRefed<Http2PushedStreamWrapper> +nsHttpTransaction::TakePushedStreamById(uint32_t aStreamId) { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aStreamId); + + auto entry = mIDToStreamMap.Lookup(aStreamId); + if (entry) { + RefPtr<Http2PushedStreamWrapper> stream = entry.Data(); + entry.Remove(); + return stream.forget(); + } + + return nullptr; +} + +void nsHttpTransaction::OnPush(Http2PushedStreamWrapper* aStream) { + LOG(("nsHttpTransaction::OnPush %p aStream=%p", this, aStream)); + MOZ_ASSERT(aStream); + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mOnPushCallback); + + RefPtr<Http2PushedStreamWrapper> stream = aStream; + auto entry = mIDToStreamMap.LookupForAdd(stream->StreamID()); + MOZ_ASSERT(!entry); + if (!entry) { + entry.OrInsert([&stream]() { return stream; }); + } + + if (NS_FAILED(mOnPushCallback(stream->StreamID(), stream->GetResourceUrl(), + stream->GetRequestString()))) { + stream->OnPushFailed(); + mIDToStreamMap.Remove(stream->StreamID()); + } } nsHttpTransaction* nsHttpTransaction::AsHttpTransaction() { return this; } HttpTransactionParent* nsHttpTransaction::AsHttpTransactionParent() { return nullptr; }
--- a/netwerk/protocol/http/nsHttpTransaction.h +++ b/netwerk/protocol/http/nsHttpTransaction.h @@ -134,16 +134,21 @@ class nsHttpTransaction final : public n void SetHttpTrailers(nsCString& aTrailers); bool IsWebsocketUpgrade(); void SetH2WSTransaction(SpdyConnectTransaction*); void OnProxyConnectComplete(int32_t aResponseCode) override; + // This is only called by Http2PushedStream::TryOnPush when a new pushed + // stream is available. The newly added stream will be taken by another + // transaction. + void OnPush(Http2PushedStreamWrapper* aStream); + private: friend class DeleteHttpTransaction; virtual ~nsHttpTransaction(); MOZ_MUST_USE nsresult Restart(); char* LocateHttpStart(char* buf, uint32_t len, bool aAllowPartialMatch); MOZ_MUST_USE nsresult ParseLine(nsACString& line); MOZ_MUST_USE nsresult ParseLineSegment(char* seg, uint32_t len); @@ -180,16 +185,19 @@ class nsHttpTransaction final : public n // Called from WriteSegments. Checks for conditions whether to throttle // reading the content. When this returns true, WriteSegments returns // WOULD_BLOCK. bool ShouldThrottle(); void NotifyTransactionObserver(nsresult reason); + already_AddRefed<Http2PushedStreamWrapper> TakePushedStreamById( + uint32_t aStreamId); + private: class UpdateSecurityCallbacks : public Runnable { public: UpdateSecurityCallbacks(nsHttpTransaction* aTrans, nsIInterfaceRequestor* aCallbacks) : Runnable("net::nsHttpTransaction::UpdateSecurityCallbacks"), mTrans(aTrans), mCallbacks(aCallbacks) {} @@ -410,14 +418,18 @@ class nsHttpTransaction final : public n uint8_t mFastOpenStatus; // H2 websocket support RefPtr<SpdyConnectTransaction> mH2WSTransaction; HttpTrafficCategory mTrafficCategory; bool mThroughCaptivePortal; int32_t mProxyConnectResponseCode; + + OnPushCallback mOnPushCallback; + nsDataHashtable<nsUint32HashKey, RefPtr<Http2PushedStreamWrapper>> + mIDToStreamMap; }; } // namespace net } // namespace mozilla #endif // nsHttpTransaction_h__