Bug 1118845 P2 Make SharedWorker override parent LoadGroup with custom proxy callbacks. r=khuey

This commit is contained in:
Ben Kelly
2015-02-21 10:09:17 -05:00
parent b3f4b187bf
commit dad79a535a
4 changed files with 230 additions and 16 deletions

View File

@@ -2260,7 +2260,9 @@ RuntimeService::CreateSharedWorkerInternal(const GlobalObject& aGlobal,
WorkerPrivate::LoadInfo loadInfo; WorkerPrivate::LoadInfo loadInfo;
nsresult rv = WorkerPrivate::GetLoadInfo(cx, window, nullptr, aScriptURL, nsresult rv = WorkerPrivate::GetLoadInfo(cx, window, nullptr, aScriptURL,
false, &loadInfo); false,
WorkerPrivate::OverrideLoadGroup,
&loadInfo);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
return CreateSharedWorkerFromLoadInfo(cx, &loadInfo, aScriptURL, aName, aType, return CreateSharedWorkerFromLoadInfo(cx, &loadInfo, aScriptURL, aName, aType,
@@ -2314,6 +2316,11 @@ RuntimeService::CreateSharedWorkerFromLoadInfo(JSContext* aCx,
NS_ENSURE_TRUE(workerPrivate, rv.ErrorCode()); NS_ENSURE_TRUE(workerPrivate, rv.ErrorCode());
created = true; created = true;
} else {
// If we're attaching to an existing SharedWorker private, then we
// must update the overriden load group to account for our document's
// load group.
workerPrivate->UpdateOverridenLoadGroup(aLoadInfo->mLoadGroup);
} }
nsRefPtr<SharedWorker> sharedWorker = new SharedWorker(window, workerPrivate); nsRefPtr<SharedWorker> sharedWorker = new SharedWorker(window, workerPrivate);

View File

@@ -2483,10 +2483,7 @@ ServiceWorkerManager::CreateServiceWorker(nsIPrincipal* aPrincipal,
// - use remote tabs = false // - use remote tabs = false
// Alternatively we could persist the original load group values and use // Alternatively we could persist the original load group values and use
// them here. // them here.
rv = NS_NewLoadGroup(getter_AddRefs(info.mLoadGroup), info.mPrincipal); WorkerPrivate::OverrideLoadInfoLoadGroup(info);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsRefPtr<ServiceWorker> serviceWorker; nsRefPtr<ServiceWorker> serviceWorker;
RuntimeService* rs = RuntimeService::GetOrCreateService(); RuntimeService* rs = RuntimeService::GetOrCreateService();

View File

@@ -15,16 +15,19 @@
#include "nsIDOMMessageEvent.h" #include "nsIDOMMessageEvent.h"
#include "nsIDocument.h" #include "nsIDocument.h"
#include "nsIDocShell.h" #include "nsIDocShell.h"
#include "nsIInterfaceRequestor.h"
#include "nsIMemoryReporter.h" #include "nsIMemoryReporter.h"
#include "nsIPermissionManager.h" #include "nsIPermissionManager.h"
#include "nsIScriptError.h" #include "nsIScriptError.h"
#include "nsIScriptGlobalObject.h" #include "nsIScriptGlobalObject.h"
#include "nsIScriptSecurityManager.h" #include "nsIScriptSecurityManager.h"
#include "nsITabChild.h"
#include "nsITextToSubURI.h" #include "nsITextToSubURI.h"
#include "nsIThreadInternal.h" #include "nsIThreadInternal.h"
#include "nsITimer.h" #include "nsITimer.h"
#include "nsIURI.h" #include "nsIURI.h"
#include "nsIURL.h" #include "nsIURL.h"
#include "nsIWeakReferenceUtils.h"
#include "nsIWorkerDebugger.h" #include "nsIWorkerDebugger.h"
#include "nsIXPConnect.h" #include "nsIXPConnect.h"
#include "nsPerformance.h" #include "nsPerformance.h"
@@ -704,13 +707,16 @@ class MainThreadReleaseRunnable MOZ_FINAL : public nsRunnable
{ {
nsTArray<nsCOMPtr<nsISupports>> mDoomed; nsTArray<nsCOMPtr<nsISupports>> mDoomed;
nsTArray<nsCString> mHostObjectURIs; nsTArray<nsCString> mHostObjectURIs;
nsCOMPtr<nsILoadGroup> mLoadGroupToCancel;
public: public:
MainThreadReleaseRunnable(nsTArray<nsCOMPtr<nsISupports>>& aDoomed, MainThreadReleaseRunnable(nsTArray<nsCOMPtr<nsISupports>>& aDoomed,
nsTArray<nsCString>& aHostObjectURIs) nsTArray<nsCString>& aHostObjectURIs,
nsCOMPtr<nsILoadGroup>& aLoadGroupToCancel)
{ {
mDoomed.SwapElements(aDoomed); mDoomed.SwapElements(aDoomed);
mHostObjectURIs.SwapElements(aHostObjectURIs); mHostObjectURIs.SwapElements(aHostObjectURIs);
mLoadGroupToCancel.swap(aLoadGroupToCancel);
} }
NS_DECL_ISUPPORTS_INHERITED NS_DECL_ISUPPORTS_INHERITED
@@ -718,6 +724,11 @@ public:
NS_IMETHOD NS_IMETHOD
Run() MOZ_OVERRIDE Run() MOZ_OVERRIDE
{ {
if (mLoadGroupToCancel) {
mLoadGroupToCancel->Cancel(NS_BINDING_ABORTED);
mLoadGroupToCancel = nullptr;
}
mDoomed.Clear(); mDoomed.Clear();
for (uint32_t index = 0; index < mHostObjectURIs.Length(); index++) { for (uint32_t index = 0; index < mHostObjectURIs.Length(); index++) {
@@ -761,6 +772,9 @@ private:
virtual bool virtual bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
{ {
nsCOMPtr<nsILoadGroup> loadGroupToCancel;
mFinishedWorker->ForgetOverridenLoadGroup(loadGroupToCancel);
nsTArray<nsCOMPtr<nsISupports>> doomed; nsTArray<nsCOMPtr<nsISupports>> doomed;
mFinishedWorker->ForgetMainThreadObjects(doomed); mFinishedWorker->ForgetMainThreadObjects(doomed);
@@ -768,7 +782,7 @@ private:
mFinishedWorker->StealHostObjectURIs(hostObjectURIs); mFinishedWorker->StealHostObjectURIs(hostObjectURIs);
nsRefPtr<MainThreadReleaseRunnable> runnable = nsRefPtr<MainThreadReleaseRunnable> runnable =
new MainThreadReleaseRunnable(doomed, hostObjectURIs); new MainThreadReleaseRunnable(doomed, hostObjectURIs, loadGroupToCancel);
if (NS_FAILED(NS_DispatchToMainThread(runnable))) { if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
NS_WARNING("Failed to dispatch, going to leak!"); NS_WARNING("Failed to dispatch, going to leak!");
} }
@@ -816,6 +830,9 @@ private:
runtime->UnregisterWorker(cx, mFinishedWorker); runtime->UnregisterWorker(cx, mFinishedWorker);
nsCOMPtr<nsILoadGroup> loadGroupToCancel;
mFinishedWorker->ForgetOverridenLoadGroup(loadGroupToCancel);
nsTArray<nsCOMPtr<nsISupports> > doomed; nsTArray<nsCOMPtr<nsISupports> > doomed;
mFinishedWorker->ForgetMainThreadObjects(doomed); mFinishedWorker->ForgetMainThreadObjects(doomed);
@@ -823,7 +840,7 @@ private:
mFinishedWorker->StealHostObjectURIs(hostObjectURIs); mFinishedWorker->StealHostObjectURIs(hostObjectURIs);
nsRefPtr<MainThreadReleaseRunnable> runnable = nsRefPtr<MainThreadReleaseRunnable> runnable =
new MainThreadReleaseRunnable(doomed, hostObjectURIs); new MainThreadReleaseRunnable(doomed, hostObjectURIs, loadGroupToCancel);
if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) { if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
NS_WARNING("Failed to dispatch, going to leak!"); NS_WARNING("Failed to dispatch, going to leak!");
} }
@@ -1982,6 +1999,129 @@ private:
} }
}; };
template <class Derived>
class WorkerPrivateParent<Derived>::InterfaceRequestor MOZ_FINAL
: public nsIInterfaceRequestor
{
NS_DECL_ISUPPORTS
public:
InterfaceRequestor(nsIPrincipal* aPrincipal, nsILoadGroup* aLoadGroup)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aPrincipal);
// Look for an existing LoadContext. This is optional and it's ok if
// we don't find one.
nsCOMPtr<nsILoadContext> baseContext;
if (aLoadGroup) {
nsCOMPtr<nsIInterfaceRequestor> callbacks;
aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
if (callbacks) {
callbacks->GetInterface(NS_GET_IID(nsILoadContext),
getter_AddRefs(baseContext));
}
}
mLoadContext = new LoadContext(aPrincipal, baseContext);
}
void
MaybeAddTabChild(nsILoadGroup* aLoadGroup)
{
MOZ_ASSERT(NS_IsMainThread());
if (!aLoadGroup) {
return;
}
nsCOMPtr<nsIInterfaceRequestor> callbacks;
aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
if (!callbacks) {
return;
}
nsCOMPtr<nsITabChild> tabChild;
callbacks->GetInterface(NS_GET_IID(nsITabChild), getter_AddRefs(tabChild));
if (!tabChild) {
return;
}
// Use weak references to the tab child. Holding a strong reference will
// not prevent an ActorDestroy() from being called on the TabChild.
// Therefore, we should let the TabChild destroy itself as soon as possible.
mTabChildList.AppendElement(do_GetWeakReference(tabChild));
}
NS_IMETHOD
GetInterface(const nsIID& aIID, void** aSink) MOZ_OVERRIDE
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mLoadContext);
if (aIID.Equals(NS_GET_IID(nsILoadContext))) {
nsCOMPtr<nsILoadContext> ref = mLoadContext;
ref.forget(aSink);
return NS_OK;
}
// If we still have an active nsITabChild, then return it. Its possible,
// though, that all of the TabChild objects have been destroyed. In that
// case we return NS_NOINTERFACE.
if(aIID.Equals(NS_GET_IID(nsITabChild))) {
nsCOMPtr<nsITabChild> tabChild = GetAnyLiveTabChild();
if (!tabChild) {
return NS_NOINTERFACE;
}
tabChild.forget(aSink);
return NS_OK;
}
return NS_NOINTERFACE;
}
private:
~InterfaceRequestor() { }
already_AddRefed<nsITabChild>
GetAnyLiveTabChild()
{
MOZ_ASSERT(NS_IsMainThread());
// Search our list of known TabChild objects for one that still exists.
while (!mTabChildList.IsEmpty()) {
nsCOMPtr<nsITabChild> tabChild =
do_QueryReferent(mTabChildList.LastElement());
// Does this tab child still exist? If so, return it. We are done.
if (tabChild) {
return tabChild.forget();
}
// Otherwise remove the stale weak reference and check the next one
mTabChildList.RemoveElementAt(mTabChildList.Length() - 1);
}
return nullptr;
}
nsCOMPtr<nsILoadContext> mLoadContext;
// Array of weak references to nsITabChild. We do not want to keep TabChild
// actors alive for long after their ActorDestroy() methods are called.
nsTArray<nsWeakPtr> mTabChildList;
};
template <class Derived>
NS_IMPL_ADDREF(WorkerPrivateParent<Derived>::InterfaceRequestor)
template <class Derived>
NS_IMPL_RELEASE(WorkerPrivateParent<Derived>::InterfaceRequestor)
template <class Derived>
NS_IMPL_QUERY_INTERFACE(WorkerPrivateParent<Derived>::InterfaceRequestor,
nsIInterfaceRequestor)
template <class Derived> template <class Derived>
class WorkerPrivateParent<Derived>::EventTarget MOZ_FINAL class WorkerPrivateParent<Derived>::EventTarget MOZ_FINAL
: public nsIEventTarget : public nsIEventTarget
@@ -2833,6 +2973,22 @@ WorkerPrivateParent<Derived>::ModifyBusyCount(JSContext* aCx, bool aIncrease)
return true; return true;
} }
template <class Derived>
void
WorkerPrivateParent<Derived>::ForgetOverridenLoadGroup(
nsCOMPtr<nsILoadGroup>& aLoadGroupOut)
{
AssertIsOnParentThread();
// If we're not overriden, then do nothing here. Let the load group get
// handled in ForgetMainThreadObjects().
if (!mLoadInfo.mInterfaceRequestor) {
return;
}
mLoadInfo.mLoadGroup.swap(aLoadGroupOut);
}
template <class Derived> template <class Derived>
void void
WorkerPrivateParent<Derived>::ForgetMainThreadObjects( WorkerPrivateParent<Derived>::ForgetMainThreadObjects(
@@ -2841,7 +2997,7 @@ WorkerPrivateParent<Derived>::ForgetMainThreadObjects(
AssertIsOnParentThread(); AssertIsOnParentThread();
MOZ_ASSERT(!mMainThreadObjectsForgotten); MOZ_ASSERT(!mMainThreadObjectsForgotten);
static const uint32_t kDoomedCount = 8; static const uint32_t kDoomedCount = 9;
aDoomed.SetCapacity(kDoomedCount); aDoomed.SetCapacity(kDoomedCount);
@@ -2853,6 +3009,7 @@ WorkerPrivateParent<Derived>::ForgetMainThreadObjects(
SwapToISupportsArray(mLoadInfo.mChannel, aDoomed); SwapToISupportsArray(mLoadInfo.mChannel, aDoomed);
SwapToISupportsArray(mLoadInfo.mCSP, aDoomed); SwapToISupportsArray(mLoadInfo.mCSP, aDoomed);
SwapToISupportsArray(mLoadInfo.mLoadGroup, aDoomed); SwapToISupportsArray(mLoadInfo.mLoadGroup, aDoomed);
SwapToISupportsArray(mLoadInfo.mInterfaceRequestor, aDoomed);
// Before adding anything here update kDoomedCount above! // Before adding anything here update kDoomedCount above!
MOZ_ASSERT(aDoomed.Length() == kDoomedCount); MOZ_ASSERT(aDoomed.Length() == kDoomedCount);
@@ -3631,6 +3788,16 @@ WorkerPrivateParent<Derived>::StealHostObjectURIs(nsTArray<nsCString>& aArray)
aArray.SwapElements(mHostObjectURIs); aArray.SwapElements(mHostObjectURIs);
} }
template <class Derived>
void
WorkerPrivateParent<Derived>::UpdateOverridenLoadGroup(nsILoadGroup* aBaseLoadGroup)
{
AssertIsOnMainThread();
// The load group should have been overriden at init time.
mLoadInfo.mInterfaceRequestor->MaybeAddTabChild(aBaseLoadGroup);
}
template <class Derived> template <class Derived>
NS_IMPL_ADDREF_INHERITED(WorkerPrivateParent<Derived>, DOMEventTargetHelper) NS_IMPL_ADDREF_INHERITED(WorkerPrivateParent<Derived>, DOMEventTargetHelper)
@@ -4062,7 +4229,8 @@ WorkerPrivate::Constructor(JSContext* aCx,
stackLoadInfo.emplace(); stackLoadInfo.emplace();
nsresult rv = GetLoadInfo(aCx, nullptr, parent, aScriptURL, nsresult rv = GetLoadInfo(aCx, nullptr, parent, aScriptURL,
aIsChromeWorker, stackLoadInfo.ptr()); aIsChromeWorker, InheritLoadGroup,
stackLoadInfo.ptr());
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
scriptloader::ReportLoadError(aCx, aScriptURL, rv, !parent); scriptloader::ReportLoadError(aCx, aScriptURL, rv, !parent);
aRv.Throw(rv); aRv.Throw(rv);
@@ -4117,7 +4285,9 @@ WorkerPrivate::Constructor(JSContext* aCx,
nsresult nsresult
WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow, WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow,
WorkerPrivate* aParent, const nsAString& aScriptURL, WorkerPrivate* aParent, const nsAString& aScriptURL,
bool aIsChromeWorker, LoadInfo* aLoadInfo) bool aIsChromeWorker,
LoadGroupBehavior aLoadGroupBehavior,
LoadInfo* aLoadInfo)
{ {
using namespace mozilla::dom::workers::scriptloader; using namespace mozilla::dom::workers::scriptloader;
using mozilla::dom::indexedDB::IDBFactory; using mozilla::dom::indexedDB::IDBFactory;
@@ -4350,10 +4520,8 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow,
loadInfo.mReportCSPViolations = false; loadInfo.mReportCSPViolations = false;
} }
if (!loadInfo.mLoadGroup) { if (!loadInfo.mLoadGroup || aLoadGroupBehavior == OverrideLoadGroup) {
rv = NS_NewLoadGroup(getter_AddRefs(loadInfo.mLoadGroup), OverrideLoadInfoLoadGroup(loadInfo);
loadInfo.mPrincipal);
NS_ENSURE_SUCCESS(rv, rv);
} }
MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(loadInfo.mLoadGroup, MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(loadInfo.mLoadGroup,
loadInfo.mPrincipal)); loadInfo.mPrincipal));
@@ -4373,6 +4541,26 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow,
return NS_OK; return NS_OK;
} }
// static
void
WorkerPrivate::OverrideLoadInfoLoadGroup(LoadInfo& aLoadInfo)
{
MOZ_ASSERT(!aLoadInfo.mInterfaceRequestor);
aLoadInfo.mInterfaceRequestor = new InterfaceRequestor(aLoadInfo.mPrincipal,
aLoadInfo.mLoadGroup);
aLoadInfo.mInterfaceRequestor->MaybeAddTabChild(aLoadInfo.mLoadGroup);
nsCOMPtr<nsILoadGroup> loadGroup =
do_CreateInstance(NS_LOADGROUP_CONTRACTID);
nsresult rv =
loadGroup->SetNotificationCallbacks(aLoadInfo.mInterfaceRequestor);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(rv));
aLoadInfo.mLoadGroup = loadGroup.forget();
}
void void
WorkerPrivate::DoRunLoop(JSContext* aCx) WorkerPrivate::DoRunLoop(JSContext* aCx)
{ {

View File

@@ -132,6 +132,7 @@ class WorkerPrivateParent : public DOMEventTargetHelper
class SynchronizeAndResumeRunnable; class SynchronizeAndResumeRunnable;
protected: protected:
class InterfaceRequestor;
class EventTarget; class EventTarget;
friend class EventTarget; friend class EventTarget;
@@ -163,6 +164,9 @@ public:
nsCOMPtr<nsIChannel> mChannel; nsCOMPtr<nsIChannel> mChannel;
nsCOMPtr<nsILoadGroup> mLoadGroup; nsCOMPtr<nsILoadGroup> mLoadGroup;
// Only set if we have a custom overriden load group
nsRefPtr<InterfaceRequestor> mInterfaceRequestor;
nsAutoPtr<PrincipalInfo> mPrincipalInfo; nsAutoPtr<PrincipalInfo> mPrincipalInfo;
nsCString mDomain; nsCString mDomain;
@@ -207,6 +211,9 @@ public:
MOZ_ASSERT(!mLoadGroup); MOZ_ASSERT(!mLoadGroup);
aOther.mLoadGroup.swap(mLoadGroup); aOther.mLoadGroup.swap(mLoadGroup);
MOZ_ASSERT(!mInterfaceRequestor);
aOther.mInterfaceRequestor.swap(mInterfaceRequestor);
MOZ_ASSERT(!mPrincipalInfo); MOZ_ASSERT(!mPrincipalInfo);
mPrincipalInfo = aOther.mPrincipalInfo.forget(); mPrincipalInfo = aOther.mPrincipalInfo.forget();
@@ -393,6 +400,9 @@ public:
bool bool
ModifyBusyCount(JSContext* aCx, bool aIncrease); ModifyBusyCount(JSContext* aCx, bool aIncrease);
void
ForgetOverridenLoadGroup(nsCOMPtr<nsILoadGroup>& aLoadGroupOut);
void void
ForgetMainThreadObjects(nsTArray<nsCOMPtr<nsISupports> >& aDoomed); ForgetMainThreadObjects(nsTArray<nsCOMPtr<nsISupports> >& aDoomed);
@@ -763,6 +773,9 @@ public:
void void
StealHostObjectURIs(nsTArray<nsCString>& aArray); StealHostObjectURIs(nsTArray<nsCString>& aArray);
void
UpdateOverridenLoadGroup(nsILoadGroup* aBaseLoadGroup);
IMPL_EVENT_HANDLER(message) IMPL_EVENT_HANDLER(message)
IMPL_EVENT_HANDLER(error) IMPL_EVENT_HANDLER(error)
@@ -921,10 +934,19 @@ public:
static bool static bool
WorkerAvailable(JSContext* /* unused */, JSObject* /* unused */); WorkerAvailable(JSContext* /* unused */, JSObject* /* unused */);
enum LoadGroupBehavior
{
InheritLoadGroup,
OverrideLoadGroup
};
static nsresult static nsresult
GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow, WorkerPrivate* aParent, GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow, WorkerPrivate* aParent,
const nsAString& aScriptURL, bool aIsChromeWorker, const nsAString& aScriptURL, bool aIsChromeWorker,
LoadInfo* aLoadInfo); LoadGroupBehavior aLoadGroupBehavior, LoadInfo* aLoadInfo);
static void
OverrideLoadInfoLoadGroup(LoadInfo& aLoadInfo);
WorkerDebugger* WorkerDebugger*
Debugger() const Debugger() const