Changeset 249629 in webkit


Ignore:
Timestamp:
Sep 7, 2019 11:10:28 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:
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r249626 r249629  
     12019-09-07  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-09-07  Chris Dumez  <cdumez@apple.com>
    219
  • trunk/LayoutTests/TestExpectations

    r249615 r249629  
    210210imported/w3c/web-platform-tests/service-workers/service-worker/fetch-mixed-content-to-outscope.https.html [ Skip ]
    211211imported/w3c/web-platform-tests/service-workers/service-worker/multipart-image.https.html [ Skip ]
    212 imported/w3c/web-platform-tests/service-workers/service-worker/postmessage-to-client-message-queue.https.html [ Skip ]
    213212imported/w3c/web-platform-tests/service-workers/service-worker/skip-waiting-using-registration.https.html [ Skip ]
    214213imported/w3c/web-platform-tests/service-workers/service-worker/skip-waiting-without-using-registration.https.html [ Skip ]
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r249627 r249629  
     12019-09-07  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-09-07  Chris Dumez  <cdumez@apple.com>
    213
  • trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/postmessage-to-client-message-queue.https-expected.txt

    r249615 r249629  
    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/mac-wk1/http/wpt/html/semantics/text-level-semantics/the-a-element/a-download-click-404-expected.txt

    r249615 r249629  
    1 CONSOLE MESSAGE: line 21: TypeError: null is not an object (evaluating 'errorFrame.contentDocument.querySelector("#error-url").click')
    21
    32
  • trunk/LayoutTests/platform/win/http/wpt/html/semantics/text-level-semantics/the-a-element/a-download-click-404-expected.txt

    r249615 r249629  
    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

    r249615 r249629  
    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

    r249627 r249629  
     12019-09-07  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-09-07  Chris Dumez  <cdumez@apple.com>
    256
  • trunk/Source/WebCore/dom/Document.cpp

    r249615 r249629  
    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

    r249615 r249629  
    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

    r249615 r249629  
    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

    r249615 r249629  
    124124        return;
    125125
    126     destinationDocument->postTask([message = WTFMove(message), sourceData = WTFMove(sourceData), sourceOrigin = WTFMove(sourceOrigin)](auto& context) mutable {
    127         if (auto* container = context.serviceWorkerContainer())
    128             container->postMessage(WTFMove(message), WTFMove(sourceData), WTFMove(sourceOrigin));
    129     });
     126    if (auto* container = destinationDocument->ensureServiceWorkerContainer())
     127        container->postMessage(WTFMove(message), WTFMove(sourceData), WTFMove(sourceOrigin));
    130128}
    131129
  • trunk/Source/WebCore/workers/service/ServiceWorkerContainer.cpp

    r249615 r249629  
    7171    : ActiveDOMObject(context)
    7272    , m_navigator(navigator)
     73    , m_messageQueue(*this)
    7374{
    7475    suspendIfNeeded();
     76   
     77    // We should queue messages until the DOMContentLoaded event has fired or startMessages() has been called.
     78    if (is<Document>(context) && downcast<Document>(*context).parsing())
     79        m_messageQueue.suspend();
    7580}
    7681
     
    311316void ServiceWorkerContainer::startMessages()
    312317{
     318    m_messageQueue.resume();
    313319}
    314320
     
    408414
    409415    auto messageEvent = MessageEvent::create(MessagePort::entanglePorts(context, WTFMove(message.transferredPorts)), message.message.releaseNonNull(), sourceOrigin, { }, WTFMove(source));
    410     dispatchEvent(messageEvent);
     416   
     417    m_messageQueue.enqueueEvent(WTFMove(messageEvent));
    411418}
    412419
     
    516523{
    517524    return !hasPendingActivity();
     525}
     526
     527void ServiceWorkerContainer::suspend(ReasonForSuspension)
     528{
     529    m_messageQueue.suspend();
     530}
     531
     532void ServiceWorkerContainer::resume()
     533{
     534    m_messageQueue.resume();
    518535}
    519536
     
    569586    removeAllEventListeners();
    570587    m_readyPromise = nullptr;
     588    m_messageQueue.close();
    571589    auto jobMap = WTFMove(m_jobMap);
    572590    for (auto& ongoingJob : jobMap.values()) {
     
    613631}
    614632
     633bool ServiceWorkerContainer::addEventListener(const AtomString& eventType, Ref<EventListener>&& eventListener, const AddEventListenerOptions& options)
     634{
     635    // Setting the onmessage EventHandler attribute on the ServiceWorkerContainer should start the messages
     636    // automatically.
     637    if (eventListener->isAttribute() && eventType == eventNames().messageEvent)
     638        startMessages();
     639
     640    return EventTargetWithInlineData::addEventListener(eventType, WTFMove(eventListener), options);
     641}
     642
    615643} // namespace WebCore
    616644
  • trunk/Source/WebCore/workers/service/ServiceWorkerContainer.h

    r249615 r249629  
    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
     
    107110    SWClientConnection& ensureSWClientConnection();
    108111
     112    // ActiveDOMObject.
    109113    const char* activeDOMObjectName() const final;
    110114    bool canSuspendForDocumentSuspension() const final;
     115    void suspend(ReasonForSuspension) final;
     116    void resume() final;
     117   
    111118    ScriptExecutionContext* scriptExecutionContext() const final { return ActiveDOMObject::scriptExecutionContext(); }
    112119    EventTargetInterface eventTargetInterface() const final { return ServiceWorkerContainerEventTargetInterfaceType; }
     
    138145    uint64_t m_lastOngoingSettledRegistrationIdentifier { 0 };
    139146    HashMap<uint64_t, ServiceWorkerRegistrationKey> m_ongoingSettledRegistrations;
     147    GenericEventQueue m_messageQueue;
    140148
    141149};
  • trunk/Tools/DumpRenderTree/mac/DumpRenderTree.mm

    r249615 r249629  
    17261726#endif
    17271727
     1728    if (done)
     1729        return;
     1730
    17281731    updateDisplay();
    17291732
Note: See TracChangeset for help on using the changeset viewer.