navigator.onLine does not work inside service workers
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 8 Jan 2018 14:43:50 +0000 (14:43 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 8 Jan 2018 14:43:50 +0000 (14:43 +0000)
https://bugs.webkit.org/show_bug.cgi?id=181079
<rdar://problem/36178606>

Patch by Youenn Fablet <youenn@apple.com> on 2018-01-08
Reviewed by Darin Adler.

Source/WebCore:

Test: http/wpt/service-workers/online.https.html

Added support for onLine by reusing a similar implementation as regular workers.
Added ServiceWorkerInternals as an interface for an object exposed as self.internals in WTR.
This object has currently one method to trigger change in the online/offline status.
This allows writing a test for the onLine feature.

Note that self.internals is inserted asynchronously after the script was evaluated.
When writing a worker script using self.internals, one must make sure to use self.internals when initialized.
online-worker.js for instance makes use of self.internals in a postMessage callback.

* CMakeLists.txt:
* DerivedSources.make:
* WebCore.xcodeproj/project.pbxproj:
* bindings/js/WorkerScriptController.h:
* dom/ScriptExecutionContext.h:
* testing/ServiceWorkerInternals.cpp: Added.
(WebCore::ServiceWorkerInternals::ServiceWorkerInternals):
(WebCore::ServiceWorkerInternals::setOnline):
* testing/ServiceWorkerInternals.h: Added.
* testing/ServiceWorkerInternals.idl: Added.
* testing/js/WebCoreTestSupport.cpp:
(WebCoreTestSupport::setupNewlyCreateServiceWorker):
* testing/js/WebCoreTestSupport.h:
* workers/service/context/SWContextManager.cpp:
(WebCore::SWContextManager::registerServiceWorkerThreadForInstall):
(WebCore::SWContextManager::startedServiceWorker):
* workers/service/context/SWContextManager.h:
(WebCore::SWContextManager::setServiceWorkerCreationCallback):
(WebCore::SWContextManager::workerByID):
* workers/service/context/ServiceWorkerThread.cpp:
(WebCore::ServiceWorkerThread::ServiceWorkerThread):
* workers/service/context/ServiceWorkerThreadProxy.cpp:
(WebCore::ServiceWorkerThreadProxy::ServiceWorkerThreadProxy):
(WebCore::ServiceWorkerThreadProxy::~ServiceWorkerThreadProxy):
(WebCore::ServiceWorkerThreadProxy::networkStateChanged):
(WebCore::ServiceWorkerThreadProxy::notifyNetworkStateChange):
* workers/service/context/ServiceWorkerThreadProxy.h:

Source/WebKit:

Added support for a callback called for each service worker proxy creation.
Callback is used by WTR to inject a self.internals object used for testing.

* WebProcess/InjectedBundle/API/c/WKBundle.cpp:
(WKBundleSetServiceWorkerProxyCreationCallback):
* WebProcess/InjectedBundle/API/c/WKBundle.h:
* WebProcess/InjectedBundle/InjectedBundle.cpp:
(WebKit::InjectedBundle::setServiceWorkerProxyCreationCallback):
* WebProcess/InjectedBundle/InjectedBundle.h:

Tools:

* WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
(WTR::InjectedBundle::initialize): Setting service worker creation callback to inject ServiceWorkerInternals object.

LayoutTests:

* http/wpt/service-workers/online-worker.js: Added.
(async.waitForOnlineEvent):
(async.doTest):
* http/wpt/service-workers/online.https-expected.txt: Added.
* http/wpt/service-workers/online.https.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@226510 268f45cc-cd09-0410-ab3c-d52691b4dbfc

27 files changed:
LayoutTests/ChangeLog
LayoutTests/http/wpt/service-workers/online-worker.js [new file with mode: 0644]
LayoutTests/http/wpt/service-workers/online.https-expected.txt [new file with mode: 0644]
LayoutTests/http/wpt/service-workers/online.https.html [new file with mode: 0644]
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/DerivedSources.make
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/bindings/js/WorkerScriptController.h
Source/WebCore/dom/ScriptExecutionContext.h
Source/WebCore/testing/ServiceWorkerInternals.cpp [new file with mode: 0644]
Source/WebCore/testing/ServiceWorkerInternals.h [new file with mode: 0644]
Source/WebCore/testing/ServiceWorkerInternals.idl [new file with mode: 0644]
Source/WebCore/testing/js/WebCoreTestSupport.cpp
Source/WebCore/testing/js/WebCoreTestSupport.h
Source/WebCore/workers/service/context/SWContextManager.cpp
Source/WebCore/workers/service/context/SWContextManager.h
Source/WebCore/workers/service/context/ServiceWorkerThread.cpp
Source/WebCore/workers/service/context/ServiceWorkerThreadProxy.cpp
Source/WebCore/workers/service/context/ServiceWorkerThreadProxy.h
Source/WebKit/ChangeLog
Source/WebKit/WebProcess/InjectedBundle/API/c/WKBundle.cpp
Source/WebKit/WebProcess/InjectedBundle/API/c/WKBundle.h
Source/WebKit/WebProcess/InjectedBundle/InjectedBundle.cpp
Source/WebKit/WebProcess/InjectedBundle/InjectedBundle.h
Tools/ChangeLog
Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp

index f9123e6..0ea586e 100644 (file)
@@ -1,5 +1,19 @@
 2018-01-08  Youenn Fablet  <youenn@apple.com>
 
+        navigator.onLine does not work inside service workers
+        https://bugs.webkit.org/show_bug.cgi?id=181079
+        <rdar://problem/36178606>
+
+        Reviewed by Darin Adler.
+
+        * http/wpt/service-workers/online-worker.js: Added.
+        (async.waitForOnlineEvent):
+        (async.doTest):
+        * http/wpt/service-workers/online.https-expected.txt: Added.
+        * http/wpt/service-workers/online.https.html: Added.
+
+2018-01-08  Youenn Fablet  <youenn@apple.com>
+
         imported/w3c/web-platform-tests/service-workers/service-worker/interfaces-sw.https.html is slow in Debug
         https://bugs.webkit.org/show_bug.cgi?id=181382
 
diff --git a/LayoutTests/http/wpt/service-workers/online-worker.js b/LayoutTests/http/wpt/service-workers/online-worker.js
new file mode 100644 (file)
index 0000000..165ce3f
--- /dev/null
@@ -0,0 +1,50 @@
+async function waitForOnlineEvent()
+{
+    var promise = new Promise((resolve, reject) => {
+        self.addEventListener("online", () => {
+            resolve("online");
+        });
+        self.addEventListener("offline", () => {
+            resolve("offline");
+        });
+        setTimeout(() => {
+            reject("No online event");
+        }, 2000);
+    });
+    return await promise;
+}
+
+async function doTest(event)
+{
+    try {
+        if (!event.data.startsWith("ONLINE")) {
+            event.source.postMessage("FAIL: received unexpected message from client");
+            return;
+        }
+
+        if (!self.internals) {
+            event.source.postMessage("FAIL: test require internals");
+            return;
+        }
+
+        internals.setOnline(true);
+        var eventName = await waitForOnlineEvent();
+        if (!navigator.onLine)
+            event.source.postMessage("FAIL: test 1");
+        if (eventName !== "online")
+            event.source.postMessage("FAIL: test 2, got " + eventName);
+
+        internals.setOnline(false);
+        var eventName = await waitForOnlineEvent();
+        if (navigator.onLine)
+            event.source.postMessage("FAIL: test 3");
+        if (eventName !== "offline")
+            event.source.postMessage("FAIL: test 4, got " + eventName);
+
+        event.source.postMessage("PASS");
+    } catch (e) {
+        event.source.postMessage(e);
+    }
+}
+
+self.addEventListener("message", doTest);
diff --git a/LayoutTests/http/wpt/service-workers/online.https-expected.txt b/LayoutTests/http/wpt/service-workers/online.https-expected.txt
new file mode 100644 (file)
index 0000000..7c818f8
--- /dev/null
@@ -0,0 +1,4 @@
+
+PASS Setup worker 
+PASS Test service worker online/offline 
+
diff --git a/LayoutTests/http/wpt/service-workers/online.https.html b/LayoutTests/http/wpt/service-workers/online.https.html
new file mode 100644 (file)
index 0000000..fa58d7d
--- /dev/null
@@ -0,0 +1,39 @@
+<html>
+<head>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<script>
+var scope = "";
+var activeWorker;
+
+promise_test(async (test) => {
+    var registration = await navigator.serviceWorker.register("online-worker.js", { scope : scope });
+    activeWorker = registration.active;
+    if (activeWorker)
+        return;
+    activeWorker = registration.installing;
+    return new Promise(resolve => {
+        activeWorker.addEventListener('statechange', () => {
+            if (activeWorker.state === "activated")
+                resolve();
+        });
+    });
+}, "Setup worker");
+
+promise_test(async (test) => {
+    var promise = new Promise((resolve, reject) => {
+        navigator.serviceWorker.addEventListener("message", (event) => {
+            resolve(event.data);
+        });
+    });
+
+    activeWorker.postMessage("ONLINE");
+    var result = await promise;
+
+    assert_equals(result, "PASS");
+}, "Test service worker online/offline");
+</script>
+</body>
+</html>
index 02fb1c1..7ab531c 100644 (file)
@@ -1549,6 +1549,7 @@ set(WebCoreTestSupport_IDL_FILES
     testing/MockCDMFactory.idl
     testing/MockContentFilterSettings.idl
     testing/MockPageOverlay.idl
+    testing/ServiceWorkerInternals.idl
     testing/TypeConversions.idl
 )
 
@@ -1568,7 +1569,7 @@ list(APPEND WebCoreTestSupport_SOURCES
     testing/MockGamepadProvider.cpp
     testing/MockPageOverlay.cpp
     testing/MockPageOverlayClient.cpp
-
+    testing/ServiceWorkerInternals.cpp
     testing/js/WebCoreTestSupport.cpp
 )
 
index 7752cb8..3d78636 100644 (file)
@@ -1,3 +1,50 @@
+2018-01-08  Youenn Fablet  <youenn@apple.com>
+
+        navigator.onLine does not work inside service workers
+        https://bugs.webkit.org/show_bug.cgi?id=181079
+        <rdar://problem/36178606>
+
+        Reviewed by Darin Adler.
+
+        Test: http/wpt/service-workers/online.https.html
+
+        Added support for onLine by reusing a similar implementation as regular workers.
+        Added ServiceWorkerInternals as an interface for an object exposed as self.internals in WTR.
+        This object has currently one method to trigger change in the online/offline status.
+        This allows writing a test for the onLine feature.
+
+        Note that self.internals is inserted asynchronously after the script was evaluated.
+        When writing a worker script using self.internals, one must make sure to use self.internals when initialized.
+        online-worker.js for instance makes use of self.internals in a postMessage callback.
+
+        * CMakeLists.txt:
+        * DerivedSources.make:
+        * WebCore.xcodeproj/project.pbxproj:
+        * bindings/js/WorkerScriptController.h:
+        * dom/ScriptExecutionContext.h:
+        * testing/ServiceWorkerInternals.cpp: Added.
+        (WebCore::ServiceWorkerInternals::ServiceWorkerInternals):
+        (WebCore::ServiceWorkerInternals::setOnline):
+        * testing/ServiceWorkerInternals.h: Added.
+        * testing/ServiceWorkerInternals.idl: Added.
+        * testing/js/WebCoreTestSupport.cpp:
+        (WebCoreTestSupport::setupNewlyCreateServiceWorker):
+        * testing/js/WebCoreTestSupport.h:
+        * workers/service/context/SWContextManager.cpp:
+        (WebCore::SWContextManager::registerServiceWorkerThreadForInstall):
+        (WebCore::SWContextManager::startedServiceWorker):
+        * workers/service/context/SWContextManager.h:
+        (WebCore::SWContextManager::setServiceWorkerCreationCallback):
+        (WebCore::SWContextManager::workerByID):
+        * workers/service/context/ServiceWorkerThread.cpp:
+        (WebCore::ServiceWorkerThread::ServiceWorkerThread):
+        * workers/service/context/ServiceWorkerThreadProxy.cpp:
+        (WebCore::ServiceWorkerThreadProxy::ServiceWorkerThreadProxy):
+        (WebCore::ServiceWorkerThreadProxy::~ServiceWorkerThreadProxy):
+        (WebCore::ServiceWorkerThreadProxy::networkStateChanged):
+        (WebCore::ServiceWorkerThreadProxy::notifyNetworkStateChange):
+        * workers/service/context/ServiceWorkerThreadProxy.h:
+
 2018-01-08  Zan Dobersek  <zdobersek@igalia.com>
 
         [Cairo] Contain shadow blur requirement state in a separate object
index 94a6db9..a0b9c80 100644 (file)
@@ -940,6 +940,7 @@ JS_BINDING_IDLS = \
     $(WebCore)/testing/MockPageOverlay.idl \
     $(WebCore)/testing/MockPaymentAddress.idl \
     $(WebCore)/testing/MockPaymentCoordinator.idl \
+    $(WebCore)/testing/ServiceWorkerInternals.idl \
     $(WebCore)/testing/TypeConversions.idl \
     $(WebCore)/workers/AbstractWorker.idl \
     $(WebCore)/workers/DedicatedWorkerGlobalScope.idl \
index 7339fc3..dacf636 100644 (file)
                417DA6D913734E6E007C57FB /* Internals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 417DA4CF13734326007C57FB /* Internals.cpp */; };
                417DA6DA13734E6E007C57FB /* Internals.h in Headers */ = {isa = PBXBuildFile; fileRef = 417DA4CE13734326007C57FB /* Internals.h */; };
                417DA71D13735DFA007C57FB /* JSInternals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 417DA71B13735DFA007C57FB /* JSInternals.cpp */; };
+               427DA71D13735DFA007C57FB /* JSServiceWorkerInternals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 427DA71B13735DFA007C57FB /* JSServiceWorkerInternals.cpp */; };
                417DA71E13735DFA007C57FB /* JSInternals.h in Headers */ = {isa = PBXBuildFile; fileRef = 417DA71C13735DFA007C57FB /* JSInternals.h */; };
+               427DA71E13735DFA007C57FB /* JSServiceWorkerInternals.h in Headers */ = {isa = PBXBuildFile; fileRef = 427DA71C13735DFA007C57FB /* JSServiceWorkerInternals.h */; };
+               417F0D821FFEE979008EF303 /* ServiceWorkerInternals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 417F0D801FFEE14F008EF303 /* ServiceWorkerInternals.cpp */; };
                41815C1E138319830057AAA4 /* WebCoreTestSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41815C1C138319830057AAA4 /* WebCoreTestSupport.cpp */; };
                41815C1F138319830057AAA4 /* WebCoreTestSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 41815C1D138319830057AAA4 /* WebCoreTestSupport.h */; settings = {ATTRIBUTES = (Private, ); }; };
                418205471E53E98C00D62207 /* RTCController.h in Headers */ = {isa = PBXBuildFile; fileRef = 418205451E53C8CD00D62207 /* RTCController.h */; settings = {ATTRIBUTES = (Private, ); }; };
                417DA4CF13734326007C57FB /* Internals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Internals.cpp; sourceTree = "<group>"; };
                417DA6D013734E02007C57FB /* libWebCoreTestSupport.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libWebCoreTestSupport.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
                417DA71B13735DFA007C57FB /* JSInternals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSInternals.cpp; sourceTree = "<group>"; };
+               427DA71B13735DFA007C57FB /* JSServiceWorkerInternals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSServiceWorkerInternals.cpp; sourceTree = "<group>"; };
                417DA71C13735DFA007C57FB /* JSInternals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSInternals.h; sourceTree = "<group>"; };
+               427DA71C13735DFA007C57FB /* JSServiceWorkerInternals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSServiceWorkerInternals.h; sourceTree = "<group>"; };
+               417F0D7E1FFEE14E008EF303 /* ServiceWorkerInternals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ServiceWorkerInternals.h; sourceTree = "<group>"; };
+               417F0D801FFEE14F008EF303 /* ServiceWorkerInternals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ServiceWorkerInternals.cpp; sourceTree = "<group>"; };
+               417F0D811FFEE150008EF303 /* ServiceWorkerInternals.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ServiceWorkerInternals.idl; sourceTree = "<group>"; };
                41813F9113818AD60057AAA4 /* Internals.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Internals.idl; sourceTree = "<group>"; };
                41815C1C138319830057AAA4 /* WebCoreTestSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebCoreTestSupport.cpp; sourceTree = "<group>"; };
                41815C1D138319830057AAA4 /* WebCoreTestSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebCoreTestSupport.h; sourceTree = "<group>"; };
                                A1CBEF631F9F11290028DE7C /* MockPaymentMethod.h */,
                                A14061891E2ECA0A0032B34E /* MockPreviewLoaderClient.cpp */,
                                A140618A1E2ECA0A0032B34E /* MockPreviewLoaderClient.h */,
+                               417F0D801FFEE14F008EF303 /* ServiceWorkerInternals.cpp */,
+                               417F0D7E1FFEE14E008EF303 /* ServiceWorkerInternals.h */,
+                               417F0D811FFEE150008EF303 /* ServiceWorkerInternals.idl */,
                                EB081CD81696084400553730 /* TypeConversions.h */,
                                EB081CD91696084400553730 /* TypeConversions.idl */,
                                E1BA67191742BEF400C20251 /* WebCoreTestShimLibrary.cpp */,
                                A146D31F1F99CA3D00D29196 /* JSMockPaymentAddress.h */,
                                A146D3191F99BCBB00D29196 /* JSMockPaymentCoordinator.cpp */,
                                A146D3181F99BCBA00D29196 /* JSMockPaymentCoordinator.h */,
+                               427DA71B13735DFA007C57FB /* JSServiceWorkerInternals.cpp */,
+                               427DA71C13735DFA007C57FB /* JSServiceWorkerInternals.h */,
                                EBF5121A1696496C0056BD25 /* JSTypeConversions.cpp */,
                                EBF5121B1696496C0056BD25 /* JSTypeConversions.h */,
                        );
                                538EC9341F99B9F7004D22A8 /* JSMockPageOverlay.h in Headers */,
                                A146D3231F99D0EF00D29196 /* JSMockPaymentAddress.h in Headers */,
                                A146D31B1F99BCFB00D29196 /* JSMockPaymentCoordinator.h in Headers */,
+                               427DA71E13735DFA007C57FB /* JSServiceWorkerInternals.h in Headers */,
                                EBF5121D1696496C0056BD25 /* JSTypeConversions.h in Headers */,
                                CDC26B41160A8CCE0026757B /* LegacyMockCDM.h in Headers */,
                                A1BF6B831AA96C7D00AF4A8A /* MockContentFilter.h in Headers */,
                                2D4150DE1C1F868C000A3BA2 /* JSMockPageOverlay.cpp in Sources */,
                                A146D3221F99D0EC00D29196 /* JSMockPaymentAddress.cpp in Sources */,
                                A146D31A1F99BCF800D29196 /* JSMockPaymentCoordinator.cpp in Sources */,
+                               427DA71D13735DFA007C57FB /* JSServiceWorkerInternals.cpp in Sources */,
                                EBF5121C1696496C0056BD25 /* JSTypeConversions.cpp in Sources */,
                                CDC26B40160A8CC60026757B /* LegacyMockCDM.cpp in Sources */,
                                CDF4B7311E03D00700E235A2 /* MockCDMFactory.cpp in Sources */,
                                A1AFEDE71F8BFF6D0087013F /* MockPaymentCoordinator.cpp in Sources */,
                                A140618B1E2ECA0A0032B34E /* MockPreviewLoaderClient.cpp in Sources */,
                                AA5F3B8F16CC4B3900455EB0 /* PlatformSpeechSynthesizerMock.cpp in Sources */,
+                               417F0D821FFEE979008EF303 /* ServiceWorkerInternals.cpp in Sources */,
                                DE7710861FA2F0D600460016 /* WebArchiveDumpSupport.mm in Sources */,
                                41815C1E138319830057AAA4 /* WebCoreTestSupport.cpp in Sources */,
                        );
index 38502a9..1c0944b 100644 (file)
@@ -94,7 +94,7 @@ private:
         if (!m_workerGlobalScopeWrapper)
             initScript();
     }
-    void initScript();
+    WEBCORE_EXPORT void initScript();
 
     RefPtr<JSC::VM> m_vm;
     WorkerGlobalScope* m_workerGlobalScope;
index ae14a15..681cdcf 100644 (file)
@@ -235,7 +235,7 @@ public:
         return ensureRejectedPromiseTrackerSlow();
     }
 
-    JSC::ExecState* execState();
+    WEBCORE_EXPORT JSC::ExecState* execState();
 
     WEBCORE_EXPORT String domainForCachePartition() const;
     void setDomainForCachePartition(String&& domain) { m_domainForCachePartition = WTFMove(domain); }
diff --git a/Source/WebCore/testing/ServiceWorkerInternals.cpp b/Source/WebCore/testing/ServiceWorkerInternals.cpp
new file mode 100644 (file)
index 0000000..d724d55
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ServiceWorkerInternals.h"
+
+#if ENABLE(SERVICE_WORKER)
+
+#include "SWContextManager.h"
+
+namespace WebCore {
+
+ServiceWorkerInternals::ServiceWorkerInternals(ServiceWorkerIdentifier identifier)
+    : m_identifier(identifier)
+{
+}
+
+ServiceWorkerInternals::~ServiceWorkerInternals() = default;
+
+void ServiceWorkerInternals::setOnline(bool isOnline)
+{
+    callOnMainThread([identifier = m_identifier, isOnline] () {
+        if (auto* proxy = SWContextManager::singleton().workerByID(identifier))
+            proxy->notifyNetworkStateChange(isOnline);
+    });
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/testing/ServiceWorkerInternals.h b/Source/WebCore/testing/ServiceWorkerInternals.h
new file mode 100644 (file)
index 0000000..38af285
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(SERVICE_WORKER)
+
+#include "ServiceWorkerIdentifier.h"
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class WEBCORE_EXPORT ServiceWorkerInternals : public RefCounted<ServiceWorkerInternals> {
+public:
+    static Ref<ServiceWorkerInternals> create(ServiceWorkerIdentifier identifier) { return adoptRef(*new ServiceWorkerInternals { identifier }); }
+    ~ServiceWorkerInternals();
+
+    void setOnline(bool isOnline);
+
+private:
+    explicit ServiceWorkerInternals(ServiceWorkerIdentifier);
+
+    ServiceWorkerIdentifier m_identifier;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/testing/ServiceWorkerInternals.idl b/Source/WebCore/testing/ServiceWorkerInternals.idl
new file mode 100644 (file)
index 0000000..5eed781
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+[
+    Conditional=SERVICE_WORKER,
+    ExportMacro=WEBCORE_TESTSUPPORT_EXPORT,
+    ImplementationLacksVTable,
+    NoInterfaceObject,
+] interface ServiceWorkerInternals {
+    void setOnline(boolean isOnline);
+};
index 268c512..15f6331 100644 (file)
 #include "Internals.h"
 #include "JSDocument.h"
 #include "JSInternals.h"
+#include "JSServiceWorkerInternals.h"
+#include "JSWorkerGlobalScope.h"
 #include "LogInitialization.h"
 #include "MockGamepadProvider.h"
 #include "Page.h"
+#include "SWContextManager.h"
+#include "ServiceWorkerGlobalScope.h"
 #include "URLParser.h"
 #include "WheelEventTestTrigger.h"
 #include <JavaScriptCore/APICast.h>
@@ -180,4 +184,21 @@ void setMockGamepadButtonValue(unsigned gamepadIndex, unsigned buttonIndex, doub
 #endif
 }
 
+void setupNewlyCreatedServiceWorker(uint64_t serviceWorkerIdentifier)
+{
+#if ENABLE(SERVICE_WORKER)
+    auto identifier = makeObjectIdentifier<ServiceWorkerIdentifierType>(serviceWorkerIdentifier);
+    SWContextManager::singleton().postTaskToServiceWorker(identifier, [identifier] (ServiceWorkerGlobalScope& globalScope) {
+        auto* script = globalScope.script();
+        if (!script)
+            return;
+
+        auto& state = *globalScope.execState();
+        JSLockHolder locker(state.vm());
+        auto* contextWrapper = script->workerGlobalScopeWrapper();
+        contextWrapper->putDirect(state.vm(), Identifier::fromString(&state, Internals::internalsId), toJS(&state, contextWrapper, ServiceWorkerInternals::create(identifier)));
+    });
+#endif
+}
+
 }
index 564094a..a26b2f7 100644 (file)
@@ -63,4 +63,6 @@ void setMockGamepadDetails(unsigned index, const WTF::String& gamepadID, unsigne
 void setMockGamepadAxisValue(unsigned index, unsigned axisIndex, double value) TEST_SUPPORT_EXPORT;
 void setMockGamepadButtonValue(unsigned index, unsigned buttonIndex, double value) TEST_SUPPORT_EXPORT;
 
+void setupNewlyCreatedServiceWorker(uint64_t serviceWorkerIdentifier) TEST_SUPPORT_EXPORT;
+
 } // namespace WebCoreTestSupport
index 624fea7..c8dc254 100644 (file)
@@ -58,10 +58,17 @@ void SWContextManager::registerServiceWorkerThreadForInstall(Ref<ServiceWorkerTh
     ASSERT_UNUSED(result, result.isNewEntry);
     
     threadProxy->thread().start([jobDataIdentifier, serviceWorkerIdentifier](const String& exceptionMessage) {
-        SWContextManager::singleton().connection()->serviceWorkerStartedWithMessage(jobDataIdentifier, serviceWorkerIdentifier, exceptionMessage);
+        SWContextManager::singleton().startedServiceWorker(jobDataIdentifier, serviceWorkerIdentifier, exceptionMessage);
     });
 }
 
+void SWContextManager::startedServiceWorker(std::optional<ServiceWorkerJobDataIdentifier> jobDataIdentifier, ServiceWorkerIdentifier serviceWorkerIdentifier, const String& exceptionMessage)
+{
+    connection()->serviceWorkerStartedWithMessage(jobDataIdentifier, serviceWorkerIdentifier, exceptionMessage);
+    if (m_serviceWorkerCreationCallback)
+        m_serviceWorkerCreationCallback(serviceWorkerIdentifier.toUInt64());
+}
+
 ServiceWorkerThreadProxy* SWContextManager::serviceWorkerThreadProxy(ServiceWorkerIdentifier identifier) const
 {
     return m_workerMap.get(identifier);
index f403d4d..add7837 100644 (file)
@@ -76,11 +76,19 @@ public:
 
     WEBCORE_EXPORT bool postTaskToServiceWorker(ServiceWorkerIdentifier, WTF::Function<void(ServiceWorkerGlobalScope&)>&&);
 
+    using ServiceWorkerCreationCallback = void(uint64_t);
+    void setServiceWorkerCreationCallback(ServiceWorkerCreationCallback* callback) { m_serviceWorkerCreationCallback = callback; }
+
+    ServiceWorkerThreadProxy* workerByID(ServiceWorkerIdentifier identifier) { return m_workerMap.get(identifier); }
+
 private:
     SWContextManager() = default;
 
+    void startedServiceWorker(std::optional<ServiceWorkerJobDataIdentifier>, ServiceWorkerIdentifier, const String& exceptionMessage);
+
     HashMap<ServiceWorkerIdentifier, RefPtr<ServiceWorkerThreadProxy>> m_workerMap;
     std::unique_ptr<Connection> m_connection;
+    ServiceWorkerCreationCallback* m_serviceWorkerCreationCallback { nullptr };
 };
 
 } // namespace WebCore
index 2939f89..d9d7d7c 100644 (file)
@@ -33,6 +33,7 @@
 #include "EventNames.h"
 #include "ExtendableMessageEvent.h"
 #include "JSDOMPromise.h"
+#include "NetworkStateNotifier.h"
 #include "SecurityOrigin.h"
 #include "ServiceWorkerFetch.h"
 #include "ServiceWorkerGlobalScope.h"
@@ -67,11 +68,10 @@ private:
 
 // FIXME: Use a valid WorkerReportingProxy
 // FIXME: Use a valid WorkerObjectProxy
-// FIXME: Use a valid isOnline flag
 // FIXME: Use valid runtime flags
 
 ServiceWorkerThread::ServiceWorkerThread(const ServiceWorkerContextData& data, PAL::SessionID, String&& userAgent, WorkerLoaderProxy& loaderProxy, WorkerDebuggerProxy& debuggerProxy, IDBClient::IDBConnectionProxy* idbConnectionProxy, SocketProvider* socketProvider)
-    : WorkerThread(data.scriptURL, "serviceworker:" + Inspector::IdentifiersFactory::createIdentifier(), WTFMove(userAgent), /* isOnline */ false, data.script, loaderProxy, debuggerProxy, DummyServiceWorkerThreadProxy::shared(), WorkerThreadStartMode::Normal, ContentSecurityPolicyResponseHeaders { }, false, SecurityOrigin::create(data.scriptURL).get(), MonotonicTime::now(), idbConnectionProxy, socketProvider, JSC::RuntimeFlags::createAllEnabled(), SessionID::defaultSessionID())
+    : WorkerThread(data.scriptURL, "serviceworker:" + Inspector::IdentifiersFactory::createIdentifier(), WTFMove(userAgent), NetworkStateNotifier::singleton().onLine(), data.script, loaderProxy, debuggerProxy, DummyServiceWorkerThreadProxy::shared(), WorkerThreadStartMode::Normal, ContentSecurityPolicyResponseHeaders { }, false, SecurityOrigin::create(data.scriptURL).get(), MonotonicTime::now(), idbConnectionProxy, socketProvider, JSC::RuntimeFlags::createAllEnabled(), SessionID::defaultSessionID())
     , m_data(data.isolatedCopy())
     , m_workerObjectProxy(DummyServiceWorkerThreadProxy::shared())
 {
index 3feb93c..f9e112f 100644 (file)
@@ -77,6 +77,12 @@ static inline IDBClient::IDBConnectionProxy* idbConnectionProxy(Document& docume
 #endif
 }
 
+static HashSet<ServiceWorkerThreadProxy*>& allServiceWorkerThreadProxies()
+{
+    static NeverDestroyed<HashSet<ServiceWorkerThreadProxy*>> set;
+    return set;
+}
+
 ServiceWorkerThreadProxy::ServiceWorkerThreadProxy(PageConfiguration&& pageConfiguration, const ServiceWorkerContextData& data, PAL::SessionID sessionID, String&& userAgent, CacheStorageProvider& cacheStorageProvider, SecurityOrigin::StorageBlockingPolicy storageBlockingPolicy)
     : m_page(createPageForServiceWorker(WTFMove(pageConfiguration), data, storageBlockingPolicy))
     , m_document(*m_page->mainFrame().document())
@@ -85,6 +91,15 @@ ServiceWorkerThreadProxy::ServiceWorkerThreadProxy(PageConfiguration&& pageConfi
     , m_sessionID(sessionID)
     , m_inspectorProxy(*this)
 {
+    static bool addedListener;
+    if (!addedListener) {
+        NetworkStateNotifier::singleton().addListener(&networkStateChanged);
+        addedListener = true;
+    }
+
+    ASSERT(!allServiceWorkerThreadProxies().contains(this));
+    allServiceWorkerThreadProxies().add(this);
+
 #if ENABLE(REMOTE_INSPECTOR)
     m_remoteDebuggable = std::make_unique<ServiceWorkerDebuggable>(*this, data);
     m_remoteDebuggable->setRemoteDebuggingAllowed(true);
@@ -92,6 +107,12 @@ ServiceWorkerThreadProxy::ServiceWorkerThreadProxy(PageConfiguration&& pageConfi
 #endif
 }
 
+ServiceWorkerThreadProxy::~ServiceWorkerThreadProxy()
+{
+    ASSERT(allServiceWorkerThreadProxies().contains(this));
+    allServiceWorkerThreadProxies().remove(this);
+}
+
 bool ServiceWorkerThreadProxy::postTaskForModeToWorkerGlobalScope(ScriptExecutionContext::Task&& task, const String& mode)
 {
     if (m_isTerminatingOrTerminated)
@@ -141,6 +162,24 @@ std::unique_ptr<FetchLoader> ServiceWorkerThreadProxy::createBlobLoader(FetchLoa
     return loader;
 }
 
+void ServiceWorkerThreadProxy::networkStateChanged(bool isOnLine)
+{
+    for (auto* proxy : allServiceWorkerThreadProxies())
+        proxy->notifyNetworkStateChange(isOnLine);
+}
+
+void ServiceWorkerThreadProxy::notifyNetworkStateChange(bool isOnline)
+{
+    if (m_isTerminatingOrTerminated)
+        return;
+
+    postTaskForModeToWorkerGlobalScope([isOnline] (ScriptExecutionContext& context) {
+        auto& globalScope = downcast<WorkerGlobalScope>(context);
+        globalScope.setIsOnline(isOnline);
+        globalScope.dispatchEvent(Event::create(isOnline ? eventNames().onlineEvent : eventNames().offlineEvent, false, false));
+    }, WorkerRunLoop::defaultMode());
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(SERVICE_WORKER)
index db1ccdf..6defbbd 100644 (file)
@@ -54,6 +54,7 @@ public:
     {
         return adoptRef(*new ServiceWorkerThreadProxy(std::forward<Args>(args)...));
     }
+    ~ServiceWorkerThreadProxy();
 
     ServiceWorkerIdentifier identifier() const { return m_serviceWorkerThread->identifier(); }
     ServiceWorkerThread& thread() { return m_serviceWorkerThread.get(); }
@@ -64,9 +65,14 @@ public:
 
     WEBCORE_EXPORT std::unique_ptr<FetchLoader> createBlobLoader(FetchLoaderClient&, const URL&);
 
+    // Public only for testing purposes.
+    WEBCORE_TESTSUPPORT_EXPORT void notifyNetworkStateChange(bool isOnline);
+
 private:
     WEBCORE_EXPORT ServiceWorkerThreadProxy(PageConfiguration&&, const ServiceWorkerContextData&, PAL::SessionID, String&& userAgent, CacheStorageProvider&, SecurityOrigin::StorageBlockingPolicy);
 
+    WEBCORE_EXPORT static void networkStateChanged(bool isOnLine);
+
     // WorkerLoaderProxy
     bool postTaskForModeToWorkerGlobalScope(ScriptExecutionContext::Task&&, const String& mode) final;
     void postTaskToLoader(ScriptExecutionContext::Task&&) final;
index 2ba04b2..86c23bc 100644 (file)
@@ -1,3 +1,21 @@
+2018-01-08  Youenn Fablet  <youenn@apple.com>
+
+        navigator.onLine does not work inside service workers
+        https://bugs.webkit.org/show_bug.cgi?id=181079
+        <rdar://problem/36178606>
+
+        Reviewed by Darin Adler.
+
+        Added support for a callback called for each service worker proxy creation.
+        Callback is used by WTR to inject a self.internals object used for testing.
+
+        * WebProcess/InjectedBundle/API/c/WKBundle.cpp:
+        (WKBundleSetServiceWorkerProxyCreationCallback):
+        * WebProcess/InjectedBundle/API/c/WKBundle.h:
+        * WebProcess/InjectedBundle/InjectedBundle.cpp:
+        (WebKit::InjectedBundle::setServiceWorkerProxyCreationCallback):
+        * WebProcess/InjectedBundle/InjectedBundle.h:
+
 2018-01-07  David Kilzer  <ddkilzer@apple.com>
 
         Enable -Wcast-qual for WebInspectorUI, WebKitLegacy, WebKit projects
index fbeed5b..7b51504 100644 (file)
@@ -40,6 +40,7 @@
 #include "WebPageGroupProxy.h"
 #include <WebCore/DatabaseTracker.h>
 #include <WebCore/ResourceLoadObserver.h>
+#include <WebCore/ServiceWorkerThreadProxy.h>
 
 using namespace WebCore;
 using namespace WebKit;
@@ -54,6 +55,11 @@ void WKBundleSetClient(WKBundleRef bundleRef, WKBundleClientBase *wkClient)
     toImpl(bundleRef)->setClient(std::make_unique<InjectedBundleClient>(wkClient));
 }
 
+void WKBundleSetServiceWorkerProxyCreationCallback(WKBundleRef bundleRef, void (*callback)(uint64_t))
+{
+    toImpl(bundleRef)->setServiceWorkerProxyCreationCallback(callback);
+}
+
 void WKBundlePostMessage(WKBundleRef bundleRef, WKStringRef messageNameRef, WKTypeRef messageBodyRef)
 {
     toImpl(bundleRef)->postMessage(toWTFString(messageNameRef), toImpl(messageBodyRef));
index 60014f7..a970934 100644 (file)
@@ -71,6 +71,7 @@ typedef struct WKBundleClientV1 {
 WK_EXPORT WKTypeID WKBundleGetTypeID();
 
 WK_EXPORT void WKBundleSetClient(WKBundleRef bundle, WKBundleClientBase* client);
+WK_EXPORT void WKBundleSetServiceWorkerProxyCreationCallback(WKBundleRef bundle, void (*)(uint64_t));
 
 WK_EXPORT void WKBundlePostMessage(WKBundleRef bundle, WKStringRef messageName, WKTypeRef messageBody);
 WK_EXPORT void WKBundlePostSynchronousMessage(WKBundleRef bundle, WKStringRef messageName, WKTypeRef messageBody, WKTypeRef* returnData);
index aead25d..d481ca5 100644 (file)
@@ -70,6 +70,7 @@
 #include <WebCore/PrintContext.h>
 #include <WebCore/ResourceHandle.h>
 #include <WebCore/RuntimeEnabledFeatures.h>
+#include <WebCore/SWContextManager.h>
 #include <WebCore/ScriptController.h>
 #include <WebCore/SecurityOrigin.h>
 #include <WebCore/SecurityPolicy.h>
@@ -118,6 +119,13 @@ void InjectedBundle::setClient(std::unique_ptr<API::InjectedBundle::Client>&& cl
         m_client = WTFMove(client);
 }
 
+void InjectedBundle::setServiceWorkerProxyCreationCallback(void (*callback)(uint64_t))
+{
+#if ENABLE(SERVICE_WORKER)
+    SWContextManager::singleton().setServiceWorkerCreationCallback(callback);
+#endif
+}
+
 void InjectedBundle::postMessage(const String& messageName, API::Object* messageBody)
 {
     auto& webProcess = WebProcess::singleton();
index 0739ce1..fc1534f 100644 (file)
@@ -87,6 +87,7 @@ public:
     void setClient(std::unique_ptr<API::InjectedBundle::Client>&&);
     void postMessage(const String&, API::Object*);
     void postSynchronousMessage(const String&, API::Object*, RefPtr<API::Object>& returnData);
+    void setServiceWorkerProxyCreationCallback(void (*)(uint64_t));
 
     WebConnection* webConnectionToUIProcess() const;
 
index 744e9cb..9c687f0 100644 (file)
@@ -1,3 +1,14 @@
+2018-01-08  Youenn Fablet  <youenn@apple.com>
+
+        navigator.onLine does not work inside service workers
+        https://bugs.webkit.org/show_bug.cgi?id=181079
+        <rdar://problem/36178606>
+
+        Reviewed by Darin Adler.
+
+        * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
+        (WTR::InjectedBundle::initialize): Setting service worker creation callback to inject ServiceWorkerInternals object.
+
 2018-01-07  Saam Barati  <sbarati@apple.com>
 
         Add total exits and total compilations sorting mode to the "full" command in display-profiler-output
index 56b0dcd..3de38c3 100644 (file)
@@ -97,7 +97,7 @@ void InjectedBundle::initialize(WKBundleRef bundle, WKTypeRef initializationUser
         didReceiveMessageToPage
     };
     WKBundleSetClient(m_bundle, &client.base);
-
+    WKBundleSetServiceWorkerProxyCreationCallback(m_bundle, WebCoreTestSupport::setupNewlyCreatedServiceWorker);
     platformInitialize(initializationUserData);
 
     activateFonts();