Bug 1318506 - Label HttpChannelChild actors with DocGroup/TabGroup (r=jduell)

This patch tries to figure out which DocGroup or TabGroup a network request
belongs to and then assign the IPC actor to that group. A DocGroup roughly
corresponds to a document and a TabGroup to a tab. Once the assignment is
made, all incoming IPC messages will be labeled with that DocGroup/TabGroup.

MozReview-Commit-ID: EzGCeGdREHl
This commit is contained in:
Bill McCloskey 2016-11-15 16:13:17 -08:00
Родитель 86da1e11a4
Коммит 2113b3347b
4 изменённых файлов: 92 добавлений и 0 удалений

Просмотреть файл

@ -94,5 +94,20 @@ ChannelEventQueue::RetargetDeliveryTo(nsIEventTarget* aTargetThread)
return NS_OK;
}
nsresult
ChannelEventQueue::ResetDeliveryTarget()
{
MutexAutoLock lock(mMutex);
MOZ_RELEASE_ASSERT(mEventQueue.IsEmpty());
MOZ_RELEASE_ASSERT(mSuspendCount == 0);
MOZ_RELEASE_ASSERT(!mSuspended);
MOZ_RELEASE_ASSERT(!mForced);
MOZ_RELEASE_ASSERT(!mFlushing);
mTargetThread = nullptr;
return NS_OK;
}
} // namespace net
} // namespace mozilla

Просмотреть файл

@ -77,6 +77,11 @@ class ChannelEventQueue final
// Retargets delivery of events to the target thread specified.
nsresult RetargetDeliveryTo(nsIEventTarget* aTargetThread);
// Nulls out the delivery target so events are delivered to the main
// thread. Should only be called when the queue is known to be empty.
// Useful if the queue will be re-used.
nsresult ResetDeliveryTarget();
private:
// Private destructor, to discourage deletion outside of Release():
~ChannelEventQueue()

Просмотреть файл

@ -12,7 +12,9 @@
#include "nsICacheEntry.h"
#include "mozilla/Unused.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/DocGroup.h"
#include "mozilla/dom/TabChild.h"
#include "mozilla/dom/TabGroup.h"
#include "mozilla/ipc/FileDescriptorSetChild.h"
#include "mozilla/ipc/IPCStreamUtils.h"
#include "mozilla/net/NeckoChild.h"
@ -20,6 +22,7 @@
#include "nsISupportsPrimitives.h"
#include "nsChannelClassifier.h"
#include "nsGlobalWindow.h"
#include "nsStringStream.h"
#include "nsHttpHandler.h"
#include "nsNetUtil.h"
@ -1212,6 +1215,10 @@ HttpChannelChild::RecvFinishInterceptedRedirect()
RefPtr<HttpChannelChild> self(this);
Send__delete__(this);
// Reset the event target to which queued messages are delivered. Otherwise
// we'll get an assertion when we re-use the channel later on.
mEventQ->ResetDeliveryTarget();
// The IPDL connection was torn down by a interception logic in
// CompleteRedirectSetup, and we need to call FinishInterceptedRedirect.
NS_DispatchToMainThread(NewRunnableMethod(this, &HttpChannelChild::FinishInterceptedRedirect));
@ -1621,6 +1628,11 @@ HttpChannelChild::ConnectParent(uint32_t registrarId)
// until OnStopRequest, or we do a redirect, or we hit an IPDL error.
AddIPDLReference();
// This must happen before the constructor message is sent. Otherwise messages
// from the parent could arrive quickly and be delivered to the wrong event
// target.
SetEventTarget();
HttpChannelConnectArgs connectArgs(registrarId, mShouldParentIntercept);
PBrowserOrId browser = static_cast<ContentChild*>(gNeckoChild->Manager())
->GetBrowserOrId(tabChild);
@ -2020,6 +2032,55 @@ HttpChannelChild::AsyncOpen2(nsIStreamListener *aListener)
return AsyncOpen(listener, nullptr);
}
// Assigns an nsIEventTarget to our IPDL actor so that IPC messages are sent to
// the correct DocGroup/TabGroup.
void
HttpChannelChild::SetEventTarget()
{
nsCOMPtr<nsILoadInfo> loadInfo;
GetLoadInfo(getter_AddRefs(loadInfo));
if (!loadInfo) {
return;
}
nsCOMPtr<nsIDOMDocument> domDoc;
loadInfo->GetLoadingDocument(getter_AddRefs(domDoc));
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
RefPtr<Dispatcher> dispatcher;
if (doc) {
dispatcher = doc->GetDocGroup();
} else {
// There's no document yet, but this might be a top-level load where we can
// find a TabGroup.
uint64_t outerWindowId;
if (NS_FAILED(loadInfo->GetOuterWindowID(&outerWindowId))) {
// No window. This might be an add-on XHR, a service worker request, or
// something else.
return;
}
RefPtr<nsGlobalWindow> window = nsGlobalWindow::GetOuterWindowWithId(outerWindowId);
if (!window) {
return;
}
#ifdef DEBUG
// We have a TabGroup. This must be a top-level load.
bool isMainDocumentChannel;
GetIsMainDocumentChannel(&isMainDocumentChannel);
MOZ_ASSERT(isMainDocumentChannel);
#endif
dispatcher = window->TabGroup();
}
if (dispatcher) {
nsCOMPtr<nsIEventTarget> target =
dispatcher->EventTargetFor(TaskCategory::Network);
gNeckoChild->SetEventTargetForActor(this, target);
mEventQ->RetargetDeliveryTo(target);
}
}
nsresult
HttpChannelChild::ContinueAsyncOpen()
{
@ -2170,6 +2231,11 @@ HttpChannelChild::ContinueAsyncOpen()
return NS_ERROR_FAILURE;
}
// This must happen before the constructor message is sent. Otherwise messages
// from the parent could arrive quickly and be delivered to the wrong event
// target.
SetEventTarget();
// 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();

Просмотреть файл

@ -182,6 +182,12 @@ private:
nsAutoPtr<nsHttpResponseHead> mHead;
};
// Sets the event target for future IPC messages. Messages will either be
// directed to the TabGroup or DocGroup, depending on the LoadInfo associated
// with the channel. Should be called when a new channel is being set up,
// before the constructor message is sent to the parent.
void SetEventTarget();
nsresult ContinueAsyncOpen();
void DoOnStartRequest(nsIRequest* aRequest, nsISupports* aContext);