diff --git a/netwerk/ipc/NeckoChannelParams.ipdlh b/netwerk/ipc/NeckoChannelParams.ipdlh index 85785ef3c45..315df68859a 100644 --- a/netwerk/ipc/NeckoChannelParams.ipdlh +++ b/netwerk/ipc/NeckoChannelParams.ipdlh @@ -116,6 +116,7 @@ struct HttpChannelOpenArgs nsCString schedulingContextID; OptionalCorsPreflightArgs preflightArgs; uint32_t initialRwin; + bool suspendAfterSynthesizeResponse; }; struct HttpChannelConnectArgs diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp index 2e74772c476..e5fdfd5f52f 100644 --- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -188,6 +188,7 @@ HttpChannelChild::HttpChannelChild() , mShouldInterceptSubsequentRedirect(false) , mRedirectingForSubsequentSynthesizedResponse(false) , mShouldParentIntercept(false) + , mSuspendParentAfterSynthesizeResponse(false) { LOG(("Creating HttpChannelChild @%x\n", this)); @@ -1889,8 +1890,11 @@ HttpChannelChild::ContinueAsyncOpen() if (mResponseHead) { openArgs.synthesizedResponseHead() = *mResponseHead; + openArgs.suspendAfterSynthesizeResponse() = + mSuspendParentAfterSynthesizeResponse; } else { openArgs.synthesizedResponseHead() = mozilla::void_t(); + openArgs.suspendAfterSynthesizeResponse() = false; } nsCOMPtr secInfoSer = do_QueryInterface(mSecurityInfo); @@ -2425,6 +2429,7 @@ HttpChannelChild::DivertToParent(ChannelDiverterChild **aChild) // yet. We need one, though, in order to have a parent side to divert to. // Therefore, create the actor just in time for us to suspend and divert it. if (mSynthesizedResponse && !RemoteChannelExists()) { + mSuspendParentAfterSynthesizeResponse = true; rv = ContinueAsyncOpen(); NS_ENSURE_SUCCESS(rv, rv); } diff --git a/netwerk/protocol/http/HttpChannelChild.h b/netwerk/protocol/http/HttpChannelChild.h index 228a0875e9a..8d3f32cfe0a 100644 --- a/netwerk/protocol/http/HttpChannelChild.h +++ b/netwerk/protocol/http/HttpChannelChild.h @@ -231,6 +231,10 @@ private: // before the network transaction is initiated. bool mShouldParentIntercept; + // Set if the corresponding parent channel should suspend after a response + // is synthesized. + bool mSuspendParentAfterSynthesizeResponse; + // true after successful AsyncOpen until OnStopRequest completes. bool RemoteChannelExists() { return mIPCOpen && !mKeptAlive; } diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp index 26e12f094bc..85600f693bc 100644 --- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -66,6 +66,7 @@ HttpChannelParent::HttpChannelParent(const PBrowserOrId& iframeEmbedding, , mSuspendedForDiversion(false) , mShouldIntercept(false) , mShouldSuspendIntercept(false) + , mSuspendAfterSynthesizeResponse(false) , mNestedFrameId(0) { LOG(("Creating HttpChannelParent [this=%p]\n", this)); @@ -132,7 +133,7 @@ HttpChannelParent::Init(const HttpChannelCreationArgs& aArgs) a.loadInfo(), a.synthesizedResponseHead(), a.synthesizedSecurityInfoSerialization(), a.cacheKey(), a.schedulingContextID(), a.preflightArgs(), - a.initialRwin()); + a.initialRwin(), a.suspendAfterSynthesizeResponse()); } case HttpChannelCreationArgs::THttpChannelConnectArgs: { @@ -276,6 +277,14 @@ HttpChannelParent::SynthesizeResponse(nsIInterceptedChannel* aChannel) mSynthesizedResponseHead = nullptr; + // Suspend now even though the FinishSynthesizeResponse runnable has + // not executed. We want to suspend after we get far enough to trigger + // the synthesis, but not actually allow the nsHttpChannel to trigger + // any OnStartRequests(). + if (mSuspendAfterSynthesizeResponse) { + mChannel->Suspend(); + } + MaybeFlushPendingDiversion(); } @@ -376,7 +385,8 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI, const uint32_t& aCacheKey, const nsCString& aSchedulingContextID, const OptionalCorsPreflightArgs& aCorsPreflightArgs, - const uint32_t& aInitialRwin) + const uint32_t& aInitialRwin, + const bool& aSuspendAfterSynthesizeResponse) { nsCOMPtr uri = DeserializeURI(aURI); if (!uri) { @@ -589,6 +599,8 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI, schedulingContextID.Parse(aSchedulingContextID.BeginReading()); mChannel->SetSchedulingContextID(schedulingContextID); + mSuspendAfterSynthesizeResponse = aSuspendAfterSynthesizeResponse; + if (loadInfo && loadInfo->GetEnforceSecurity()) { rv = mChannel->AsyncOpen2(mParentListener); } diff --git a/netwerk/protocol/http/HttpChannelParent.h b/netwerk/protocol/http/HttpChannelParent.h index 0fee2e70ed5..f75fc1b9268 100644 --- a/netwerk/protocol/http/HttpChannelParent.h +++ b/netwerk/protocol/http/HttpChannelParent.h @@ -128,7 +128,8 @@ protected: const uint32_t& aCacheKey, const nsCString& aSchedulingContextID, const OptionalCorsPreflightArgs& aCorsPreflightArgs, - const uint32_t& aInitialRwin); + const uint32_t& aInitialRwin, + const bool& aSuspendAfterSynthesizeResponse); virtual bool RecvSetPriority(const uint16_t& priority) override; virtual bool RecvSetClassOfService(const uint32_t& cos) override; @@ -238,6 +239,8 @@ private: bool mShouldIntercept : 1; // Set if this channel should suspend on interception. bool mShouldSuspendIntercept : 1; + // Set if this channel should be suspended after synthesizing a response. + bool mSuspendAfterSynthesizeResponse : 1; dom::TabId mNestedFrameId;