Changeset 249338 in webkit


Ignore:
Timestamp:
Aug 30, 2019 12:03:35 PM (5 years ago)
Author:
Chris Dumez
Message:

Add support for postMessage buffering between the service worker and window
https://bugs.webkit.org/show_bug.cgi?id=201169

Reviewed by Youenn Fablet.

LayoutTests/imported/w3c:

Rebaseline WPT test that is now passing.

  • web-platform-tests/service-workers/service-worker/postmessage-to-client-message-queue.https-expected.txt:

Source/WebCore:

As per the Service Worker specification, a service worker client's message
queue is initially disabled and only gets enabled after:

  • The DOMContentLoaded event has been fired

or

  • The client sets the navigator.serviceWorker.onmessage event handler

or

  • navigator.serviceWorker.startMessages() is called

While the message queue is disabled, messages posted by the service worker
to the client simply get queued and only get processed once the queue gets
enabled.

No new tests, rebaselined existing test.

  • dom/Document.cpp:

(WebCore::Document::finishedParsing):
Call startMessages() on the ServiceWorkerContainer once the DOMContentLoaded event has
been fired.

  • dom/ScriptExecutionContext.cpp:

(WebCore::ScriptExecutionContext::ensureServiceWorkerContainer):

  • dom/ScriptExecutionContext.h:
  • workers/service/SWClientConnection.cpp:

(WebCore::SWClientConnection::postMessageToServiceWorkerClient):
Fix a bug where a service worker would not be able to post a message to a client until
that client has accessed navigator.serviceWorker (since the ServiceWorkerContainer is
lazy initialized). To address the issue, we now initialize the ServiceWorkerContainer
when a message is received from the service worker. Previously, messages were just
getting dropped.

  • workers/service/ServiceWorkerContainer.cpp:

(WebCore::ServiceWorkerContainer::ServiceWorkerContainer):
When the ServiceWorkerContainer is constructed, suspend its message queue if its context
document is still parsing.

(WebCore::ServiceWorkerContainer::startMessages):
Resume the message queue when startMessages() is called.

(WebCore::ServiceWorkerContainer::postMessage):
Enqueue the event instead of firing it right away.

(WebCore::ServiceWorkerContainer::addEventListener):
if navigator.serviceWorker.onmessage event handler gets set by the JavaScript, call
startMessages().

  • workers/service/ServiceWorkerContainer.h:

LayoutTests:

Unskip test that is no longer timing out.

  • resources/testharnessreport.js:

(self.testRunner.add_completion_callback):
Use testRunner.forceImmediateCompletion() instead of notifyDone() for WPT tests.
testRunner.notifyDone() does not work in case of load error or when the load
does not finish. The WPT test was timing out because the load does not finish for
testing purposes.

Location:
trunk
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r249330 r249338  
     12019-08-30  Chris Dumez  <cdumez@apple.com>
     2
     3        Add support for postMessage buffering between the service worker and window
     4        https://bugs.webkit.org/show_bug.cgi?id=201169
     5
     6        Reviewed by Youenn Fablet.
     7
     8        * TestExpectations:
     9        Unskip test that is no longer timing out.
     10
     11        * resources/testharnessreport.js:
     12        (self.testRunner.add_completion_callback):
     13        Use testRunner.forceImmediateCompletion() instead of notifyDone() for WPT tests.
     14        testRunner.notifyDone() does not work in case of load error or when the load
     15        does not finish. The WPT test was timing out because the load does not finish for
     16        testing purposes.
     17
    1182019-08-30  Devin Rousso  <drousso@apple.com>
    219
  • trunk/LayoutTests/TestExpectations

    r249123 r249338  
    209209imported/w3c/web-platform-tests/service-workers/service-worker/fetch-mixed-content-to-outscope.https.html [ Skip ]
    210210imported/w3c/web-platform-tests/service-workers/service-worker/multipart-image.https.html [ Skip ]
    211 imported/w3c/web-platform-tests/service-workers/service-worker/postmessage-to-client-message-queue.https.html [ Skip ]
    212211imported/w3c/web-platform-tests/service-workers/service-worker/skip-waiting-using-registration.https.html [ Skip ]
    213212imported/w3c/web-platform-tests/service-workers/service-worker/skip-waiting-without-using-registration.https.html [ Skip ]
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r249334 r249338  
     12019-08-30  Chris Dumez  <cdumez@apple.com>
     2
     3        Add support for postMessage buffering between the service worker and window
     4        https://bugs.webkit.org/show_bug.cgi?id=201169
     5
     6        Reviewed by Youenn Fablet.
     7
     8        Rebaseline WPT test that is now passing.
     9
     10        * web-platform-tests/service-workers/service-worker/postmessage-to-client-message-queue.https-expected.txt:
     11
    1122019-08-30  Youenn Fablet  <youenn@apple.com>
    213
  • trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/postmessage-to-client-message-queue.https-expected.txt

    r238592 r249338  
    11
    2 Harness Error (TIMEOUT), message = null
     2PASS Messages from ServiceWorker to Client only received after DOMContentLoaded event.
     3PASS Messages from ServiceWorker to Client only received after calling startMessages().
     4PASS Messages from ServiceWorker to Client only received after setting onmessage.
     5PASS Microtasks run before dispatching messages after calling startMessages().
     6PASS Microtasks run before dispatching messages after setting onmessage.
    37
    4 TIMEOUT Messages from ServiceWorker to Client only received after DOMContentLoaded event. Test timed out
    5 NOTRUN Messages from ServiceWorker to Client only received after calling startMessages().
    6 NOTRUN Messages from ServiceWorker to Client only received after setting onmessage.
    7 NOTRUN Microtasks run before dispatching messages after calling startMessages().
    8 NOTRUN Microtasks run before dispatching messages after setting onmessage.
    9 
  • trunk/LayoutTests/platform/win/http/wpt/html/semantics/text-level-semantics/the-a-element/a-download-click-404-expected.txt

    r229286 r249338  
    1 CONSOLE MESSAGE: line 21: TypeError: null is not an object (evaluating 'errorFrame.contentDocument.querySelector("#error-url").click')
    21
    32
  • trunk/LayoutTests/resources/testharnessreport.js

    r244749 r249338  
    9999        // from the page and therefore reduce the output.
    100100        setTimeout(function () {
    101             testRunner.notifyDone();
     101            testRunner.forceImmediateCompletion();
    102102        }, 0);
    103103    });
  • trunk/Source/WebCore/ChangeLog

    r249336 r249338  
     12019-08-30  Chris Dumez  <cdumez@apple.com>
     2
     3        Add support for postMessage buffering between the service worker and window
     4        https://bugs.webkit.org/show_bug.cgi?id=201169
     5
     6        Reviewed by Youenn Fablet.
     7
     8        As per the Service Worker specification, a service worker client's message
     9        queue is initially disabled and only gets enabled after:
     10        - The DOMContentLoaded event has been fired
     11        or
     12        - The client sets the navigator.serviceWorker.onmessage event handler
     13        or
     14        - navigator.serviceWorker.startMessages() is called
     15
     16        While the message queue is disabled, messages posted by the service worker
     17        to the client simply get queued and only get processed once the queue gets
     18        enabled.
     19
     20        No new tests, rebaselined existing test.
     21
     22        * dom/Document.cpp:
     23        (WebCore::Document::finishedParsing):
     24        Call startMessages() on the ServiceWorkerContainer once the DOMContentLoaded event has
     25        been fired.
     26
     27        * dom/ScriptExecutionContext.cpp:
     28        (WebCore::ScriptExecutionContext::ensureServiceWorkerContainer):
     29        * dom/ScriptExecutionContext.h:
     30        * workers/service/SWClientConnection.cpp:
     31        (WebCore::SWClientConnection::postMessageToServiceWorkerClient):
     32        Fix a bug where a service worker would not be able to post a message to a client until
     33        that client has accessed navigator.serviceWorker (since the ServiceWorkerContainer is
     34        lazy initialized). To address the issue, we now initialize the ServiceWorkerContainer
     35        when a message is received from the service worker. Previously, messages were just
     36        getting dropped.
     37
     38        * workers/service/ServiceWorkerContainer.cpp:
     39        (WebCore::ServiceWorkerContainer::ServiceWorkerContainer):
     40        When the ServiceWorkerContainer is constructed, suspend its message queue if its context
     41        document is still parsing.
     42
     43        (WebCore::ServiceWorkerContainer::startMessages):
     44        Resume the message queue when startMessages() is called.
     45
     46        (WebCore::ServiceWorkerContainer::postMessage):
     47        Enqueue the event instead of firing it right away.
     48
     49        (WebCore::ServiceWorkerContainer::addEventListener):
     50        if navigator.serviceWorker.onmessage event handler gets set by the JavaScript, call
     51        startMessages().
     52
     53        * workers/service/ServiceWorkerContainer.h:
     54
    1552019-08-30  Simon Fraser  <simon.fraser@apple.com>
    256
  • trunk/Source/WebCore/dom/Document.cpp

    r249295 r249338  
    194194#include "SelectorQuery.h"
    195195#include "ServiceWorkerClientData.h"
     196#include "ServiceWorkerContainer.h"
    196197#include "ServiceWorkerProvider.h"
    197198#include "Settings.h"
     
    57095710    // Parser should have picked up all speculative preloads by now
    57105711    m_cachedResourceLoader->clearPreloads(CachedResourceLoader::ClearPreloadsMode::ClearSpeculativePreloads);
     5712
     5713#if ENABLE(SERVICE_WORKER)
     5714    if (RuntimeEnabledFeatures::sharedFeatures().serviceWorkerEnabled()) {
     5715        // Stop queuing service worker client messages now that the DOMContentLoaded event has been fired.
     5716        if (auto* serviceWorkerContainer = this->serviceWorkerContainer())
     5717            serviceWorkerContainer->startMessages();
     5718    }
     5719#endif
    57115720}
    57125721
  • trunk/Source/WebCore/dom/ScriptExecutionContext.cpp

    r248846 r249338  
    613613}
    614614
     615ServiceWorkerContainer* ScriptExecutionContext::ensureServiceWorkerContainer()
     616{
     617    NavigatorBase* navigator = nullptr;
     618    if (is<Document>(*this)) {
     619        if (auto* window = downcast<Document>(*this).domWindow())
     620            navigator = &window->navigator();
     621    } else
     622        navigator = &downcast<WorkerGlobalScope>(*this).navigator();
     623       
     624    return navigator ? &navigator->serviceWorker() : nullptr;
     625}
     626
    615627bool ScriptExecutionContext::postTaskTo(const DocumentOrWorkerIdentifier& contextIdentifier, WTF::Function<void(ScriptExecutionContext&)>&& task)
    616628{
  • trunk/Source/WebCore/dom/ScriptExecutionContext.h

    r241602 r249338  
    256256
    257257    ServiceWorkerContainer* serviceWorkerContainer();
     258    ServiceWorkerContainer* ensureServiceWorkerContainer();
    258259
    259260    WEBCORE_EXPORT static bool postTaskTo(const DocumentOrWorkerIdentifier&, WTF::Function<void(ScriptExecutionContext&)>&&);
  • trunk/Source/WebCore/workers/service/SWClientConnection.cpp

    r244160 r249338  
    126126        return;
    127127
    128     destinationDocument->postTask([message = WTFMove(message), sourceData = WTFMove(sourceData), sourceOrigin = WTFMove(sourceOrigin)](auto& context) mutable {
    129         if (auto* container = context.serviceWorkerContainer())
    130             container->postMessage(WTFMove(message), WTFMove(sourceData), WTFMove(sourceOrigin));
    131     });
     128    if (auto* container = destinationDocument->ensureServiceWorkerContainer())
     129        container->postMessage(WTFMove(message), WTFMove(sourceData), WTFMove(sourceOrigin));
    132130}
    133131
  • trunk/Source/WebCore/workers/service/ServiceWorkerContainer.cpp

    r248846 r249338  
    6565    : ActiveDOMObject(context)
    6666    , m_navigator(navigator)
     67    , m_messageQueue(*this)
    6768{
    6869    suspendIfNeeded();
     70   
     71    // We should queue messages until the DOMContentLoaded event has fired or startMessages() has been called.
     72    if (is<Document>(context) && downcast<Document>(*context).parsing())
     73        m_messageQueue.suspend();
    6974}
    7075
     
    379384void ServiceWorkerContainer::startMessages()
    380385{
     386    m_messageQueue.resume();
    381387}
    382388
     
    476482
    477483    auto messageEvent = MessageEvent::create(MessagePort::entanglePorts(context, WTFMove(message.transferredPorts)), message.message.releaseNonNull(), sourceOrigin, { }, WTFMove(source));
    478     dispatchEvent(messageEvent);
     484   
     485    m_messageQueue.enqueueEvent(WTFMove(messageEvent));
    479486}
    480487
     
    584591{
    585592    return !hasPendingActivity();
     593}
     594
     595void ServiceWorkerContainer::suspend(ReasonForSuspension)
     596{
     597    m_messageQueue.suspend();
     598}
     599
     600void ServiceWorkerContainer::resume()
     601{
     602    m_messageQueue.resume();
    586603}
    587604
     
    637654    m_pendingPromises.clear();
    638655    m_readyPromise = nullptr;
     656    m_messageQueue.close();
    639657    auto jobMap = WTFMove(m_jobMap);
    640658    for (auto& ongoingJob : jobMap.values()) {
     
    681699}
    682700
     701bool ServiceWorkerContainer::addEventListener(const AtomString& eventType, Ref<EventListener>&& eventListener, const AddEventListenerOptions& options)
     702{
     703    // Setting the onmessage EventHandler attribute on the ServiceWorkerContainer should start the messages
     704    // automatically.
     705    if (eventListener->isAttribute() && eventType == eventNames().messageEvent)
     706        startMessages();
     707
     708    return EventTargetWithInlineData::addEventListener(eventType, WTFMove(eventListener), options);
     709}
     710
    683711} // namespace WebCore
    684712
  • trunk/Source/WebCore/workers/service/ServiceWorkerContainer.h

    r248762 r249338  
    3131#include "DOMPromiseProxy.h"
    3232#include "EventTarget.h"
     33#include "GenericEventQueue.h"
    3334#include "SWClientConnection.h"
    3435#include "SWServer.h"
     
    9192
    9293private:
     94    bool addEventListener(const AtomString& eventType, Ref<EventListener>&&, const AddEventListenerOptions& = { }) final;
     95
    9396    void scheduleJob(std::unique_ptr<ServiceWorkerJob>&&);
    9497
     
    110113    SWClientConnection& ensureSWClientConnection();
    111114
     115    // ActiveDOMObject.
    112116    const char* activeDOMObjectName() const final;
    113117    bool canSuspendForDocumentSuspension() const final;
     118    void suspend(ReasonForSuspension) final;
     119    void resume() final;
     120   
    114121    ScriptExecutionContext* scriptExecutionContext() const final { return ActiveDOMObject::scriptExecutionContext(); }
    115122    EventTargetInterface eventTargetInterface() const final { return ServiceWorkerContainerEventTargetInterfaceType; }
     
    155162    uint64_t m_lastOngoingSettledRegistrationIdentifier { 0 };
    156163    HashMap<uint64_t, ServiceWorkerRegistrationKey> m_ongoingSettledRegistrations;
     164    GenericEventQueue m_messageQueue;
    157165
    158166};
Note: See TracChangeset for help on using the changeset viewer.