Bug 1217909 P8 Track navigation interceptions per scope in ServiceWorkerManager. r=catalinb

This commit is contained in:
Ben Kelly 2015-11-16 08:04:11 -08:00
parent cbacc47a48
commit 9b0e251d1f
7 changed files with 136 additions and 1 deletions

View File

@ -3240,6 +3240,8 @@ ServiceWorkerManager::PrepareFetchEvent(const OriginAttributes& aOriginAttribute
// This should only happen if IsAvailable() returned true.
MOZ_ASSERT(registration->mActiveWorker);
serviceWorker = registration->mActiveWorker;
AddNavigationInterception(serviceWorker->Scope(), aChannel);
}
if (NS_WARN_IF(aRv.Failed()) || !serviceWorker) {
@ -4190,6 +4192,76 @@ ServiceWorkerManager::AddRegisteringDocument(const nsACString& aScope,
list->AppendElement(do_GetWeakReference(aDoc));
}
class ServiceWorkerManager::InterceptionReleaseHandle final : public nsISupports
{
const nsCString mScope;
// Weak reference to channel is safe, because the channel holds a
// reference to this object. Also, the pointer is only used for
// comparison purposes.
nsIInterceptedChannel* mChannel;
~InterceptionReleaseHandle()
{
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
swm->RemoveNavigationInterception(mScope, mChannel);
}
public:
InterceptionReleaseHandle(const nsACString& aScope,
nsIInterceptedChannel* aChannel)
: mScope(aScope)
, mChannel(aChannel)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!aScope.IsEmpty());
MOZ_ASSERT(mChannel);
}
NS_DECL_ISUPPORTS
};
NS_IMPL_ISUPPORTS0(ServiceWorkerManager::InterceptionReleaseHandle);
void
ServiceWorkerManager::AddNavigationInterception(const nsACString& aScope,
nsIInterceptedChannel* aChannel)
{
AssertIsOnMainThread();
MOZ_ASSERT(!aScope.IsEmpty());
MOZ_ASSERT(aChannel);
InterceptionList* list =
mNavigationInterceptions.LookupOrAdd(aScope);
MOZ_ASSERT(list);
MOZ_ASSERT(!list->Contains(aChannel));
nsCOMPtr<nsISupports> releaseHandle =
new InterceptionReleaseHandle(aScope, aChannel);
aChannel->SetReleaseHandle(releaseHandle);
list->AppendElement(aChannel);
}
void
ServiceWorkerManager::RemoveNavigationInterception(const nsACString& aScope,
nsIInterceptedChannel* aChannel)
{
AssertIsOnMainThread();
MOZ_ASSERT(aChannel);
InterceptionList* list =
mNavigationInterceptions.Get(aScope);
if (list) {
MOZ_ALWAYS_TRUE(list->RemoveElement(aChannel));
MOZ_ASSERT(!list->Contains(aChannel));
if (list->IsEmpty()) {
list = nullptr;
nsAutoPtr<InterceptionList> doomed;
mNavigationInterceptions.RemoveAndForget(aScope, doomed);
}
}
}
NS_IMPL_ISUPPORTS(ServiceWorkerInfo, nsIServiceWorkerInfo)
NS_IMETHODIMP

View File

@ -328,6 +328,18 @@ public:
typedef nsTArray<nsCOMPtr<nsIWeakReference>> WeakDocumentList;
nsClassHashtable<nsCStringHashKey, WeakDocumentList> mRegisteringDocuments;
// Track all intercepted navigation channels for a given scope. Channels are
// placed in the appropriate list before dispatch the FetchEvent to the worker
// thread and removed once FetchEvent processing dispatches back to the main
// thread.
//
// Note: Its safe to use weak references here because a RAII-style callback
// is registered with the channel before its added to this list. We
// are guaranteed the callback will fire before and remove the ref
// from this list before the channel is destroyed.
typedef nsTArray<nsIInterceptedChannel*> InterceptionList;
nsClassHashtable<nsCStringHashKey, InterceptionList> mNavigationInterceptions;
bool
IsAvailable(const OriginAttributes& aOriginAttributes, nsIURI* aURI);
@ -622,6 +634,16 @@ private:
void
AddRegisteringDocument(const nsACString& aScope, nsIDocument* aDoc);
class InterceptionReleaseHandle;
void
AddNavigationInterception(const nsACString& aScope,
nsIInterceptedChannel* aChannel);
void
RemoveNavigationInterception(const nsACString& aScope,
nsIInterceptedChannel* aChannel);
};
} // namespace workers

View File

@ -56,6 +56,7 @@ InterceptedJARChannel::ResetInterception()
mSynthesizedInput = nullptr;
mChannel->ResetInterception();
mReleaseHandle = nullptr;
mChannel = nullptr;
return NS_OK;
}
@ -93,6 +94,7 @@ InterceptedJARChannel::FinishSynthesizedResponse(const nsACString& aFinalURLSpec
mChannel->OverrideWithSynthesizedResponse(mSynthesizedInput, mContentType);
mResponseBody = nullptr;
mReleaseHandle = nullptr;
mChannel = nullptr;
return NS_OK;
}
@ -109,6 +111,7 @@ InterceptedJARChannel::Cancel(nsresult aStatus)
nsresult rv = mChannel->Cancel(aStatus);
NS_ENSURE_SUCCESS(rv, rv);
mResponseBody = nullptr;
mReleaseHandle = nullptr;
mChannel = nullptr;
return NS_OK;
}
@ -129,6 +132,16 @@ InterceptedJARChannel::GetConsoleReportCollector(nsIConsoleReportCollector**)
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
InterceptedJARChannel::SetReleaseHandle(nsISupports* aHandle)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mReleaseHandle);
MOZ_ASSERT(aHandle);
mReleaseHandle = aHandle;
return NS_OK;
}
void
InterceptedJARChannel::NotifyController()
{

View File

@ -41,6 +41,8 @@ class InterceptedJARChannel : public nsIInterceptedChannel
// The stream to write the body of the synthesized response.
nsCOMPtr<nsIOutputStream> mResponseBody;
nsCOMPtr<nsISupports> mReleaseHandle;
// The content type of the synthesized response.
nsCString mContentType;

View File

@ -29,7 +29,7 @@ class ChannelInfo;
* which do not implement nsIChannel.
*/
[scriptable, uuid(231bb567-90e1-4973-9728-7dab93ab29a8)]
[scriptable, uuid(64439e24-eda5-4f39-9a7e-162c4b5e0150)]
interface nsIInterceptedChannel : nsISupports
{
/**
@ -100,6 +100,14 @@ interface nsIInterceptedChannel : nsISupports
return reporter.forget();
}
%}
/**
* Allow the ServiceWorkerManager to set an RAII-style object on the
* intercepted channel that should be released once the channel is
* torn down.
*/
[noscript]
void setReleaseHandle(in nsISupports aHandle);
};
/**

View File

@ -118,6 +118,16 @@ InterceptedChannelBase::GetConsoleReportCollector(nsIConsoleReportCollector** aC
return NS_OK;
}
NS_IMETHODIMP
InterceptedChannelBase::SetReleaseHandle(nsISupports* aHandle)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mReleaseHandle);
MOZ_ASSERT(aHandle);
mReleaseHandle = aHandle;
return NS_OK;
}
InterceptedChannelChrome::InterceptedChannelChrome(nsHttpChannel* aChannel,
nsINetworkInterceptController* aController,
nsICacheEntry* aEntry)
@ -172,6 +182,7 @@ InterceptedChannelChrome::ResetInterception()
nsresult rv = mChannel->StartRedirectChannelToURI(uri, nsIChannelEventSink::REDIRECT_INTERNAL);
NS_ENSURE_SUCCESS(rv, rv);
mReleaseHandle = nullptr;
mChannel = nullptr;
return NS_OK;
}
@ -265,6 +276,7 @@ InterceptedChannelChrome::FinishSynthesizedResponse(const nsACString& aFinalURLS
NS_ENSURE_SUCCESS(rv, rv);
}
}
mReleaseHandle = nullptr;
mChannel = nullptr;
return NS_OK;
}
@ -284,6 +296,7 @@ InterceptedChannelChrome::Cancel(nsresult aStatus)
// to cancel which will provide OnStart/OnStopRequest to the channel.
nsresult rv = mChannel->AsyncAbort(aStatus);
NS_ENSURE_SUCCESS(rv, rv);
mReleaseHandle = nullptr;
return NS_OK;
}
@ -349,6 +362,7 @@ InterceptedChannelContent::ResetInterception()
mSynthesizedInput = nullptr;
mChannel->ResetInterception();
mReleaseHandle = nullptr;
mChannel = nullptr;
return NS_OK;
}
@ -407,6 +421,7 @@ InterceptedChannelContent::FinishSynthesizedResponse(const nsACString& aFinalURL
}
mResponseBody = nullptr;
mReleaseHandle = nullptr;
mChannel = nullptr;
mStreamListener = nullptr;
return NS_OK;
@ -427,6 +442,7 @@ InterceptedChannelContent::Cancel(nsresult aStatus)
// to cancel which will provide OnStart/OnStopRequest to the channel.
nsresult rv = mChannel->AsyncAbort(aStatus);
NS_ENSURE_SUCCESS(rv, rv);
mReleaseHandle = nullptr;
mChannel = nullptr;
mStreamListener = nullptr;
return NS_OK;

View File

@ -37,6 +37,7 @@ protected:
Maybe<nsAutoPtr<nsHttpResponseHead>> mSynthesizedResponseHead;
nsCOMPtr<nsIConsoleReportCollector> mReportCollector;
nsCOMPtr<nsISupports> mReleaseHandle;
void EnsureSynthesizedResponse();
void DoNotifyController();
@ -55,6 +56,7 @@ public:
NS_IMETHOD GetResponseBody(nsIOutputStream** aOutput) override;
NS_IMETHOD GetConsoleReportCollector(nsIConsoleReportCollector** aCollectorOut) override;
NS_IMETHOD SetReleaseHandle(nsISupports* aHandle) override;
};
class InterceptedChannelChrome : public InterceptedChannelBase