Title: [205110] trunk
Revision
205110
Author
[email protected]
Date
2016-08-28 23:49:42 -0700 (Sun, 28 Aug 2016)

Log Message

[Fetch API] Ensure response cloning works when data is loading
https://bugs.webkit.org/show_bug.cgi?id=161137

Patch by Youenn Fablet <[email protected]> on 2016-08-28
Reviewed by Darin Adler.

LayoutTests/imported/w3c:

* web-platform-tests/fetch/api/response/response-clone-expected.txt:
* web-platform-tests/fetch/api/response/response-clone.html: New tests highly inspired from Chromium similar tests.

Source/WebCore:

Test: http/tests/fetch/clone-after-load-is-finished.html and updated wpt test

FetchBody is only able to clone data when requested by Response in case the data is already there.
If data is loaded from FetchLoader, each received chunk should be given to each cloned response.
The simplest approach is to create a ReadableStream body for the cloned Response and use it for the teeing.

* Modules/fetch/FetchResponse.cpp:
(WebCore::FetchResponse::BodyLoader::didSucceed): Postpone stream closing if there is still data to enqueue in the FetchBody.
* Modules/fetch/FetchResponse.h:
* Modules/fetch/FetchResponse.idl:
* Modules/fetch/FetchResponse.js:
(clone): If response is being loaded, create a ReadableStream body so that loaded data cloning is handled by ReadableStream tee.
* Modules/streams/ReadableStreamInternals.js: Restrict firstReadCallback to the case of a readable ReadableStream.
If stream is errored or closed, FetchResponse will already have disposed of its source.
(readFromReadableStreamDefaultReader):
* bindings/js/WebCoreBuiltinNames.h:

LayoutTests:

* http/tests/fetch/clone-response-body-expected.txt: Added.
* http/tests/fetch/clone-response-body.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (205109 => 205110)


--- trunk/LayoutTests/ChangeLog	2016-08-29 05:57:16 UTC (rev 205109)
+++ trunk/LayoutTests/ChangeLog	2016-08-29 06:49:42 UTC (rev 205110)
@@ -1,3 +1,13 @@
+2016-08-28  Youenn Fablet  <[email protected]>
+
+        [Fetch API] Ensure response cloning works when data is loading
+        https://bugs.webkit.org/show_bug.cgi?id=161137
+
+        Reviewed by Darin Adler.
+
+        * http/tests/fetch/clone-response-body-expected.txt: Added.
+        * http/tests/fetch/clone-response-body.html: Added.
+
 2016-08-28  Jiewen Tan  <[email protected]>
 
         Unreviewed, update iOS simulator WK1 flaky tests.

Added: trunk/LayoutTests/http/tests/fetch/clone-response-body-expected.txt (0 => 205110)


--- trunk/LayoutTests/http/tests/fetch/clone-response-body-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/fetch/clone-response-body-expected.txt	2016-08-29 06:49:42 UTC (rev 205110)
@@ -0,0 +1,4 @@
+
+PASS Ensure that cloning works when load is finished 
+PASS Ensure that cloning works when load is ongoing 
+

Added: trunk/LayoutTests/http/tests/fetch/clone-response-body.html (0 => 205110)


--- trunk/LayoutTests/http/tests/fetch/clone-response-body.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/fetch/clone-response-body.html	2016-08-29 06:49:42 UTC (rev 205110)
@@ -0,0 +1,51 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>Response clone after load is finished</title>
+    <script src=""
+    <script src=""
+  </head>
+  <body>
+    <script>
+promise_test(function(t) {
+    var clone;
+    return fetch('/resources/testharnessreport.js').then(function(res) {
+        var resolveFunction;
+        var promise = new Promise((resolve) => {
+            resolveFunction = resolve;
+        });
+        setTimeout(() => {
+            // Load should be finished by now
+            clone = res.clone();
+            var string;
+            return res.text().then((value) => {
+                 string = value;
+                 return clone.text();
+            }).then((value) => {
+                assert_equals(value, string);
+                resolveFunction();
+            });
+        }, 1000);
+        return promise;
+    });
+}, 'Ensure that cloning works when load is finished');
+
+promise_test(function(t) {
+    var clone;
+    return fetch('/download-json-with-delay.php?iteration=2&delay=1').then(function(res) {
+        // All data should not be enqueued yet.
+        clone = res.clone();
+        var string;
+        return res.text().then((value) => {
+            string = value;
+            return clone.text();
+        }).then((value) => {
+            assert_equals(value, string);
+        });
+    });
+}, 'Ensure that cloning works when load is ongoing');
+
+    </script>
+  </body>
+</html>

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (205109 => 205110)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2016-08-29 05:57:16 UTC (rev 205109)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2016-08-29 06:49:42 UTC (rev 205110)
@@ -1,3 +1,13 @@
+2016-08-28  Youenn Fablet  <[email protected]>
+
+        [Fetch API] Ensure response cloning works when data is loading
+        https://bugs.webkit.org/show_bug.cgi?id=161137
+
+        Reviewed by Darin Adler.
+
+        * web-platform-tests/fetch/api/response/response-clone-expected.txt:
+        * web-platform-tests/fetch/api/response/response-clone.html: New tests highly inspired from Chromium similar tests.
+
 2016-08-27  Youenn Fablet  <[email protected]>
 
         [Fetch API] Opaque responses should not have any body

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-clone-expected.txt (205109 => 205110)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-clone-expected.txt	2016-08-29 05:57:16 UTC (rev 205109)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-clone-expected.txt	2016-08-29 06:49:42 UTC (rev 205110)
@@ -4,4 +4,6 @@
 PASS Check orginal response's body after cloning 
 PASS Check cloned response's body 
 PASS Cannot clone a disturbed response 
+PASS Cloned responses should provide the same data 
+PASS Cancelling stream should not affect cloned one 
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-clone.html (205109 => 205110)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-clone.html	2016-08-29 05:57:16 UTC (rev 205109)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-clone.html	2016-08-29 06:49:42 UTC (rev 205110)
@@ -61,6 +61,38 @@
               "Expect TypeError exception");
         });
       }, "Cannot clone a disturbed response");
+
+    promise_test(function(t) {
+        var clone;
+        var result;
+        var response;
+        return fetch('../resources/trickle.py?count=2&delay=100').then(function(res) {
+            clone = res.clone();
+            response = res;
+            return clone.arrayBuffer();
+        }).then(function(r) {
+            assert_equals(r.byteLength, 26);
+            result = r;
+            return response.arrayBuffer();
+        }).then(function(r) {
+            assert_array_equals(r, result, "cloned responses should provide the same data");
+        });
+     }, 'Cloned responses should provide the same data');
+
+    promise_test(function(t) {
+        var clone;
+        return fetch('../resources/trickle.py?count=2&delay=100').then(function(res) {
+            clone = res.clone();
+            res.body.cancel();
+            assert_true(res.bodyUsed);
+            assert_false(clone.bodyUsed);
+            return clone.arrayBuffer();
+        }).then(function(r) {
+            assert_equals(r.byteLength, 26);
+            assert_true(clone.bodyUsed);
+        });
+    }, 'Cancelling stream should not affect cloned one');
+
     </script>
   </body>
 </html>

Modified: trunk/Source/WebCore/ChangeLog (205109 => 205110)


--- trunk/Source/WebCore/ChangeLog	2016-08-29 05:57:16 UTC (rev 205109)
+++ trunk/Source/WebCore/ChangeLog	2016-08-29 06:49:42 UTC (rev 205110)
@@ -1,3 +1,27 @@
+2016-08-28  Youenn Fablet  <[email protected]>
+
+        [Fetch API] Ensure response cloning works when data is loading
+        https://bugs.webkit.org/show_bug.cgi?id=161137
+
+        Reviewed by Darin Adler.
+
+        Test: http/tests/fetch/clone-after-load-is-finished.html and updated wpt test
+
+        FetchBody is only able to clone data when requested by Response in case the data is already there.
+        If data is loaded from FetchLoader, each received chunk should be given to each cloned response.
+        The simplest approach is to create a ReadableStream body for the cloned Response and use it for the teeing.
+
+        * Modules/fetch/FetchResponse.cpp:
+        (WebCore::FetchResponse::BodyLoader::didSucceed): Postpone stream closing if there is still data to enqueue in the FetchBody.
+        * Modules/fetch/FetchResponse.h:
+        * Modules/fetch/FetchResponse.idl:
+        * Modules/fetch/FetchResponse.js:
+        (clone): If response is being loaded, create a ReadableStream body so that loaded data cloning is handled by ReadableStream tee.
+        * Modules/streams/ReadableStreamInternals.js: Restrict firstReadCallback to the case of a readable ReadableStream.
+        If stream is errored or closed, FetchResponse will already have disposed of its source.
+        (readFromReadableStreamDefaultReader):
+        * bindings/js/WebCoreBuiltinNames.h:
+
 2016-08-28  Andreas Kling  <[email protected]>
 
         document.title setter can't throw.

Modified: trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp (205109 => 205110)


--- trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp	2016-08-29 05:57:16 UTC (rev 205109)
+++ trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp	2016-08-29 06:49:42 UTC (rev 205110)
@@ -127,13 +127,16 @@
 void FetchResponse::BodyLoader::didSucceed()
 {
     ASSERT(m_response.hasPendingActivity());
+    m_response.m_body.loadingSucceeded();
+
 #if ENABLE(STREAMS_API)
-    if (m_response.m_readableStreamSource) {
+    if (m_response.m_readableStreamSource && m_response.m_body.type() != FetchBody::Type::Loaded) {
+        // We only close the stream if FetchBody already enqueued data.
+        // Otherwise, FetchBody will close the stream when enqueuing data.
         m_response.m_readableStreamSource->close();
         m_response.m_readableStreamSource = nullptr;
     }
 #endif
-    m_response.m_body.loadingSucceeded();
 
     if (m_loader->isStarted())
         m_response.m_bodyLoader = Nullopt;

Modified: trunk/Source/WebCore/Modules/fetch/FetchResponse.h (205109 => 205110)


--- trunk/Source/WebCore/Modules/fetch/FetchResponse.h	2016-08-29 05:57:16 UTC (rev 205109)
+++ trunk/Source/WebCore/Modules/fetch/FetchResponse.h	2016-08-29 06:49:42 UTC (rev 205110)
@@ -85,6 +85,7 @@
     void consumeBodyAsStream();
     void cancel();
 #endif
+    bool isLoading() const { return body().type() == FetchBody::Type::Loading; }
 
 private:
     FetchResponse(ScriptExecutionContext&, FetchBody&&, Ref<FetchHeaders>&&, ResourceResponse&&);

Modified: trunk/Source/WebCore/Modules/fetch/FetchResponse.idl (205109 => 205110)


--- trunk/Source/WebCore/Modules/fetch/FetchResponse.idl	2016-08-29 05:57:16 UTC (rev 205109)
+++ trunk/Source/WebCore/Modules/fetch/FetchResponse.idl	2016-08-29 06:49:42 UTC (rev 205110)
@@ -70,6 +70,7 @@
     [Conditional=STREAMS_API, PrivateIdentifier] Promise finishConsumingStream();
 
     [PrivateIdentifier] Promise consume(unsigned short type);
+    [PrivateIdentifier] boolean isLoading();
     [PrivateIdentifier, RaisesException] void setStatus(unsigned short status, DOMString statusText);
     [CallWith=ScriptState, PrivateIdentifier] void initializeWith(any body);
     [PrivateIdentifier, NewObject] ReadableStreamSource createReadableStreamSource();

Modified: trunk/Source/WebCore/Modules/fetch/FetchResponse.js (205109 => 205110)


--- trunk/Source/WebCore/Modules/fetch/FetchResponse.js	2016-08-29 05:57:16 UTC (rev 205109)
+++ trunk/Source/WebCore/Modules/fetch/FetchResponse.js	2016-08-29 06:49:42 UTC (rev 205110)
@@ -87,6 +87,14 @@
         throw new @TypeError("Cannot clone a disturbed Response");
 
     var cloned = @Response.prototype.@cloneForJS.@call(this);
+
+    // Let's create @body if response body is loading to provide data to both clones.
+    if (@Response.prototype.@isLoading.@call(this) && !this.@body) {
+        var source = @Response.prototype.@createReadableStreamSource.@call(this);
+        @assert(!!source);
+        this.@body = new @ReadableStream(source);
+    }
+
     if (this.@body) {
         var teedReadableStreams = @teeReadableStream(this.@body, false);
         this.@body = teedReadableStreams[0];

Modified: trunk/Source/WebCore/Modules/streams/ReadableStreamInternals.js (205109 => 205110)


--- trunk/Source/WebCore/Modules/streams/ReadableStreamInternals.js	2016-08-29 05:57:16 UTC (rev 205109)
+++ trunk/Source/WebCore/Modules/streams/ReadableStreamInternals.js	2016-08-29 06:49:42 UTC (rev 205110)
@@ -343,7 +343,7 @@
     @assert(!!stream);
 
     // Native sources may want to start enqueueing at the time of the first read request.
-    if (!stream.@disturbed && stream.@underlyingSource.@firstReadCallback)
+    if (!stream.@disturbed && stream.@state === @streamReadable && stream.@underlyingSource.@firstReadCallback)
         stream.@underlyingSource.@firstReadCallback();
 
     stream.@disturbed = true;

Modified: trunk/Source/WebCore/bindings/js/WebCoreBuiltinNames.h (205109 => 205110)


--- trunk/Source/WebCore/bindings/js/WebCoreBuiltinNames.h	2016-08-29 05:57:16 UTC (rev 205109)
+++ trunk/Source/WebCore/bindings/js/WebCoreBuiltinNames.h	2016-08-29 06:49:42 UTC (rev 205110)
@@ -54,6 +54,7 @@
     macro(getTracks) \
     macro(initializeWith) \
     macro(isDisturbed) \
+    macro(isLoading) \
     macro(localStreams) \
     macro(makeThisTypeError) \
     macro(makeGetterTypeError) \
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to