mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 13:23:07 +00:00
import change from rmottola/Arctic-Fox:
- Bug 1146557 P1 Fix CacheStorage and Cache to QI to nsISupports correctly. r=ehsan (b56ba80cd) - Bug 1146557 P2 Flip dom.caches.enabled to true on non-release builds. (b1ac38779) - Bug 1126014 - DomainPolicy support for e10s. r=mrbkap (484fa7f8d) - Bug 1092102 - Implement worker debugger runnables; (cfb3cb53d) - Bug 1092102 - Implement WorkerDebugger.initialize; (24f467b14) - Bug 1092102 - Implement WorkerDebugger.postMessage; (ad69a161d) - Bug 1092102 - Implement WorkerDebuggerGlobalScope.reportError; (f937913f2) - Bug 1092102 - Implement WorkerDebuggerGlobalScope.enterEventLoop; (d1d0ad392) - Bug 1092102 - Implement WorkerDebuggerGlobalScope.setImmediate (a22de0f0d) - Bug 1092102 - Implement WorkerDebuggerGlobalScope.createSandbox (d281de130) - Bug 1092102 followup: Add missing 'override' annotation on DebuggerImmediateRunnable::IsDebuggerRunnable(). (b4d053cfe) - Bug 1092102, followup 2: Add missing 'override' annotation to WorkerDebuggerSandboxPrivate::GetGlobalJSObject() (and 'virtual', for consistency). (72c9f3c84) - Bug 1092102 - Rename Suspend/Resume to Freeze/Thaw; (a7f2b5c11) - Bug 1092102 - Implement WorkerDebugger.isFrozen; (805ba0e9e)
This commit is contained in:
+112
-6
@@ -5,17 +5,50 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "DomainPolicy.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/ipc/URIUtils.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "nsIMessageManager.h"
|
||||
#include "nsScriptSecurityManager.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace ipc;
|
||||
using namespace dom;
|
||||
|
||||
NS_IMPL_ISUPPORTS(DomainPolicy, nsIDomainPolicy)
|
||||
|
||||
DomainPolicy::DomainPolicy() : mBlacklist(new DomainSet())
|
||||
, mSuperBlacklist(new DomainSet())
|
||||
, mWhitelist(new DomainSet())
|
||||
, mSuperWhitelist(new DomainSet())
|
||||
{}
|
||||
static nsresult
|
||||
BroadcastDomainSetChange(DomainSetType aSetType, DomainSetChangeType aChangeType,
|
||||
nsIURI* aDomain = nullptr)
|
||||
{
|
||||
MOZ_ASSERT(XRE_GetProcessType() == GoannaProcessType_Default,
|
||||
"DomainPolicy should only be exposed to the chrome process.");
|
||||
|
||||
nsTArray<ContentParent*> parents;
|
||||
ContentParent::GetAll(parents);
|
||||
if (!parents.Length()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
OptionalURIParams uri;
|
||||
SerializeURI(aDomain, uri);
|
||||
|
||||
for (uint32_t i = 0; i < parents.Length(); i++) {
|
||||
unused << parents[i]->SendDomainSetChanged(aSetType, aChangeType, uri);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
DomainPolicy::DomainPolicy() : mBlacklist(new DomainSet(BLACKLIST))
|
||||
, mSuperBlacklist(new DomainSet(SUPER_BLACKLIST))
|
||||
, mWhitelist(new DomainSet(WHITELIST))
|
||||
, mSuperWhitelist(new DomainSet(SUPER_WHITELIST))
|
||||
{
|
||||
if (XRE_GetProcessType() == GoannaProcessType_Default) {
|
||||
BroadcastDomainSetChange(NO_TYPE, ACTIVATE_POLICY);
|
||||
}
|
||||
}
|
||||
|
||||
DomainPolicy::~DomainPolicy()
|
||||
{
|
||||
@@ -75,10 +108,47 @@ DomainPolicy::Deactivate()
|
||||
mSuperWhitelist = nullptr;
|
||||
|
||||
// Inform the SSM.
|
||||
nsScriptSecurityManager::GetScriptSecurityManager()->DeactivateDomainPolicy();
|
||||
nsScriptSecurityManager* ssm = nsScriptSecurityManager::GetScriptSecurityManager();
|
||||
if (ssm) {
|
||||
ssm->DeactivateDomainPolicy();
|
||||
}
|
||||
if (XRE_GetProcessType() == GoannaProcessType_Default) {
|
||||
BroadcastDomainSetChange(NO_TYPE, DEACTIVATE_POLICY);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
DomainPolicy::CloneDomainPolicy(DomainPolicyClone* aClone)
|
||||
{
|
||||
aClone->active() = true;
|
||||
static_cast<DomainSet*>(mBlacklist.get())->CloneSet(&aClone->blacklist());
|
||||
static_cast<DomainSet*>(mSuperBlacklist.get())->CloneSet(&aClone->superBlacklist());
|
||||
static_cast<DomainSet*>(mWhitelist.get())->CloneSet(&aClone->whitelist());
|
||||
static_cast<DomainSet*>(mSuperWhitelist.get())->CloneSet(&aClone->superWhitelist());
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
CopyURIs(const InfallibleTArray<URIParams>& aDomains, nsIDomainSet* aSet)
|
||||
{
|
||||
for (uint32_t i = 0; i < aDomains.Length(); i++) {
|
||||
nsCOMPtr<nsIURI> uri = DeserializeURI(aDomains[i]);
|
||||
aSet->Add(uri);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DomainPolicy::ApplyClone(DomainPolicyClone* aClone)
|
||||
{
|
||||
nsCOMPtr<nsIDomainSet> list;
|
||||
|
||||
CopyURIs(aClone->blacklist(), mBlacklist);
|
||||
CopyURIs(aClone->whitelist(), mWhitelist);
|
||||
CopyURIs(aClone->superBlacklist(), mSuperBlacklist);
|
||||
CopyURIs(aClone->superWhitelist(), mSuperWhitelist);
|
||||
}
|
||||
|
||||
static already_AddRefed<nsIURI>
|
||||
GetCanonicalClone(nsIURI* aURI)
|
||||
{
|
||||
@@ -100,6 +170,9 @@ DomainSet::Add(nsIURI* aDomain)
|
||||
nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain);
|
||||
NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE);
|
||||
mHashTable.PutEntry(clone);
|
||||
if (XRE_GetProcessType() == GoannaProcessType_Default)
|
||||
return BroadcastDomainSetChange(mType, ADD_DOMAIN, aDomain);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -109,6 +182,9 @@ DomainSet::Remove(nsIURI* aDomain)
|
||||
nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain);
|
||||
NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE);
|
||||
mHashTable.RemoveEntry(clone);
|
||||
if (XRE_GetProcessType() == GoannaProcessType_Default)
|
||||
return BroadcastDomainSetChange(mType, REMOVE_DOMAIN, aDomain);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -116,6 +192,9 @@ NS_IMETHODIMP
|
||||
DomainSet::Clear()
|
||||
{
|
||||
mHashTable.Clear();
|
||||
if (XRE_GetProcessType() == GoannaProcessType_Default)
|
||||
return BroadcastDomainSetChange(mType, CLEAR_DOMAINS);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -160,4 +239,31 @@ DomainSet::ContainsSuperDomain(nsIURI* aDomain, bool* aContains)
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DomainSet::GetType(uint32_t* aType)
|
||||
{
|
||||
*aType = mType;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static
|
||||
PLDHashOperator
|
||||
DomainEnumerator(nsURIHashKey* aEntry, void* aUserArg)
|
||||
{
|
||||
InfallibleTArray<URIParams>* uris = static_cast<InfallibleTArray<URIParams>*>(aUserArg);
|
||||
nsIURI* key = aEntry->GetKey();
|
||||
|
||||
URIParams uri;
|
||||
SerializeURI(key, uri);
|
||||
|
||||
uris->AppendElement(uri);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
DomainSet::CloneSet(InfallibleTArray<URIParams>* aDomains)
|
||||
{
|
||||
mHashTable.EnumerateEntries(DomainEnumerator, aDomains);
|
||||
}
|
||||
|
||||
} /* namespace mozilla */
|
||||
|
||||
+30
-1
@@ -13,6 +13,30 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class nsIContentParent;
|
||||
};
|
||||
|
||||
namespace ipc {
|
||||
class URIParams;
|
||||
};
|
||||
|
||||
enum DomainSetChangeType{
|
||||
ACTIVATE_POLICY,
|
||||
DEACTIVATE_POLICY,
|
||||
ADD_DOMAIN,
|
||||
REMOVE_DOMAIN,
|
||||
CLEAR_DOMAINS
|
||||
};
|
||||
|
||||
enum DomainSetType{
|
||||
NO_TYPE,
|
||||
BLACKLIST,
|
||||
SUPER_BLACKLIST,
|
||||
WHITELIST,
|
||||
SUPER_WHITELIST
|
||||
};
|
||||
|
||||
class DomainPolicy : public nsIDomainPolicy
|
||||
{
|
||||
public:
|
||||
@@ -35,11 +59,16 @@ public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOMAINSET
|
||||
|
||||
DomainSet() {}
|
||||
explicit DomainSet(DomainSetType aType)
|
||||
: mType(aType)
|
||||
{}
|
||||
|
||||
void CloneSet(InfallibleTArray<mozilla::ipc::URIParams>* aDomains);
|
||||
|
||||
protected:
|
||||
virtual ~DomainSet() {}
|
||||
nsTHashtable<nsURIHashKey> mHashTable;
|
||||
DomainSetType mType;
|
||||
};
|
||||
|
||||
} /* namespace mozilla */
|
||||
|
||||
@@ -8,6 +8,16 @@
|
||||
interface nsIURI;
|
||||
interface nsIDomainSet;
|
||||
|
||||
%{ C++
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class DomainPolicyClone;
|
||||
}
|
||||
}
|
||||
%}
|
||||
|
||||
[ptr] native DomainPolicyClonePtr(mozilla::dom::DomainPolicyClone);
|
||||
|
||||
/*
|
||||
* When a domain policy is instantiated by invoking activateDomainPolicy() on
|
||||
* nsIScriptSecurityManager, these domain sets are consulted when each new
|
||||
@@ -20,7 +30,7 @@ interface nsIDomainSet;
|
||||
* When deactivate() is invoked, the domain sets are emptied, and the
|
||||
* nsIDomainPolicy ceases to have any effect on the system.
|
||||
*/
|
||||
[scriptable, builtinclass, uuid(27b10f54-f34b-42b7-8594-4348d3ad7953)]
|
||||
[scriptable, builtinclass, uuid(82b24a20-6701-4d40-a0f9-f5dc7321b555)]
|
||||
interface nsIDomainPolicy : nsISupports
|
||||
{
|
||||
readonly attribute nsIDomainSet blacklist;
|
||||
@@ -29,11 +39,19 @@ interface nsIDomainPolicy : nsISupports
|
||||
readonly attribute nsIDomainSet superWhitelist;
|
||||
|
||||
void deactivate();
|
||||
|
||||
[noscript, notxpcom] void cloneDomainPolicy(in DomainPolicyClonePtr aClone);
|
||||
[noscript, notxpcom] void applyClone(in DomainPolicyClonePtr aClone);
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(946a01ff-6525-4007-a2c2-447ebe1875d3)]
|
||||
[scriptable, builtinclass, uuid(665c981b-0a0f-4229-ac06-a826e02d4f69)]
|
||||
interface nsIDomainSet : nsISupports
|
||||
{
|
||||
/*
|
||||
* The type of the set. See: DomainSetType
|
||||
*/
|
||||
[noscript] readonly attribute uint32_t type;
|
||||
|
||||
/*
|
||||
* Add a domain to the set. No-op if it already exists.
|
||||
*/
|
||||
|
||||
@@ -14,12 +14,19 @@ interface nsILoadContext;
|
||||
|
||||
%{ C++
|
||||
#include "jspubtd.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class DomainPolicyClone;
|
||||
}
|
||||
}
|
||||
%}
|
||||
|
||||
[ptr] native JSContextPtr(JSContext);
|
||||
[ptr] native JSObjectPtr(JSObject);
|
||||
[ptr] native DomainPolicyClonePtr(mozilla::dom::DomainPolicyClone);
|
||||
|
||||
[scriptable, uuid(f649959d-dae3-4027-83fd-5b7f8c8a8815)]
|
||||
[scriptable, uuid(ba602ca6-dc7a-457e-a57a-ee5b343fd863)]
|
||||
interface nsIScriptSecurityManager : nsISupports
|
||||
{
|
||||
/**
|
||||
@@ -240,6 +247,22 @@ interface nsIScriptSecurityManager : nsISupports
|
||||
nsIDomainPolicy activateDomainPolicy();
|
||||
readonly attribute boolean domainPolicyActive;
|
||||
|
||||
/**
|
||||
* Only the parent process can directly access domain policies, child
|
||||
* processes only have a read-only mirror to the one in the parent.
|
||||
* For child processes the mirror is updated via messages
|
||||
* and ContentChild will hold the DomainPolicy by calling
|
||||
* ActivateDomainPolicyInternal directly. New consumer to this
|
||||
* function should not be addded.
|
||||
*/
|
||||
[noscript] nsIDomainPolicy activateDomainPolicyInternal();
|
||||
|
||||
/**
|
||||
* This function is for internal use only. Every time a child process is spawned, we
|
||||
* must clone any active domain policies in the parent to the new child.
|
||||
*/
|
||||
[noscript, notxpcom] void cloneDomainPolicy(in DomainPolicyClonePtr aClone);
|
||||
|
||||
/**
|
||||
* Query mechanism for the above policy.
|
||||
*
|
||||
|
||||
@@ -1320,9 +1320,14 @@ static StaticRefPtr<nsScriptSecurityManager> gScriptSecMan;
|
||||
nsScriptSecurityManager::~nsScriptSecurityManager(void)
|
||||
{
|
||||
Preferences::RemoveObservers(this, kObservedPrefs);
|
||||
if (mDomainPolicy)
|
||||
if (mDomainPolicy) {
|
||||
mDomainPolicy->Deactivate();
|
||||
MOZ_ASSERT(!mDomainPolicy);
|
||||
}
|
||||
// ContentChild might hold a reference to the domain policy,
|
||||
// and it might release it only after the security manager is
|
||||
// gone. But we can still assert this for the main process.
|
||||
MOZ_ASSERT_IF(XRE_GetProcessType() == GoannaProcessType_Default,
|
||||
!mDomainPolicy);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1537,6 +1542,16 @@ nsScriptSecurityManager::GetDomainPolicyActive(bool *aRv)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScriptSecurityManager::ActivateDomainPolicy(nsIDomainPolicy** aRv)
|
||||
{
|
||||
if (XRE_GetProcessType() != GoannaProcessType_Default) {
|
||||
return NS_ERROR_SERVICE_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return ActivateDomainPolicyInternal(aRv);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScriptSecurityManager::ActivateDomainPolicyInternal(nsIDomainPolicy** aRv)
|
||||
{
|
||||
// We only allow one domain policy at a time. The holder of the previous
|
||||
// policy must explicitly deactivate it first.
|
||||
@@ -1558,6 +1573,17 @@ nsScriptSecurityManager::DeactivateDomainPolicy()
|
||||
mDomainPolicy = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
nsScriptSecurityManager::CloneDomainPolicy(DomainPolicyClone* aClone)
|
||||
{
|
||||
MOZ_ASSERT(aClone);
|
||||
if (mDomainPolicy) {
|
||||
mDomainPolicy->CloneDomainPolicy(aClone);
|
||||
} else {
|
||||
aClone->active() = false;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScriptSecurityManager::PolicyAllowsScript(nsIURI* aURI, bool *aRv)
|
||||
{
|
||||
|
||||
@@ -13154,8 +13154,8 @@ nsGlobalWindow::SuspendTimeouts(uint32_t aIncrease,
|
||||
}
|
||||
DisableGamepadUpdates();
|
||||
|
||||
// Suspend all of the workers for this window.
|
||||
mozilla::dom::workers::SuspendWorkersForWindow(this);
|
||||
// Freeze all of the workers for this window.
|
||||
mozilla::dom::workers::FreezeWorkersForWindow(this);
|
||||
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
for (nsTimeout *t = mTimeouts.getFirst(); t; t = t->getNext()) {
|
||||
@@ -13243,8 +13243,8 @@ nsGlobalWindow::ResumeTimeouts(bool aThawChildren)
|
||||
mAudioContexts[i]->Resume();
|
||||
}
|
||||
|
||||
// Resume all of the workers for this window.
|
||||
mozilla::dom::workers::ResumeWorkersForWindow(this);
|
||||
// Thaw all of the workers for this window.
|
||||
mozilla::dom::workers::ThawWorkersForWindow(this);
|
||||
|
||||
// Restore all of the timeouts, using the stored time remaining
|
||||
// (stored in timeout->mTimeRemaining).
|
||||
|
||||
@@ -1513,7 +1513,7 @@ DOMInterfaces = {
|
||||
'headerFile': 'mozilla/dom/WorkerScope.h',
|
||||
'nativeType': 'mozilla::dom::workers::WorkerDebuggerGlobalScope',
|
||||
'implicitJSContext': [
|
||||
'dump', 'global',
|
||||
'dump', 'global', 'setImmediate', 'reportError',
|
||||
],
|
||||
},
|
||||
|
||||
|
||||
Vendored
+1
@@ -93,6 +93,7 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(mozilla::dom::cache::Cache)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Cache)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
Cache::Cache(nsIGlobalObject* aGlobal, CacheChild* aActor)
|
||||
|
||||
Vendored
+1
@@ -55,6 +55,7 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(mozilla::dom::cache::CacheStorage)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CacheStorage)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIIPCBackgroundChildCreateCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIIPCBackgroundChildCreateCallback)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "mozilla/docshell/OfflineCacheUpdateChild.h"
|
||||
#include "mozilla/dom/ContentBridgeChild.h"
|
||||
#include "mozilla/dom/ContentBridgeParent.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/DOMStorageIPC.h"
|
||||
#include "mozilla/dom/ExternalHelperAppChild.h"
|
||||
#include "mozilla/dom/ProcessGlobal.h"
|
||||
@@ -108,8 +109,9 @@
|
||||
#include "mozilla/dom/PMemoryReportRequestChild.h"
|
||||
#include "mozilla/dom/PCycleCollectWithLogsChild.h"
|
||||
|
||||
#ifdef MOZ_PERMISSIONS
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
|
||||
#ifdef MOZ_PERMISSIONS
|
||||
#include "nsPermission.h"
|
||||
#include "nsPermissionManager.h"
|
||||
#endif
|
||||
@@ -166,6 +168,7 @@
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsDeviceStorage.h"
|
||||
#include "AudioChannelService.h"
|
||||
#include "DomainPolicy.h"
|
||||
#include "mozilla/dom/DataStoreService.h"
|
||||
#include "mozilla/dom/telephony/PTelephonyChild.h"
|
||||
#include "mozilla/dom/time/DateCacheCleaner.h"
|
||||
@@ -739,9 +742,21 @@ ContentChild::InitXPCOM()
|
||||
|
||||
bool isOffline;
|
||||
ClipboardCapabilities clipboardCaps;
|
||||
SendGetXPCOMProcessAttributes(&isOffline, &mAvailableDictionaries, &clipboardCaps);
|
||||
DomainPolicyClone domainPolicy;
|
||||
|
||||
SendGetXPCOMProcessAttributes(&isOffline, &mAvailableDictionaries, &clipboardCaps, &domainPolicy);
|
||||
RecvSetOffline(isOffline);
|
||||
|
||||
if (domainPolicy.active()) {
|
||||
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
|
||||
MOZ_ASSERT(ssm);
|
||||
ssm->ActivateDomainPolicyInternal(getter_AddRefs(mPolicy));
|
||||
if (!mPolicy) {
|
||||
MOZ_CRASH("Failed to activate domain policy.");
|
||||
}
|
||||
mPolicy->ApplyClone(&domainPolicy);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIClipboard> clipboard(do_GetService("@mozilla.org/widget/clipboard;1"));
|
||||
if (nsCOMPtr<nsIClipboardProxy> clipboardProxy = do_QueryInterface(clipboard)) {
|
||||
clipboardProxy->SetCapabilities(clipboardCaps);
|
||||
@@ -2528,9 +2543,83 @@ ContentChild::RecvAssociatePluginId(const uint32_t& aPluginId,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::RecvDomainSetChanged(const uint32_t& aSetType, const uint32_t& aChangeType,
|
||||
const OptionalURIParams& aDomain)
|
||||
{
|
||||
if (aChangeType == ACTIVATE_POLICY) {
|
||||
if (mPolicy) {
|
||||
return true;
|
||||
}
|
||||
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
|
||||
MOZ_ASSERT(ssm);
|
||||
ssm->ActivateDomainPolicyInternal(getter_AddRefs(mPolicy));
|
||||
return !!mPolicy;
|
||||
} else if (!mPolicy) {
|
||||
MOZ_ASSERT_UNREACHABLE("If the domain policy is not active yet,"
|
||||
" the first message should be ACTIVATE_POLICY");
|
||||
return false;
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(mPolicy, false);
|
||||
|
||||
if (aChangeType == DEACTIVATE_POLICY) {
|
||||
mPolicy->Deactivate();
|
||||
mPolicy = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDomainSet> set;
|
||||
switch(aSetType) {
|
||||
case BLACKLIST:
|
||||
mPolicy->GetBlacklist(getter_AddRefs(set));
|
||||
break;
|
||||
case SUPER_BLACKLIST:
|
||||
mPolicy->GetSuperBlacklist(getter_AddRefs(set));
|
||||
break;
|
||||
case WHITELIST:
|
||||
mPolicy->GetWhitelist(getter_AddRefs(set));
|
||||
break;
|
||||
case SUPER_WHITELIST:
|
||||
mPolicy->GetSuperWhitelist(getter_AddRefs(set));
|
||||
break;
|
||||
default:
|
||||
NS_NOTREACHED("Unexpected setType");
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(set);
|
||||
|
||||
nsCOMPtr<nsIURI> uri = DeserializeURI(aDomain);
|
||||
|
||||
switch(aChangeType) {
|
||||
case ADD_DOMAIN:
|
||||
NS_ENSURE_TRUE(uri, false);
|
||||
set->Add(uri);
|
||||
break;
|
||||
case REMOVE_DOMAIN:
|
||||
NS_ENSURE_TRUE(uri, false);
|
||||
set->Remove(uri);
|
||||
break;
|
||||
case CLEAR_DOMAINS:
|
||||
set->Clear();
|
||||
break;
|
||||
default:
|
||||
NS_NOTREACHED("Unexpected changeType");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::RecvShutdown()
|
||||
{
|
||||
if (mPolicy) {
|
||||
mPolicy->Deactivate();
|
||||
mPolicy = nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||
if (os) {
|
||||
os->NotifyObservers(this, "content-child-shutdown", nullptr);
|
||||
|
||||
@@ -24,6 +24,7 @@ class nsIDOMBlob;
|
||||
class nsIObserver;
|
||||
struct ResourceMapping;
|
||||
struct OverrideMapping;
|
||||
class nsIDomainPolicy;
|
||||
|
||||
namespace mozilla {
|
||||
class RemoteSpellcheckEngineChild;
|
||||
@@ -378,6 +379,8 @@ public:
|
||||
nsTArray<nsCString>&& aThreadNameFilters) override;
|
||||
virtual bool RecvStopProfiler() override;
|
||||
virtual bool RecvGetProfile(nsCString* aProfile) override;
|
||||
virtual bool RecvDomainSetChanged(const uint32_t& aSetType, const uint32_t& aChangeType,
|
||||
const OptionalURIParams& aDomain) override;
|
||||
virtual bool RecvShutdown() override;
|
||||
|
||||
#ifdef ANDROID
|
||||
@@ -475,6 +478,8 @@ private:
|
||||
|
||||
static ContentChild* sSingleton;
|
||||
|
||||
nsCOMPtr<nsIDomainPolicy> mPolicy;
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(ContentChild);
|
||||
};
|
||||
|
||||
|
||||
@@ -2710,8 +2710,9 @@ ContentParent::RecvAddNewProcess(const uint32_t& aPid,
|
||||
bool isOffline;
|
||||
InfallibleTArray<nsString> unusedDictionaries;
|
||||
ClipboardCapabilities clipboardCaps;
|
||||
DomainPolicyClone domainPolicy;
|
||||
RecvGetXPCOMProcessAttributes(&isOffline, &unusedDictionaries,
|
||||
&clipboardCaps);
|
||||
&clipboardCaps, &domainPolicy);
|
||||
mozilla::unused << content->SendSetOffline(isOffline);
|
||||
MOZ_ASSERT(!clipboardCaps.supportsSelectionClipboard() &&
|
||||
!clipboardCaps.supportsFindClipboard(),
|
||||
@@ -3022,7 +3023,8 @@ ContentParent::RecvGetProcessAttributes(ContentParentId* aCpId,
|
||||
bool
|
||||
ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
|
||||
InfallibleTArray<nsString>* dictionaries,
|
||||
ClipboardCapabilities* clipboardCaps)
|
||||
ClipboardCapabilities* clipboardCaps,
|
||||
DomainPolicyClone* domainPolicy)
|
||||
{
|
||||
nsCOMPtr<nsIIOService> io(do_GetIOService());
|
||||
MOZ_ASSERT(io, "No IO service?");
|
||||
@@ -3043,6 +3045,11 @@ ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
|
||||
rv = clipboard->SupportsFindClipboard(&clipboardCaps->supportsFindClipboard());
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
||||
// Let's copy the domain policy from the parent to the child (if it's active).
|
||||
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
|
||||
NS_ENSURE_TRUE(ssm, false);
|
||||
ssm->CloneDomainPolicy(domainPolicy);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -497,7 +497,8 @@ private:
|
||||
bool* aIsForBrowser) override;
|
||||
virtual bool RecvGetXPCOMProcessAttributes(bool* aIsOffline,
|
||||
InfallibleTArray<nsString>* dictionaries,
|
||||
ClipboardCapabilities* clipboardCaps)
|
||||
ClipboardCapabilities* clipboardCaps,
|
||||
DomainPolicyClone* domainPolicy)
|
||||
override;
|
||||
|
||||
virtual bool DeallocPJavaScriptParent(mozilla::jsipc::PJavaScriptParent*) override;
|
||||
|
||||
+13
-1
@@ -345,6 +345,15 @@ union OptionalContentId
|
||||
void_t;
|
||||
};
|
||||
|
||||
struct DomainPolicyClone
|
||||
{
|
||||
bool active;
|
||||
URIParams[] blacklist;
|
||||
URIParams[] whitelist;
|
||||
URIParams[] superBlacklist;
|
||||
URIParams[] superWhitelist;
|
||||
};
|
||||
|
||||
prio(normal upto urgent) sync protocol PContent
|
||||
{
|
||||
parent spawns PPluginModule;
|
||||
@@ -550,6 +559,8 @@ child:
|
||||
|
||||
NuwaFreeze();
|
||||
|
||||
async DomainSetChanged(uint32_t aSetType, uint32_t aChangeType, OptionalURIParams aDomain);
|
||||
|
||||
/**
|
||||
* Notify the child to shutdown. The child will in turn call FinishShutdown
|
||||
* and let the parent close the channel.
|
||||
@@ -584,7 +595,8 @@ parent:
|
||||
returns (ContentParentId cpId, bool isForApp, bool isForBrowser);
|
||||
sync GetXPCOMProcessAttributes()
|
||||
returns (bool isOffline, nsString[] dictionaries,
|
||||
ClipboardCapabilities clipboardCaps);
|
||||
ClipboardCapabilities clipboardCaps,
|
||||
DomainPolicyClone domainPolicy);
|
||||
|
||||
sync CreateChildProcess(IPCTabContext context,
|
||||
ProcessPriority priority,
|
||||
|
||||
@@ -147,6 +147,7 @@ for var in ('MOZ_PERMISSIONS', 'MOZ_CHILD_PERMISSIONS'):
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['tests/browser.ini']
|
||||
MOCHITEST_CHROME_MANIFESTS += ['tests/chrome.ini']
|
||||
MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
|
||||
|
||||
|
||||
@@ -6,6 +6,24 @@
|
||||
[Global=(WorkerDebugger), Exposed=WorkerDebugger]
|
||||
interface WorkerDebuggerGlobalScope : EventTarget {
|
||||
readonly attribute object global;
|
||||
|
||||
object createSandbox(DOMString name, object prototype);
|
||||
|
||||
[Throws]
|
||||
void loadSubScript(DOMString url, optional object sandbox);
|
||||
|
||||
void enterEventLoop();
|
||||
|
||||
void leaveEventLoop();
|
||||
|
||||
void postMessage(DOMString message);
|
||||
|
||||
attribute EventHandler onmessage;
|
||||
|
||||
[Throws]
|
||||
void setImmediate(Function handler);
|
||||
|
||||
void reportError(DOMString message);
|
||||
};
|
||||
|
||||
// So you can debug while you debug
|
||||
|
||||
@@ -280,7 +280,7 @@ MessagePort::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
|
||||
if (IsClosed()) {
|
||||
preventDispatch = true;
|
||||
} else if (NS_IsMainThread() && mSharedWorker->IsSuspended()) {
|
||||
} else if (NS_IsMainThread() && mSharedWorker->IsFrozen()) {
|
||||
mSharedWorker->QueueEvent(event);
|
||||
preventDispatch = true;
|
||||
} else if (!mStarted) {
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
|
||||
#include "Principal.h"
|
||||
#include "SharedWorker.h"
|
||||
#include "WorkerDebuggerManager.h"
|
||||
#include "WorkerPrivate.h"
|
||||
#include "WorkerRunnable.h"
|
||||
#include "WorkerThread.h"
|
||||
@@ -870,14 +871,14 @@ JSObject*
|
||||
Wrap(JSContext *cx, JS::HandleObject existing, JS::HandleObject obj)
|
||||
{
|
||||
JSObject* targetGlobal = JS::CurrentGlobalOrNull(cx);
|
||||
if (!IsDebuggerGlobal(targetGlobal)) {
|
||||
if (!IsDebuggerGlobal(targetGlobal) && !IsDebuggerSandbox(targetGlobal)) {
|
||||
MOZ_CRASH("There should be no edges from the debuggee to the debugger.");
|
||||
}
|
||||
|
||||
JSObject* originGlobal = js::GetGlobalForObjectCrossCompartment(obj);
|
||||
|
||||
const js::Wrapper* wrapper = nullptr;
|
||||
if (IsDebuggerGlobal(originGlobal)) {
|
||||
if (IsDebuggerGlobal(originGlobal) || IsDebuggerSandbox(originGlobal)) {
|
||||
wrapper = &js::CrossCompartmentWrapper::singleton;
|
||||
} else {
|
||||
if (obj != originGlobal) {
|
||||
@@ -1243,22 +1244,22 @@ CancelWorkersForWindow(nsPIDOMWindow* aWindow)
|
||||
}
|
||||
|
||||
void
|
||||
SuspendWorkersForWindow(nsPIDOMWindow* aWindow)
|
||||
FreezeWorkersForWindow(nsPIDOMWindow* aWindow)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
RuntimeService* runtime = RuntimeService::GetService();
|
||||
if (runtime) {
|
||||
runtime->SuspendWorkersForWindow(aWindow);
|
||||
runtime->FreezeWorkersForWindow(aWindow);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ResumeWorkersForWindow(nsPIDOMWindow* aWindow)
|
||||
ThawWorkersForWindow(nsPIDOMWindow* aWindow)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
RuntimeService* runtime = RuntimeService::GetService();
|
||||
if (runtime) {
|
||||
runtime->ResumeWorkersForWindow(aWindow);
|
||||
runtime->ThawWorkersForWindow(aWindow);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1918,6 +1919,12 @@ RuntimeService::Shutdown()
|
||||
// That's it, no more workers.
|
||||
mShuttingDown = true;
|
||||
|
||||
// Remove all listeners from the worker debugger manager to ensure that it
|
||||
// gets properly destroyed.
|
||||
if (NS_FAILED(ClearWorkerDebuggerManagerListeners())) {
|
||||
NS_WARNING("Failed to clear worker debugger manager listeners!");
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
NS_WARN_IF_FALSE(obs, "Failed to get observer service?!");
|
||||
|
||||
@@ -2211,7 +2218,7 @@ RuntimeService::CancelWorkersForWindow(nsPIDOMWindow* aWindow)
|
||||
}
|
||||
|
||||
void
|
||||
RuntimeService::SuspendWorkersForWindow(nsPIDOMWindow* aWindow)
|
||||
RuntimeService::FreezeWorkersForWindow(nsPIDOMWindow* aWindow)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aWindow);
|
||||
@@ -2227,7 +2234,7 @@ RuntimeService::SuspendWorkersForWindow(nsPIDOMWindow* aWindow)
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
for (uint32_t index = 0; index < workers.Length(); index++) {
|
||||
if (!workers[index]->Suspend(cx, aWindow)) {
|
||||
if (!workers[index]->Freeze(cx, aWindow)) {
|
||||
JS_ReportPendingException(cx);
|
||||
}
|
||||
}
|
||||
@@ -2235,7 +2242,7 @@ RuntimeService::SuspendWorkersForWindow(nsPIDOMWindow* aWindow)
|
||||
}
|
||||
|
||||
void
|
||||
RuntimeService::ResumeWorkersForWindow(nsPIDOMWindow* aWindow)
|
||||
RuntimeService::ThawWorkersForWindow(nsPIDOMWindow* aWindow)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aWindow);
|
||||
@@ -2251,7 +2258,7 @@ RuntimeService::ResumeWorkersForWindow(nsPIDOMWindow* aWindow)
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
for (uint32_t index = 0; index < workers.Length(); index++) {
|
||||
if (!workers[index]->SynchronizeAndResume(cx, aWindow)) {
|
||||
if (!workers[index]->Thaw(cx, aWindow)) {
|
||||
JS_ReportPendingException(cx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,10 +129,10 @@ public:
|
||||
CancelWorkersForWindow(nsPIDOMWindow* aWindow);
|
||||
|
||||
void
|
||||
SuspendWorkersForWindow(nsPIDOMWindow* aWindow);
|
||||
FreezeWorkersForWindow(nsPIDOMWindow* aWindow);
|
||||
|
||||
void
|
||||
ResumeWorkersForWindow(nsPIDOMWindow* aWindow);
|
||||
ThawWorkersForWindow(nsPIDOMWindow* aWindow);
|
||||
|
||||
nsresult
|
||||
CreateSharedWorker(const GlobalObject& aGlobal,
|
||||
|
||||
@@ -53,7 +53,8 @@ ChannelFromScriptURL(nsIPrincipal* principal,
|
||||
nsIIOService* ios,
|
||||
nsIScriptSecurityManager* secMan,
|
||||
const nsAString& aScriptURL,
|
||||
bool aIsWorkerScript,
|
||||
bool aIsMainScript,
|
||||
WorkerScriptType aWorkerScriptType,
|
||||
nsIChannel** aChannel)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
@@ -84,10 +85,22 @@ ChannelFromScriptURL(nsIPrincipal* principal,
|
||||
}
|
||||
}
|
||||
|
||||
// If this script loader is being used to make a new worker then we need
|
||||
// to do a same-origin check. Otherwise we need to clear the load with the
|
||||
// security manager.
|
||||
if (aIsWorkerScript) {
|
||||
if (aWorkerScriptType == DebuggerScript) {
|
||||
bool isChrome = false;
|
||||
NS_ENSURE_SUCCESS(uri->SchemeIs("chrome", &isChrome),
|
||||
NS_ERROR_DOM_SECURITY_ERR);
|
||||
|
||||
bool isResource = false;
|
||||
NS_ENSURE_SUCCESS(uri->SchemeIs("resource", &isResource),
|
||||
NS_ERROR_DOM_SECURITY_ERR);
|
||||
|
||||
if (!isChrome && !isResource) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
} else if (aIsMainScript) {
|
||||
// If this script loader is being used to make a new worker then we need
|
||||
// to do a same-origin check. Otherwise we need to clear the load with the
|
||||
// security manager.
|
||||
nsCString scheme;
|
||||
rv = uri->GetScheme(scheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@@ -190,6 +203,9 @@ private:
|
||||
~ScriptExecutorRunnable()
|
||||
{ }
|
||||
|
||||
virtual bool
|
||||
IsDebuggerRunnable() const override;
|
||||
|
||||
virtual bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override;
|
||||
|
||||
@@ -214,7 +230,8 @@ class ScriptLoaderRunnable final : public WorkerFeature,
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
|
||||
nsTArray<ScriptLoadInfo> mLoadInfos;
|
||||
bool mIsWorkerScript;
|
||||
bool mIsMainScript;
|
||||
WorkerScriptType mWorkerScriptType;
|
||||
bool mCanceled;
|
||||
bool mCanceledMainThread;
|
||||
|
||||
@@ -224,14 +241,15 @@ public:
|
||||
ScriptLoaderRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
nsIEventTarget* aSyncLoopTarget,
|
||||
nsTArray<ScriptLoadInfo>& aLoadInfos,
|
||||
bool aIsWorkerScript)
|
||||
bool aIsMainScript,
|
||||
WorkerScriptType aWorkerScriptType)
|
||||
: mWorkerPrivate(aWorkerPrivate), mSyncLoopTarget(aSyncLoopTarget),
|
||||
mIsWorkerScript(aIsWorkerScript), mCanceled(false),
|
||||
mCanceledMainThread(false)
|
||||
mIsMainScript(aIsMainScript), mWorkerScriptType(aWorkerScriptType),
|
||||
mCanceled(false), mCanceledMainThread(false)
|
||||
{
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(aSyncLoopTarget);
|
||||
MOZ_ASSERT_IF(aIsWorkerScript, aLoadInfos.Length() == 1);
|
||||
MOZ_ASSERT_IF(aIsMainScript, aLoadInfos.Length() == 1);
|
||||
|
||||
mLoadInfos.SwapElements(aLoadInfos);
|
||||
}
|
||||
@@ -300,6 +318,12 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IsMainWorkerScript() const
|
||||
{
|
||||
return mIsMainScript && mWorkerScriptType == WorkerScript;
|
||||
}
|
||||
|
||||
void
|
||||
CancelMainThread()
|
||||
{
|
||||
@@ -338,7 +362,7 @@ private:
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = mWorkerPrivate->GetLoadGroup();
|
||||
if (!principal) {
|
||||
NS_ASSERTION(parentWorker, "Must have a principal!");
|
||||
NS_ASSERTION(mIsWorkerScript, "Must have a principal for importScripts!");
|
||||
NS_ASSERTION(mIsMainScript, "Must have a principal for importScripts!");
|
||||
|
||||
principal = parentWorker->GetPrincipal();
|
||||
loadGroup = parentWorker->GetLoadGroup();
|
||||
@@ -348,7 +372,7 @@ private:
|
||||
|
||||
// Figure out our base URI.
|
||||
nsCOMPtr<nsIURI> baseURI;
|
||||
if (mIsWorkerScript) {
|
||||
if (mIsMainScript) {
|
||||
if (parentWorker) {
|
||||
baseURI = parentWorker->GetBaseURI();
|
||||
NS_ASSERTION(baseURI, "Should have been set already!");
|
||||
@@ -367,7 +391,7 @@ private:
|
||||
nsCOMPtr<nsIDocument> parentDoc = mWorkerPrivate->GetDocument();
|
||||
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
if (mIsWorkerScript) {
|
||||
if (IsMainWorkerScript()) {
|
||||
// May be null.
|
||||
channel = mWorkerPrivate->ForgetWorkerChannel();
|
||||
}
|
||||
@@ -383,8 +407,8 @@ private:
|
||||
|
||||
if (!channel) {
|
||||
rv = ChannelFromScriptURL(principal, baseURI, parentDoc, loadGroup, ios,
|
||||
secMan, loadInfo.mURL, mIsWorkerScript,
|
||||
getter_AddRefs(channel));
|
||||
secMan, loadInfo.mURL, mIsMainScript,
|
||||
mWorkerScriptType, getter_AddRefs(channel));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
@@ -489,7 +513,7 @@ private:
|
||||
|
||||
// Update the principal of the worker and its base URI if we just loaded the
|
||||
// worker's primary script.
|
||||
if (mIsWorkerScript) {
|
||||
if (IsMainWorkerScript()) {
|
||||
// Take care of the base URI first.
|
||||
mWorkerPrivate->SetBaseURI(finalURI);
|
||||
|
||||
@@ -572,7 +596,7 @@ private:
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
if (mIsWorkerScript) {
|
||||
if (IsMainWorkerScript()) {
|
||||
mWorkerPrivate->WorkerScriptLoaded();
|
||||
}
|
||||
|
||||
@@ -699,6 +723,15 @@ ScriptExecutorRunnable::ScriptExecutorRunnable(
|
||||
MOZ_ASSERT(aLastIndex < aScriptLoader.mLoadInfos.Length());
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptExecutorRunnable::IsDebuggerRunnable() const
|
||||
{
|
||||
// ScriptExecutorRunnable is used to execute both worker and debugger scripts.
|
||||
// In the latter case, the runnable needs to be dispatched to the debugger
|
||||
// queue.
|
||||
return mScriptLoader.mWorkerScriptType == DebuggerScript;
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptExecutorRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
@@ -757,6 +790,10 @@ ScriptExecutorRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
options.setFileAndLine(filename.get(), 1)
|
||||
.setNoScriptRval(true);
|
||||
|
||||
if (mScriptLoader.mWorkerScriptType == DebuggerScript) {
|
||||
options.setVersion(JSVERSION_LATEST);
|
||||
}
|
||||
|
||||
JS::SourceBufferHolder srcBuf(loadInfo.mScriptTextBuf,
|
||||
loadInfo.mScriptTextLength,
|
||||
JS::SourceBufferHolder::GiveOwnership);
|
||||
@@ -814,7 +851,8 @@ ScriptExecutorRunnable::ShutdownScriptLoader(JSContext* aCx,
|
||||
|
||||
bool
|
||||
LoadAllScripts(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
||||
nsTArray<ScriptLoadInfo>& aLoadInfos, bool aIsWorkerScript)
|
||||
nsTArray<ScriptLoadInfo>& aLoadInfos, bool aIsMainScript,
|
||||
WorkerScriptType aWorkerScriptType)
|
||||
{
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
NS_ASSERTION(!aLoadInfos.IsEmpty(), "Bad arguments!");
|
||||
@@ -823,7 +861,7 @@ LoadAllScripts(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
||||
|
||||
nsRefPtr<ScriptLoaderRunnable> loader =
|
||||
new ScriptLoaderRunnable(aWorkerPrivate, syncLoop.EventTarget(),
|
||||
aLoadInfos, aIsWorkerScript);
|
||||
aLoadInfos, aIsMainScript, aWorkerScriptType);
|
||||
|
||||
NS_ASSERTION(aLoadInfos.IsEmpty(), "Should have swapped!");
|
||||
|
||||
@@ -863,7 +901,7 @@ ChannelFromScriptURLMainThread(nsIPrincipal* aPrincipal,
|
||||
NS_ASSERTION(secMan, "This should never be null!");
|
||||
|
||||
return ChannelFromScriptURL(aPrincipal, aBaseURI, aParentDoc, aLoadGroup,
|
||||
ios, secMan, aScriptURL, true, aChannel);
|
||||
ios, secMan, aScriptURL, true, WorkerScript, aChannel);
|
||||
}
|
||||
|
||||
nsresult
|
||||
@@ -922,7 +960,8 @@ void ReportLoadError(JSContext* aCx, const nsAString& aURL,
|
||||
}
|
||||
|
||||
bool
|
||||
LoadWorkerScript(JSContext* aCx)
|
||||
LoadMainScript(JSContext* aCx, const nsAString& aScriptURL,
|
||||
WorkerScriptType aWorkerScriptType)
|
||||
{
|
||||
WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
|
||||
NS_ASSERTION(worker, "This should never be null!");
|
||||
@@ -930,14 +969,15 @@ LoadWorkerScript(JSContext* aCx)
|
||||
nsTArray<ScriptLoadInfo> loadInfos;
|
||||
|
||||
ScriptLoadInfo* info = loadInfos.AppendElement();
|
||||
info->mURL = worker->ScriptURL();
|
||||
info->mURL = aScriptURL;
|
||||
|
||||
return LoadAllScripts(aCx, worker, loadInfos, true);
|
||||
return LoadAllScripts(aCx, worker, loadInfos, true, aWorkerScriptType);
|
||||
}
|
||||
|
||||
void
|
||||
Load(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
||||
const Sequence<nsString>& aScriptURLs, ErrorResult& aRv)
|
||||
const nsTArray<nsString>& aScriptURLs, WorkerScriptType aWorkerScriptType,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
const uint32_t urlCount = aScriptURLs.Length();
|
||||
|
||||
@@ -957,7 +997,7 @@ Load(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
||||
loadInfos[index].mURL = aScriptURLs[index];
|
||||
}
|
||||
|
||||
if (!LoadAllScripts(aCx, aWorkerPrivate, loadInfos, false)) {
|
||||
if (!LoadAllScripts(aCx, aWorkerPrivate, loadInfos, false, aWorkerScriptType)) {
|
||||
// LoadAllScripts can fail if we're shutting down.
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,11 @@ class Sequence;
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
enum WorkerScriptType {
|
||||
WorkerScript,
|
||||
DebuggerScript
|
||||
};
|
||||
|
||||
namespace scriptloader {
|
||||
|
||||
nsresult
|
||||
@@ -48,11 +53,13 @@ ChannelFromScriptURLWorkerThread(JSContext* aCx,
|
||||
void ReportLoadError(JSContext* aCx, const nsAString& aURL,
|
||||
nsresult aLoadResult, bool aIsMainThread);
|
||||
|
||||
bool LoadWorkerScript(JSContext* aCx);
|
||||
bool LoadMainScript(JSContext* aCx, const nsAString& aScriptURL,
|
||||
WorkerScriptType aWorkerScriptType);
|
||||
|
||||
void Load(JSContext* aCx,
|
||||
WorkerPrivate* aWorkerPrivate,
|
||||
const mozilla::dom::Sequence<nsString>& aScriptURLs,
|
||||
const nsTArray<nsString>& aScriptURLs,
|
||||
WorkerScriptType aWorkerScriptType,
|
||||
mozilla::ErrorResult& aRv);
|
||||
|
||||
} // namespace scriptloader
|
||||
|
||||
@@ -27,7 +27,7 @@ USING_WORKERS_NAMESPACE
|
||||
SharedWorker::SharedWorker(nsPIDOMWindow* aWindow,
|
||||
WorkerPrivate* aWorkerPrivate)
|
||||
: DOMEventTargetHelper(aWindow), mWorkerPrivate(aWorkerPrivate),
|
||||
mSuspended(false)
|
||||
mFrozen(false)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
@@ -85,25 +85,25 @@ SharedWorker::Port()
|
||||
}
|
||||
|
||||
void
|
||||
SharedWorker::Suspend()
|
||||
SharedWorker::Freeze()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(!IsSuspended());
|
||||
MOZ_ASSERT(!IsFrozen());
|
||||
|
||||
mSuspended = true;
|
||||
mFrozen = true;
|
||||
}
|
||||
|
||||
void
|
||||
SharedWorker::Resume()
|
||||
SharedWorker::Thaw()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(IsSuspended());
|
||||
MOZ_ASSERT(IsFrozen());
|
||||
|
||||
mSuspended = false;
|
||||
mFrozen = false;
|
||||
|
||||
if (!mSuspendedEvents.IsEmpty()) {
|
||||
if (!mFrozenEvents.IsEmpty()) {
|
||||
nsTArray<nsCOMPtr<nsIDOMEvent>> events;
|
||||
mSuspendedEvents.SwapElements(events);
|
||||
mFrozenEvents.SwapElements(events);
|
||||
|
||||
for (uint32_t index = 0; index < events.Length(); index++) {
|
||||
nsCOMPtr<nsIDOMEvent>& event = events[index];
|
||||
@@ -127,9 +127,9 @@ SharedWorker::QueueEvent(nsIDOMEvent* aEvent)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aEvent);
|
||||
MOZ_ASSERT(IsSuspended());
|
||||
MOZ_ASSERT(IsFrozen());
|
||||
|
||||
mSuspendedEvents.AppendElement(aEvent);
|
||||
mFrozenEvents.AppendElement(aEvent);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -181,14 +181,14 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(SharedWorker)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SharedWorker,
|
||||
DOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessagePort)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuspendedEvents)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrozenEvents)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(SharedWorker,
|
||||
DOMEventTargetHelper)
|
||||
tmp->Close();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessagePort)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuspendedEvents)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrozenEvents)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
JSObject*
|
||||
@@ -206,7 +206,7 @@ SharedWorker::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
|
||||
nsIDOMEvent*& event = aVisitor.mDOMEvent;
|
||||
|
||||
if (IsSuspended() && event) {
|
||||
if (IsFrozen() && event) {
|
||||
QueueEvent(event);
|
||||
|
||||
aVisitor.mCanHandle = false;
|
||||
|
||||
@@ -35,9 +35,9 @@ class SharedWorker final : public DOMEventTargetHelper
|
||||
|
||||
nsRefPtr<WorkerPrivate> mWorkerPrivate;
|
||||
nsRefPtr<MessagePort> mMessagePort;
|
||||
nsTArray<nsCOMPtr<nsIDOMEvent>> mSuspendedEvents;
|
||||
nsTArray<nsCOMPtr<nsIDOMEvent>> mFrozenEvents;
|
||||
uint64_t mSerial;
|
||||
bool mSuspended;
|
||||
bool mFrozen;
|
||||
|
||||
public:
|
||||
static already_AddRefed<SharedWorker>
|
||||
@@ -55,16 +55,16 @@ public:
|
||||
}
|
||||
|
||||
bool
|
||||
IsSuspended() const
|
||||
IsFrozen() const
|
||||
{
|
||||
return mSuspended;
|
||||
return mFrozen;
|
||||
}
|
||||
|
||||
void
|
||||
Suspend();
|
||||
Freeze();
|
||||
|
||||
void
|
||||
Resume();
|
||||
Thaw();
|
||||
|
||||
void
|
||||
QueueEvent(nsIDOMEvent* aEvent);
|
||||
|
||||
@@ -141,6 +141,16 @@ WorkerDebuggerManager::RemoveListener(
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
WorkerDebuggerManager::ClearListeners()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
mListeners.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
WorkerDebuggerManager::RegisterDebugger(WorkerDebugger* aDebugger)
|
||||
{
|
||||
|
||||
@@ -41,9 +41,9 @@ public:
|
||||
static WorkerDebuggerManager*
|
||||
GetOrCreateService()
|
||||
{
|
||||
nsCOMPtr<nsIWorkerDebuggerManager> wdm =
|
||||
nsCOMPtr<nsIWorkerDebuggerManager> manager =
|
||||
do_GetService(WORKERDEBUGGERMANAGER_CONTRACTID);
|
||||
return static_cast<WorkerDebuggerManager*>(wdm.get());
|
||||
return static_cast<WorkerDebuggerManager*>(manager.get());
|
||||
}
|
||||
|
||||
WorkerDebuggerManager();
|
||||
@@ -51,6 +51,8 @@ public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIWORKERDEBUGGERMANAGER
|
||||
|
||||
void ClearListeners();
|
||||
|
||||
void RegisterDebugger(WorkerDebugger* aDebugger);
|
||||
|
||||
void UnregisterDebugger(WorkerDebugger* aDebugger);
|
||||
@@ -64,6 +66,19 @@ private:
|
||||
void UnregisterDebuggerOnMainThread(WorkerDebugger* aDebugger);
|
||||
};
|
||||
|
||||
inline nsresult
|
||||
ClearWorkerDebuggerManagerListeners()
|
||||
{
|
||||
nsRefPtr<WorkerDebuggerManager> manager =
|
||||
WorkerDebuggerManager::GetOrCreateService();
|
||||
if (!manager) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
manager->ClearListeners();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
inline nsresult
|
||||
RegisterWorkerDebugger(WorkerDebugger* aDebugger)
|
||||
{
|
||||
|
||||
+583
-187
File diff suppressed because it is too large
Load Diff
+76
-23
@@ -56,6 +56,8 @@ class PrincipalInfo;
|
||||
|
||||
struct PRThread;
|
||||
|
||||
class ReportDebuggerErrorRunnable;
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
class AutoSyncLoopHolder;
|
||||
@@ -122,8 +124,6 @@ public:
|
||||
template <class Derived>
|
||||
class WorkerPrivateParent : public DOMEventTargetHelper
|
||||
{
|
||||
class SynchronizeAndResumeRunnable;
|
||||
|
||||
protected:
|
||||
class EventTarget;
|
||||
friend class EventTarget;
|
||||
@@ -166,7 +166,6 @@ private:
|
||||
|
||||
// Only used for top level workers.
|
||||
nsTArray<nsCOMPtr<nsIRunnable>> mQueuedRunnables;
|
||||
nsRevocableEventPtr<SynchronizeAndResumeRunnable> mSynchronizeRunnable;
|
||||
|
||||
// Only for ChromeWorkers without window and only touched on the main thread.
|
||||
nsTArray<nsCString> mHostObjectURIs;
|
||||
@@ -181,7 +180,7 @@ private:
|
||||
uint64_t mBusyCount;
|
||||
uint64_t mMessagePortSerial;
|
||||
Status mParentStatus;
|
||||
bool mParentSuspended;
|
||||
bool mParentFrozen;
|
||||
bool mIsChromeWorker;
|
||||
bool mMainThreadObjectsForgotten;
|
||||
WorkerType mWorkerType;
|
||||
@@ -261,6 +260,9 @@ public:
|
||||
nsresult
|
||||
DispatchControlRunnable(WorkerControlRunnable* aWorkerControlRunnable);
|
||||
|
||||
nsresult
|
||||
DispatchDebuggerRunnable(WorkerRunnable* aDebuggerRunnable);
|
||||
|
||||
already_AddRefed<WorkerRunnable>
|
||||
MaybeWrapAsWorkerRunnable(nsIRunnable* aRunnable);
|
||||
|
||||
@@ -290,17 +292,13 @@ public:
|
||||
return Notify(aCx, Killing);
|
||||
}
|
||||
|
||||
// We can assume that an nsPIDOMWindow will be available for Suspend, Resume
|
||||
// and SynchronizeAndResume as these are only used for globals going in and
|
||||
// out of the bfcache.
|
||||
// We can assume that an nsPIDOMWindow will be available for Freeze, Thaw
|
||||
// as these are only used for globals going in and out of the bfcache.
|
||||
bool
|
||||
Suspend(JSContext* aCx, nsPIDOMWindow* aWindow);
|
||||
Freeze(JSContext* aCx, nsPIDOMWindow* aWindow);
|
||||
|
||||
bool
|
||||
Resume(JSContext* aCx, nsPIDOMWindow* aWindow);
|
||||
|
||||
bool
|
||||
SynchronizeAndResume(JSContext* aCx, nsPIDOMWindow* aWindow);
|
||||
Thaw(JSContext* aCx, nsPIDOMWindow* aWindow);
|
||||
|
||||
bool
|
||||
Terminate(JSContext* aCx)
|
||||
@@ -409,10 +407,10 @@ public:
|
||||
}
|
||||
|
||||
bool
|
||||
IsSuspended() const
|
||||
IsFrozen() const
|
||||
{
|
||||
AssertIsOnParentThread();
|
||||
return mParentSuspended;
|
||||
return mParentFrozen;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -718,6 +716,8 @@ public:
|
||||
};
|
||||
|
||||
class WorkerDebugger : public nsIWorkerDebugger {
|
||||
friend class ::ReportDebuggerErrorRunnable;
|
||||
|
||||
mozilla::Mutex mMutex;
|
||||
mozilla::CondVar mCondVar;
|
||||
|
||||
@@ -726,6 +726,8 @@ class WorkerDebugger : public nsIWorkerDebugger {
|
||||
bool mIsEnabled;
|
||||
|
||||
// Only touched on the main thread.
|
||||
bool mIsInitialized;
|
||||
bool mIsFrozen;
|
||||
nsTArray<nsCOMPtr<nsIWorkerDebuggerListener>> mListeners;
|
||||
|
||||
public:
|
||||
@@ -734,18 +736,51 @@ public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIWORKERDEBUGGER
|
||||
|
||||
void AssertIsOnParentThread();
|
||||
void
|
||||
AssertIsOnParentThread();
|
||||
|
||||
void WaitIsEnabled(bool aIsEnabled);
|
||||
void
|
||||
WaitIsEnabled(bool aIsEnabled);
|
||||
|
||||
void Enable();
|
||||
void
|
||||
Enable();
|
||||
|
||||
void Disable();
|
||||
void
|
||||
Disable();
|
||||
|
||||
void
|
||||
Freeze();
|
||||
|
||||
void
|
||||
Thaw();
|
||||
|
||||
void
|
||||
PostMessageToDebugger(const nsAString& aMessage);
|
||||
|
||||
void
|
||||
ReportErrorToDebugger(const nsAString& aFilename, uint32_t aLineno,
|
||||
const nsAString& aMessage);
|
||||
|
||||
private:
|
||||
virtual ~WorkerDebugger();
|
||||
virtual
|
||||
~WorkerDebugger();
|
||||
|
||||
void NotifyIsEnabled(bool aIsEnabled);
|
||||
void
|
||||
NotifyIsEnabled(bool aIsEnabled);
|
||||
|
||||
void
|
||||
FreezeOnMainThread();
|
||||
|
||||
void
|
||||
ThawOnMainThread();
|
||||
|
||||
void
|
||||
PostMessageToDebuggerOnMainThread(const nsAString& aMessage);
|
||||
|
||||
void
|
||||
ReportErrorToDebuggerOnMainThread(const nsAString& aFilename,
|
||||
uint32_t aLineno,
|
||||
const nsAString& aMessage);
|
||||
};
|
||||
|
||||
class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
|
||||
@@ -771,6 +806,7 @@ class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
|
||||
nsRefPtr<WorkerDebugger> mDebugger;
|
||||
|
||||
Queue<WorkerControlRunnable*, 4> mControlQueue;
|
||||
Queue<WorkerRunnable*, 4> mDebuggerQueue;
|
||||
|
||||
// Touched on multiple threads, protected with mMutex.
|
||||
JSContext* mJSContext;
|
||||
@@ -785,6 +821,7 @@ class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
|
||||
nsTArray<ParentType*> mChildWorkers;
|
||||
nsTArray<WorkerFeature*> mFeatures;
|
||||
nsTArray<nsAutoPtr<TimeoutInfo>> mTimeouts;
|
||||
uint32_t mDebuggerEventLoopLevel;
|
||||
|
||||
struct SyncLoopInfo
|
||||
{
|
||||
@@ -820,7 +857,7 @@ class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
|
||||
uint32_t mErrorHandlerRecursionCount;
|
||||
uint32_t mNextTimeoutId;
|
||||
Status mStatus;
|
||||
bool mSuspended;
|
||||
bool mFrozen;
|
||||
bool mTimerRunning;
|
||||
bool mRunningExpiredTimeouts;
|
||||
bool mCloseHandlerStarted;
|
||||
@@ -895,10 +932,10 @@ public:
|
||||
}
|
||||
|
||||
bool
|
||||
SuspendInternal(JSContext* aCx);
|
||||
FreezeInternal(JSContext* aCx);
|
||||
|
||||
bool
|
||||
ResumeInternal(JSContext* aCx);
|
||||
ThawInternal(JSContext* aCx);
|
||||
|
||||
void
|
||||
TraceTimeouts(const TraceCallbacks& aCallbacks, void* aClosure) const;
|
||||
@@ -945,6 +982,22 @@ public:
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
EnterDebuggerEventLoop();
|
||||
|
||||
void
|
||||
LeaveDebuggerEventLoop();
|
||||
|
||||
void
|
||||
PostMessageToDebugger(const nsAString& aMessage);
|
||||
|
||||
void
|
||||
SetDebuggerImmediate(JSContext* aCx, Function& aHandler, ErrorResult& aRv);
|
||||
|
||||
void
|
||||
ReportErrorToDebugger(const nsAString& aFilename, uint32_t aLineno,
|
||||
const nsAString& aMessage);
|
||||
|
||||
bool
|
||||
NotifyInternal(JSContext* aCx, Status aStatus);
|
||||
|
||||
|
||||
@@ -50,6 +50,22 @@ WorkerRunnable::WorkerRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
WorkerRunnable::IsDebuggerRunnable() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
nsIGlobalObject*
|
||||
WorkerRunnable::DefaultGlobalObject() const
|
||||
{
|
||||
if (IsDebuggerRunnable()) {
|
||||
return mWorkerPrivate->DebuggerGlobalScope();
|
||||
} else {
|
||||
return mWorkerPrivate->GlobalScope();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerRunnable::PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
@@ -121,7 +137,11 @@ WorkerRunnable::DispatchInternal()
|
||||
{
|
||||
if (mBehavior == WorkerThreadModifyBusyCount ||
|
||||
mBehavior == WorkerThreadUnchangedBusyCount) {
|
||||
return NS_SUCCEEDED(mWorkerPrivate->Dispatch(this));
|
||||
if (IsDebuggerRunnable()) {
|
||||
return NS_SUCCEEDED(mWorkerPrivate->DispatchDebuggerRunnable(this));
|
||||
} else {
|
||||
return NS_SUCCEEDED(mWorkerPrivate->Dispatch(this));
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mBehavior == ParentThreadUnchangedBusyCount);
|
||||
@@ -285,9 +305,13 @@ WorkerRunnable::Run()
|
||||
MOZ_ASSERT(isMainThread == NS_IsMainThread());
|
||||
nsRefPtr<WorkerPrivate> kungFuDeathGrip;
|
||||
if (targetIsWorkerThread) {
|
||||
globalObject = mWorkerPrivate->GlobalScope();
|
||||
}
|
||||
else {
|
||||
JSObject* global = JS::CurrentGlobalOrNull(GetCurrentThreadJSContext());
|
||||
if (global) {
|
||||
globalObject = GetGlobalObjectForGlobal(global);
|
||||
} else {
|
||||
globalObject = DefaultGlobalObject();
|
||||
}
|
||||
} else {
|
||||
kungFuDeathGrip = mWorkerPrivate;
|
||||
if (isMainThread) {
|
||||
globalObject = static_cast<nsGlobalWindow*>(mWorkerPrivate->GetWindow());
|
||||
@@ -327,8 +351,8 @@ WorkerRunnable::Run()
|
||||
|
||||
// In the case of CompileScriptRunnnable, WorkerRun above can cause us to
|
||||
// lazily create a global, so we construct aes here before calling PostRun.
|
||||
if (targetIsWorkerThread && !aes && mWorkerPrivate->GlobalScope()) {
|
||||
aes.emplace(mWorkerPrivate->GlobalScope(), false, GetCurrentThreadJSContext());
|
||||
if (targetIsWorkerThread && !aes && DefaultGlobalObject()) {
|
||||
aes.emplace(DefaultGlobalObject(), false, GetCurrentThreadJSContext());
|
||||
cx = aes->cx();
|
||||
}
|
||||
|
||||
@@ -349,6 +373,14 @@ WorkerRunnable::Cancel()
|
||||
return (canceledCount == 1) ? NS_OK : NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
void
|
||||
WorkerDebuggerRunnable::PostDispatch(JSContext* aCx,
|
||||
WorkerPrivate* aWorkerPrivate,
|
||||
bool aDispatchResult)
|
||||
{
|
||||
MaybeReportMainThreadException(aCx, aDispatchResult);
|
||||
}
|
||||
|
||||
WorkerSyncRunnable::WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
nsIEventTarget* aSyncLoopTarget)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
|
||||
|
||||
@@ -99,6 +99,14 @@ protected:
|
||||
virtual ~WorkerRunnable()
|
||||
{ }
|
||||
|
||||
// Returns true if this runnable should be dispatched to the debugger queue,
|
||||
// and false otherwise.
|
||||
virtual bool
|
||||
IsDebuggerRunnable() const;
|
||||
|
||||
nsIGlobalObject*
|
||||
DefaultGlobalObject() const;
|
||||
|
||||
// By default asserts that Dispatch() is being called on the right thread
|
||||
// (ParentThread if |mTarget| is WorkerThread, or WorkerThread otherwise).
|
||||
// Also increments the busy count of |mWorkerPrivate| if targeting the
|
||||
@@ -133,6 +141,38 @@ protected:
|
||||
NS_DECL_NSIRUNNABLE
|
||||
};
|
||||
|
||||
// This runnable is used to send a message to a worker debugger.
|
||||
class WorkerDebuggerRunnable : public WorkerRunnable
|
||||
{
|
||||
protected:
|
||||
explicit WorkerDebuggerRunnable(WorkerPrivate* aWorkerPrivate)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~WorkerDebuggerRunnable()
|
||||
{ }
|
||||
|
||||
private:
|
||||
virtual bool
|
||||
IsDebuggerRunnable() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void
|
||||
PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
||||
bool aDispatchResult) override;
|
||||
};
|
||||
|
||||
// This runnable is used to send a message directly to a worker's sync loop.
|
||||
class WorkerSyncRunnable : public WorkerRunnable
|
||||
{
|
||||
|
||||
+230
-2
@@ -208,7 +208,7 @@ WorkerGlobalScope::ImportScripts(JSContext* aCx,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
scriptloader::Load(aCx, mWorkerPrivate, aScriptURLs, aRv);
|
||||
scriptloader::Load(aCx, mWorkerPrivate, aScriptURLs, WorkerScript, aRv);
|
||||
}
|
||||
|
||||
int32_t
|
||||
@@ -513,6 +513,220 @@ WorkerDebuggerGlobalScope::GetGlobal(JSContext* aCx,
|
||||
aGlobal.set(mWorkerPrivate->GetOrCreateGlobalScope(aCx)->GetWrapper());
|
||||
}
|
||||
|
||||
class WorkerDebuggerSandboxPrivate : public nsIGlobalObject,
|
||||
public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
explicit WorkerDebuggerSandboxPrivate(JSObject *global)
|
||||
{
|
||||
SetWrapper(global);
|
||||
}
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(WorkerDebuggerSandboxPrivate,
|
||||
nsIGlobalObject)
|
||||
|
||||
virtual JSObject *GetGlobalJSObject() override
|
||||
{
|
||||
return GetWrapper();
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* cx,
|
||||
JS::Handle<JSObject*> aGivenProto) override
|
||||
{
|
||||
MOZ_CRASH("WorkerDebuggerSandboxPrivate doesn't use DOM bindings!");
|
||||
}
|
||||
|
||||
private:
|
||||
virtual ~WorkerDebuggerSandboxPrivate()
|
||||
{
|
||||
ClearWrapper();
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WorkerDebuggerSandboxPrivate)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(WorkerDebuggerSandboxPrivate)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(WorkerDebuggerSandboxPrivate)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WorkerDebuggerSandboxPrivate)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
static bool
|
||||
workerdebuggersandbox_enumerate(JSContext *cx, JS::Handle<JSObject *> obj)
|
||||
{
|
||||
return JS_EnumerateStandardClasses(cx, obj);
|
||||
}
|
||||
|
||||
static bool
|
||||
workerdebuggersandbox_resolve(JSContext *cx, JS::Handle<JSObject *> obj,
|
||||
JS::Handle<jsid> id, bool *resolvedp)
|
||||
{
|
||||
return JS_ResolveStandardClass(cx, obj, id, resolvedp);
|
||||
}
|
||||
|
||||
static bool
|
||||
workerdebuggersandbox_convert(JSContext *cx, JS::Handle<JSObject *> obj,
|
||||
JSType type, JS::MutableHandle<JS::Value> vp)
|
||||
{
|
||||
if (type == JSTYPE_OBJECT) {
|
||||
vp.set(OBJECT_TO_JSVAL(obj));
|
||||
return true;
|
||||
}
|
||||
|
||||
return JS::OrdinaryToPrimitive(cx, obj, type, vp);
|
||||
}
|
||||
|
||||
static void
|
||||
workerdebuggersandbox_finalize(js::FreeOp *fop, JSObject *obj)
|
||||
{
|
||||
nsIGlobalObject *globalObject =
|
||||
static_cast<nsIGlobalObject *>(JS_GetPrivate(obj));
|
||||
NS_RELEASE(globalObject);
|
||||
}
|
||||
|
||||
static void
|
||||
workerdebuggersandbox_moved(JSObject *obj, const JSObject *old)
|
||||
{
|
||||
}
|
||||
|
||||
const js::Class workerdebuggersandbox_class = {
|
||||
"workerdebuggersandbox",
|
||||
JSCLASS_GLOBAL_FLAGS | JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
workerdebuggersandbox_enumerate,
|
||||
workerdebuggersandbox_resolve,
|
||||
workerdebuggersandbox_convert,
|
||||
workerdebuggersandbox_finalize,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
JS_GlobalObjectTraceHook,
|
||||
JS_NULL_CLASS_SPEC, {
|
||||
nullptr,
|
||||
nullptr,
|
||||
false,
|
||||
nullptr,
|
||||
workerdebuggersandbox_moved
|
||||
}, JS_NULL_OBJECT_OPS
|
||||
};
|
||||
|
||||
void
|
||||
WorkerDebuggerGlobalScope::CreateSandbox(JSContext* aCx, const nsAString& aName,
|
||||
JS::Handle<JSObject*> aPrototype,
|
||||
JS::MutableHandle<JSObject*> aResult)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
JS::CompartmentOptions options;
|
||||
options.setInvisibleToDebugger(true);
|
||||
|
||||
JS::Rooted<JSObject*> sandbox(aCx,
|
||||
JS_NewGlobalObject(aCx, js::Jsvalify(&workerdebuggersandbox_class), nullptr,
|
||||
JS::DontFireOnNewGlobalHook, options));
|
||||
if (!sandbox) {
|
||||
JS_ReportError(aCx, "Can't create sandbox!");
|
||||
aResult.set(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
JSAutoCompartment ac(aCx, sandbox);
|
||||
|
||||
JS::Rooted<JSObject*> prototype(aCx, aPrototype);
|
||||
if (!JS_WrapObject(aCx, &prototype)) {
|
||||
JS_ReportError(aCx, "Can't wrap sandbox prototype!");
|
||||
aResult.set(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!JS_SetPrototype(aCx, sandbox, prototype)) {
|
||||
JS_ReportError(aCx, "Can't set sandbox prototype!");
|
||||
aResult.set(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> globalObject =
|
||||
new WorkerDebuggerSandboxPrivate(sandbox);
|
||||
|
||||
// Pass on ownership of globalObject to |sandbox|.
|
||||
JS_SetPrivate(sandbox, globalObject.forget().take());
|
||||
}
|
||||
|
||||
JS_FireOnNewGlobalObject(aCx, sandbox);
|
||||
|
||||
if (!JS_WrapObject(aCx, &sandbox)) {
|
||||
JS_ReportError(aCx, "Can't wrap sandbox!");
|
||||
aResult.set(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
aResult.set(sandbox);
|
||||
}
|
||||
|
||||
void
|
||||
WorkerDebuggerGlobalScope::LoadSubScript(JSContext* aCx,
|
||||
const nsAString& aURL,
|
||||
const Optional<JS::Handle<JSObject*>>& aSandbox,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
Maybe<JSAutoCompartment> ac;
|
||||
if (aSandbox.WasPassed()) {
|
||||
JS::Rooted<JSObject*> sandbox(aCx, js::CheckedUnwrap(aSandbox.Value()));
|
||||
if (!IsDebuggerSandbox(sandbox)) {
|
||||
aRv.Throw(NS_ERROR_INVALID_ARG);
|
||||
return;
|
||||
}
|
||||
|
||||
ac.emplace(aCx, sandbox);
|
||||
}
|
||||
|
||||
nsTArray<nsString> urls;
|
||||
urls.AppendElement(aURL);
|
||||
scriptloader::Load(aCx, mWorkerPrivate, urls, DebuggerScript, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
WorkerDebuggerGlobalScope::EnterEventLoop()
|
||||
{
|
||||
mWorkerPrivate->EnterDebuggerEventLoop();
|
||||
}
|
||||
|
||||
void
|
||||
WorkerDebuggerGlobalScope::LeaveEventLoop()
|
||||
{
|
||||
mWorkerPrivate->LeaveDebuggerEventLoop();
|
||||
}
|
||||
|
||||
void
|
||||
WorkerDebuggerGlobalScope::PostMessage(const nsAString& aMessage)
|
||||
{
|
||||
mWorkerPrivate->PostMessageToDebugger(aMessage);
|
||||
}
|
||||
|
||||
void
|
||||
WorkerDebuggerGlobalScope::SetImmediate(JSContext* aCx, Function& aHandler,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
mWorkerPrivate->SetDebuggerImmediate(aCx, aHandler, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
WorkerDebuggerGlobalScope::ReportError(JSContext* aCx,
|
||||
const nsAString& aMessage)
|
||||
{
|
||||
JS::AutoFilename afn;
|
||||
uint32_t lineno = 0;
|
||||
JS::DescribeScriptedCaller(aCx, &afn, &lineno);
|
||||
nsString filename(NS_ConvertUTF8toUTF16(afn.get()));
|
||||
mWorkerPrivate->ReportErrorToDebugger(filename, lineno, aMessage);
|
||||
}
|
||||
|
||||
void
|
||||
WorkerDebuggerGlobalScope::Dump(JSContext* aCx,
|
||||
const Optional<nsAString>& aString) const
|
||||
@@ -525,10 +739,18 @@ GetGlobalObjectForGlobal(JSObject* global)
|
||||
{
|
||||
nsIGlobalObject* globalObject = nullptr;
|
||||
UNWRAP_WORKER_OBJECT(WorkerGlobalScope, global, globalObject);
|
||||
|
||||
if (!globalObject) {
|
||||
UNWRAP_OBJECT(WorkerDebuggerGlobalScope, global, globalObject);
|
||||
MOZ_ASSERT(globalObject);
|
||||
|
||||
if (!globalObject) {
|
||||
MOZ_ASSERT(IsDebuggerSandbox(global));
|
||||
globalObject = static_cast<nsIGlobalObject *>(JS_GetPrivate(global));
|
||||
|
||||
MOZ_ASSERT(globalObject);
|
||||
}
|
||||
}
|
||||
|
||||
return globalObject;
|
||||
}
|
||||
|
||||
@@ -548,6 +770,12 @@ IsDebuggerGlobal(JSObject* object)
|
||||
globalObject)) && !!globalObject;
|
||||
}
|
||||
|
||||
bool
|
||||
IsDebuggerSandbox(JSObject* object)
|
||||
{
|
||||
return js::GetObjectClass(object) == &workerdebuggersandbox_class;
|
||||
}
|
||||
|
||||
bool
|
||||
GetterOnlyJSNative(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
|
||||
{
|
||||
|
||||
@@ -264,6 +264,33 @@ public:
|
||||
void
|
||||
GetGlobal(JSContext* aCx, JS::MutableHandle<JSObject*> aGlobal);
|
||||
|
||||
void
|
||||
CreateSandbox(JSContext* aCx, const nsAString& aName,
|
||||
JS::Handle<JSObject*> aPrototype,
|
||||
JS::MutableHandle<JSObject*> aResult);
|
||||
|
||||
void
|
||||
LoadSubScript(JSContext* aCx, const nsAString& aURL,
|
||||
const Optional<JS::Handle<JSObject*>>& aSandbox,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
EnterEventLoop();
|
||||
|
||||
void
|
||||
LeaveEventLoop();
|
||||
|
||||
void
|
||||
PostMessage(const nsAString& aMessage);
|
||||
|
||||
IMPL_EVENT_HANDLER(message)
|
||||
|
||||
void
|
||||
SetImmediate(JSContext* aCx, Function& aHandler, ErrorResult& aRv);
|
||||
|
||||
void
|
||||
ReportError(JSContext* aCx, const nsAString& aMessage);
|
||||
|
||||
void
|
||||
Dump(JSContext* aCx, const Optional<nsAString>& aString) const;
|
||||
|
||||
|
||||
@@ -262,10 +262,10 @@ void
|
||||
CancelWorkersForWindow(nsPIDOMWindow* aWindow);
|
||||
|
||||
void
|
||||
SuspendWorkersForWindow(nsPIDOMWindow* aWindow);
|
||||
FreezeWorkersForWindow(nsPIDOMWindow* aWindow);
|
||||
|
||||
void
|
||||
ResumeWorkersForWindow(nsPIDOMWindow* aWindow);
|
||||
ThawWorkersForWindow(nsPIDOMWindow* aWindow);
|
||||
|
||||
class WorkerTask
|
||||
{
|
||||
@@ -338,6 +338,9 @@ IsWorkerGlobal(JSObject* global);
|
||||
bool
|
||||
IsDebuggerGlobal(JSObject* global);
|
||||
|
||||
bool
|
||||
IsDebuggerSandbox(JSObject* object);
|
||||
|
||||
// Throws the JSMSG_GETTER_ONLY exception. This shouldn't be used going
|
||||
// forward -- getter-only properties should just use JS_PSG for the setter
|
||||
// (implying no setter at all), which will not throw when set in non-strict
|
||||
|
||||
@@ -2,13 +2,22 @@
|
||||
|
||||
interface nsIDOMWindow;
|
||||
|
||||
[scriptable, uuid(54fd2dd3-c01b-4f71-888f-462f37a54f57)]
|
||||
[scriptable, uuid(530db841-1b2c-485a-beeb-f2b1acb9714e)]
|
||||
interface nsIWorkerDebuggerListener : nsISupports
|
||||
{
|
||||
void onClose();
|
||||
|
||||
void onError(in DOMString filename, in unsigned long lineno,
|
||||
in DOMString message);
|
||||
|
||||
void onFreeze();
|
||||
|
||||
void onMessage(in DOMString message);
|
||||
|
||||
void onThaw();
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(0833b363-bffe-4cdb-ad50-1c4563e0C8ff)]
|
||||
[scriptable, builtinclass, uuid(d7c73e54-3c41-4393-9d13-fa2ed4Ba6764)]
|
||||
interface nsIWorkerDebugger : nsISupports
|
||||
{
|
||||
const unsigned long TYPE_DEDICATED = 0;
|
||||
@@ -19,6 +28,8 @@ interface nsIWorkerDebugger : nsISupports
|
||||
|
||||
readonly attribute bool isChrome;
|
||||
|
||||
readonly attribute bool isFrozen;
|
||||
|
||||
readonly attribute nsIWorkerDebugger parent;
|
||||
|
||||
readonly attribute unsigned long type;
|
||||
@@ -27,6 +38,12 @@ interface nsIWorkerDebugger : nsISupports
|
||||
|
||||
readonly attribute nsIDOMWindow window;
|
||||
|
||||
[implicit_jscontext]
|
||||
void initialize(in DOMString url);
|
||||
|
||||
[implicit_jscontext, binaryname(PostMessageMoz)]
|
||||
void postMessage(in DOMString message);
|
||||
|
||||
void addListener(in nsIWorkerDebuggerListener listener);
|
||||
|
||||
void removeListener(in nsIWorkerDebuggerListener listener);
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
"use strict";
|
||||
|
||||
self.onmessage = function () {};
|
||||
|
||||
debugger;
|
||||
postMessage("worker");
|
||||
@@ -0,0 +1,6 @@
|
||||
"use strict";
|
||||
|
||||
var dbg = new Debugger(global);
|
||||
dbg.onDebuggerStatement = function (frame) {
|
||||
frame.eval("postMessage('debugger');");
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
"use strict";
|
||||
|
||||
var worker = new Worker("WorkerDebugger.initialize_childWorker.js");
|
||||
worker.onmessage = function (event) {
|
||||
postMessage("child:" + event.data);
|
||||
};
|
||||
|
||||
debugger;
|
||||
postMessage("worker");
|
||||
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script>
|
||||
var worker = new Worker("WorkerDebugger.isFrozen_worker1.js");
|
||||
worker.onmessage = function () {
|
||||
parent.postMessage("ready", "*");
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
This is page 1.
|
||||
</body>
|
||||
<html>
|
||||
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script>
|
||||
var worker = new Worker("WorkerDebugger.isFrozen_worker2.js");
|
||||
worker.onmessage = function () {
|
||||
parent.postMessage("ready", "*");
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
This is page 2.
|
||||
</body>
|
||||
<html>
|
||||
@@ -0,0 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
onmessage = function () {};
|
||||
|
||||
postMessage("ready");
|
||||
@@ -0,0 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
onmessage = function () {};
|
||||
|
||||
postMessage("ready");
|
||||
@@ -0,0 +1,3 @@
|
||||
"use strict";
|
||||
|
||||
self.onmessage = function () {};
|
||||
@@ -0,0 +1,9 @@
|
||||
"use strict"
|
||||
|
||||
this.onmessage = function (event) {
|
||||
switch (event.data) {
|
||||
case "ping":
|
||||
postMessage("pong");
|
||||
break;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
"use strict";
|
||||
|
||||
var worker = new Worker("WorkerDebugger.postMessage_childWorker.js");
|
||||
@@ -0,0 +1,9 @@
|
||||
"use strict";
|
||||
|
||||
const SANDBOX_URL = "WorkerDebuggerGlobalScope.createSandbox_sandbox.js";
|
||||
|
||||
let prototype = {
|
||||
self: this,
|
||||
};
|
||||
let sandbox = createSandbox(SANDBOX_URL, prototype);
|
||||
loadSubScript(SANDBOX_URL, sandbox);
|
||||
@@ -0,0 +1,9 @@
|
||||
"use strict";
|
||||
|
||||
self.addEventListener("message", function(event) {
|
||||
switch (event.data) {
|
||||
case "ping":
|
||||
self.postMessage("pong");
|
||||
break;
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
"use strict";
|
||||
|
||||
self.onmessage = function () {};
|
||||
@@ -0,0 +1,14 @@
|
||||
"use strict";
|
||||
|
||||
function f() {
|
||||
debugger;
|
||||
}
|
||||
|
||||
self.onmessage = function (event) {
|
||||
switch (event.data) {
|
||||
case "ping":
|
||||
debugger;
|
||||
postMessage("pong");
|
||||
break;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
"use strict";
|
||||
|
||||
let frames = [];
|
||||
|
||||
var dbg = new Debugger(global);
|
||||
dbg.onDebuggerStatement = function (frame) {
|
||||
frames.push(frame);
|
||||
postMessage("paused");
|
||||
enterEventLoop();
|
||||
frames.pop();
|
||||
postMessage("resumed");
|
||||
};
|
||||
|
||||
this.onmessage = function (event) {
|
||||
switch (event.data) {
|
||||
case "eval":
|
||||
frames[frames.length - 1].eval("f()");
|
||||
postMessage("evalled");
|
||||
break;
|
||||
|
||||
case "ping":
|
||||
postMessage("pong");
|
||||
break;
|
||||
|
||||
case "resume":
|
||||
leaveEventLoop();
|
||||
break;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
"use strict";
|
||||
|
||||
function f() {
|
||||
debugger;
|
||||
}
|
||||
|
||||
var worker = new Worker("WorkerDebuggerGlobalScope.enterEventLoop_childWorker.js");
|
||||
|
||||
worker.onmessage = function (event) {
|
||||
postMessage("child:" + event.data);
|
||||
};
|
||||
|
||||
self.onmessage = function (event) {
|
||||
var message = event.data;
|
||||
if (message.indexOf(":") >= 0) {
|
||||
worker.postMessage(message.split(":")[1]);
|
||||
return;
|
||||
}
|
||||
switch (message) {
|
||||
case "ping":
|
||||
debugger;
|
||||
postMessage("pong");
|
||||
break;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
self.onerror = function () {
|
||||
postMessage("error");
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
"use strict";
|
||||
|
||||
this.onmessage = function (event) {
|
||||
switch (event.data) {
|
||||
case "report":
|
||||
reportError("reported");
|
||||
break;
|
||||
case "throw":
|
||||
throw new Error("thrown");
|
||||
break;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
"use strict";
|
||||
|
||||
var worker = new Worker("WorkerDebuggerGlobalScope.reportError_childWorker.js");
|
||||
|
||||
worker.onmessage = function (event) {
|
||||
postMessage("child:" + event.data);
|
||||
};
|
||||
|
||||
self.onerror = function () {
|
||||
postMessage("error");
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
"use strict";
|
||||
|
||||
this.onmessage = function (event) {
|
||||
switch (event.data) {
|
||||
case "ping":
|
||||
setImmediate(function () {
|
||||
postMessage("pong1");
|
||||
});
|
||||
postMessage("pong2");
|
||||
break;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
"use strict"
|
||||
|
||||
self.onmessage = function () {};
|
||||
@@ -1,3 +1,3 @@
|
||||
"use strict";
|
||||
|
||||
onmessage = function () {};
|
||||
self.onmessage = function () {};
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
"use strict";
|
||||
|
||||
onmessage = function () {};
|
||||
self.onmessage = function () {};
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
var worker = new Worker("WorkerDebugger_childWorker.js");
|
||||
@@ -1,6 +1,6 @@
|
||||
"use strict";
|
||||
|
||||
onconnect = function (event) {
|
||||
self.onconnect = function (event) {
|
||||
event.ports[0].onmessage = function (event) {
|
||||
switch (event.data) {
|
||||
case "close":
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
"use strict";
|
||||
|
||||
var worker = new Worker("WorkerDebugger_childWorker.js");
|
||||
self.onmessage = function (event) {
|
||||
postMessage("child:" + event.data);
|
||||
};
|
||||
debugger;
|
||||
postMessage("worker");
|
||||
@@ -1,9 +1,30 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
WorkerDebugger.initialize_childWorker.js
|
||||
WorkerDebugger.initialize_debugger.js
|
||||
WorkerDebugger.initialize_worker.js
|
||||
WorkerDebugger.isFrozen_iframe1.html
|
||||
WorkerDebugger.isFrozen_iframe2.html
|
||||
WorkerDebugger.isFrozen_worker1.js
|
||||
WorkerDebugger.isFrozen_worker2.js
|
||||
WorkerDebugger.postMessage_childWorker.js
|
||||
WorkerDebugger.postMessage_debugger.js
|
||||
WorkerDebugger.postMessage_worker.js
|
||||
WorkerDebuggerGlobalScope.createSandbox_debugger.js
|
||||
WorkerDebuggerGlobalScope.createSandbox_sandbox.js
|
||||
WorkerDebuggerGlobalScope.createSandbox_worker.js
|
||||
WorkerDebuggerGlobalScope.enterEventLoop_childWorker.js
|
||||
WorkerDebuggerGlobalScope.enterEventLoop_debugger.js
|
||||
WorkerDebuggerGlobalScope.enterEventLoop_worker.js
|
||||
WorkerDebuggerGlobalScope.reportError_childWorker.js
|
||||
WorkerDebuggerGlobalScope.reportError_debugger.js
|
||||
WorkerDebuggerGlobalScope.reportError_worker.js
|
||||
WorkerDebuggerGlobalScope.setImmediate_debugger.js
|
||||
WorkerDebuggerGlobalScope.setImmediate_worker.js
|
||||
WorkerDebuggerManager_childWorker.js
|
||||
WorkerDebuggerManager_parentWorker.js
|
||||
WorkerDebuggerManager_worker.js
|
||||
WorkerDebugger_childWorker.js
|
||||
WorkerDebugger_parentWorker.js
|
||||
WorkerDebugger_worker.js
|
||||
WorkerDebugger_sharedWorker.js
|
||||
WorkerTest.jsm
|
||||
WorkerTest_subworker.js
|
||||
@@ -28,6 +49,13 @@ support-files =
|
||||
bug1062920_worker.js
|
||||
|
||||
[test_WorkerDebugger.xul]
|
||||
[test_WorkerDebugger.initialize.xul]
|
||||
[test_WorkerDebugger.isFrozen.xul]
|
||||
[test_WorkerDebugger.postMessage.xul]
|
||||
[test_WorkerDebuggerGlobalScope.createSandbox.xul]
|
||||
[test_WorkerDebuggerGlobalScope.enterEventLoop.xul]
|
||||
[test_WorkerDebuggerGlobalScope.reportError.xul]
|
||||
[test_WorkerDebuggerGlobalScope.setImmediate.xul]
|
||||
[test_WorkerDebuggerManager.xul]
|
||||
[test_bug883784.jsm]
|
||||
[test_bug883784.xul]
|
||||
|
||||
@@ -13,6 +13,8 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const wdm = Cc["@mozilla.org/dom/workers/workerdebuggermanager;1"].
|
||||
getService(Ci.nsIWorkerDebuggerManager);
|
||||
|
||||
const BASE_URL = "chrome://mochitests/content/chrome/dom/workers/test/";
|
||||
|
||||
var gRemainingTests = 0;
|
||||
|
||||
function waitForWorkerFinish() {
|
||||
@@ -47,50 +49,54 @@ function* generateDebuggers() {
|
||||
}
|
||||
}
|
||||
|
||||
function findDebugger(predicate) {
|
||||
function findDebugger(url) {
|
||||
for (let dbg of generateDebuggers()) {
|
||||
if (predicate(dbg)) {
|
||||
if (dbg.url === url) {
|
||||
return dbg;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function waitForRegister(predicate = () => true) {
|
||||
function waitForRegister(url, dbgUrl) {
|
||||
return new Promise(function (resolve) {
|
||||
wdm.addListener({
|
||||
onRegister: function (dbg) {
|
||||
if (!predicate(dbg)) {
|
||||
if (dbg.url !== url) {
|
||||
return;
|
||||
}
|
||||
ok(true, "Debugger with url " + url + " should be registered.");
|
||||
wdm.removeListener(this);
|
||||
if (dbgUrl) {
|
||||
info("Initializing worker debugger with url " + url + ".");
|
||||
dbg.initialize(dbgUrl);
|
||||
}
|
||||
resolve(dbg);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function waitForUnregister(predicate = () => true) {
|
||||
function waitForUnregister(url) {
|
||||
return new Promise(function (resolve) {
|
||||
wdm.addListener({
|
||||
onUnregister: function (dbg) {
|
||||
if (!predicate(dbg)) {
|
||||
if (dbg.url !== url) {
|
||||
return;
|
||||
}
|
||||
ok(true, "Debugger with url " + url + " should be unregistered.");
|
||||
wdm.removeListener(this);
|
||||
resolve(dbg);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function waitForDebuggerClose(dbg, predicate = () => true) {
|
||||
function waitForDebuggerClose(dbg) {
|
||||
return new Promise(function (resolve) {
|
||||
dbg.addListener({
|
||||
onClose: function () {
|
||||
if (!predicate()) {
|
||||
return;
|
||||
}
|
||||
ok(true, "Debugger should be closed.");
|
||||
dbg.removeListener(this);
|
||||
resolve();
|
||||
}
|
||||
@@ -98,17 +104,92 @@ function waitForDebuggerClose(dbg, predicate = () => true) {
|
||||
});
|
||||
}
|
||||
|
||||
function waitForDebuggerError(dbg) {
|
||||
return new Promise(function (resolve) {
|
||||
dbg.addListener({
|
||||
onError: function (filename, lineno, message) {
|
||||
dbg.removeListener(this);
|
||||
resolve(new Error(message, filename, lineno));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function waitForDebuggerMessage(dbg, message) {
|
||||
return new Promise(function (resolve) {
|
||||
dbg.addListener({
|
||||
onMessage: function (message1) {
|
||||
if (message !== message1) {
|
||||
return;
|
||||
}
|
||||
ok(true, "Should receive " + message + " message from debugger.");
|
||||
dbg.removeListener(this);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function waitForDebuggerFreeze(dbg) {
|
||||
return new Promise(function (resolve) {
|
||||
dbg.addListener({
|
||||
onFreeze: function () {
|
||||
dbg.removeListener(this);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function waitForDebuggerThaw(dbg) {
|
||||
return new Promise(function (resolve) {
|
||||
dbg.addListener({
|
||||
onThaw: function () {
|
||||
dbg.removeListener(this);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function waitForWindowMessage(window, message) {
|
||||
return new Promise(function (resolve) {
|
||||
let onmessage = function (event) {
|
||||
if (event.data !== event.data) {
|
||||
return;
|
||||
}
|
||||
window.removeEventListener("message", onmessage, false);
|
||||
resolve();
|
||||
};
|
||||
window.addEventListener("message", onmessage, false);
|
||||
});
|
||||
}
|
||||
|
||||
function waitForWorkerMessage(worker, message) {
|
||||
return new Promise(function (resolve) {
|
||||
worker.addEventListener("message", function onmessage(event) {
|
||||
if (event.data !== message) {
|
||||
return;
|
||||
}
|
||||
ok(true, "Should receive " + message + " message from worker.");
|
||||
worker.removeEventListener("message", onmessage);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function waitForMultiple(promises) {
|
||||
return new Promise(function (resolve) {
|
||||
let results = [];
|
||||
let values = [];
|
||||
for (let i = 0; i < promises.length; ++i) {
|
||||
let promise = promises[i];
|
||||
let index = i;
|
||||
promise.then(function (result) {
|
||||
is(results.length, index, "events should occur in the specified order");
|
||||
results.push(result);
|
||||
if (results.length === promises.length) {
|
||||
resolve(results);
|
||||
promises[i].then(function (value) {
|
||||
is(index + 1, values.length + 1,
|
||||
"Promise " + (values.length + 1) + " out of " + promises.length +
|
||||
" should be resolved.");
|
||||
values.push(value);
|
||||
if (values.length === promises.length) {
|
||||
resolve(values);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<window title="Test for WorkerDebugger.initialize"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="test();">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
<script type="application/javascript" src="dom_worker_helper.js"/>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
const WORKER_URL = "WorkerDebugger.initialize_worker.js";
|
||||
const CHILD_WORKER_URL = "WorkerDebugger.initialize_childWorker.js";
|
||||
const DEBUGGER_URL = BASE_URL + "WorkerDebugger.initialize_debugger.js";
|
||||
|
||||
function test() {
|
||||
Task.spawn(function* () {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
info("Create a worker that creates a child worker, wait for their " +
|
||||
"debuggers to be registered, and initialize them.");
|
||||
let promise = waitForMultiple([
|
||||
waitForRegister(WORKER_URL, DEBUGGER_URL),
|
||||
waitForRegister(CHILD_WORKER_URL, DEBUGGER_URL)
|
||||
]);
|
||||
let worker = new Worker(WORKER_URL);
|
||||
yield promise;
|
||||
|
||||
info("Check that the debuggers are initialized before the workers " +
|
||||
"start running.");
|
||||
yield waitForMultiple([
|
||||
waitForWorkerMessage(worker, "debugger"),
|
||||
waitForWorkerMessage(worker, "worker"),
|
||||
waitForWorkerMessage(worker, "child:debugger"),
|
||||
waitForWorkerMessage(worker, "child:worker")
|
||||
]);
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display:none;"></div>
|
||||
<pre id="test"></pre>
|
||||
</body>
|
||||
<label id="test-result"/>
|
||||
</window>
|
||||
@@ -0,0 +1,98 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<window title="Test for WorkerDebugger.isFrozen"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="test();">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
<script type="application/javascript" src="dom_worker_helper.js"/>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
const CACHE_SUBFRAMES = "browser.sessionhistory.cache_subframes";
|
||||
const MAX_TOTAL_VIEWERS = "browser.sessionhistory.max_total_viewers";
|
||||
|
||||
const IFRAME1_URL = "WorkerDebugger.isFrozen_iframe1.html";
|
||||
const IFRAME2_URL = "WorkerDebugger.isFrozen_iframe2.html";
|
||||
|
||||
const WORKER1_URL = "WorkerDebugger.isFrozen_worker1.js";
|
||||
const WORKER2_URL = "WorkerDebugger.isFrozen_worker2.js";
|
||||
|
||||
function test() {
|
||||
Task.spawn(function* () {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var oldMaxTotalViewers = SpecialPowers.getIntPref(MAX_TOTAL_VIEWERS);
|
||||
|
||||
SpecialPowers.setBoolPref(CACHE_SUBFRAMES, true);
|
||||
SpecialPowers.setIntPref(MAX_TOTAL_VIEWERS, 10);
|
||||
|
||||
let iframe = $("iframe");
|
||||
|
||||
let promise = waitForMultiple([
|
||||
waitForRegister(WORKER1_URL),
|
||||
waitForWindowMessage(window, "ready"),
|
||||
]);
|
||||
iframe.src = IFRAME1_URL;
|
||||
let [dbg1] = yield promise;
|
||||
is(dbg1.isClosed, false,
|
||||
"debugger for worker on page 1 should not be closed");
|
||||
is(dbg1.isFrozen, false,
|
||||
"debugger for worker on page 1 should not be frozen");
|
||||
|
||||
promise = waitForMultiple([
|
||||
waitForDebuggerFreeze(dbg1),
|
||||
waitForRegister(WORKER2_URL),
|
||||
waitForWindowMessage(window, "ready"),
|
||||
]);
|
||||
iframe.src = IFRAME2_URL;
|
||||
let [_, dbg2] = yield promise;
|
||||
is(dbg1.isClosed, false,
|
||||
"debugger for worker on page 1 should not be closed");
|
||||
is(dbg1.isFrozen, true,
|
||||
"debugger for worker on page 1 should be frozen");
|
||||
is(dbg2.isClosed, false,
|
||||
"debugger for worker on page 2 should not be closed");
|
||||
is(dbg2.isFrozen, false,
|
||||
"debugger for worker on page 2 should not be frozen");
|
||||
|
||||
promise = waitForMultiple([
|
||||
waitForDebuggerFreeze(dbg2),
|
||||
waitForDebuggerThaw(dbg1),
|
||||
]);
|
||||
iframe.contentWindow.history.back();
|
||||
yield promise;
|
||||
is(dbg1.isClosed, false,
|
||||
"debugger for worker on page 1 should not be closed")
|
||||
is(dbg1.isFrozen, false,
|
||||
"debugger for worker on page 1 should not be frozen");
|
||||
is(dbg2.isClosed, false,
|
||||
"debugger for worker on page 2 should not be closed");
|
||||
is(dbg2.isFrozen, true,
|
||||
"debugger for worker on page 2 should be frozen");
|
||||
|
||||
SpecialPowers.clearUserPref(CACHE_SUBFRAMES);
|
||||
SpecialPowers.setIntPref(MAX_TOTAL_VIEWERS, oldMaxTotalViewers);
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display:none;"></div>
|
||||
<pre id="test"></pre>
|
||||
<iframe id="iframe"></iframe>
|
||||
</body>
|
||||
<label id="test-result"/>
|
||||
</window>
|
||||
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<window title="Test for WorkerDebugger.postMessage"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="test();">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
<script type="application/javascript" src="dom_worker_helper.js"/>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
const WORKER_URL = "WorkerDebugger.postMessage_worker.js";
|
||||
const CHILD_WORKER_URL = "WorkerDebugger.postMessage_childWorker.js";
|
||||
const DEBUGGER_URL = BASE_URL + "WorkerDebugger.postMessage_debugger.js";
|
||||
|
||||
function test() {
|
||||
Task.spawn(function* () {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
info("Create a worker that creates a child worker, wait for their " +
|
||||
"debuggers to be registered, and initialize them.");
|
||||
let promise = waitForMultiple([
|
||||
waitForRegister(WORKER_URL, DEBUGGER_URL),
|
||||
waitForRegister(CHILD_WORKER_URL, DEBUGGER_URL)
|
||||
]);
|
||||
let worker = new Worker(WORKER_URL);
|
||||
let [dbg, childDbg] = yield promise;
|
||||
|
||||
info("Send a request to the worker debugger. This should cause the " +
|
||||
"the worker debugger to send a response.");
|
||||
promise = waitForDebuggerMessage(dbg, "pong");
|
||||
dbg.postMessage("ping");
|
||||
yield promise;
|
||||
|
||||
info("Send a request to the child worker debugger. This should cause " +
|
||||
"the child worker debugger to send a response.");
|
||||
promise = waitForDebuggerMessage(childDbg, "pong");
|
||||
childDbg.postMessage("ping");
|
||||
yield promise;
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display:none;"></div>
|
||||
<pre id="test"></pre>
|
||||
</body>
|
||||
<label id="test-result"/>
|
||||
</window>
|
||||
@@ -16,7 +16,7 @@
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
const PARENT_WORKER_URL = "WorkerDebugger_parentWorker.js";
|
||||
const WORKER_URL = "WorkerDebugger_worker.js";
|
||||
const CHILD_WORKER_URL = "WorkerDebugger_childWorker.js";
|
||||
const SHARED_WORKER_URL = "WorkerDebugger_sharedWorker.js";
|
||||
|
||||
@@ -24,65 +24,89 @@
|
||||
Task.spawn(function* () {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
info("Create a top-level chrome worker that creates a non-top-level " +
|
||||
"content worker and wait for their debuggers to be registered.");
|
||||
let promise = waitForMultiple([
|
||||
waitForRegister((dbg) => dbg.url === PARENT_WORKER_URL),
|
||||
waitForRegister((dbg) => dbg.url === CHILD_WORKER_URL),
|
||||
waitForRegister(WORKER_URL),
|
||||
waitForRegister(CHILD_WORKER_URL)
|
||||
]);
|
||||
worker = new ChromeWorker(PARENT_WORKER_URL);
|
||||
let dbgs = yield promise;
|
||||
is(dbgs[0].isChrome, true, "debugger should be for chrome worker");
|
||||
is(dbgs[0].parent, null,
|
||||
"debugger for a top-level worker should not have parent");
|
||||
is(dbgs[0].type, Ci.nsIWorkerDebugger.TYPE_DEDICATED,
|
||||
"debugger should be for dedicated worker");
|
||||
is(dbgs[0].window, window,
|
||||
"debugger for top-level dedicated worker should have window");
|
||||
is(dbgs[1].isChrome, false, "debugger should be for content worker");
|
||||
is(dbgs[1].parent, dbgs[0],
|
||||
"debugger for child worker should have parent");
|
||||
is(dbgs[1].type, Ci.nsIWorkerDebugger.TYPE_DEDICATED);
|
||||
is(dbgs[1].window, null,
|
||||
"debugger for non-top-level worker should not have window");
|
||||
worker = new ChromeWorker(WORKER_URL);
|
||||
let [dbg, childDbg] = yield promise;
|
||||
|
||||
info("Check that the top-level chrome worker debugger has the " +
|
||||
"correct properties.");
|
||||
is(dbg.isChrome, true,
|
||||
"Chrome worker debugger should be chrome.");
|
||||
is(dbg.parent, null,
|
||||
"Top-level debugger should not have parent.");
|
||||
is(dbg.type, Ci.nsIWorkerDebugger.TYPE_DEDICATED,
|
||||
"Chrome worker debugger should be dedicated.");
|
||||
is(dbg.window, window,
|
||||
"Top-level dedicated worker debugger should have window.");
|
||||
|
||||
info("Check that the non-top-level content worker debugger has the " +
|
||||
"correct properties.");
|
||||
is(childDbg.isChrome, false,
|
||||
"Content worker debugger should be content.");
|
||||
is(childDbg.parent, dbg,
|
||||
"Non-top-level worker debugger should have parent.");
|
||||
is(childDbg.type, Ci.nsIWorkerDebugger.TYPE_DEDICATED,
|
||||
"Content worker debugger should be dedicated.");
|
||||
is(childDbg.window, null,
|
||||
"Non-top-level worker debugger should not have window.");
|
||||
|
||||
info("Terminate the top-level chrome worker and the non-top-level " +
|
||||
"content worker, and wait for their debuggers to be " +
|
||||
"unregistered and closed.");
|
||||
promise = waitForMultiple([
|
||||
waitForUnregister((dbg) => dbg.url === CHILD_WORKER_URL),
|
||||
waitForDebuggerClose(dbgs[1]),
|
||||
waitForUnregister((dbg) => dbg.url === PARENT_WORKER_URL),
|
||||
waitForDebuggerClose(dbgs[0]),
|
||||
waitForUnregister(CHILD_WORKER_URL),
|
||||
waitForDebuggerClose(childDbg),
|
||||
waitForUnregister(WORKER_URL),
|
||||
waitForDebuggerClose(dbg),
|
||||
]);
|
||||
worker.terminate();
|
||||
yield promise;
|
||||
|
||||
promise = waitForRegister();
|
||||
info("Create a shared worker and wait for its debugger to be " +
|
||||
"registered");
|
||||
promise = waitForRegister(SHARED_WORKER_URL);
|
||||
worker = new SharedWorker(SHARED_WORKER_URL);
|
||||
let dbg = yield promise;
|
||||
is(dbg.isChrome, false, "debugger should be for content worker");
|
||||
is(dbg.parent, null,
|
||||
"debugger for top-level worker should not have parent");
|
||||
is(dbg.type, Ci.nsIWorkerDebugger.TYPE_SHARED,
|
||||
"debugger should be for shared worker");
|
||||
is(dbg.window, null,
|
||||
"debugger for non-dedicated worker should not have window");
|
||||
let sharedDbg = yield promise;
|
||||
|
||||
info("Check that the shared worker debugger has the correct " +
|
||||
"properties.");
|
||||
is(sharedDbg.isChrome, false,
|
||||
"Shared worker debugger should be content.");
|
||||
is(sharedDbg.parent, null,
|
||||
"Shared worker debugger should not have parent.");
|
||||
is(sharedDbg.type, Ci.nsIWorkerDebugger.TYPE_SHARED,
|
||||
"Shared worker debugger should be shared.");
|
||||
is(sharedDbg.window, null,
|
||||
"Shared worker debugger should not have window.");
|
||||
|
||||
info("Create a shared worker with the same URL and check that its " +
|
||||
"debugger is not registered again.");
|
||||
let listener = {
|
||||
onRegistered: function () {
|
||||
ok(false,
|
||||
"debugger for shared worker should not be registered twice");
|
||||
"Shared worker debugger should not be registered again.");
|
||||
},
|
||||
};
|
||||
wdm.addListener(listener);
|
||||
worker = new SharedWorker(SHARED_WORKER_URL);
|
||||
|
||||
dbg.addListener({
|
||||
onClose: function () {
|
||||
is(dbg.isClosed, true, "debugger should be closed");
|
||||
wdm.removeListener(listener);
|
||||
dbg.removeListener(this);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
});
|
||||
info("Send a message to the shared worker to tell it to close " +
|
||||
"itself, and wait for its debugger to be closed.");
|
||||
promise = waitForMultiple([
|
||||
waitForUnregister(SHARED_WORKER_URL),
|
||||
waitForDebuggerClose(sharedDbg)
|
||||
]);
|
||||
worker.port.start();
|
||||
worker.port.postMessage("close");
|
||||
yield promise;
|
||||
|
||||
wdm.removeListener(listener);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<window title="Test for WorkerDebuggerGlobalScope.createSandbox"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="test();">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
<script type="application/javascript" src="dom_worker_helper.js"/>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
const WORKER_URL = "WorkerDebuggerGlobalScope.createSandbox_worker.js";
|
||||
const DEBUGGER_URL = BASE_URL + "WorkerDebuggerGlobalScope.createSandbox_debugger.js";
|
||||
|
||||
function test() {
|
||||
Task.spawn(function* () {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
info("Create a worker, wait for its debugger to be registered, and " +
|
||||
"initialize it.");
|
||||
let promise = waitForRegister(WORKER_URL, DEBUGGER_URL);
|
||||
let worker = new Worker(WORKER_URL);
|
||||
let dbg = yield promise;
|
||||
|
||||
info("Send a request to the worker debugger. This should cause the " +
|
||||
"worker debugger to send a response from within a sandbox.");
|
||||
promise = waitForDebuggerMessage(dbg, "pong");
|
||||
dbg.postMessage("ping");
|
||||
yield promise;
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display:none;"></div>
|
||||
<pre id="test"></pre>
|
||||
</body>
|
||||
<label id="test-result"/>
|
||||
</window>
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<window title="Test for WorkerDebuggerGlobalScope.enterEventLoop"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="test();">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
<script type="application/javascript" src="dom_worker_helper.js"/>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
const WORKER_URL = "WorkerDebuggerGlobalScope.enterEventLoop_worker.js";
|
||||
const CHILD_WORKER_URL = "WorkerDebuggerGlobalScope.enterEventLoop_childWorker.js";
|
||||
const DEBUGGER_URL = BASE_URL + "WorkerDebuggerGlobalScope.enterEventLoop_debugger.js";
|
||||
|
||||
function test() {
|
||||
Task.spawn(function* () {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
info("Create a worker that creates a child worker, wait for their " +
|
||||
"debuggers to be registered, and initialize them.");
|
||||
let promise = waitForMultiple([
|
||||
waitForRegister(WORKER_URL, DEBUGGER_URL),
|
||||
waitForRegister(CHILD_WORKER_URL, DEBUGGER_URL)
|
||||
]);
|
||||
let worker = new Worker(WORKER_URL);
|
||||
let [dbg, childDbg] = yield promise;
|
||||
|
||||
info("Send a request to the child worker. This should cause the " +
|
||||
"child worker debugger to enter a nested event loop.");
|
||||
promise = waitForDebuggerMessage(childDbg, "paused");
|
||||
worker.postMessage("child:ping");
|
||||
yield promise;
|
||||
|
||||
info("Send a request to the child worker debugger. This should cause " +
|
||||
"the child worker debugger to enter a second nested event loop.");
|
||||
promise = waitForDebuggerMessage(childDbg, "paused");
|
||||
childDbg.postMessage("eval");
|
||||
yield promise;
|
||||
|
||||
info("Send a request to the child worker debugger. This should cause " +
|
||||
"the child worker debugger to leave its second nested event " +
|
||||
"loop. The child worker debugger should not send a response " +
|
||||
"for its previous request until after it has left the nested " +
|
||||
"event loop.");
|
||||
promise = waitForMultiple([
|
||||
waitForDebuggerMessage(childDbg, "resumed"),
|
||||
waitForDebuggerMessage(childDbg, "evalled")
|
||||
]);
|
||||
childDbg.postMessage("resume");
|
||||
yield promise;
|
||||
|
||||
info("Send a request to the child worker debugger. This should cause " +
|
||||
"the child worker debugger to leave its first nested event loop." +
|
||||
"The child worker should not send a response for its earlier " +
|
||||
"request until after the child worker debugger has left the " +
|
||||
"nested event loop.");
|
||||
promise = waitForMultiple([
|
||||
waitForDebuggerMessage(childDbg, "resumed"),
|
||||
waitForWorkerMessage(worker, "child:pong")
|
||||
]);
|
||||
childDbg.postMessage("resume");
|
||||
yield promise;
|
||||
|
||||
info("Send a request to the worker. This should cause the worker " +
|
||||
"debugger to enter a nested event loop.");
|
||||
promise = waitForDebuggerMessage(dbg, "paused");
|
||||
worker.postMessage("ping");
|
||||
yield promise;
|
||||
|
||||
info("Terminate the worker. This should not cause the worker " +
|
||||
"debugger to terminate as well.");
|
||||
worker.terminate();
|
||||
|
||||
worker.onmessage = function () {
|
||||
ok(false, "Worker should have been terminated.");
|
||||
};
|
||||
|
||||
info("Send a request to the worker debugger. This should cause the " +
|
||||
"worker debugger to enter a second nested event loop.");
|
||||
promise = waitForDebuggerMessage(dbg, "paused");
|
||||
dbg.postMessage("eval");
|
||||
yield promise;
|
||||
|
||||
info("Send a request to the worker debugger. This should cause the " +
|
||||
"worker debugger to leave its second nested event loop. The " +
|
||||
"worker debugger should not send a response for the previous " +
|
||||
"request until after leaving the nested event loop.");
|
||||
promise = waitForMultiple([
|
||||
waitForDebuggerMessage(dbg, "resumed"),
|
||||
waitForDebuggerMessage(dbg, "evalled")
|
||||
]);
|
||||
dbg.postMessage("resume");
|
||||
yield promise;
|
||||
|
||||
info("Send a request to the worker debugger. This should cause the " +
|
||||
"worker debugger to leave its first nested event loop. The " +
|
||||
"worker should not send a response for its earlier request, " +
|
||||
"since it has been terminated.");
|
||||
promise = waitForMultiple([
|
||||
waitForDebuggerMessage(dbg, "resumed"),
|
||||
]);
|
||||
dbg.postMessage("resume");
|
||||
yield promise;
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display:none;"></div>
|
||||
<pre id="test"></pre>
|
||||
</body>
|
||||
<label id="test-result"/>
|
||||
</window>
|
||||
@@ -0,0 +1,98 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<window title="Test for WorkerDebuggerGlobalScope.reportError"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="test();">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
<script type="application/javascript" src="dom_worker_helper.js"/>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
const WORKER_URL = "WorkerDebuggerGlobalScope.reportError_worker.js";
|
||||
const CHILD_WORKER_URL = "WorkerDebuggerGlobalScope.reportError_childWorker.js";
|
||||
const DEBUGGER_URL = BASE_URL + "WorkerDebuggerGlobalScope.reportError_debugger.js";
|
||||
|
||||
function test() {
|
||||
Task.spawn(function* () {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
info("Create a worker that creates a child worker, wait for their " +
|
||||
"debuggers to be registered, and initialize them.");
|
||||
let promise = waitForMultiple([
|
||||
waitForRegister(WORKER_URL, DEBUGGER_URL),
|
||||
waitForRegister(CHILD_WORKER_URL, DEBUGGER_URL)
|
||||
]);
|
||||
let worker = new Worker(WORKER_URL);
|
||||
let [dbg, childDbg] = yield promise;
|
||||
|
||||
worker.onmessage = function () {
|
||||
ok(false, "Debugger error events should not be fired at workers.");
|
||||
};
|
||||
|
||||
info("Send a request to the worker debugger. This should cause the " +
|
||||
"worker debugger to report an error.");
|
||||
promise = waitForDebuggerError(dbg);
|
||||
dbg.postMessage("report");
|
||||
let error = yield promise;
|
||||
is(error.fileName, DEBUGGER_URL,
|
||||
"fileName should be name of file from which error is reported.");
|
||||
is(error.lineNumber, 6,
|
||||
"lineNumber should be line number from which error is reported.");
|
||||
is(error.message, "reported", "message should be reported.");
|
||||
|
||||
info("Send a request to the worker debugger. This should cause the " +
|
||||
"worker debugger to throw an error.");
|
||||
promise = waitForDebuggerError(dbg);
|
||||
dbg.postMessage("throw");
|
||||
error = yield promise;
|
||||
is(error.fileName, DEBUGGER_URL,
|
||||
"fileName should be name of file from which error is thrown");
|
||||
is(error.lineNumber, 9,
|
||||
"lineNumber should be line number from which error is thrown");
|
||||
is(error.message, "Error: thrown", "message should be Error: thrown");
|
||||
|
||||
info("Send a reqeust to the child worker debugger. This should cause " +
|
||||
"the child worker debugger to report an error.");
|
||||
promise = waitForDebuggerError(childDbg);
|
||||
childDbg.postMessage("report");
|
||||
error = yield promise;
|
||||
is(error.fileName, DEBUGGER_URL,
|
||||
"fileName should be name of file from which error is reported.");
|
||||
is(error.lineNumber, 6,
|
||||
"lineNumber should be line number from which error is reported.");
|
||||
is(error.message, "reported", "message should be reported.");
|
||||
|
||||
info("Send a message to the child worker debugger. This should cause " +
|
||||
"the child worker debugger to throw an error.");
|
||||
promise = waitForDebuggerError(childDbg);
|
||||
childDbg.postMessage("throw");
|
||||
error = yield promise;
|
||||
is(error.fileName, DEBUGGER_URL,
|
||||
"fileName should be name of file from which error is thrown");
|
||||
is(error.lineNumber, 9,
|
||||
"lineNumber should be line number from which error is thrown");
|
||||
is(error.message, "Error: thrown", "message should be Error: thrown");
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display:none;"></div>
|
||||
<pre id="test"></pre>
|
||||
</body>
|
||||
<label id="test-result"/>
|
||||
</window>
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<window title="Test for WorkerDebuggerGlobalScope.setImmediate"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="test();">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
<script type="application/javascript" src="dom_worker_helper.js"/>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
const WORKER_URL = "WorkerDebuggerGlobalScope.setImmediate_worker.js";
|
||||
const DEBUGGER_URL = BASE_URL + "WorkerDebuggerGlobalScope.setImmediate_debugger.js";
|
||||
|
||||
function test() {
|
||||
Task.spawn(function* () {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
let promise = waitForRegister(WORKER_URL, DEBUGGER_URL);
|
||||
let worker = new Worker(WORKER_URL);
|
||||
let dbg = yield promise;
|
||||
|
||||
info("Send a request to the worker debugger. This should cause a " +
|
||||
"the worker debugger to send two responses. The worker debugger " +
|
||||
"should send the second response before the first one, since " +
|
||||
"the latter is delayed until the next tick of the event loop.");
|
||||
promise = waitForMultiple([
|
||||
waitForDebuggerMessage(dbg, "pong2"),
|
||||
waitForDebuggerMessage(dbg, "pong1")
|
||||
]);
|
||||
dbg.postMessage("ping");
|
||||
yield promise;
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display:none;"></div>
|
||||
<pre id="test"></pre>
|
||||
</body>
|
||||
<label id="test-result"/>
|
||||
</window>
|
||||
@@ -16,65 +16,79 @@
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
const PARENT_WORKER_URL = "WorkerDebuggerManager_parentWorker.js";
|
||||
const WORKER_URL = "WorkerDebuggerManager_worker.js";
|
||||
const CHILD_WORKER_URL = "WorkerDebuggerManager_childWorker.js";
|
||||
|
||||
function test() {
|
||||
Task.spawn(function* () {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
ok(!findDebugger((dbg) => dbg.url === PARENT_WORKER_URL),
|
||||
"debugger for parent worker should not be enumerated before it is " +
|
||||
"registered");
|
||||
ok(!findDebugger((dbg) => dbg.url === CHILD_WORKER_URL),
|
||||
"debugger for child worker should not be enumerated before it is " +
|
||||
"registered");
|
||||
info("Check that worker debuggers are not enumerated before they are " +
|
||||
"registered.");
|
||||
ok(!findDebugger(WORKER_URL),
|
||||
"Worker debugger should not be enumerated before it is registered.");
|
||||
ok(!findDebugger(CHILD_WORKER_URL),
|
||||
"Child worker debugger should not be enumerated before it is " +
|
||||
"registered.");
|
||||
|
||||
info("Create a worker that creates a child worker, and wait for " +
|
||||
"their debuggers to be registered.");
|
||||
let promise = waitForMultiple([
|
||||
waitForRegister((dbg) => dbg.url === PARENT_WORKER_URL),
|
||||
waitForRegister((dbg) => dbg.url === CHILD_WORKER_URL),
|
||||
waitForRegister(WORKER_URL),
|
||||
waitForRegister(CHILD_WORKER_URL)
|
||||
]);
|
||||
let worker = new Worker(PARENT_WORKER_URL);
|
||||
let dbgs = yield promise;
|
||||
is(dbgs[0].isClosed, false,
|
||||
"debugger for parent worker should not be closed after it is " +
|
||||
"registered");
|
||||
is(dbgs[1].isClosed, false,
|
||||
"debugger for child worker should not be closed after it is " +
|
||||
"registered");
|
||||
let worker = new Worker(WORKER_URL);
|
||||
let [dbg, childDbg] = yield promise;
|
||||
|
||||
ok(findDebugger((dbg) => dbg.url === PARENT_WORKER_URL),
|
||||
"debugger for parent worker should be enumerated after it is " +
|
||||
"registered");
|
||||
ok(findDebugger((dbg) => dbg.url === CHILD_WORKER_URL),
|
||||
"debugger for child worker should be enumerated after it is " +
|
||||
"registered");
|
||||
info("Check that worker debuggers are enumerated after they are " +
|
||||
"registered.");
|
||||
ok(findDebugger(WORKER_URL),
|
||||
"Worker debugger should be enumerated after it is registered.");
|
||||
ok(findDebugger(CHILD_WORKER_URL),
|
||||
"Child worker debugger should be enumerated after it is " +
|
||||
"registered.");
|
||||
|
||||
info("Check that worker debuggers are not closed before they are " +
|
||||
"unregistered.");
|
||||
is(dbg.isClosed, false,
|
||||
"Worker debugger should not be closed before it is unregistered.");
|
||||
is(childDbg.isClosed, false,
|
||||
"Child worker debugger should not be closed before it is " +
|
||||
"unregistered");
|
||||
|
||||
info("Terminate the worker and the child worker, and wait for their " +
|
||||
"debuggers to be unregistered.");
|
||||
promise = waitForMultiple([
|
||||
waitForUnregister((dbg) => dbg.url === CHILD_WORKER_URL),
|
||||
waitForUnregister((dbg) => dbg.url === PARENT_WORKER_URL),
|
||||
waitForUnregister(CHILD_WORKER_URL),
|
||||
waitForUnregister(WORKER_URL),
|
||||
]);
|
||||
worker.terminate();
|
||||
dbgs = yield promise;
|
||||
is(dbgs[0].isClosed, true,
|
||||
"debugger for parent worker should be closed after it is " +
|
||||
"unregistered");
|
||||
is(dbgs[1].isClosed, true,
|
||||
"debugger for child worker should be closed after it is " +
|
||||
"unregistered");
|
||||
assertThrows(() => dbgs[0].url,
|
||||
"accessing debugger for parent worker should throw " +
|
||||
"after it is closed");
|
||||
assertThrows(() => dbgs[0].url,
|
||||
"accessing debugger for child worker should throw after " +
|
||||
"it is closed");
|
||||
yield promise;
|
||||
|
||||
ok(!findDebugger((dbg) => dbg.url === PARENT_WORKER_URL),
|
||||
"debugger for parent worker should not be enumerated after it is " +
|
||||
"unregistered");
|
||||
ok(!findDebugger((dbg) => dbg.url === CHILD_WORKER_URL),
|
||||
"debugger for child worker should not be enumerated after it is " +
|
||||
"unregistered");
|
||||
info("Check that worker debuggers are not enumerated after they are " +
|
||||
"unregistered.");
|
||||
ok(!findDebugger(WORKER_URL),
|
||||
"Worker debugger should not be enumerated after it is " +
|
||||
"unregistered.");
|
||||
ok(!findDebugger(CHILD_WORKER_URL),
|
||||
"Child worker debugger should not be enumerated after it is " +
|
||||
"unregistered.");
|
||||
|
||||
info("Check that worker debuggers are closed after they are " +
|
||||
"unregistered.");
|
||||
is(dbg.isClosed, true,
|
||||
"Worker debugger should be closed after it is unregistered.");
|
||||
is(childDbg.isClosed, true,
|
||||
"Child worker debugger should be closed after it is unregistered.");
|
||||
|
||||
info("Check that property accesses on worker debuggers throws " +
|
||||
"after they are closed.");
|
||||
assertThrows(() => dbg.url,
|
||||
"Property accesses on worker debugger should throw " +
|
||||
"after it is closed.");
|
||||
assertThrows(() => childDbg.url,
|
||||
"Property accesses on child worker debugger should " +
|
||||
"throw after it is closed.");
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
@@ -4768,7 +4768,11 @@ pref("beacon.enabled", true);
|
||||
pref("camera.control.face_detection.enabled", true);
|
||||
|
||||
// SW Cache API
|
||||
#ifdef RELEASE_BUILD
|
||||
pref("dom.caches.enabled", false);
|
||||
#else
|
||||
pref("dom.caches.enabled", true);
|
||||
#endif // RELEASE_BUILD
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
// Empirically, this is the value returned by hal::GetTotalSystemMemory()
|
||||
|
||||
Reference in New Issue
Block a user