summaryrefslogtreecommitdiffstats
path: root/dom/workers
diff options
context:
space:
mode:
Diffstat (limited to 'dom/workers')
-rw-r--r--dom/workers/RuntimeService.cpp15
-rw-r--r--dom/workers/ScriptLoader.cpp14
-rw-r--r--dom/workers/ServiceWorkerEvents.cpp14
-rw-r--r--dom/workers/ServiceWorkerPrivate.cpp45
-rw-r--r--dom/workers/ServiceWorkerPrivate.h1
-rw-r--r--dom/workers/WorkerNavigator.cpp2
-rw-r--r--dom/workers/WorkerPrivate.cpp24
-rw-r--r--dom/workers/WorkerPrivate.h29
-rw-r--r--dom/workers/WorkerRunnable.cpp13
-rw-r--r--dom/workers/WorkerRunnable.h9
-rw-r--r--dom/workers/test/serviceworkers/chrome.ini3
-rw-r--r--dom/workers/test/serviceworkers/fetch_event_worker.js23
-rw-r--r--dom/workers/test/serviceworkers/test_devtools_serviceworker_interception.html168
-rw-r--r--dom/workers/test/serviceworkers/test_serviceworker_interfaces.js6
-rw-r--r--dom/workers/test/test_worker_interfaces.js6
15 files changed, 289 insertions, 83 deletions
diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp
index 1739f3d31..e1910536f 100644
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -587,7 +587,7 @@ ContentSecurityPolicyAllows(JSContext* aCx)
new LogViolationDetailsRunnable(worker, fileName, lineNum);
ErrorResult rv;
- runnable->Dispatch(rv);
+ runnable->Dispatch(Killing, rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
}
@@ -2811,13 +2811,6 @@ WorkerThreadPrimaryRunnable::Run()
}
{
-#ifdef MOZ_ENABLE_PROFILER_SPS
- PseudoStack* stack = mozilla_get_pseudo_stack();
- if (stack) {
- stack->sampleContext(cx);
- }
-#endif
-
{
JSAutoRequest ar(cx);
@@ -2829,12 +2822,6 @@ WorkerThreadPrimaryRunnable::Run()
}
BackgroundChild::CloseForCurrentThread();
-
-#ifdef MOZ_ENABLE_PROFILER_SPS
- if (stack) {
- stack->sampleContext(nullptr);
- }
-#endif
}
// There may still be runnables on the debugger event queue that hold a
diff --git a/dom/workers/ScriptLoader.cpp b/dom/workers/ScriptLoader.cpp
index 46545e737..56b18441e 100644
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -2118,12 +2118,16 @@ LoadAllScripts(WorkerPrivate* aWorkerPrivate,
aWorkerPrivate->AssertIsOnWorkerThread();
NS_ASSERTION(!aLoadInfos.IsEmpty(), "Bad arguments!");
- AutoSyncLoopHolder syncLoop(aWorkerPrivate);
+ AutoSyncLoopHolder syncLoop(aWorkerPrivate, Terminating);
+ nsCOMPtr<nsIEventTarget> syncLoopTarget = syncLoop.GetEventTarget();
+ if (!syncLoopTarget) {
+ aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+ return;
+ }
RefPtr<ScriptLoaderRunnable> loader =
- new ScriptLoaderRunnable(aWorkerPrivate, syncLoop.EventTarget(),
- aLoadInfos, aIsMainScript, aWorkerScriptType,
- aRv);
+ new ScriptLoaderRunnable(aWorkerPrivate, syncLoopTarget, aLoadInfos,
+ aIsMainScript, aWorkerScriptType, aRv);
NS_ASSERTION(aLoadInfos.IsEmpty(), "Should have swapped!");
@@ -2184,7 +2188,7 @@ ChannelFromScriptURLWorkerThread(JSContext* aCx,
new ChannelGetterRunnable(aParent, aScriptURL, aChannel);
ErrorResult rv;
- getter->Dispatch(rv);
+ getter->Dispatch(Terminating, rv);
if (rv.Failed()) {
NS_ERROR("Failed to dispatch!");
return rv.StealNSResult();
diff --git a/dom/workers/ServiceWorkerEvents.cpp b/dom/workers/ServiceWorkerEvents.cpp
index 09b09a24b..1f79e2c92 100644
--- a/dom/workers/ServiceWorkerEvents.cpp
+++ b/dom/workers/ServiceWorkerEvents.cpp
@@ -12,6 +12,7 @@
#include "nsINetworkInterceptController.h"
#include "nsIOutputStream.h"
#include "nsIScriptError.h"
+#include "nsITimedChannel.h"
#include "nsIUnicodeDecoder.h"
#include "nsIUnicodeEncoder.h"
#include "nsContentPolicyUtils.h"
@@ -108,6 +109,12 @@ NS_IMETHODIMP
CancelChannelRunnable::Run()
{
MOZ_ASSERT(NS_IsMainThread());
+
+ // TODO: When bug 1204254 is implemented, this time marker should be moved to
+ // the point where the body of the network request is complete.
+ mChannel->SetHandleFetchEventEnd(TimeStamp::Now());
+ mChannel->SaveTimeStampsToUnderlyingChannel();
+
mChannel->Cancel(mStatus);
mRegistration->MaybeScheduleUpdate();
return NS_OK;
@@ -230,6 +237,9 @@ public:
return NS_OK;
}
+ mChannel->SetHandleFetchEventEnd(TimeStamp::Now());
+ mChannel->SaveTimeStampsToUnderlyingChannel();
+
nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
if (obsService) {
obsService->NotifyObservers(underlyingChannel, "service-worker-synthesized-response", nullptr);
@@ -948,10 +958,8 @@ ExtendableEvent::GetPromise()
}
JSContext* cx = jsapi.cx();
- GlobalObject global(cx, globalObj->GetGlobalJSObject());
-
ErrorResult result;
- RefPtr<Promise> p = Promise::All(global, Move(mPromises), result);
+ RefPtr<Promise> p = Promise::All(cx, Move(mPromises), result);
if (NS_WARN_IF(result.MaybeSetPendingException(cx))) {
return nullptr;
}
diff --git a/dom/workers/ServiceWorkerPrivate.cpp b/dom/workers/ServiceWorkerPrivate.cpp
index eaa548f95..24b2e11e6 100644
--- a/dom/workers/ServiceWorkerPrivate.cpp
+++ b/dom/workers/ServiceWorkerPrivate.cpp
@@ -13,6 +13,7 @@
#include "nsINetworkInterceptController.h"
#include "nsIPushErrorReporter.h"
#include "nsISupportsImpl.h"
+#include "nsITimedChannel.h"
#include "nsIUploadChannel2.h"
#include "nsNetUtil.h"
#include "nsProxyRelease.h"
@@ -1255,6 +1256,7 @@ class FetchEventRunnable : public ExtendableFunctionalEventWorkerRunnable
nsCString mMethod;
nsString mClientId;
bool mIsReload;
+ bool mMarkLaunchServiceWorkerEnd;
RequestCache mCacheMode;
RequestMode mRequestMode;
RequestRedirect mRequestRedirect;
@@ -1273,13 +1275,15 @@ public:
const nsACString& aScriptSpec,
nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration,
const nsAString& aDocumentId,
- bool aIsReload)
+ bool aIsReload,
+ bool aMarkLaunchServiceWorkerEnd)
: ExtendableFunctionalEventWorkerRunnable(
aWorkerPrivate, aKeepAliveToken, aRegistration)
, mInterceptedChannel(aChannel)
, mScriptSpec(aScriptSpec)
, mClientId(aDocumentId)
, mIsReload(aIsReload)
+ , mMarkLaunchServiceWorkerEnd(aMarkLaunchServiceWorkerEnd)
, mCacheMode(RequestCache::Default)
, mRequestMode(RequestMode::No_cors)
, mRequestRedirect(RequestRedirect::Follow)
@@ -1417,6 +1421,12 @@ public:
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
{
MOZ_ASSERT(aWorkerPrivate);
+
+ if (mMarkLaunchServiceWorkerEnd) {
+ mInterceptedChannel->SetLaunchServiceWorkerEnd(TimeStamp::Now());
+ }
+
+ mInterceptedChannel->SetDispatchFetchEventEnd(TimeStamp::Now());
return DispatchFetchEvent(aCx, aWorkerPrivate);
}
@@ -1445,6 +1455,10 @@ private:
NS_IMETHOD Run() override
{
AssertIsOnMainThread();
+
+ mChannel->SetHandleFetchEventEnd(TimeStamp::Now());
+ mChannel->SaveTimeStampsToUnderlyingChannel();
+
nsresult rv = mChannel->ResetInterception();
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"Failed to resume intercepted network request");
@@ -1520,6 +1534,8 @@ private:
event->PostInit(mInterceptedChannel, mRegistration, mScriptSpec);
event->SetTrusted(true);
+ mInterceptedChannel->SetHandleFetchEventStart(TimeStamp::Now());
+
RefPtr<EventTarget> target = do_QueryObject(aWorkerPrivate->GlobalScope());
nsresult rv2 = target->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
if (NS_WARN_IF(NS_FAILED(rv2)) || !event->WaitToRespond()) {
@@ -1614,9 +1630,21 @@ ServiceWorkerPrivate::SendFetchEvent(nsIInterceptedChannel* aChannel,
nsCOMPtr<nsIRunnable> failRunnable =
NewRunnableMethod(aChannel, &nsIInterceptedChannel::ResetInterception);
- nsresult rv = SpawnWorkerIfNeeded(FetchEvent, failRunnable, aLoadGroup);
+ aChannel->SetLaunchServiceWorkerStart(TimeStamp::Now());
+ aChannel->SetDispatchFetchEventStart(TimeStamp::Now());
+
+ bool newWorkerCreated = false;
+ nsresult rv = SpawnWorkerIfNeeded(FetchEvent,
+ failRunnable,
+ &newWorkerCreated,
+ aLoadGroup);
+
NS_ENSURE_SUCCESS(rv, rv);
+ if (!newWorkerCreated) {
+ aChannel->SetLaunchServiceWorkerEnd(TimeStamp::Now());
+ }
+
nsMainThreadPtrHandle<nsIInterceptedChannel> handle(
new nsMainThreadPtrHolder<nsIInterceptedChannel>(aChannel, false));
@@ -1646,7 +1674,7 @@ ServiceWorkerPrivate::SendFetchEvent(nsIInterceptedChannel* aChannel,
RefPtr<FetchEventRunnable> r =
new FetchEventRunnable(mWorkerPrivate, token, handle,
mInfo->ScriptSpec(), regInfo,
- aDocumentId, aIsReload);
+ aDocumentId, aIsReload, newWorkerCreated);
rv = r->Init();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
@@ -1669,6 +1697,7 @@ ServiceWorkerPrivate::SendFetchEvent(nsIInterceptedChannel* aChannel,
nsresult
ServiceWorkerPrivate::SpawnWorkerIfNeeded(WakeUpReason aWhy,
nsIRunnable* aLoadFailedRunnable,
+ bool* aNewWorkerCreated,
nsILoadGroup* aLoadGroup)
{
AssertIsOnMainThread();
@@ -1679,6 +1708,12 @@ ServiceWorkerPrivate::SpawnWorkerIfNeeded(WakeUpReason aWhy,
// the overriden load group when intercepting a fetch.
MOZ_ASSERT_IF(aWhy == FetchEvent, aLoadGroup);
+ // Defaults to no new worker created, but if there is one, we'll set the value
+ // to true at the end of this function.
+ if (aNewWorkerCreated) {
+ *aNewWorkerCreated = false;
+ }
+
if (mWorkerPrivate) {
mWorkerPrivate->UpdateOverridenLoadGroup(aLoadGroup);
RenewKeepAliveToken(aWhy);
@@ -1762,6 +1797,10 @@ ServiceWorkerPrivate::SpawnWorkerIfNeeded(WakeUpReason aWhy,
RenewKeepAliveToken(aWhy);
+ if (aNewWorkerCreated) {
+ *aNewWorkerCreated = true;
+ }
+
return NS_OK;
}
diff --git a/dom/workers/ServiceWorkerPrivate.h b/dom/workers/ServiceWorkerPrivate.h
index 8d59ea1d0..911b07a11 100644
--- a/dom/workers/ServiceWorkerPrivate.h
+++ b/dom/workers/ServiceWorkerPrivate.h
@@ -189,6 +189,7 @@ private:
nsresult
SpawnWorkerIfNeeded(WakeUpReason aWhy,
nsIRunnable* aLoadFailedRunnable,
+ bool* aNewWorkerCreated = nullptr,
nsILoadGroup* aLoadGroup = nullptr);
~ServiceWorkerPrivate();
diff --git a/dom/workers/WorkerNavigator.cpp b/dom/workers/WorkerNavigator.cpp
index 682c7a22c..f79896881 100644
--- a/dom/workers/WorkerNavigator.cpp
+++ b/dom/workers/WorkerNavigator.cpp
@@ -152,7 +152,7 @@ WorkerNavigator::GetUserAgent(nsString& aUserAgent, ErrorResult& aRv) const
RefPtr<GetUserAgentRunnable> runnable =
new GetUserAgentRunnable(workerPrivate, aUserAgent);
- runnable->Dispatch(aRv);
+ runnable->Dispatch(Terminating, aRv);
}
uint64_t
diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp
index bd8a33032..612090027 100644
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -2419,8 +2419,6 @@ WorkerPrivateParent<Derived>::WorkerPrivateParent(
MOZ_ASSERT_IF(mIsChromeWorker, mIsSecureContext);
MOZ_ASSERT(IsDedicatedWorker());
- mNowBaseTimeStamp = aParent->NowBaseTimeStamp();
- mNowBaseTimeHighRes = aParent->NowBaseTime();
if (aParent->mParentFrozen) {
Freeze(nullptr);
@@ -2451,18 +2449,6 @@ WorkerPrivateParent<Derived>::WorkerPrivateParent(
.creationOptions().setSecureContext(true);
}
- if (IsDedicatedWorker() && mLoadInfo.mWindow &&
- mLoadInfo.mWindow->GetPerformance()) {
- mNowBaseTimeStamp = mLoadInfo.mWindow->GetPerformance()->GetDOMTiming()->
- GetNavigationStartTimeStamp();
- mNowBaseTimeHighRes =
- mLoadInfo.mWindow->GetPerformance()->GetDOMTiming()->
- GetNavigationStartHighRes();
- } else {
- mNowBaseTimeStamp = CreationTimeStamp();
- mNowBaseTimeHighRes = CreationTime();
- }
-
// Our parent can get suspended after it initiates the async creation
// of a new worker thread. In this case suspend the new worker as well.
if (mLoadInfo.mWindow && mLoadInfo.mWindow->IsSuspended()) {
@@ -5460,10 +5446,18 @@ WorkerPrivate::CancelAllTimeouts()
}
already_AddRefed<nsIEventTarget>
-WorkerPrivate::CreateNewSyncLoop()
+WorkerPrivate::CreateNewSyncLoop(Status aFailStatus)
{
AssertIsOnWorkerThread();
+ {
+ MutexAutoLock lock(mMutex);
+
+ if (mStatus >= aFailStatus) {
+ return nullptr;
+ }
+ }
+
nsCOMPtr<nsIThreadInternal> thread = do_QueryInterface(NS_GetCurrentThread());
MOZ_ASSERT(thread);
diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h
index 465c0f9a3..20a530205 100644
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -216,8 +216,6 @@ private:
WorkerType mWorkerType;
TimeStamp mCreationTimeStamp;
DOMHighResTimeStamp mCreationTimeHighRes;
- TimeStamp mNowBaseTimeStamp;
- DOMHighResTimeStamp mNowBaseTimeHighRes;
protected:
// The worker is owned by its thread, which is represented here. This is set
@@ -579,14 +577,11 @@ public:
return mCreationTimeHighRes;
}
- TimeStamp NowBaseTimeStamp() const
+ DOMHighResTimeStamp TimeStampToDOMHighRes(const TimeStamp& aTimeStamp) const
{
- return mNowBaseTimeStamp;
- }
-
- DOMHighResTimeStamp NowBaseTime() const
- {
- return mNowBaseTimeHighRes;
+ MOZ_ASSERT(!aTimeStamp.IsNull());
+ TimeDuration duration = aTimeStamp - mCreationTimeStamp;
+ return duration.ToMilliseconds();
}
nsIPrincipal*
@@ -1447,8 +1442,11 @@ private:
memcpy(aPreferences, mPreferences, WORKERPREF_COUNT * sizeof(bool));
}
+ // If the worker shutdown status is equal or greater then aFailStatus, this
+ // operation will fail and nullptr will be returned. See WorkerHolder.h for
+ // more information about the correct value to use.
already_AddRefed<nsIEventTarget>
- CreateNewSyncLoop();
+ CreateNewSyncLoop(Status aFailStatus);
bool
RunCurrentSyncLoop();
@@ -1523,9 +1521,11 @@ class AutoSyncLoopHolder
uint32_t mIndex;
public:
- explicit AutoSyncLoopHolder(WorkerPrivate* aWorkerPrivate)
+ // See CreateNewSyncLoop() for more information about the correct value to use
+ // for aFailStatus.
+ AutoSyncLoopHolder(WorkerPrivate* aWorkerPrivate, Status aFailStatus)
: mWorkerPrivate(aWorkerPrivate)
- , mTarget(aWorkerPrivate->CreateNewSyncLoop())
+ , mTarget(aWorkerPrivate->CreateNewSyncLoop(aFailStatus))
, mIndex(aWorkerPrivate->mSyncLoopStack.Length() - 1)
{
aWorkerPrivate->AssertIsOnWorkerThread();
@@ -1533,7 +1533,7 @@ public:
~AutoSyncLoopHolder()
{
- if (mWorkerPrivate) {
+ if (mWorkerPrivate && mTarget) {
mWorkerPrivate->AssertIsOnWorkerThread();
mWorkerPrivate->StopSyncLoop(mTarget, false);
mWorkerPrivate->DestroySyncLoop(mIndex);
@@ -1552,8 +1552,9 @@ public:
}
nsIEventTarget*
- EventTarget() const
+ GetEventTarget() const
{
+ // This can be null if CreateNewSyncLoop() fails.
return mTarget;
}
};
diff --git a/dom/workers/WorkerRunnable.cpp b/dom/workers/WorkerRunnable.cpp
index 1e16d7254..6bbe40f66 100644
--- a/dom/workers/WorkerRunnable.cpp
+++ b/dom/workers/WorkerRunnable.cpp
@@ -568,15 +568,20 @@ WorkerMainThreadRunnable::WorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate
}
void
-WorkerMainThreadRunnable::Dispatch(ErrorResult& aRv)
+WorkerMainThreadRunnable::Dispatch(Status aFailStatus, ErrorResult& aRv)
{
mWorkerPrivate->AssertIsOnWorkerThread();
TimeStamp startTime = TimeStamp::NowLoRes();
- AutoSyncLoopHolder syncLoop(mWorkerPrivate);
+ AutoSyncLoopHolder syncLoop(mWorkerPrivate, aFailStatus);
- mSyncLoopTarget = syncLoop.EventTarget();
+ mSyncLoopTarget = syncLoop.GetEventTarget();
+ if (!mSyncLoopTarget) {
+ // SyncLoop creation can fail if the worker is shutting down.
+ aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+ return;
+ }
DebugOnly<nsresult> rv = mWorkerPrivate->DispatchToMainThread(this);
MOZ_ASSERT(NS_SUCCEEDED(rv),
@@ -621,7 +626,7 @@ bool
WorkerCheckAPIExposureOnMainThreadRunnable::Dispatch()
{
ErrorResult rv;
- WorkerMainThreadRunnable::Dispatch(rv);
+ WorkerMainThreadRunnable::Dispatch(Terminating, rv);
bool ok = !rv.Failed();
rv.SuppressException();
return ok;
diff --git a/dom/workers/WorkerRunnable.h b/dom/workers/WorkerRunnable.h
index c65060f44..8249a8053 100644
--- a/dom/workers/WorkerRunnable.h
+++ b/dom/workers/WorkerRunnable.h
@@ -401,9 +401,12 @@ protected:
public:
// Dispatch the runnable to the main thread. If dispatch to main thread
- // fails, or if the worker is shut down while dispatching, an error will be
- // reported on aRv. In that case the error MUST be propagated out to script.
- void Dispatch(ErrorResult& aRv);
+ // fails, or if the worker is in a state equal or greater of aFailStatus, an
+ // error will be reported on aRv. Normally you want to use 'Terminating' for
+ // aFailStatus, except if you want an infallible runnable. In this case, use
+ // 'Killing'.
+ // In that case the error MUST be propagated out to script.
+ void Dispatch(Status aFailStatus, ErrorResult& aRv);
private:
NS_IMETHOD Run() override;
diff --git a/dom/workers/test/serviceworkers/chrome.ini b/dom/workers/test/serviceworkers/chrome.ini
index e064e7fd0..6d7dbebd0 100644
--- a/dom/workers/test/serviceworkers/chrome.ini
+++ b/dom/workers/test/serviceworkers/chrome.ini
@@ -3,6 +3,8 @@ skip-if = os == 'android'
support-files =
chrome_helpers.js
empty.js
+ fetch.js
+ hello.html
serviceworker.html
serviceworkerinfo_iframe.html
serviceworkermanager_iframe.html
@@ -10,6 +12,7 @@ support-files =
worker.js
worker2.js
+[test_devtools_serviceworker_interception.html]
[test_privateBrowsing.html]
[test_serviceworkerinfo.xul]
[test_serviceworkermanager.xul]
diff --git a/dom/workers/test/serviceworkers/fetch_event_worker.js b/dom/workers/test/serviceworkers/fetch_event_worker.js
index 1caef71e8..895128e2c 100644
--- a/dom/workers/test/serviceworkers/fetch_event_worker.js
+++ b/dom/workers/test/serviceworkers/fetch_event_worker.js
@@ -148,28 +148,21 @@ onfetch = function(ev) {
}
else if (ev.request.url.includes("navigate.html")) {
- var navigateModeCorrectlyChecked = false;
var requests = [ // should not throw
new Request(ev.request),
new Request(ev.request, undefined),
new Request(ev.request, null),
new Request(ev.request, {}),
new Request(ev.request, {someUnrelatedProperty: 42}),
+ new Request(ev.request, {method: "GET"}),
];
- try {
- var request3 = new Request(ev.request, {method: "GET"}); // should throw
- } catch(e) {
- navigateModeCorrectlyChecked = requests[0].mode == "navigate";
- }
- if (navigateModeCorrectlyChecked) {
- ev.respondWith(Promise.resolve(
- new Response("<script>window.frameElement.test_result = true;</script>", {
- headers : {
- "Content-Type": "text/html"
- }
- })
- ));
- }
+ ev.respondWith(Promise.resolve(
+ new Response("<script>window.frameElement.test_result = true;</script>", {
+ headers : {
+ "Content-Type": "text/html"
+ }
+ })
+ ));
}
else if (ev.request.url.includes("nonexistent_worker_script.js")) {
diff --git a/dom/workers/test/serviceworkers/test_devtools_serviceworker_interception.html b/dom/workers/test/serviceworkers/test_devtools_serviceworker_interception.html
new file mode 100644
index 000000000..d49ebb2c9
--- /dev/null
+++ b/dom/workers/test/serviceworkers/test_devtools_serviceworker_interception.html
@@ -0,0 +1,168 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1168875 - test devtools serviceworker interception.</title>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet"
+ type="text/css"
+ href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+<script class="testbody" type="text/javascript">
+
+// Constants
+const Ci = Components.interfaces;
+const workerScope = "http://mochi.test:8888/chrome/dom/workers/test/serviceworkers/";
+const workerURL = workerScope + "fetch.js";
+const contentPage = workerScope + "hello.html";
+
+function createTestWindow(aURL) {
+ var mainwindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShellTreeItem)
+ .rootTreeItem
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindow);
+ var win = mainwindow.OpenBrowserWindow(contentPage);
+
+ return new Promise(aResolve => {
+ win.addEventListener("DOMContentLoaded", function callback() {
+ if (win.content.location.href != aURL) {
+ win.gBrowser.loadURI(aURL);
+ return;
+ }
+
+ win.removeEventListener("DOMContentLoaded", callback);
+ aResolve(win.content);
+ });
+ });
+}
+
+function executeTest(aWindow) {
+ var registration;
+
+ return Promise.resolve()
+ // Should not be intercepted.
+ .then(_ => fetchAndCheckTimedChannel(aWindow, false, true, "hello.html"))
+
+ // Regist a service worker.
+ .then(_ => register(aWindow, workerURL, workerScope))
+ .then(r => registration = r)
+
+ // Should be intercpeted and synthesized.
+ .then(_ => fetchAndCheckTimedChannel(aWindow, true, false, "fake.html"))
+
+ // Should be intercepted but still fetch from network.
+ .then(_ => fetchAndCheckTimedChannel(aWindow, true, true,
+ "hello.html?ForBypassingHttpCache"))
+
+ // Tear down
+ .then(_ => registration.unregister());
+}
+
+function register(aWindow, aURL, aScope) {
+ return aWindow.navigator.serviceWorker.register(aURL, {scope: aScope})
+ .then(r => {
+ var worker = r.installing;
+ return new Promise(function(aResolve) {
+ worker.onstatechange = function() {
+ if (worker.state == "activated") {
+ aResolve(r);
+ }
+ }
+ });
+ });
+}
+
+function fetchAndCheckTimedChannel(aWindow, aIntercepted, aFetch, aURL) {
+ var resolveFunction;
+ var promise = new Promise(aResolve => resolveFunction = aResolve);
+
+ var topic = aFetch ? "http-on-examine-response"
+ : "service-worker-synthesized-response";
+
+ function observer(aSubject) {
+ var channel = aSubject.QueryInterface(Ci.nsIChannel);
+ ok(channel.URI.spec.endsWith(aURL));
+
+ var tc = aSubject.QueryInterface(Ci.nsITimedChannel);
+
+ // Check service worker related timings.
+ var serviceWorkerTimings = [{start: tc.launchServiceWorkerStartTime,
+ end: tc.launchServiceWorkerEndTime},
+ {start: tc.dispatchFetchEventStartTime,
+ end: tc.dispatchFetchEventEndTime},
+ {start: tc.handleFetchEventStartTime,
+ end: tc.handleFetchEventEndTime}];
+ if (aIntercepted) {
+ serviceWorkerTimings.reduce((aPreviousTimings, aCurrentTimings) => {
+ ok(aPreviousTimings.start <= aCurrentTimings.start,
+ "Start time order check.");
+ ok(aPreviousTimings.end <= aCurrentTimings.end,
+ "End time order check.");
+ ok(aCurrentTimings.start <= aCurrentTimings.end,
+ "Start time should be smaller than end time.");
+ return aCurrentTimings;
+ });
+ } else {
+ serviceWorkerTimings.forEach(aTimings => {
+ is(aTimings.start, 0);
+ is(aTimings.end, 0);
+ });
+ }
+
+ // Check network related timings.
+ var networkTimings = [tc.domainLookupStartTime,
+ tc.domainLookupEndTime,
+ tc.connectStartTime,
+ tc.connectEndTime,
+ tc.requestStartTime,
+ tc.responseStartTime,
+ tc.responseEndTime];
+ if (aFetch) {
+ networkTimings.reduce((aPreviousTiming, aCurrentTiming) => {
+ ok(aPreviousTiming <= aCurrentTiming);
+ return aCurrentTiming;
+ });
+ } else {
+ networkTimings.forEach(aTiming => is(aTiming, 0));
+ }
+
+ SpecialPowers.removeObserver(observer, topic);
+ resolveFunction();
+ }
+
+ SpecialPowers.addObserver(observer, topic, false);
+
+ // return promise;
+ return Promise.all([aWindow.fetch(aURL), promise]);
+}
+
+function runTest() {
+ return Promise.resolve()
+ .then(_ => createTestWindow(contentPage))
+ .then(w => executeTest(w))
+ .catch(e => ok(false, "Some test failed with error " + e))
+ .then(_ => SimpleTest.finish());
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({"set": [
+ ["dom.serviceWorkers.exemptFromPerDomainMax", true],
+ ["dom.serviceWorkers.enabled", true],
+ ["dom.serviceWorkers.testing.enabled", true],
+]}, runTest);
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
index 9dbfcc099..b337b13ba 100644
--- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
+++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
@@ -38,7 +38,7 @@ var ecmaGlobals =
"Int32Array",
"Int8Array",
"InternalError",
- {name: "Intl", android: false},
+ "Intl",
"Iterator",
"JSON",
"Map",
@@ -172,9 +172,9 @@ var interfaceNamesInGlobalScope =
// IMPORTANT: Do not change this list without review from a DOM peer!
"PerformanceMeasure",
// IMPORTANT: Do not change this list without review from a DOM peer!
- { name: "PerformanceObserver", nightly: true },
+ "PerformanceObserver",
// IMPORTANT: Do not change this list without review from a DOM peer!
- { name: "PerformanceObserverEntryList", nightly: true },
+ "PerformanceObserverEntryList",
// IMPORTANT: Do not change this list without review from a DOM peer!
"Request",
// IMPORTANT: Do not change this list without review from a DOM peer!
diff --git a/dom/workers/test/test_worker_interfaces.js b/dom/workers/test/test_worker_interfaces.js
index e0647682c..159278f9a 100644
--- a/dom/workers/test/test_worker_interfaces.js
+++ b/dom/workers/test/test_worker_interfaces.js
@@ -38,7 +38,7 @@ var ecmaGlobals =
"Int32Array",
"Int8Array",
"InternalError",
- {name: "Intl", android: false},
+ "Intl",
"Iterator",
"JSON",
"Map",
@@ -163,9 +163,9 @@ var interfaceNamesInGlobalScope =
// IMPORTANT: Do not change this list without review from a DOM peer!
"PerformanceMeasure",
// IMPORTANT: Do not change this list without review from a DOM peer!
- { name: "PerformanceObserver", nightly: true },
+ "PerformanceObserver",
// IMPORTANT: Do not change this list without review from a DOM peer!
- { name: "PerformanceObserverEntryList", nightly: true },
+ "PerformanceObserverEntryList",
// IMPORTANT: Do not change this list without review from a DOM peer!
"Request",
// IMPORTANT: Do not change this list without review from a DOM peer!