mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1157283 - Recreate IPC redirected HTTP channels as necessary after intercepting the request in the child. r=mayhemer
This commit is contained in:
parent
23551b0aaa
commit
961d0686c7
@ -21,7 +21,7 @@ function fetchXHR(name, onload, onerror, headers) {
|
||||
x.send();
|
||||
}
|
||||
|
||||
fetchXHR('synthesized.txt', function(xhr) {
|
||||
fetchXHR('bare-synthesized.txt', function(xhr) {
|
||||
my_ok(xhr.status == 200, "load should be successful");
|
||||
my_ok(xhr.responseText == "synthesized response body", "load should have synthesized response");
|
||||
finish();
|
||||
@ -46,16 +46,33 @@ fetchXHR('synthesized-headers.txt', function(xhr) {
|
||||
finish();
|
||||
});
|
||||
|
||||
fetch('synthesized-redirect-real-file.txt', function(xhr) {
|
||||
fetchXHR('synthesized-redirect-real-file.txt', function(xhr) {
|
||||
dump("Got status AARRGH " + xhr.status + " " + xhr.responseText + "\n");
|
||||
my_ok(xhr.status == 200, "load should be successful");
|
||||
my_ok(xhr.responseText == "This is a real file.\n", "Redirect to real file should complete.");
|
||||
finish();
|
||||
});
|
||||
|
||||
fetch('synthesized-redirect-synthesized.txt', function(xhr) {
|
||||
fetchXHR('synthesized-redirect-twice-real-file.txt', function(xhr) {
|
||||
my_ok(xhr.status == 200, "load should be successful");
|
||||
my_ok(xhr.responseText == "synthesized response body", "load should have synthesized response");
|
||||
my_ok(xhr.responseText == "This is a real file.\n", "Redirect to real file (twice) should complete.");
|
||||
finish();
|
||||
});
|
||||
|
||||
fetchXHR('synthesized-redirect-synthesized.txt', function(xhr) {
|
||||
my_ok(xhr.status == 200, "synth+redirect+synth load should be successful");
|
||||
my_ok(xhr.responseText == "synthesized response body", "load should have redirected+synthesized response");
|
||||
finish();
|
||||
});
|
||||
|
||||
fetchXHR('synthesized-redirect-twice-synthesized.txt', function(xhr) {
|
||||
my_ok(xhr.status == 200, "synth+redirect+synth (twice) load should be successful");
|
||||
my_ok(xhr.responseText == "synthesized response body", "load should have redirected+synthesized (twice) response");
|
||||
finish();
|
||||
});
|
||||
|
||||
fetchXHR('fetch/redirect.sjs', function(xhr) {
|
||||
my_ok(xhr.status == 404, "redirected load should be uninterrupted");
|
||||
finish();
|
||||
});
|
||||
|
||||
|
4
dom/workers/test/serviceworkers/fetch/redirect.sjs
Normal file
4
dom/workers/test/serviceworkers/fetch/redirect.sjs
Normal file
@ -0,0 +1,4 @@
|
||||
function handleRequest(request, response) {
|
||||
response.setStatusLine(request.httpVersion, 301, "Moved Permanently");
|
||||
response.setHeader("Location", "synthesized-redirect-twice-real-file.txt");
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
var seenIndex = false;
|
||||
|
||||
onfetch = function(ev) {
|
||||
if (ev.request.url.includes("synthesized.txt")) {
|
||||
if (ev.request.url.includes("bare-synthesized.txt")) {
|
||||
ev.respondWith(Promise.resolve(
|
||||
new Response("synthesized response body", {})
|
||||
));
|
||||
@ -33,12 +33,24 @@ onfetch = function(ev) {
|
||||
));
|
||||
}
|
||||
|
||||
else if (ev.request.url.includes("synthesized-redirect-synthesized.txt")) {
|
||||
else if (ev.request.url.includes("synthesized-redirect-twice-real-file.txt")) {
|
||||
ev.respondWith(Promise.resolve(
|
||||
Response.redirect("synthesized.txt")
|
||||
Response.redirect("synthesized-redirect-real-file.txt")
|
||||
));
|
||||
}
|
||||
|
||||
else if (ev.request.url.includes("synthesized-redirect-synthesized.txt")) {
|
||||
ev.respondWith(Promise.resolve(
|
||||
Response.redirect("bare-synthesized.txt")
|
||||
));
|
||||
}
|
||||
|
||||
else if (ev.request.url.includes("synthesized-redirect-twice-synthesized.txt")) {
|
||||
ev.respondWith(Promise.resolve(
|
||||
Response.redirect("synthesized-redirect-synthesized.txt")
|
||||
));
|
||||
}
|
||||
|
||||
else if (ev.request.url.includes("ignored.txt")) {
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ support-files =
|
||||
fetch/fetch_worker_script.js
|
||||
fetch/fetch_tests.js
|
||||
fetch/deliver-gzip.sjs
|
||||
fetch/redirect.sjs
|
||||
fetch/real-file.txt
|
||||
fetch/context/index.html
|
||||
fetch/context/register.html
|
||||
|
@ -73,6 +73,7 @@ struct HttpChannelOpenArgs
|
||||
struct HttpChannelConnectArgs
|
||||
{
|
||||
uint32_t channelId;
|
||||
bool shouldIntercept;
|
||||
};
|
||||
|
||||
union HttpChannelCreationArgs
|
||||
|
@ -2254,6 +2254,14 @@ HttpBaseChannel::SetupReplacementChannel(nsIURI *newURI,
|
||||
}
|
||||
}
|
||||
|
||||
// Preserve any skip-serviceworker-flag if possible.
|
||||
if (mForceNoIntercept) {
|
||||
nsCOMPtr<nsIHttpChannelInternal> httpChan = do_QueryInterface(newChannel);
|
||||
if (httpChan) {
|
||||
httpChan->ForceNoIntercept();
|
||||
}
|
||||
}
|
||||
|
||||
// Propagate our loadinfo if needed.
|
||||
newChannel->SetLoadInfo(mLoadInfo);
|
||||
|
||||
|
@ -177,6 +177,8 @@ HttpChannelChild::HttpChannelChild()
|
||||
, mDivertingToParent(false)
|
||||
, mFlushedForDiversion(false)
|
||||
, mSuspendSent(false)
|
||||
, mSynthesizedResponse(false)
|
||||
, mShouldParentIntercept(false)
|
||||
{
|
||||
LOG(("Creating HttpChannelChild @%x\n", this));
|
||||
|
||||
@ -1111,6 +1113,14 @@ HttpChannelChild::Redirect1Begin(const uint32_t& newChannelId,
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIHttpChannelChild> httpChannelChild = do_QueryInterface(newChannel);
|
||||
if (mSynthesizedResponse && 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.
|
||||
httpChannelChild->ForceIntercepted();
|
||||
}
|
||||
|
||||
mRedirectChannelChild = do_QueryInterface(newChannel);
|
||||
if (mRedirectChannelChild) {
|
||||
mRedirectChannelChild->ConnectParent(newChannelId);
|
||||
@ -1261,7 +1271,7 @@ HttpChannelChild::ConnectParent(uint32_t id)
|
||||
// until OnStopRequest, or we do a redirect, or we hit an IPDL error.
|
||||
AddIPDLReference();
|
||||
|
||||
HttpChannelConnectArgs connectArgs(id);
|
||||
HttpChannelConnectArgs connectArgs(id, mShouldParentIntercept);
|
||||
PBrowserOrId browser = static_cast<ContentChild*>(gNeckoChild->Manager())
|
||||
->GetBrowserOrId(tabChild);
|
||||
if (!gNeckoChild->
|
||||
@ -1283,6 +1293,15 @@ HttpChannelChild::CompleteRedirectSetup(nsIStreamListener *listener,
|
||||
NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
|
||||
NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
|
||||
|
||||
if (mShouldParentIntercept) {
|
||||
// This is a redirected channel, and the corresponding parent channel has started
|
||||
// AsyncOpen but was intercepted and suspended. We must tear it down and start
|
||||
// fresh - we will intercept the child channel this time, before creating a new
|
||||
// parent channel unnecessarily.
|
||||
PHttpChannelChild::Send__delete__(this);
|
||||
return AsyncOpen(listener, aContext);
|
||||
}
|
||||
|
||||
/*
|
||||
* No need to check for cancel: we don't get here if nsHttpChannel canceled
|
||||
* before AsyncOpen(); if it's canceled after that, OnStart/Stop will just
|
||||
@ -2149,6 +2168,10 @@ HttpChannelChild::ResetInterception()
|
||||
}
|
||||
mInterceptListener = nullptr;
|
||||
|
||||
// The chance to intercept any further requests associated with this channel
|
||||
// (such as redirects) has passed.
|
||||
ForceNoIntercept();
|
||||
|
||||
// Continue with the original cross-process request
|
||||
nsresult rv = ContinueAsyncOpen();
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
@ -2163,6 +2186,7 @@ HttpChannelChild::OverrideWithSynthesizedResponse(nsAutoPtr<nsHttpResponseHead>&
|
||||
SetApplyConversion(false);
|
||||
|
||||
mResponseHead = aResponseHead;
|
||||
mSynthesizedResponse = true;
|
||||
|
||||
uint16_t status = mResponseHead->Status();
|
||||
if (status != 200 && status != 404) {
|
||||
@ -2206,4 +2230,11 @@ HttpChannelChild::OverrideWithSynthesizedResponse(nsAutoPtr<nsHttpResponseHead>&
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HttpChannelChild::ForceIntercepted()
|
||||
{
|
||||
mShouldParentIntercept = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
}} // mozilla::net
|
||||
|
@ -195,6 +195,14 @@ private:
|
||||
// diverting callbacks to parent.
|
||||
bool mSuspendSent;
|
||||
|
||||
// Set if a response was synthesized, indicating that any forthcoming redirects
|
||||
// should be intercepted.
|
||||
bool mSynthesizedResponse;
|
||||
|
||||
// Set if the corresponding parent channel should force an interception to occur
|
||||
// before the network transaction is initiated.
|
||||
bool mShouldParentIntercept;
|
||||
|
||||
// true after successful AsyncOpen until OnStopRequest completes.
|
||||
bool RemoteChannelExists() { return mIPCOpen && !mKeptAlive; }
|
||||
|
||||
|
@ -57,6 +57,8 @@ HttpChannelParent::HttpChannelParent(const PBrowserOrId& iframeEmbedding,
|
||||
, mDivertingFromChild(false)
|
||||
, mDivertedOnStartRequest(false)
|
||||
, mSuspendedForDiversion(false)
|
||||
, mShouldIntercept(false)
|
||||
, mShouldSuspendIntercept(false)
|
||||
, mNestedFrameId(0)
|
||||
{
|
||||
LOG(("Creating HttpChannelParent [this=%p]\n", this));
|
||||
@ -92,6 +94,13 @@ HttpChannelParent::ActorDestroy(ActorDestroyReason why)
|
||||
// yet, but child process has crashed. We must not try to send any more msgs
|
||||
// to child, or IPDL will kill chrome process, too.
|
||||
mIPCClosed = true;
|
||||
|
||||
// If this is an intercepted channel, we need to make sure that any resources are
|
||||
// cleaned up to avoid leaks.
|
||||
if (mInterceptedChannel) {
|
||||
mInterceptedChannel->Cancel();
|
||||
mInterceptedChannel = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
@ -118,7 +127,7 @@ HttpChannelParent::Init(const HttpChannelCreationArgs& aArgs)
|
||||
case HttpChannelCreationArgs::THttpChannelConnectArgs:
|
||||
{
|
||||
const HttpChannelConnectArgs& cArgs = aArgs.get_HttpChannelConnectArgs();
|
||||
return ConnectChannel(cArgs.channelId());
|
||||
return ConnectChannel(cArgs.channelId(), cArgs.shouldIntercept());
|
||||
}
|
||||
default:
|
||||
NS_NOTREACHED("unknown open type");
|
||||
@ -143,7 +152,7 @@ NS_IMPL_ISUPPORTS(HttpChannelParent,
|
||||
NS_IMETHODIMP
|
||||
HttpChannelParent::ShouldPrepareForIntercept(nsIURI* aURI, bool aIsNavigate, bool* aShouldIntercept)
|
||||
{
|
||||
*aShouldIntercept = !!mSynthesizedResponseHead;
|
||||
*aShouldIntercept = mShouldIntercept;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -188,6 +197,11 @@ public:
|
||||
NS_IMETHODIMP
|
||||
HttpChannelParent::ChannelIntercepted(nsIInterceptedChannel* aChannel)
|
||||
{
|
||||
if (mShouldSuspendIntercept) {
|
||||
mInterceptedChannel = aChannel;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
aChannel->SynthesizeStatus(mSynthesizedResponseHead->Status(),
|
||||
mSynthesizedResponseHead->StatusText());
|
||||
nsCOMPtr<nsIHttpHeaderVisitor> visitor = new HeaderVisitor(aChannel);
|
||||
@ -388,6 +402,9 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI,
|
||||
|
||||
if (aSynthesizedResponseHead.type() == OptionalHttpResponseHead::TnsHttpResponseHead) {
|
||||
mSynthesizedResponseHead = new nsHttpResponseHead(aSynthesizedResponseHead.get_nsHttpResponseHead());
|
||||
mShouldIntercept = true;
|
||||
} else {
|
||||
mChannel->ForceNoIntercept();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupportsPRUint32> cacheKey =
|
||||
@ -467,7 +484,7 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI,
|
||||
}
|
||||
|
||||
bool
|
||||
HttpChannelParent::ConnectChannel(const uint32_t& channelId)
|
||||
HttpChannelParent::ConnectChannel(const uint32_t& channelId, const bool& shouldIntercept)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
@ -478,6 +495,13 @@ HttpChannelParent::ConnectChannel(const uint32_t& channelId)
|
||||
mChannel = static_cast<nsHttpChannel*>(channel.get());
|
||||
LOG((" found channel %p, rv=%08x", mChannel.get(), rv));
|
||||
|
||||
mShouldIntercept = shouldIntercept;
|
||||
if (mShouldIntercept) {
|
||||
// When an interception occurs, this channel should suspend all further activity.
|
||||
// It will be torn down and recreated if necessary.
|
||||
mShouldSuspendIntercept = true;
|
||||
}
|
||||
|
||||
if (mPBOverride != kPBOverride_Unset) {
|
||||
// redirected-to channel may not support PB
|
||||
nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryObject(mChannel);
|
||||
|
@ -88,7 +88,7 @@ public:
|
||||
protected:
|
||||
// used to connect redirected-to channel in parent with just created
|
||||
// ChildChannel. Used during redirects.
|
||||
bool ConnectChannel(const uint32_t& channelId);
|
||||
bool ConnectChannel(const uint32_t& channelId, const bool& shouldIntercept);
|
||||
|
||||
bool DoAsyncOpen(const URIParams& uri,
|
||||
const OptionalURIParams& originalUri,
|
||||
@ -204,7 +204,15 @@ private:
|
||||
|
||||
bool mSuspendedForDiversion;
|
||||
|
||||
// Set if this channel should be intercepted before it sets up the HTTP transaction.
|
||||
bool mShouldIntercept : 1;
|
||||
// Set if this channel should suspend on interception.
|
||||
bool mShouldSuspendIntercept : 1;
|
||||
|
||||
dom::TabId mNestedFrameId;
|
||||
|
||||
// Handle to the channel wrapper if this channel has been intercepted.
|
||||
nsCOMPtr<nsIInterceptedChannel> mInterceptedChannel;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
|
@ -7,11 +7,15 @@
|
||||
|
||||
[ptr] native RequestHeaderTuples(mozilla::net::RequestHeaderTuples);
|
||||
|
||||
[uuid(306ACF4D-C6DF-4EF6-BDA9-5CB92E83EDD9)]
|
||||
[uuid(3842c5e9-b5b1-400c-8eb7-936a3316ff21)]
|
||||
interface nsIHttpChannelChild : nsISupports
|
||||
{
|
||||
void addCookiesToRequest();
|
||||
|
||||
// Mark this channel as requiring an interception; this will propagate
|
||||
// to the corresponding parent channel when a redirect occurs.
|
||||
void forceIntercepted();
|
||||
|
||||
// Headers that the channel client has set via SetRequestHeader.
|
||||
readonly attribute RequestHeaderTuples clientSetRequestHeaders;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user