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) \