Bug 1405286: Part 1 - Allow retrieving the delivery target from retargetable requests. r=dragana

After data delivery for a request has been retargeted, there's no reliable way
to get the appropriate event target to re-dispatch data events after
asynchronous processing.


While it's technically possible to retrieve the current thread from
OnDataAvailable callbacks and re-use that for later dispatch, that approach
has some issues:

1) It's not currently possible to reliably map the current thread to the
thread pool that owns it. That means that if data delivery is being targetted
to a thread pool, attempts to redispatch events to the previous delivery
thread might lead to long delays when one thread in a pool is blocked.

2) If a filter wishes to dispatch data events to the wrapped listeners before
it's recieved any data (as extensions StreamFilters sometimes do), there's no
way to determine the proper event target without waiting for initial data to
be received.


Simply returning the correct event target from the request solves both of
these problems.

MozReview-Commit-ID: CJxq7O4399R

--HG--
extra : rebase_source : db2f659ecad16daafdbcc108d7b1a51ea1af31f9
This commit is contained in:
Kris Maglione 2017-10-14 18:30:38 -07:00
parent 05889a48b5
commit 635fc0e1ae
8 changed files with 93 additions and 0 deletions

View File

@ -1174,6 +1174,19 @@ nsJARChannel::RetargetDeliveryTo(nsIEventTarget* aEventTarget)
return request->RetargetDeliveryTo(aEventTarget);
}
NS_IMETHODIMP
nsJARChannel::GetDeliveryTarget(nsIEventTarget** aEventTarget)
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIThreadRetargetableRequest> request = do_QueryInterface(mRequest);
if (!request) {
return NS_ERROR_NO_INTERFACE;
}
return request->GetDeliveryTarget(aEventTarget);
}
NS_IMETHODIMP
nsJARChannel::CheckListenerChain()
{

View File

@ -974,6 +974,20 @@ nsBaseChannel::RetargetDeliveryTo(nsIEventTarget* aEventTarget)
return req->RetargetDeliveryTo(aEventTarget);
}
NS_IMETHODIMP
nsBaseChannel::GetDeliveryTarget(nsIEventTarget** aEventTarget)
{
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_TRUE(mRequest, NS_ERROR_NOT_INITIALIZED);
nsCOMPtr<nsIThreadRetargetableRequest> req;
req = do_QueryInterface(mRequest);
NS_ENSURE_TRUE(req, NS_ERROR_NOT_IMPLEMENTED);
return req->GetDeliveryTarget(aEventTarget);
}
NS_IMETHODIMP
nsBaseChannel::CheckListenerChain()
{

View File

@ -32,4 +32,12 @@ interface nsIThreadRetargetableRequest : nsISupports
* the new target thread.
*/
void retargetDeliveryTo(in nsIEventTarget aNewTarget);
/**
* Returns the event target where OnDataAvailable events will be dispatched.
*
* This is only valid after OnStartRequest has been called. Any time before
* that point, the value may be changed by `retargetDeliveryTo` calls.
*/
readonly attribute nsIEventTarget deliveryTarget;
};

View File

@ -775,3 +775,13 @@ nsInputStreamPump::RetargetDeliveryTo(nsIEventTarget* aNewTarget)
(nsIStreamListener*)mListener, static_cast<uint32_t>(rv)));
return rv;
}
NS_IMETHODIMP
nsInputStreamPump::GetDeliveryTarget(nsIEventTarget** aNewTarget)
{
RecursiveMutexAutoLock lock(mMutex);
nsCOMPtr<nsIEventTarget> target = mTargetThread;
target.forget(aNewTarget);
return NS_OK;
}

View File

@ -3386,6 +3386,19 @@ HttpChannelChild::RetargetDeliveryTo(nsIEventTarget* aNewTarget)
return NS_OK;
}
NS_IMETHODIMP
HttpChannelChild::GetDeliveryTarget(nsIEventTarget** aEventTarget)
{
MutexAutoLock lock(mEventTargetMutex);
nsCOMPtr<nsIEventTarget> target = mODATarget;
if (!mODATarget) {
target = GetCurrentThreadEventTarget();
}
target.forget(aEventTarget);
return NS_OK;
}
void
HttpChannelChild::ResetInterception()
{

View File

@ -1078,6 +1078,15 @@ InterceptedHttpChannel::RetargetDeliveryTo(nsIEventTarget* aNewTarget)
return mPump->RetargetDeliveryTo(aNewTarget);
}
NS_IMETHODIMP
InterceptedHttpChannel::GetDeliveryTarget(nsIEventTarget** aEventTarget)
{
if (!mPump) {
return NS_ERROR_NOT_AVAILABLE;
}
return mPump->GetDeliveryTarget(aEventTarget);
}
NS_IMETHODIMP
InterceptedHttpChannel::CheckListenerChain()
{

View File

@ -7751,6 +7751,19 @@ nsHttpChannel::RetargetDeliveryTo(nsIEventTarget* aNewTarget)
return rv;
}
NS_IMETHODIMP
nsHttpChannel::GetDeliveryTarget(nsIEventTarget** aEventTarget)
{
if (mCachePump) {
return mCachePump->GetDeliveryTarget(aEventTarget);
}
if (mTransactionPump) {
return mTransactionPump->GetDeliveryTarget(aEventTarget);
}
return NS_ERROR_NOT_AVAILABLE;
}
//-----------------------------------------------------------------------------
// nsHttpChannel::nsThreadRetargetableStreamListener
//-----------------------------------------------------------------------------

View File

@ -359,6 +359,19 @@ BaseWebSocketChannel::RetargetDeliveryTo(nsIEventTarget* aTargetThread)
return NS_OK;
}
NS_IMETHODIMP
BaseWebSocketChannel::GetDeliveryTarget(nsIEventTarget** aTargetThread)
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIEventTarget> target = mTargetThread;
if (!target) {
target = GetCurrentThreadEventTarget();
}
target.forget(aTargetThread);
return NS_OK;
}
BaseWebSocketChannel::ListenerAndContextContainer::ListenerAndContextContainer(
nsIWebSocketListener* aListener,
nsISupports* aContext)