Title: [206857] trunk/Source/WebCore
Revision
206857
Author
commit-qu...@webkit.org
Date
2016-10-06 02:43:52 -0700 (Thu, 06 Oct 2016)

Log Message

[Fetch API] Use ReadableStream pull to transfer binary data to stream when application needs it
https://bugs.webkit.org/show_bug.cgi?id=162892

Patch by Youenn Fablet <you...@apple.com> on 2016-10-06
Reviewed by Alex Christensen.

Covered by existing tests.

Before this patch, FetchResponse was never resolving the start promise.
This way, it could enqueue data, error or close the stream whenever desired.

With this patch, FetchResponse will feed the stream when being asked to.
This allows keeping the data in WebCore until the application needs it.
This is only implemented for network data.
For other data owned by response (blob, text...), data will be enqueued like previously as fast as possible.

Note that FetchResponse can enqueue/error/close the stream at any time since JSFetchResponse has a reference to the stream.
And the stream has a reference to the controller.

In addition to transfer binary chunks to ReadableStream only when needed, WebCore is now aware of the data
stored in the response, which may allow applying backpressure to the network source in the future.

* Modules/fetch/FetchResponse.cpp:
(WebCore::FetchResponse::BodyLoader::didSucceed):
(WebCore::FetchResponse::BodyLoader::didReceiveData): Enqueuing only if stream is pulling.
Otherwise, storing in FetchBodyConsumer. If stream is pulling, we enqueue both buffered data and received chunk.
(WebCore::FetchResponse::consumeBodyAsStream): Resolving pull promise if we enqueued some buffered data.
(WebCore::FetchResponse::closeStream):
(WebCore::FetchResponse::feedStream): If we have some buffered data, we enqueue it. If there is no loader, the stream can be closed.
* Modules/fetch/FetchResponse.h:
* Modules/fetch/FetchResponseSource.cpp:
(WebCore::FetchResponseSource::doPull):
(WebCore::FetchResponseSource::close):
(WebCore::FetchResponseSource::error):
* Modules/fetch/FetchResponseSource.h:
* Modules/streams/ReadableStreamSource.h:
(WebCore::ReadableStreamSource::isPulling): Renamed from isStarting.
(WebCore::ReadableStreamSource::isStarting): Deleted.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (206856 => 206857)


--- trunk/Source/WebCore/ChangeLog	2016-10-06 08:54:49 UTC (rev 206856)
+++ trunk/Source/WebCore/ChangeLog	2016-10-06 09:43:52 UTC (rev 206857)
@@ -1,3 +1,43 @@
+2016-10-06  Youenn Fablet  <you...@apple.com>
+
+        [Fetch API] Use ReadableStream pull to transfer binary data to stream when application needs it
+        https://bugs.webkit.org/show_bug.cgi?id=162892
+
+        Reviewed by Alex Christensen.
+
+        Covered by existing tests.
+
+        Before this patch, FetchResponse was never resolving the start promise.
+        This way, it could enqueue data, error or close the stream whenever desired.
+
+        With this patch, FetchResponse will feed the stream when being asked to.
+        This allows keeping the data in WebCore until the application needs it.
+        This is only implemented for network data.
+        For other data owned by response (blob, text...), data will be enqueued like previously as fast as possible.
+
+        Note that FetchResponse can enqueue/error/close the stream at any time since JSFetchResponse has a reference to the stream.
+        And the stream has a reference to the controller.
+
+        In addition to transfer binary chunks to ReadableStream only when needed, WebCore is now aware of the data
+        stored in the response, which may allow applying backpressure to the network source in the future.
+
+        * Modules/fetch/FetchResponse.cpp:
+        (WebCore::FetchResponse::BodyLoader::didSucceed):
+        (WebCore::FetchResponse::BodyLoader::didReceiveData): Enqueuing only if stream is pulling.
+        Otherwise, storing in FetchBodyConsumer. If stream is pulling, we enqueue both buffered data and received chunk.
+        (WebCore::FetchResponse::consumeBodyAsStream): Resolving pull promise if we enqueued some buffered data.
+        (WebCore::FetchResponse::closeStream):
+        (WebCore::FetchResponse::feedStream): If we have some buffered data, we enqueue it. If there is no loader, the stream can be closed.
+        * Modules/fetch/FetchResponse.h:
+        * Modules/fetch/FetchResponseSource.cpp:
+        (WebCore::FetchResponseSource::doPull):
+        (WebCore::FetchResponseSource::close):
+        (WebCore::FetchResponseSource::error):
+        * Modules/fetch/FetchResponseSource.h:
+        * Modules/streams/ReadableStreamSource.h:
+        (WebCore::ReadableStreamSource::isPulling): Renamed from isStarting.
+        (WebCore::ReadableStreamSource::isStarting): Deleted.
+
 2016-10-06  Adam Bergkvist  <adam.bergkv...@ericsson.com>
 
         WebRTC: Add support for the icecandidate event in MediaEndpointPeerConnection

Modified: trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp (206856 => 206857)


--- trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp	2016-10-06 08:54:49 UTC (rev 206856)
+++ trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp	2016-10-06 09:43:52 UTC (rev 206857)
@@ -128,12 +128,8 @@
     m_response.m_body->loadingSucceeded();
 
 #if ENABLE(READABLE_STREAM_API)
-    if (m_response.m_readableStreamSource && !m_response.body().consumer().hasData()) {
-        // We only close the stream if FetchBody already enqueued all data.
-        // Otherwise, FetchBody will close the stream after enqueuing the data.
-        m_response.m_readableStreamSource->close();
-        m_response.m_readableStreamSource = nullptr;
-    }
+    if (m_response.m_readableStreamSource && !m_response.body().consumer().hasData())
+        m_response.closeStream();
 #endif
 
     if (m_loader->isStarted())
@@ -182,9 +178,22 @@
 {
 #if ENABLE(READABLE_STREAM_API)
     ASSERT(m_response.m_readableStreamSource);
+    auto& source = *m_response.m_readableStreamSource;
 
-    if (!m_response.m_readableStreamSource->enqueue(ArrayBuffer::tryCreate(data, size)))
+    if (!source.isPulling()) {
+        m_response.body().consumer().append(data, size);
+        return;
+    }
+
+    if (m_response.body().consumer().hasData() && !source.enqueue(m_response.body().consumer().takeAsArrayBuffer())) {
         stop();
+        return;
+    }
+    if (!source.enqueue(ArrayBuffer::tryCreate(data, size))) {
+        stop();
+        return;
+    }
+    source.resolvePullPromise();
 #else
     UNUSED_PARAM(data);
     UNUSED_PARAM(size);
@@ -257,7 +266,7 @@
     m_isDisturbed = true;
     if (!isLoading()) {
         body().consumeAsStream(*this, *m_readableStreamSource);
-        if (!m_readableStreamSource->isStarting())
+        if (!m_readableStreamSource->isPulling())
             m_readableStreamSource = nullptr;
         return;
     }
@@ -266,12 +275,41 @@
 
     RefPtr<SharedBuffer> data = ""
     if (data) {
-        // FIXME: We might want to enqueue each internal SharedBuffer chunk as an individual ArrayBuffer.
-        if (!m_readableStreamSource->enqueue(data->createArrayBuffer()))
+        if (!m_readableStreamSource->enqueue(data->createArrayBuffer())) {
             stop();
+            return;
+        }
+        m_readableStreamSource->resolvePullPromise();
     }
 }
 
+void FetchResponse::closeStream()
+{
+    ASSERT(m_readableStreamSource);
+    m_readableStreamSource->close();
+    m_readableStreamSource = nullptr;
+}
+
+void FetchResponse::feedStream()
+{
+    ASSERT(m_readableStreamSource);
+    bool shouldCloseStream = !m_bodyLoader;
+
+    if (body().consumer().hasData()) {
+        if (!m_readableStreamSource->enqueue(body().consumer().takeAsArrayBuffer())) {
+            stop();
+            return;
+        }
+        if (!shouldCloseStream) {
+            m_readableStreamSource->resolvePullPromise();
+            return;
+        }
+    } else if (!shouldCloseStream)
+        return;
+
+    closeStream();
+}
+
 ReadableStreamSource* FetchResponse::createReadableStreamSource()
 {
     ASSERT(!m_readableStreamSource);

Modified: trunk/Source/WebCore/Modules/fetch/FetchResponse.h (206856 => 206857)


--- trunk/Source/WebCore/Modules/fetch/FetchResponse.h	2016-10-06 08:54:49 UTC (rev 206856)
+++ trunk/Source/WebCore/Modules/fetch/FetchResponse.h	2016-10-06 09:43:52 UTC (rev 206857)
@@ -82,6 +82,7 @@
 #if ENABLE(READABLE_STREAM_API)
     ReadableStreamSource* createReadableStreamSource();
     void consumeBodyAsStream();
+    void feedStream();
     void cancel();
 #endif
     bool isLoading() const { return !!m_bodyLoader; }
@@ -96,6 +97,10 @@
     const char* activeDOMObjectName() const final;
     bool canSuspendForDocumentSuspension() const final;
 
+#if ENABLE(READABLE_STREAM_API)
+    void closeStream();
+#endif
+
     class BodyLoader final : public FetchLoaderClient {
     public:
         BodyLoader(FetchResponse&, FetchPromise&&);

Modified: trunk/Source/WebCore/Modules/fetch/FetchResponseSource.cpp (206856 => 206857)


--- trunk/Source/WebCore/Modules/fetch/FetchResponseSource.cpp	2016-10-06 08:54:49 UTC (rev 206856)
+++ trunk/Source/WebCore/Modules/fetch/FetchResponseSource.cpp	2016-10-06 09:43:52 UTC (rev 206857)
@@ -62,7 +62,7 @@
 
 void FetchResponseSource::doPull()
 {
-    ASSERT_NOT_REACHED();
+    m_response.feedStream();
 }
 
 void FetchResponseSource::doCancel()
@@ -73,13 +73,11 @@
 
 void FetchResponseSource::close()
 {
-    ASSERT(isStarting());
     controller().close();
     clean();
 }
 void FetchResponseSource::error(const String& value)
 {
-    ASSERT(isStarting());
     controller().error(value);
     clean();
 }

Modified: trunk/Source/WebCore/Modules/fetch/FetchResponseSource.h (206856 => 206857)


--- trunk/Source/WebCore/Modules/fetch/FetchResponseSource.h	2016-10-06 08:54:49 UTC (rev 206856)
+++ trunk/Source/WebCore/Modules/fetch/FetchResponseSource.h	2016-10-06 09:43:52 UTC (rev 206857)
@@ -51,6 +51,8 @@
     bool isCancelling() const { return m_isCancelling; }
     bool isReadableStreamLocked() const;
 
+    void resolvePullPromise() { pullFinished(); }
+
 private:
     void doStart() final;
     void doPull() final;

Modified: trunk/Source/WebCore/Modules/streams/ReadableStreamSource.h (206856 => 206857)


--- trunk/Source/WebCore/Modules/streams/ReadableStreamSource.h	2016-10-06 08:54:49 UTC (rev 206856)
+++ trunk/Source/WebCore/Modules/streams/ReadableStreamSource.h	2016-10-06 09:43:52 UTC (rev 206857)
@@ -48,7 +48,7 @@
     void pull(Promise&&);
     void cancel(JSC::JSValue);
 
-    bool isStarting() const { return !!m_promise; }
+    bool isPulling() const { return !!m_promise; }
 
 protected:
     ReadableStreamDefaultController& controller() { return m_controller.value(); }
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to