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
--- a/netwerk/ipc/ChannelEventQueue.cpp
+++ b/netwerk/ipc/ChannelEventQueue.cpp
@@ -89,10 +89,25 @@ ChannelEventQueue::RetargetDeliveryTo(ns
MOZ_RELEASE_ASSERT(aTargetThread);
mTargetThread = do_QueryInterface(aTargetThread);
MOZ_RELEASE_ASSERT(mTargetThread);
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
--- a/netwerk/ipc/ChannelEventQueue.h
+++ b/netwerk/ipc/ChannelEventQueue.h
@@ -71,16 +71,17 @@ class ChannelEventQueue final
// called when the channel owning the event queue is suspended/resumed.
inline void Suspend();
// Resume flushes the queue asynchronously, i.e. items in queue will be
// dispatched in a new event on the current thread.
void Resume();
// Retargets delivery of events to the target thread specified.
nsresult RetargetDeliveryTo(nsIEventTarget* aTargetThread);
+ nsresult ResetDeliveryTarget();
private:
// Private destructor, to discourage deletion outside of Release():
~ChannelEventQueue()
{
}
inline void MaybeFlushQueue();
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -7,24 +7,27 @@
// HttpLog.h should generally be included first
#include "HttpLog.h"
#include "nsHttp.h"
#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"
#include "mozilla/net/HttpChannelChild.h"
#include "nsISupportsPrimitives.h"
#include "nsChannelClassifier.h"
+#include "nsGlobalWindow.h"
#include "nsStringStream.h"
#include "nsHttpHandler.h"
#include "nsNetUtil.h"
#include "nsSerializationHelper.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/Performance.h"
#include "mozilla/ipc/InputStreamUtils.h"
#include "mozilla/ipc/URIUtils.h"
@@ -1194,16 +1197,18 @@ HttpChannelChild::OverrideRunnable::Run(
mozilla::ipc::IPCResult
HttpChannelChild::RecvFinishInterceptedRedirect()
{
// Hold a ref to this to keep it from being deleted by Send__delete__()
RefPtr<HttpChannelChild> self(this);
Send__delete__(this);
+ 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));
return IPC_OK();
}
void
@@ -1596,16 +1601,18 @@ HttpChannelChild::ConnectParent(uint32_t
}
HttpBaseChannel::SetDocshellUserAgentOverride();
// 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();
+ SetEventTarget();
+
HttpChannelConnectArgs connectArgs(registrarId, mShouldParentIntercept);
PBrowserOrId browser = static_cast<ContentChild*>(gNeckoChild->Manager())
->GetBrowserOrId(tabChild);
if (!gNeckoChild->
SendPHttpChannelConstructor(this, browser,
IPC::SerializedLoadContext(this),
connectArgs)) {
return NS_ERROR_FAILURE;
@@ -1987,16 +1994,55 @@ NS_IMETHODIMP
HttpChannelChild::AsyncOpen2(nsIStreamListener *aListener)
{
nsCOMPtr<nsIStreamListener> listener = aListener;
nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
NS_ENSURE_SUCCESS(rv, rv);
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 {
+ // Top-level loads won't have a DocGroup yet. So instead we target them at
+ // the TabGroup, which is the best we can do at this time.
+ uint64_t outerWindowId;
+ if (NS_FAILED(loadInfo->GetOuterWindowID(&outerWindowId))) {
+ return;
+ }
+ RefPtr<nsGlobalWindow> window = nsGlobalWindow::GetOuterWindowWithId(outerWindowId);
+ if (!window) {
+ return;
+ }
+ dispatcher = window->TabGroup();
+ }
+
+ if (dispatcher) {
+ nsCOMPtr<nsIEventTarget> target =
+ dispatcher->EventTargetFor(TaskCategory::Network);
+ gNeckoChild->SetEventTargetForActor(this, target);
+ mEventQ->RetargetDeliveryTo(target);
+ }
+}
+
nsresult
HttpChannelChild::ContinueAsyncOpen()
{
nsCString appCacheClientId;
if (mInheritApplicationCache) {
// Pick up an application cache from the notification
// callbacks if available
nsCOMPtr<nsIApplicationCacheContainer> appCacheContainer;
@@ -2122,16 +2168,18 @@ HttpChannelChild::ContinueAsyncOpen()
return NS_ERROR_FAILURE;
}
ContentChild* cc = static_cast<ContentChild*>(gNeckoChild->Manager());
if (cc->IsShuttingDown()) {
return NS_ERROR_FAILURE;
}
+ 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();
PBrowserOrId browser = cc->GetBrowserOrId(tabChild);
if (!gNeckoChild->SendPHttpChannelConstructor(this, browser,
IPC::SerializedLoadContext(this),
openArgs)) {
--- a/netwerk/protocol/http/HttpChannelChild.h
+++ b/netwerk/protocol/http/HttpChannelChild.h
@@ -174,16 +174,18 @@ private:
private:
RefPtr<HttpChannelChild> mChannel;
RefPtr<HttpChannelChild> mNewChannel;
RefPtr<InterceptStreamListener> mListener;
nsCOMPtr<nsIInputStream> mInput;
nsAutoPtr<nsHttpResponseHead> mHead;
};
+ void SetEventTarget();
+
nsresult ContinueAsyncOpen();
void DoOnStartRequest(nsIRequest* aRequest, nsISupports* aContext);
void DoOnStatus(nsIRequest* aRequest, nsresult status);
void DoOnProgress(nsIRequest* aRequest, int64_t progress, int64_t progressMax);
void DoOnDataAvailable(nsIRequest* aRequest, nsISupports* aContext, nsIInputStream* aStream,
uint64_t offset, uint32_t count);
void DoPreOnStopRequest(nsresult aStatus);