зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1173811
- Part 2: Propagate the response URL to intercepted channels when necessary (e10s). r=mayhemer,bkelly
This commit is contained in:
Родитель
d3726427db
Коммит
de85fb3b8a
|
@ -184,6 +184,8 @@ HttpChannelChild::HttpChannelChild()
|
|||
, mFlushedForDiversion(false)
|
||||
, mSuspendSent(false)
|
||||
, mSynthesizedResponse(false)
|
||||
, mShouldInterceptSubsequentRedirect(false)
|
||||
, mRedirectingForSubsequentSynthesizedResponse(false)
|
||||
, mShouldParentIntercept(false)
|
||||
{
|
||||
LOG(("Creating HttpChannelChild @%x\n", this));
|
||||
|
@ -1157,25 +1159,17 @@ HttpChannelChild::RecvRedirect1Begin(const uint32_t& newChannelId,
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
HttpChannelChild::Redirect1Begin(const uint32_t& newChannelId,
|
||||
const URIParams& newUri,
|
||||
const uint32_t& redirectFlags,
|
||||
const nsHttpResponseHead& responseHead,
|
||||
const nsACString& securityInfoSerialization)
|
||||
nsresult
|
||||
HttpChannelChild::SetupRedirect(nsIURI* uri,
|
||||
const nsHttpResponseHead* responseHead,
|
||||
nsIChannel** outChannel)
|
||||
{
|
||||
LOG(("HttpChannelChild::Redirect1Begin [this=%p]\n", this));
|
||||
LOG(("HttpChannelChild::SetupRedirect [this=%p]\n", this));
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIIOService> ioService;
|
||||
rv = gHttpHandler->GetIOService(getter_AddRefs(ioService));
|
||||
if (NS_FAILED(rv)) {
|
||||
// Veto redirect. nsHttpChannel decides to cancel or continue.
|
||||
OnRedirectVerifyCallback(rv);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri = DeserializeURI(newUri);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIChannel> newChannel;
|
||||
rv = NS_NewChannelInternal(getter_AddRefs(newChannel),
|
||||
|
@ -1185,33 +1179,19 @@ HttpChannelChild::Redirect1Begin(const uint32_t& newChannelId,
|
|||
nullptr, // aCallbacks
|
||||
nsIRequest::LOAD_NORMAL,
|
||||
ioService);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
// Veto redirect. nsHttpChannel decides to cancel or continue.
|
||||
OnRedirectVerifyCallback(rv);
|
||||
return;
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// We won't get OnStartRequest, set cookies here.
|
||||
mResponseHead = new nsHttpResponseHead(responseHead);
|
||||
|
||||
if (!securityInfoSerialization.IsEmpty()) {
|
||||
NS_DeserializeObject(securityInfoSerialization,
|
||||
getter_AddRefs(mSecurityInfo));
|
||||
}
|
||||
mResponseHead = new nsHttpResponseHead(*responseHead);
|
||||
|
||||
bool rewriteToGET = HttpBaseChannel::ShouldRewriteRedirectToGET(mResponseHead->Status(),
|
||||
mRequestHead.ParsedMethod());
|
||||
|
||||
rv = SetupReplacementChannel(uri, newChannel, !rewriteToGET);
|
||||
if (NS_FAILED(rv)) {
|
||||
// Veto redirect. nsHttpChannel decides to cancel or continue.
|
||||
OnRedirectVerifyCallback(rv);
|
||||
return;
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIHttpChannelChild> httpChannelChild = do_QueryInterface(newChannel);
|
||||
if (mSynthesizedResponse && httpChannelChild) {
|
||||
if (mShouldInterceptSubsequentRedirect && httpChannelChild) {
|
||||
// In the case where there was a synthesized response that caused a redirection,
|
||||
// we must force the new channel to intercept the request in the parent before a
|
||||
// network transaction is initiated.
|
||||
|
@ -1219,15 +1199,64 @@ HttpChannelChild::Redirect1Begin(const uint32_t& newChannelId,
|
|||
}
|
||||
|
||||
mRedirectChannelChild = do_QueryInterface(newChannel);
|
||||
if (mRedirectChannelChild) {
|
||||
mRedirectChannelChild->ConnectParent(newChannelId);
|
||||
newChannel.forget(outChannel);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HttpChannelChild::Redirect1Begin(const uint32_t& newChannelId,
|
||||
const URIParams& newUri,
|
||||
const uint32_t& redirectFlags,
|
||||
const nsHttpResponseHead& responseHead,
|
||||
const nsACString& securityInfoSerialization)
|
||||
{
|
||||
LOG(("HttpChannelChild::Redirect1Begin [this=%p]\n", this));
|
||||
|
||||
nsCOMPtr<nsIURI> uri = DeserializeURI(newUri);
|
||||
|
||||
if (!securityInfoSerialization.IsEmpty()) {
|
||||
NS_DeserializeObject(securityInfoSerialization,
|
||||
getter_AddRefs(mSecurityInfo));
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIChannel> newChannel;
|
||||
nsresult rv = SetupRedirect(uri,
|
||||
&responseHead,
|
||||
getter_AddRefs(newChannel));
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (mRedirectChannelChild) {
|
||||
mRedirectChannelChild->ConnectParent(newChannelId);
|
||||
rv = gHttpHandler->AsyncOnChannelRedirect(this,
|
||||
newChannel,
|
||||
redirectFlags);
|
||||
} else {
|
||||
LOG((" redirecting to a protocol that doesn't implement"
|
||||
" nsIChildChannel"));
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
OnRedirectVerifyCallback(rv);
|
||||
}
|
||||
|
||||
void
|
||||
HttpChannelChild::BeginNonIPCRedirect(nsIURI* responseURI,
|
||||
const nsHttpResponseHead* responseHead)
|
||||
{
|
||||
LOG(("HttpChannelChild::BeginNonIPCRedirect [this=%p]\n", this));
|
||||
|
||||
nsCOMPtr<nsIChannel> newChannel;
|
||||
nsresult rv = SetupRedirect(responseURI,
|
||||
responseHead,
|
||||
getter_AddRefs(newChannel));
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = gHttpHandler->AsyncOnChannelRedirect(this,
|
||||
newChannel,
|
||||
redirectFlags);
|
||||
} else {
|
||||
LOG((" redirecting to a protocol that doesn't implement"
|
||||
" nsIChildChannel"));
|
||||
rv = NS_ERROR_FAILURE;
|
||||
nsIChannelEventSink::REDIRECT_INTERNAL);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
|
@ -1435,6 +1464,34 @@ HttpChannelChild::CompleteRedirectSetup(nsIStreamListener *listener,
|
|||
// HttpChannelChild::nsIAsyncVerifyRedirectCallback
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class OverrideRunnable : public nsRunnable {
|
||||
RefPtr<HttpChannelChild> mChannel;
|
||||
RefPtr<HttpChannelChild> mNewChannel;
|
||||
RefPtr<InterceptStreamListener> mListener;
|
||||
nsCOMPtr<nsIInputStream> mInput;
|
||||
nsAutoPtr<nsHttpResponseHead> mHead;
|
||||
|
||||
public:
|
||||
OverrideRunnable(HttpChannelChild* aChannel,
|
||||
HttpChannelChild* aNewChannel,
|
||||
InterceptStreamListener* aListener,
|
||||
nsIInputStream* aInput,
|
||||
nsAutoPtr<nsHttpResponseHead>& aHead)
|
||||
: mChannel(aChannel)
|
||||
, mNewChannel(aNewChannel)
|
||||
, mListener(aListener)
|
||||
, mInput(aInput)
|
||||
, mHead(aHead)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
mChannel->Redirect3Complete();
|
||||
mNewChannel->OverrideWithSynthesizedResponse(mHead, mInput, mListener);
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
HttpChannelChild::OnRedirectVerifyCallback(nsresult result)
|
||||
{
|
||||
|
@ -1448,6 +1505,21 @@ HttpChannelChild::OnRedirectVerifyCallback(nsresult result)
|
|||
newHttpChannel->SetOriginalURI(mOriginalURI);
|
||||
}
|
||||
|
||||
if (mRedirectingForSubsequentSynthesizedResponse) {
|
||||
nsCOMPtr<nsIHttpChannelChild> httpChannelChild = do_QueryInterface(mRedirectChannelChild);
|
||||
MOZ_ASSERT(httpChannelChild);
|
||||
RefPtr<HttpChannelChild> redirectedChannel =
|
||||
static_cast<HttpChannelChild*>(httpChannelChild.get());
|
||||
|
||||
RefPtr<InterceptStreamListener> streamListener =
|
||||
new InterceptStreamListener(redirectedChannel, mListenerContext);
|
||||
|
||||
NS_DispatchToMainThread(new OverrideRunnable(this, redirectedChannel,
|
||||
streamListener, mSynthesizedInput,
|
||||
mResponseHead));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RequestHeaderTuples emptyHeaders;
|
||||
RequestHeaderTuples* headerTuples = &emptyHeaders;
|
||||
nsLoadFlags loadFlags = 0;
|
||||
|
@ -2385,8 +2457,10 @@ HttpChannelChild::GetResponseSynthesized(bool* aSynthesized)
|
|||
void
|
||||
HttpChannelChild::OverrideWithSynthesizedResponse(nsAutoPtr<nsHttpResponseHead>& aResponseHead,
|
||||
nsIInputStream* aSynthesizedInput,
|
||||
nsIStreamListener* aStreamListener)
|
||||
InterceptStreamListener* aStreamListener)
|
||||
{
|
||||
mInterceptListener = aStreamListener;
|
||||
|
||||
// Intercepted responses should already be decoded. If its a redirect,
|
||||
// however, we want to respect the encoding of the final result instead.
|
||||
if (!WillRedirect(aResponseHead)) {
|
||||
|
@ -2397,6 +2471,7 @@ HttpChannelChild::OverrideWithSynthesizedResponse(nsAutoPtr<nsHttpResponseHead>&
|
|||
mSynthesizedResponse = true;
|
||||
|
||||
if (WillRedirect(mResponseHead)) {
|
||||
mShouldInterceptSubsequentRedirect = true;
|
||||
// Continue with the original cross-process request
|
||||
nsresult rv = ContinueAsyncOpen();
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
@ -2450,6 +2525,14 @@ HttpChannelChild::ForceIntercepted(uint64_t aInterceptionID)
|
|||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
void
|
||||
HttpChannelChild::ForceIntercepted(nsIInputStream* aSynthesizedInput)
|
||||
{
|
||||
mSynthesizedInput = aSynthesizedInput;
|
||||
mSynthesizedResponse = true;
|
||||
mRedirectingForSubsequentSynthesizedResponse = true;
|
||||
}
|
||||
|
||||
bool
|
||||
HttpChannelChild::RecvIssueDeprecationWarning(const uint32_t& warning,
|
||||
const bool& asError)
|
||||
|
|
|
@ -37,6 +37,7 @@ namespace net {
|
|||
|
||||
class InterceptedChannelContent;
|
||||
class InterceptStreamListener;
|
||||
class OverrideRunnable;
|
||||
|
||||
class HttpChannelChild final : public PHttpChannelChild
|
||||
, public HttpBaseChannel
|
||||
|
@ -175,12 +176,16 @@ private:
|
|||
// asynchronously read from the pump.
|
||||
void OverrideWithSynthesizedResponse(nsAutoPtr<nsHttpResponseHead>& aResponseHead,
|
||||
nsIInputStream* aSynthesizedInput,
|
||||
nsIStreamListener* aStreamListener);
|
||||
InterceptStreamListener* aStreamListener);
|
||||
|
||||
void ForceIntercepted(nsIInputStream* aSynthesizedInput);
|
||||
|
||||
RequestHeaderTuples mClientSetRequestHeaders;
|
||||
nsCOMPtr<nsIChildChannel> mRedirectChannelChild;
|
||||
RefPtr<InterceptStreamListener> mInterceptListener;
|
||||
RefPtr<nsInputStreamPump> mSynthesizedResponsePump;
|
||||
nsAutoPtr<nsHttpResponseHead> mSynthesizedResponseHead;
|
||||
nsCOMPtr<nsIInputStream> mSynthesizedInput;
|
||||
int64_t mSynthesizedStreamLength;
|
||||
|
||||
bool mIsFromCache;
|
||||
|
@ -215,6 +220,13 @@ private:
|
|||
// should be intercepted.
|
||||
bool mSynthesizedResponse;
|
||||
|
||||
// Set if a synthesized response should cause us to explictly allows intercepting
|
||||
// an expected forthcoming redirect.
|
||||
bool mShouldInterceptSubsequentRedirect;
|
||||
// Set if a redirection is being initiated to facilitate providing a synthesized
|
||||
// response to a channel using a different principal than the current one.
|
||||
bool mRedirectingForSubsequentSynthesizedResponse;
|
||||
|
||||
// Set if the corresponding parent channel should force an interception to occur
|
||||
// before the network transaction is initiated.
|
||||
bool mShouldParentIntercept;
|
||||
|
@ -260,6 +272,16 @@ private:
|
|||
void Redirect3Complete();
|
||||
void DeleteSelf();
|
||||
|
||||
// Create a a new channel to be used in a redirection, based on the provided
|
||||
// response headers.
|
||||
nsresult SetupRedirect(nsIURI* uri,
|
||||
const nsHttpResponseHead* responseHead,
|
||||
nsIChannel** outChannel);
|
||||
|
||||
// Perform a redirection without communicating with the parent process at all.
|
||||
void BeginNonIPCRedirect(nsIURI* responseURI,
|
||||
const nsHttpResponseHead* responseHead);
|
||||
|
||||
friend class AssociateApplicationCacheEvent;
|
||||
friend class StartRequestEvent;
|
||||
friend class StopRequestEvent;
|
||||
|
@ -275,6 +297,7 @@ private:
|
|||
friend class HttpAsyncAborter<HttpChannelChild>;
|
||||
friend class InterceptStreamListener;
|
||||
friend class InterceptedChannelContent;
|
||||
friend class OverrideRunnable;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
@ -284,7 +284,7 @@ InterceptedChannelChrome::GetInternalContentPolicyType(nsContentPolicyType* aPol
|
|||
|
||||
InterceptedChannelContent::InterceptedChannelContent(HttpChannelChild* aChannel,
|
||||
nsINetworkInterceptController* aController,
|
||||
nsIStreamListener* aListener)
|
||||
InterceptStreamListener* aListener)
|
||||
: InterceptedChannelBase(aController)
|
||||
, mChannel(aChannel)
|
||||
, mStreamListener(aListener)
|
||||
|
@ -353,9 +353,27 @@ InterceptedChannelContent::FinishSynthesizedResponse(const nsACString& aFinalURL
|
|||
|
||||
EnsureSynthesizedResponse();
|
||||
|
||||
mChannel->OverrideWithSynthesizedResponse(mSynthesizedResponseHead.ref(),
|
||||
mSynthesizedInput,
|
||||
mStreamListener);
|
||||
nsCOMPtr<nsIURI> originalURI;
|
||||
mChannel->GetURI(getter_AddRefs(originalURI));
|
||||
|
||||
nsCOMPtr<nsIURI> responseURI;
|
||||
if (!aFinalURLSpec.IsEmpty()) {
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(responseURI), aFinalURLSpec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
responseURI = originalURI;
|
||||
}
|
||||
|
||||
bool equal = false;
|
||||
originalURI->Equals(responseURI, &equal);
|
||||
if (!equal) {
|
||||
mChannel->ForceIntercepted(mSynthesizedInput);
|
||||
mChannel->BeginNonIPCRedirect(responseURI, *mSynthesizedResponseHead.ptr());
|
||||
} else {
|
||||
mChannel->OverrideWithSynthesizedResponse(mSynthesizedResponseHead.ref(),
|
||||
mSynthesizedInput,
|
||||
mStreamListener);
|
||||
}
|
||||
|
||||
mResponseBody = nullptr;
|
||||
mChannel = nullptr;
|
||||
|
|
|
@ -21,6 +21,7 @@ namespace net {
|
|||
class nsHttpChannel;
|
||||
class HttpChannelChild;
|
||||
class nsHttpResponseHead;
|
||||
class InterceptStreamListener;
|
||||
|
||||
// An object representing a channel that has been intercepted. This avoids complicating
|
||||
// the actual channel implementation with the details of synthesizing responses.
|
||||
|
@ -93,11 +94,11 @@ class InterceptedChannelContent : public InterceptedChannelBase
|
|||
|
||||
// Listener for the synthesized response to fix up the notifications before they reach
|
||||
// the actual channel.
|
||||
nsCOMPtr<nsIStreamListener> mStreamListener;
|
||||
RefPtr<InterceptStreamListener> mStreamListener;
|
||||
public:
|
||||
InterceptedChannelContent(HttpChannelChild* aChannel,
|
||||
nsINetworkInterceptController* aController,
|
||||
nsIStreamListener* aListener);
|
||||
InterceptStreamListener* aListener);
|
||||
|
||||
NS_IMETHOD ResetInterception() override;
|
||||
NS_IMETHOD FinishSynthesizedResponse(const nsACString& aFinalURLSpec) override;
|
||||
|
|
Загрузка…
Ссылка в новой задаче