Title: [203719] trunk
Revision
203719
Author
commit-qu...@webkit.org
Date
2016-07-26 09:03:01 -0700 (Tue, 26 Jul 2016)

Log Message

[Fetch API] Response constructor should be able to take a ReadableStream as body
https://bugs.webkit.org/show_bug.cgi?id=159804

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

LayoutTests/imported/w3c:

* web-platform-tests/fetch/api/response/response-consume-empty-expected.txt:
* web-platform-tests/fetch/api/response/response-consume-expected.txt:
* web-platform-tests/fetch/api/response/response-consume.html: Updating test to exercice Response coonstructor with a ReadableStream.

Source/WebCore:

Covered by existing and updated tests.

Introduced FetchBodyConsumer to encapsulate the code responsible to adapt FetchBody internal data to the requests made by user scripts.
This refactoring eases the handling of internal data coming from ReadableStream.

FetchLoader is now delegating conversion from the data to its m_consumer field.
If m_consumer is null, FetchLoader calls FetchLoaderClient::didReceiveData (streaming reception mode).
Clients of FetchLoader needs to pass a FetchBodyConsumer to the FetchLoader to do the data adaptation at loader creation time.

Added support for body data passed as a ReadableStream to Response.
This requires to set @body internal slot of the Response object in the constructor initialization JS built-in.

To actually use that data, Body accessors are also implemented as JS built-in for Response.
Since there is no need to do so for Request, FetchResponse is no longer marked as implementing FetchBody but all
FetchBody IDL description is inlined in FetchResponse.idl.

For each body accessor (arrayBuffer, blob, json, text), the corresponding JS built-in checks whether @body internal slot is set.
If that is not the case, regular handling is done through a new private method called @consume.
If @body internal slot is set, chunks are pumped from the ReadableStream using ReadableStream internal built-ins functions.
Data handling is done in C++ through the private methods @startConsumingStream, @consumeChunk and @finishConsumingStream.

To support cloning of Response with bodies, clone method is also implemented as a JS built-in.
Main clone is done through @cloneFoJS private method implemented in C++.
JS built-in clone code does the teeing of the ReadableStream using ReadableStream JS built-in internal functions.

Introducing a new ReadableStream type for FetchBody to cope with body being stored in a ReadableStream.

Introducing a new Loaded type for FetchBody to cope with body being stored in the FetchBodyConsumer owned by FetchBody.
This allows removing the conversion of data to JSC::ArrayBuffer which was done by defaut at the end of Fetch loading if user script did not request data before.
At the end of a load, the data remains in FetchBodyConsumer and the body is marked as Loaded.
If the user wants to get the data after data finished being loaded, FetchBodyConsumer will do the required conversions.

Introducing DeferredWrapper::resolveWithNewValue to handle the case of resolving promises with new objects.
This allows directly using toJSNewlyCreated instead of toJS.

* CMakeLists.txt: Adding FetchBodyConsumer.
* Modules/fetch/FetchBody.cpp: Moving data adaptation code to FetchBodyConsumer.
(WebCore::FetchBody::extract):
(WebCore::FetchBody::arrayBuffer):
(WebCore::FetchBody::blob): Setting contentType in FetchBodyConsumer to handle proper creation of blob.
(WebCore::FetchBody::json):
(WebCore::FetchBody::text):
(WebCore::FetchBody::consume): Refactoring and added case of Loaded bodies.
(WebCore::FetchBody::consumeAsStream): Ditto.
(WebCore::FetchBody::consumeArrayBuffer):
(WebCore::FetchBody::consumeText):
(WebCore::FetchBody::consumeBlob):
(WebCore::FetchBody::loadingFailed):
(WebCore::FetchBody::loadingSucceeded):
(WebCore::FetchBody::loadingType): Deleted.
(WebCore::blobFromArrayBuffer): Deleted.
(WebCore::FetchBody::fulfillTextPromise): Deleted.
(WebCore::FetchBody::loadedAsArrayBuffer): Deleted.
(WebCore::FetchBody::loadedAsText): Deleted.
* Modules/fetch/FetchBody.h:
(WebCore::FetchBody::consumer):
* Modules/fetch/FetchBodyConsumer.cpp: Added, responsible of data adaptation.
(WebCore::blobFromData):
(WebCore::FetchBodyConsumer::resolveWithData):
(WebCore::FetchBodyConsumer::resolve):
(WebCore::FetchBodyConsumer::append):
(WebCore::FetchBodyConsumer::takeData):
(WebCore::FetchBodyConsumer::takeAsArrayBuffer):
(WebCore::FetchBodyConsumer::takeAsBlob):
(WebCore::FetchBodyConsumer::takeAsText):
* Modules/fetch/FetchBodyConsumer.h: Added.
(WebCore::FetchBodyConsumer::FetchBodyConsumer):
(WebCore::FetchBodyConsumer::setContentType):
(WebCore::FetchBodyConsumer::setType):
(WebCore::FetchBodyConsumer::type):
(WebCore::FetchBodyConsumer::clean):
(WebCore::FetchBodyConsumer::hasData):
* Modules/fetch/FetchBodyOwner.cpp:
(WebCore::FetchBodyOwner::loadBlob):
(WebCore::FetchBodyOwner::blobLoadingSucceeded):
(WebCore::FetchBodyOwner::loadedBlobAsText): Deleted.
* Modules/fetch/FetchBodyOwner.h:
(WebCore::FetchBodyOwner::loadedBlobAsArrayBuffer): Deleted.
* Modules/fetch/FetchInternals.js:
(consumeStream): Pump ReadableStream data and send it to FetchResponse to be converted according user need.
* Modules/fetch/FetchLoader.cpp:
(WebCore::FetchLoader::FetchLoader): FetchLoader is simplified as it has two nodes: consumer mode in which case
data is sent to the consumer and no-consumer mode in which case data is passed to loader client. The second mode
is used to conveyy data to ReadableStream source.
(WebCore::FetchLoader::stop):
(WebCore::FetchLoader::startStreaming):
(WebCore::FetchLoader::didReceiveData):
(WebCore::FetchLoader::didFinishLoading): Deleted.
* Modules/fetch/FetchLoader.h:
* Modules/fetch/FetchLoaderClient.h:
(WebCore::FetchLoaderClient::didFinishLoadingAsText): Deleted.
(WebCore::FetchLoaderClient::didFinishLoadingAsArrayBuffer): Deleted.
* Modules/fetch/FetchResponse.cpp:
(WebCore::FetchResponse::cloneForJS):
(WebCore::FetchResponse::BodyLoader::didSucceed):
(WebCore::FetchResponse::BodyLoader::start):
(WebCore::FetchResponse::consume): Introduced to consume data stored in body and not in ReadableStream.
(WebCore::FetchResponse::startConsumingStream): Introduced to start process of consuming data stored in the ReadableStream.
(WebCore::FetchResponse::consumeChunk): Reception of ReadableStream data.
(WebCore::FetchResponse::finishConsumingStream): Doing the final conversion.
(WebCore::FetchResponse::clone): Deleted.
(WebCore::FetchResponse::BodyLoader::didFinishLoadingAsArrayBuffer): Deleted.
* Modules/fetch/FetchResponse.h:
* Modules/fetch/FetchResponse.idl: Inlining of FetchBody methods/attributes and adding private methods.
* Modules/fetch/FetchResponse.js:
(initializeFetchResponse):
(clone):
(arrayBuffer):
(blob):
(formData):
(json):
(text):
* WebCore.xcodeproj/project.pbxproj:
* bindings/js/JSDOMPromise.h:
(WebCore::DeferredWrapper::resolveWithNewValue):
* bindings/js/WebCoreBuiltinNames.h:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (203718 => 203719)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2016-07-26 13:26:35 UTC (rev 203718)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2016-07-26 16:03:01 UTC (rev 203719)
@@ -1,3 +1,14 @@
+2016-07-26  Youenn Fablet  <you...@apple.com>
+
+        [Fetch API] Response constructor should be able to take a ReadableStream as body
+        https://bugs.webkit.org/show_bug.cgi?id=159804
+
+        Reviewed by Alex Christensen.
+
+        * web-platform-tests/fetch/api/response/response-consume-empty-expected.txt:
+        * web-platform-tests/fetch/api/response/response-consume-expected.txt:
+        * web-platform-tests/fetch/api/response/response-consume.html: Updating test to exercice Response coonstructor with a ReadableStream.
+
 2016-07-25  Chris Dumez  <cdu...@apple.com>
 
         Second parameter to Range.setStart() / setEnd() should be mandatory

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-empty-expected.txt (203718 => 203719)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-empty-expected.txt	2016-07-26 13:26:35 UTC (rev 203718)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-empty-expected.txt	2016-07-26 16:03:01 UTC (rev 203719)
@@ -3,7 +3,7 @@
 PASS Consume response's body as blob 
 PASS Consume response's body as arrayBuffer 
 PASS Consume response's body as json 
-FAIL Consume response's body as formData promise_test: Unhandled rejection with value: undefined
+FAIL Consume response's body as formData promise_test: Unhandled rejection with value: "Not implemented"
 PASS Consume empty blob response body as arrayBuffer 
 PASS Consume empty text response body as arrayBuffer 
 PASS Consume empty blob response body as text 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-expected.txt (203718 => 203719)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-expected.txt	2016-07-26 13:26:35 UTC (rev 203718)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-expected.txt	2016-07-26 16:03:01 UTC (rev 203719)
@@ -3,9 +3,13 @@
 PASS Consume response's body as blob 
 PASS Consume response's body as arrayBuffer 
 PASS Consume response's body as json 
-FAIL Consume response's body as formData promise_test: Unhandled rejection with value: undefined
+FAIL Consume response's body as formData promise_test: Unhandled rejection with value: "Not implemented"
 PASS Consume blob response's body as blob 
 PASS Consume blob response's body as text 
 PASS Consume blob response's body as json 
 PASS Consume blob response's body as arrayBuffer 
+PASS Consume stream response's body as blob 
+PASS Consume stream response's body as text 
+PASS Consume stream response's body as json 
+PASS Consume stream response's body as arrayBuffer 
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume.html (203718 => 203719)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume.html	2016-07-26 13:26:35 UTC (rev 203718)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume.html	2016-07-26 16:03:01 UTC (rev 203719)
@@ -92,6 +92,25 @@
     checkBlobResponseBody(blob, textData, "json", checkBodyJSON);
     checkBlobResponseBody(blob, textData, "arrayBuffer", checkBodyArrayBuffer);
 
+    function checkReadableStreamResponseBody(streamData, bodyType, checkFunction) {
+      promise_test(function(test) {
+        var stream = new ReadableStream({
+          start: function(controller) {
+            controller.enqueue((stringToArray(streamData)));
+            controller.close();
+          }
+        });
+        var response = new Response(stream);
+        assert_false(response.bodyUsed, "bodyUsed is false at init");
+        return checkFunction(response, streamData);
+      }, "Consume stream response's body as " + bodyType);
+    }
+
+    checkReadableStreamResponseBody(textData, "blob", checkBodyBlob);
+    checkReadableStreamResponseBody(textData, "text", checkBodyText);
+    checkReadableStreamResponseBody(textData, "json", checkBodyJSON);
+    checkReadableStreamResponseBody(textData, "arrayBuffer", checkBodyArrayBuffer);
+
     </script>
   </body>
 </html>

Modified: trunk/Source/WebCore/CMakeLists.txt (203718 => 203719)


--- trunk/Source/WebCore/CMakeLists.txt	2016-07-26 13:26:35 UTC (rev 203718)
+++ trunk/Source/WebCore/CMakeLists.txt	2016-07-26 16:03:01 UTC (rev 203719)
@@ -818,6 +818,7 @@
 
     Modules/fetch/DOMWindowFetch.cpp
     Modules/fetch/FetchBody.cpp
+    Modules/fetch/FetchBodyConsumer.cpp
     Modules/fetch/FetchBodyOwner.cpp
     Modules/fetch/FetchHeaders.cpp
     Modules/fetch/FetchLoader.cpp

Modified: trunk/Source/WebCore/ChangeLog (203718 => 203719)


--- trunk/Source/WebCore/ChangeLog	2016-07-26 13:26:35 UTC (rev 203718)
+++ trunk/Source/WebCore/ChangeLog	2016-07-26 16:03:01 UTC (rev 203719)
@@ -1,3 +1,127 @@
+2016-07-26  Youenn Fablet  <you...@apple.com>
+
+        [Fetch API] Response constructor should be able to take a ReadableStream as body
+        https://bugs.webkit.org/show_bug.cgi?id=159804
+
+        Reviewed by Alex Christensen.
+
+        Covered by existing and updated tests.
+
+        Introduced FetchBodyConsumer to encapsulate the code responsible to adapt FetchBody internal data to the requests made by user scripts.
+        This refactoring eases the handling of internal data coming from ReadableStream.
+
+        FetchLoader is now delegating conversion from the data to its m_consumer field.
+        If m_consumer is null, FetchLoader calls FetchLoaderClient::didReceiveData (streaming reception mode).
+        Clients of FetchLoader needs to pass a FetchBodyConsumer to the FetchLoader to do the data adaptation at loader creation time.
+
+        Added support for body data passed as a ReadableStream to Response.
+        This requires to set @body internal slot of the Response object in the constructor initialization JS built-in.
+
+        To actually use that data, Body accessors are also implemented as JS built-in for Response.
+        Since there is no need to do so for Request, FetchResponse is no longer marked as implementing FetchBody but all
+        FetchBody IDL description is inlined in FetchResponse.idl.
+
+        For each body accessor (arrayBuffer, blob, json, text), the corresponding JS built-in checks whether @body internal slot is set.
+        If that is not the case, regular handling is done through a new private method called @consume.
+        If @body internal slot is set, chunks are pumped from the ReadableStream using ReadableStream internal built-ins functions.
+        Data handling is done in C++ through the private methods @startConsumingStream, @consumeChunk and @finishConsumingStream.
+
+        To support cloning of Response with bodies, clone method is also implemented as a JS built-in.
+        Main clone is done through @cloneFoJS private method implemented in C++.
+        JS built-in clone code does the teeing of the ReadableStream using ReadableStream JS built-in internal functions.
+
+        Introducing a new ReadableStream type for FetchBody to cope with body being stored in a ReadableStream.
+
+        Introducing a new Loaded type for FetchBody to cope with body being stored in the FetchBodyConsumer owned by FetchBody.
+        This allows removing the conversion of data to JSC::ArrayBuffer which was done by defaut at the end of Fetch loading if user script did not request data before.
+        At the end of a load, the data remains in FetchBodyConsumer and the body is marked as Loaded.
+        If the user wants to get the data after data finished being loaded, FetchBodyConsumer will do the required conversions.
+
+        Introducing DeferredWrapper::resolveWithNewValue to handle the case of resolving promises with new objects.
+        This allows directly using toJSNewlyCreated instead of toJS.
+
+        * CMakeLists.txt: Adding FetchBodyConsumer.
+        * Modules/fetch/FetchBody.cpp: Moving data adaptation code to FetchBodyConsumer.
+        (WebCore::FetchBody::extract):
+        (WebCore::FetchBody::arrayBuffer):
+        (WebCore::FetchBody::blob): Setting contentType in FetchBodyConsumer to handle proper creation of blob.
+        (WebCore::FetchBody::json):
+        (WebCore::FetchBody::text):
+        (WebCore::FetchBody::consume): Refactoring and added case of Loaded bodies.
+        (WebCore::FetchBody::consumeAsStream): Ditto.
+        (WebCore::FetchBody::consumeArrayBuffer):
+        (WebCore::FetchBody::consumeText):
+        (WebCore::FetchBody::consumeBlob):
+        (WebCore::FetchBody::loadingFailed):
+        (WebCore::FetchBody::loadingSucceeded):
+        (WebCore::FetchBody::loadingType): Deleted.
+        (WebCore::blobFromArrayBuffer): Deleted.
+        (WebCore::FetchBody::fulfillTextPromise): Deleted.
+        (WebCore::FetchBody::loadedAsArrayBuffer): Deleted.
+        (WebCore::FetchBody::loadedAsText): Deleted.
+        * Modules/fetch/FetchBody.h:
+        (WebCore::FetchBody::consumer):
+        * Modules/fetch/FetchBodyConsumer.cpp: Added, responsible of data adaptation.
+        (WebCore::blobFromData):
+        (WebCore::FetchBodyConsumer::resolveWithData):
+        (WebCore::FetchBodyConsumer::resolve):
+        (WebCore::FetchBodyConsumer::append):
+        (WebCore::FetchBodyConsumer::takeData):
+        (WebCore::FetchBodyConsumer::takeAsArrayBuffer):
+        (WebCore::FetchBodyConsumer::takeAsBlob):
+        (WebCore::FetchBodyConsumer::takeAsText):
+        * Modules/fetch/FetchBodyConsumer.h: Added.
+        (WebCore::FetchBodyConsumer::FetchBodyConsumer):
+        (WebCore::FetchBodyConsumer::setContentType):
+        (WebCore::FetchBodyConsumer::setType):
+        (WebCore::FetchBodyConsumer::type):
+        (WebCore::FetchBodyConsumer::clean):
+        (WebCore::FetchBodyConsumer::hasData):
+        * Modules/fetch/FetchBodyOwner.cpp:
+        (WebCore::FetchBodyOwner::loadBlob):
+        (WebCore::FetchBodyOwner::blobLoadingSucceeded):
+        (WebCore::FetchBodyOwner::loadedBlobAsText): Deleted.
+        * Modules/fetch/FetchBodyOwner.h:
+        (WebCore::FetchBodyOwner::loadedBlobAsArrayBuffer): Deleted.
+        * Modules/fetch/FetchInternals.js:
+        (consumeStream): Pump ReadableStream data and send it to FetchResponse to be converted according user need.
+        * Modules/fetch/FetchLoader.cpp:
+        (WebCore::FetchLoader::FetchLoader): FetchLoader is simplified as it has two nodes: consumer mode in which case
+        data is sent to the consumer and no-consumer mode in which case data is passed to loader client. The second mode
+        is used to conveyy data to ReadableStream source.
+        (WebCore::FetchLoader::stop):
+        (WebCore::FetchLoader::startStreaming):
+        (WebCore::FetchLoader::didReceiveData):
+        (WebCore::FetchLoader::didFinishLoading): Deleted.
+        * Modules/fetch/FetchLoader.h:
+        * Modules/fetch/FetchLoaderClient.h:
+        (WebCore::FetchLoaderClient::didFinishLoadingAsText): Deleted.
+        (WebCore::FetchLoaderClient::didFinishLoadingAsArrayBuffer): Deleted.
+        * Modules/fetch/FetchResponse.cpp:
+        (WebCore::FetchResponse::cloneForJS):
+        (WebCore::FetchResponse::BodyLoader::didSucceed):
+        (WebCore::FetchResponse::BodyLoader::start):
+        (WebCore::FetchResponse::consume): Introduced to consume data stored in body and not in ReadableStream.
+        (WebCore::FetchResponse::startConsumingStream): Introduced to start process of consuming data stored in the ReadableStream.
+        (WebCore::FetchResponse::consumeChunk): Reception of ReadableStream data.
+        (WebCore::FetchResponse::finishConsumingStream): Doing the final conversion.
+        (WebCore::FetchResponse::clone): Deleted.
+        (WebCore::FetchResponse::BodyLoader::didFinishLoadingAsArrayBuffer): Deleted.
+        * Modules/fetch/FetchResponse.h:
+        * Modules/fetch/FetchResponse.idl: Inlining of FetchBody methods/attributes and adding private methods.
+        * Modules/fetch/FetchResponse.js:
+        (initializeFetchResponse):
+        (clone):
+        (arrayBuffer):
+        (blob):
+        (formData):
+        (json):
+        (text):
+        * WebCore.xcodeproj/project.pbxproj:
+        * bindings/js/JSDOMPromise.h:
+        (WebCore::DeferredWrapper::resolveWithNewValue):
+        * bindings/js/WebCoreBuiltinNames.h:
+
 2016-07-25  Sergio Villar Senin  <svil...@igalia.com>
 
         [css-grid] repeat() syntax should take a <track-list> argument

Modified: trunk/Source/WebCore/Modules/fetch/FetchBody.cpp (203718 => 203719)


--- trunk/Source/WebCore/Modules/fetch/FetchBody.cpp	2016-07-26 13:26:35 UTC (rev 203718)
+++ trunk/Source/WebCore/Modules/fetch/FetchBody.cpp	2016-07-26 16:03:01 UTC (rev 203719)
@@ -39,12 +39,11 @@
 #include "HTTPParsers.h"
 #include "JSBlob.h"
 #include "JSDOMFormData.h"
+#include "JSReadableStream.h"
 #include "ReadableStreamSource.h"
 
 namespace WebCore {
 
-static Ref<Blob> blobFromArrayBuffer(ArrayBuffer*, const String&);
-
 FetchBody::FetchBody(Ref<Blob>&& blob)
     : m_type(Type::Blob)
     , m_mimeType(blob->type())
@@ -75,6 +74,8 @@
         return FetchBody(*JSDOMFormData::toWrapped(value));
     if (value.isString())
         return FetchBody(value.toWTFString(&state));
+    if (value.inherits(JSReadableStream::info()))
+        return { Type::ReadableStream };
     return { };
 }
 
@@ -89,13 +90,16 @@
 void FetchBody::arrayBuffer(FetchBodyOwner& owner, DeferredWrapper&& promise)
 {
     ASSERT(m_type != Type::None);
-    consume(owner, Consumer::Type::ArrayBuffer, WTFMove(promise));
+    m_consumer.setType(FetchBodyConsumer::Type::ArrayBuffer);
+    consume(owner, WTFMove(promise));
 }
 
 void FetchBody::blob(FetchBodyOwner& owner, DeferredWrapper&& promise)
 {
     ASSERT(m_type != Type::None);
-    consume(owner, Consumer::Type::Blob, WTFMove(promise));
+    m_consumer.setType(FetchBodyConsumer::Type::Blob);
+    m_consumer.setContentType(Blob::normalizedContentType(extractMIMETypeFromMediaType(m_mimeType)));
+    consume(owner, WTFMove(promise));
 }
 
 void FetchBody::json(FetchBodyOwner& owner, DeferredWrapper&& promise)
@@ -106,7 +110,8 @@
         fulfillPromiseWithJSON(promise, m_text);
         return;
     }
-    consume(owner, Consumer::Type::JSON, WTFMove(promise));
+    m_consumer.setType(FetchBodyConsumer::Type::JSON);
+    consume(owner, WTFMove(promise));
 }
 
 void FetchBody::text(FetchBodyOwner& owner, DeferredWrapper&& promise)
@@ -117,113 +122,95 @@
         promise.resolve(m_text);
         return;
     }
-    consume(owner, Consumer::Type::Text, WTFMove(promise));
+    m_consumer.setType(FetchBodyConsumer::Type::Text);
+    consume(owner, WTFMove(promise));
 }
 
-void FetchBody::consume(FetchBodyOwner& owner, Consumer::Type type, DeferredWrapper&& promise)
+void FetchBody::consume(FetchBodyOwner& owner, DeferredWrapper&& promise)
 {
-    if (m_type == Type::ArrayBuffer) {
-        consumeArrayBuffer(type, promise);
+    // This should be handled by FetchBodyOwner
+    ASSERT(m_type != Type::None);
+    // This should be handled by JS built-ins
+    ASSERT(m_type != Type::ReadableStream);
+
+    switch (m_type) {
+    case Type::ArrayBuffer:
+        consumeArrayBuffer(promise);
         return;
-    }
-    if (m_type == Type::Text) {
-        consumeText(type, promise);
+    case Type::Text:
+        consumeText(promise);
         return;
-    }
-    if (m_type == Type::Blob) {
-        consumeBlob(owner, type, WTFMove(promise));
+    case Type::Blob:
+        consumeBlob(owner, WTFMove(promise));
         return;
-    }
-    if (m_type == Type::Loading) {
-        // FIXME: We should be able to change the loading type to text if consumer type is JSON or Text.
-        m_consumer = Consumer({type, WTFMove(promise)});
+    case Type::Loading:
+        m_consumePromise = WTFMove(promise);
         return;
+    case Type::Loaded:
+        m_consumer.resolve(promise);
+        return;
+    default:
+        // FIXME: Support other types.
+        promise.reject(0);
     }
-
-    // FIXME: Support other types.
-    promise.reject(0);
 }
 
 #if ENABLE(STREAMS_API)
 void FetchBody::consumeAsStream(FetchBodyOwner& owner, FetchResponseSource& source)
 {
+    // This should be handled by FetchResponse
     ASSERT(m_type != Type::Loading);
+    // This should be handled by JS built-ins
+    ASSERT(m_type != Type::ReadableStream);
 
+    bool closeStream = false;
     switch (m_type) {
     case Type::ArrayBuffer:
         ASSERT(m_data);
-        if (source.enqueue(RefPtr<JSC::ArrayBuffer>(m_data)))
-            source.close();
-        return;
+        closeStream = source.enqueue(RefPtr<JSC::ArrayBuffer>(m_data));
+        break;
     case Type::Text: {
         Vector<uint8_t> data = ""
-        if (source.enqueue(ArrayBuffer::tryCreate(data.data(), data.size())))
-            source.close();
-        return;
+        closeStream = source.enqueue(ArrayBuffer::tryCreate(data.data(), data.size()));
+        break;
     }
     case Type::Blob:
         ASSERT(m_blob);
-        owner.loadBlob(*m_blob, FetchLoader::Type::Stream);
-        return;
+        owner.loadBlob(*m_blob, nullptr);
+        break;
     case Type::None:
-        source.close();
-        return;
+        closeStream = true;
+        break;
+    case Type::Loaded: {
+        closeStream = source.enqueue(m_consumer.takeAsArrayBuffer());
+        break;
+    }
     default:
         source.error(ASCIILiteral("not implemented"));
     }
+
+    if (closeStream)
+        source.close();
 }
 #endif
 
-void FetchBody::consumeArrayBuffer(Consumer::Type type, DeferredWrapper& promise)
+void FetchBody::consumeArrayBuffer(DeferredWrapper& promise)
 {
-    if (type == Consumer::Type::ArrayBuffer) {
-        fulfillPromiseWithArrayBuffer(promise, m_data.get());
-        return;
-    }
-    if (type == Consumer::Type::Blob) {
-        promise.resolve(blobFromArrayBuffer(m_data.get(), Blob::normalizedContentType(extractMIMETypeFromMediaType(m_mimeType))));
-        return;
-    }
-
-    ASSERT(type == Consumer::Type::Text || type == Consumer::Type::JSON);
-    // FIXME: Do we need TextResourceDecoder to create a String to decode UTF-8 data.
-    fulfillTextPromise(type, TextResourceDecoder::create(ASCIILiteral("text/plain"), "UTF-8")->decodeAndFlush(static_cast<const char*>(m_data->data()), m_data->byteLength()), promise);
+    m_consumer.resolveWithData(promise, static_cast<const uint8_t*>(m_data->data()), m_data->byteLength());
 }
 
-void FetchBody::consumeText(Consumer::Type type, DeferredWrapper& promise)
+void FetchBody::consumeText(DeferredWrapper& promise)
 {
-    ASSERT(type == Consumer::Type::ArrayBuffer || type == Consumer::Type::Blob);
-
-    if (type == Consumer::Type::ArrayBuffer) {
-        Vector<uint8_t> data = ""
-        fulfillPromiseWithArrayBuffer(promise, data.data(), data.size());
-        return;
-    }
-    String contentType = Blob::normalizedContentType(extractMIMETypeFromMediaType(m_mimeType));
-    promise.resolve(Blob::create(extractFromText(), contentType));
+    Vector<uint8_t> data = ""
+    m_consumer.resolveWithData(promise, data.data(), data.size());
 }
 
-FetchLoader::Type FetchBody::loadingType(Consumer::Type type)
+void FetchBody::consumeBlob(FetchBodyOwner& owner, DeferredWrapper&& promise)
 {
-    switch (type) {
-    case Consumer::Type::JSON:
-    case Consumer::Type::Text:
-        return FetchLoader::Type::Text;
-    case Consumer::Type::Blob:
-    case Consumer::Type::ArrayBuffer:
-        return FetchLoader::Type::ArrayBuffer;
-    default:
-        ASSERT_NOT_REACHED();
-        return FetchLoader::Type::ArrayBuffer;
-    };
-}
-
-void FetchBody::consumeBlob(FetchBodyOwner& owner, Consumer::Type type, DeferredWrapper&& promise)
-{
     ASSERT(m_blob);
 
-    m_consumer = Consumer({type, WTFMove(promise)});
-    owner.loadBlob(*m_blob, loadingType(type));
+    m_consumePromise = WTFMove(promise);
+    owner.loadBlob(*m_blob, &m_consumer);
 }
 
 Vector<uint8_t> FetchBody::extractFromText() const
@@ -236,65 +223,23 @@
     return value;
 }
 
-static inline Ref<Blob> blobFromArrayBuffer(ArrayBuffer* buffer, const String& contentType)
-{
-    if (!buffer)
-        return Blob::create(Vector<uint8_t>(), contentType);
-
-    // FIXME: We should try to move buffer to Blob without doing this copy.
-    Vector<uint8_t> value(buffer->byteLength());
-    memcpy(value.data(), buffer->data(), buffer->byteLength());
-    return Blob::create(WTFMove(value), contentType);
-}
-
-void FetchBody::fulfillTextPromise(FetchBody::Consumer::Type type, const String& text, DeferredWrapper& promise)
-{
-    ASSERT(type == Consumer::Type::Text || type == Consumer::Type::JSON);
-    if (type == FetchBody::Consumer::Type::Text)
-        promise.resolve(text);
-    else
-        fulfillPromiseWithJSON(promise, text);
-}
-
 void FetchBody::loadingFailed()
 {
-    ASSERT(m_consumer);
-    m_consumer->promise.reject(0);
-    m_consumer = Nullopt;
+    if (m_consumePromise) {
+        m_consumePromise->reject(0);
+        m_consumePromise = Nullopt;
+    }
 }
 
-void FetchBody::loadedAsArrayBuffer(RefPtr<ArrayBuffer>&& buffer)
+void FetchBody::loadingSucceeded()
 {
-    if (m_type == Type::Loading) {
-        m_type = Type::ArrayBuffer;
-        m_data = buffer;
-        if (m_consumer) {
-            consumeArrayBuffer(m_consumer->type, m_consumer->promise);
-            m_consumer = Nullopt;
-        }
-        return;
+    m_type = m_consumer.hasData() ? Type::Loaded : Type::None;
+    if (m_consumePromise) {
+        m_consumer.resolve(*m_consumePromise);
+        m_consumePromise = Nullopt;
     }
-
-    ASSERT(m_consumer);
-    ASSERT(m_consumer->type == Consumer::Type::Blob || m_consumer->type == Consumer::Type::ArrayBuffer);
-    if (m_consumer->type == Consumer::Type::ArrayBuffer)
-        fulfillPromiseWithArrayBuffer(m_consumer->promise, buffer.get());
-    else {
-        ASSERT(m_blob);
-        m_consumer->promise.resolve(blobFromArrayBuffer(buffer.get(), m_blob->type()));
-    }
-    m_consumer = Nullopt;
 }
 
-void FetchBody::loadedAsText(String&& text)
-{
-    ASSERT(m_consumer);
-    ASSERT(m_consumer->type == Consumer::Type::Text || m_consumer->type == Consumer::Type::JSON);
-
-    fulfillTextPromise(m_consumer->type, text, m_consumer->promise);
-    m_consumer = Nullopt;
-}
-
 RefPtr<FormData> FetchBody::bodyForInternalRequest() const
 {
     if (m_type == Type::None)

Modified: trunk/Source/WebCore/Modules/fetch/FetchBody.h (203718 => 203719)


--- trunk/Source/WebCore/Modules/fetch/FetchBody.h	2016-07-26 13:26:35 UTC (rev 203718)
+++ trunk/Source/WebCore/Modules/fetch/FetchBody.h	2016-07-26 16:03:01 UTC (rev 203719)
@@ -33,6 +33,7 @@
 
 #include "Blob.h"
 #include "DOMFormData.h"
+#include "FetchBodyConsumer.h"
 #include "FetchLoader.h"
 #include "JSDOMPromise.h"
 
@@ -70,14 +71,15 @@
     FetchBody() = default;
 
     void loadingFailed();
-    void loadedAsArrayBuffer(RefPtr<ArrayBuffer>&&);
-    void loadedAsText(String&&);
+    void loadingSucceeded();
 
     RefPtr<FormData> bodyForInternalRequest() const;
 
-    enum class Type { None, ArrayBuffer, Loading, Text, Blob, FormData };
+    enum class Type { None, ArrayBuffer, Blob, FormData, Text, Loading, Loaded, ReadableStream };
     Type type() const { return m_type; }
 
+    FetchBodyConsumer& consumer() { return m_consumer; }
+
 private:
     FetchBody(Ref<Blob>&&);
     FetchBody(Ref<DOMFormData>&&);
@@ -84,21 +86,12 @@
     FetchBody(String&&);
     FetchBody(Type type) : m_type(type) { }
 
-    struct Consumer {
-        enum class Type { Text, Blob, JSON, ArrayBuffer };
+    void consume(FetchBodyOwner&, DeferredWrapper&&);
 
-        Type type;
-        DeferredWrapper promise;
-    };
-    void consume(FetchBodyOwner&, Consumer::Type, DeferredWrapper&&);
-
     Vector<uint8_t> extractFromText() const;
-    void consumeArrayBuffer(Consumer::Type, DeferredWrapper&);
-    void consumeText(Consumer::Type, DeferredWrapper&);
-    void consumeBlob(FetchBodyOwner&, Consumer::Type, DeferredWrapper&&);
-    static FetchLoader::Type loadingType(Consumer::Type);
-    static void fulfillTextPromise(FetchBody::Consumer::Type, const String&, DeferredWrapper&);
-    static void fulfillArrayBufferPromise(FetchBody::Consumer::Type, const String&, DeferredWrapper&);
+    void consumeArrayBuffer(DeferredWrapper&);
+    void consumeText(DeferredWrapper&);
+    void consumeBlob(FetchBodyOwner&, DeferredWrapper&&);
 
     Type m_type { Type::None };
     String m_mimeType;
@@ -109,7 +102,8 @@
     RefPtr<ArrayBuffer> m_data;
     String m_text;
 
-    Optional<Consumer> m_consumer;
+    FetchBodyConsumer m_consumer { FetchBodyConsumer::Type::None };
+    Optional<DeferredWrapper> m_consumePromise;
 };
 
 } // namespace WebCore

Added: trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp (0 => 203719)


--- trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp	                        (rev 0)
+++ trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp	2016-07-26 16:03:01 UTC (rev 203719)
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2016 Apple Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted, provided that the following conditions
+ * are required to be met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Inc. nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. AND ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FetchBodyConsumer.h"
+
+#if ENABLE(FETCH_API)
+
+#include "JSBlob.h"
+#include "JSDOMPromise.h"
+
+namespace WebCore {
+
+static inline Ref<Blob> blobFromData(const unsigned char* data, unsigned length, const String& contentType)
+{
+    Vector<uint8_t> value(length);
+    memcpy(value.data(), data, length);
+    return Blob::create(WTFMove(value), contentType);
+}
+
+void FetchBodyConsumer::resolveWithData(DeferredWrapper& promise, const unsigned char* data, unsigned length)
+{
+    switch (m_type) {
+    case Type::ArrayBuffer:
+        fulfillPromiseWithArrayBuffer(promise, data, length);
+        return;
+    case Type::Blob:
+        promise.resolveWithNewlyCreated(blobFromData(data, length, m_contentType));
+        return;
+    case Type::JSON:
+        fulfillPromiseWithJSON(promise, String(data, length));
+        return;
+    case Type::Text:
+        promise.resolve(String(data, length));
+        return;
+    case Type::None:
+        ASSERT_NOT_REACHED();
+        return;
+    }
+}
+
+void FetchBodyConsumer::resolve(DeferredWrapper& promise)
+{
+    ASSERT(m_type != Type::None);
+    switch (m_type) {
+    case Type::ArrayBuffer:
+        fulfillPromiseWithArrayBuffer(promise, takeAsArrayBuffer().get());
+        return;
+    case Type::Blob:
+        promise.resolveWithNewlyCreated(takeAsBlob());
+        return;
+    case Type::JSON:
+        fulfillPromiseWithJSON(promise, takeAsText());
+        return;
+    case Type::Text:
+        promise.resolve(takeAsText());
+        return;
+    case Type::None:
+        ASSERT_NOT_REACHED();
+        return;
+    }
+}
+
+void FetchBodyConsumer::append(const char* data, unsigned length)
+{
+    if (!m_buffer) {
+        m_buffer = SharedBuffer::create(data, length);
+        return;
+    }
+    m_buffer->append(data, length);
+}
+
+void FetchBodyConsumer::append(const unsigned char* data, unsigned length)
+{
+    append(reinterpret_cast<const char*>(data), length);
+}
+
+RefPtr<SharedBuffer> FetchBodyConsumer::takeData()
+{
+    return WTFMove(m_buffer);
+}
+
+RefPtr<JSC::ArrayBuffer> FetchBodyConsumer::takeAsArrayBuffer()
+{
+    if (!m_buffer)
+        return ArrayBuffer::tryCreate(nullptr, 0);
+
+    auto arrayBuffer = m_buffer->createArrayBuffer();
+    m_buffer = nullptr;
+    return arrayBuffer;
+}
+
+Ref<Blob> FetchBodyConsumer::takeAsBlob()
+{
+    ASSERT(m_buffer);
+    if (!m_buffer)
+        return Blob::create();
+
+    // FIXME: We should try to move m_buffer to Blob without doing extra copy.
+    return blobFromData(reinterpret_cast<const unsigned char*>(m_buffer->data()), m_buffer->size(), m_contentType);
+}
+
+String FetchBodyConsumer::takeAsText()
+{
+    if (!m_buffer)
+        return String();
+
+    auto text = String(m_buffer->data(), m_buffer->size());
+    m_buffer = nullptr;
+    return text;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(FETCH_API)

Copied: trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.h (from rev 203718, trunk/Source/WebCore/Modules/fetch/FetchLoaderClient.h) (0 => 203719)


--- trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.h	                        (rev 0)
+++ trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.h	2016-07-26 16:03:01 UTC (rev 203719)
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016 Apple Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted, provided that the following conditions
+ * are required to be met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Inc. nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. AND ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(FETCH_API)
+
+#include "SharedBuffer.h"
+
+namespace WebCore {
+
+class Blob;
+class DeferredWrapper;
+
+class FetchBodyConsumer {
+public:
+    // Type is used in FetchResponse.js and should be kept synchronized with it.
+    enum class Type { None, ArrayBuffer, Blob, JSON, Text };
+
+    FetchBodyConsumer(Type type) : m_type(type) { }
+
+    void append(const char* data, unsigned);
+    void append(const unsigned char* data, unsigned);
+
+    RefPtr<SharedBuffer> takeData();
+    RefPtr<JSC::ArrayBuffer> takeAsArrayBuffer();
+    Ref<Blob> takeAsBlob();
+    String takeAsText();
+
+    void setContentType(const String& contentType) { m_contentType = contentType; }
+    void setType(Type type) { m_type = type; }
+
+    void clean() { m_buffer = nullptr; }
+
+    void resolve(DeferredWrapper&);
+    void resolveWithData(DeferredWrapper&, const unsigned char*, unsigned);
+
+    bool hasData() const { return !!m_buffer; }
+
+private:
+    Type m_type;
+    String m_contentType;
+    RefPtr<SharedBuffer> m_buffer;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(FETCH_API)

Modified: trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.cpp (203718 => 203719)


--- trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.cpp	2016-07-26 13:26:35 UTC (rev 203718)
+++ trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.cpp	2016-07-26 16:03:01 UTC (rev 203719)
@@ -138,7 +138,7 @@
     m_body.text(*this, WTFMove(promise));
 }
 
-void FetchBodyOwner::loadBlob(Blob& blob, FetchLoader::Type type)
+void FetchBodyOwner::loadBlob(Blob& blob, FetchBodyConsumer* consumer)
 {
     // Can only be called once for a body instance.
     ASSERT(isDisturbed());
@@ -150,7 +150,7 @@
     }
 
     m_blobLoader = { *this };
-    m_blobLoader->loader = std::make_unique<FetchLoader>(type, *m_blobLoader);
+    m_blobLoader->loader = std::make_unique<FetchLoader>(*m_blobLoader, consumer);
 
     m_blobLoader->loader->start(*scriptExecutionContext(), blob);
     if (!m_blobLoader->loader->isStarted()) {
@@ -169,11 +169,6 @@
     unsetPendingActivity(this);
 }
 
-void FetchBodyOwner::loadedBlobAsText(String&& text)
-{
-    m_body.loadedAsText(WTFMove(text));
-}
-
 void FetchBodyOwner::blobLoadingSucceeded()
 {
     ASSERT(m_body.type() == FetchBody::Type::Blob);
@@ -184,7 +179,7 @@
         m_readableStreamSource = nullptr;
     }
 #endif
-
+    m_body.loadingSucceeded();
     finishBlobLoading();
 }
 

Modified: trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.h (203718 => 203719)


--- trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.h	2016-07-26 13:26:35 UTC (rev 203718)
+++ trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.h	2016-07-26 16:03:01 UTC (rev 203719)
@@ -52,7 +52,7 @@
     void json(DeferredWrapper&&);
     void text(DeferredWrapper&&);
 
-    void loadBlob(Blob&, FetchLoader::Type);
+    void loadBlob(Blob&, FetchBodyConsumer*);
 
     bool isActive() const { return !!m_blobLoader; }
 
@@ -67,8 +67,6 @@
 
 private:
     // Blob loading routines
-    void loadedBlobAsText(String&&);
-    void loadedBlobAsArrayBuffer(RefPtr<ArrayBuffer>&& buffer) { m_body.loadedAsArrayBuffer(WTFMove(buffer)); }
     void blobChunk(const char*, size_t);
     void blobLoadingSucceeded();
     void blobLoadingFailed();
@@ -78,8 +76,6 @@
         BlobLoader(FetchBodyOwner&);
 
         // FetchLoaderClient API
-        void didFinishLoadingAsText(String&& text) final { owner.loadedBlobAsText(WTFMove(text)); }
-        void didFinishLoadingAsArrayBuffer(RefPtr<ArrayBuffer>&& buffer) final { owner.loadedBlobAsArrayBuffer(WTFMove(buffer)); }
         void didReceiveResponse(const ResourceResponse&) final;
         void didReceiveData(const char* data, size_t size) final { owner.blobChunk(data, size); }
         void didFail() final;

Modified: trunk/Source/WebCore/Modules/fetch/FetchInternals.js (203718 => 203719)


--- trunk/Source/WebCore/Modules/fetch/FetchInternals.js	2016-07-26 13:26:35 UTC (rev 203718)
+++ trunk/Source/WebCore/Modules/fetch/FetchInternals.js	2016-07-26 16:03:01 UTC (rev 203719)
@@ -51,3 +51,27 @@
         @Headers.prototype.@appendFromJS.@call(headers, name, headersInit[name]);
     }
 }
+
+function consumeStream(response, type)
+{
+    @assert(response instanceof @Response);
+    @assert(response.@body instanceof @ReadableStream);
+
+    if (@isReadableStreamDisturbed(response.@body))
+        return @Promise.@reject(new @TypeError("Cannot consume a disturbed Response body ReadableStream"));
+
+    try {
+        let reader = new @ReadableStreamReader(response.@body);
+
+        @Response.prototype.@startConsumingStream.@call(response, type);
+        let pull = (result) => {
+            if (result.done)
+                return @Response.prototype.@finishConsumingStream.@call(response);
+            @Response.prototype.@consumeChunk.@call(response, result.value);
+            return @Promise.prototype.@then.@call(@readFromReadableStreamReader(reader), pull);
+        }
+        return @Promise.prototype.@then.@call(@readFromReadableStreamReader(reader), pull);
+    } catch(e) {
+        return @Promise.@reject(e);
+    }
+}

Modified: trunk/Source/WebCore/Modules/fetch/FetchLoader.cpp (203718 => 203719)


--- trunk/Source/WebCore/Modules/fetch/FetchLoader.cpp	2016-07-26 13:26:35 UTC (rev 203718)
+++ trunk/Source/WebCore/Modules/fetch/FetchLoader.cpp	2016-07-26 16:03:01 UTC (rev 203719)
@@ -89,15 +89,16 @@
     m_isStarted = m_loader;
 }
 
-FetchLoader::FetchLoader(Type type, FetchLoaderClient& client)
-    : m_type(type)
-    , m_client(client)
+FetchLoader::FetchLoader(FetchLoaderClient& client, FetchBodyConsumer* consumer)
+    : m_client(client)
+    , m_consumer(consumer)
 {
 }
 
 void FetchLoader::stop()
 {
-    m_data = nullptr;
+    if (m_consumer)
+        m_consumer->clean();
     if (m_loader)
         m_loader->cancel();
 }
@@ -104,9 +105,10 @@
 
 RefPtr<SharedBuffer> FetchLoader::startStreaming()
 {
-    ASSERT(m_type == Type::ArrayBuffer);
-    m_type = Type::Stream;
-    return WTFMove(m_data);
+    ASSERT(m_consumer);
+    auto firstChunk = m_consumer->takeData();
+    m_consumer = nullptr;
+    return firstChunk;
 }
 
 void FetchLoader::didReceiveResponse(unsigned long, const ResourceResponse& response)
@@ -114,29 +116,17 @@
     m_client.didReceiveResponse(response);
 }
 
-// FIXME: We should make text and blob creation more efficient.
-// We might also want to merge this class with FileReaderLoader.
 void FetchLoader::didReceiveData(const char* value, int size)
 {
-    if (m_type == Type::Stream) {
+    if (!m_consumer) {
         m_client.didReceiveData(value, size);
         return;
     }
-    if (!m_data) {
-        m_data = SharedBuffer::create(value, size);
-        return;
-    }
-    m_data->append(value, size);
+    m_consumer->append(value, size);
 }
 
 void FetchLoader::didFinishLoading(unsigned long, double)
 {
-    if (m_type == Type::ArrayBuffer)
-        m_client.didFinishLoadingAsArrayBuffer(m_data ? m_data->createArrayBuffer() : ArrayBuffer::tryCreate(nullptr, 0));
-    else if (m_type == Type::Text)
-        m_client.didFinishLoadingAsText(m_data ? TextResourceDecoder::create(ASCIILiteral("text/plain"), "UTF-8")->decodeAndFlush(m_data->data(), m_data->size()): String());
-    m_data = nullptr;
-
     m_client.didSucceed();
 }
 

Modified: trunk/Source/WebCore/Modules/fetch/FetchLoader.h (203718 => 203719)


--- trunk/Source/WebCore/Modules/fetch/FetchLoader.h	2016-07-26 13:26:35 UTC (rev 203718)
+++ trunk/Source/WebCore/Modules/fetch/FetchLoader.h	2016-07-26 16:03:01 UTC (rev 203719)
@@ -26,12 +26,11 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef FetchLoader_h
-#define FetchLoader_h
+#pragma once
 
 #if ENABLE(FETCH_API)
 
-#include "SharedBuffer.h"
+#include "FetchBodyConsumer.h"
 #include "ThreadableLoader.h"
 #include "ThreadableLoaderClient.h"
 
@@ -44,10 +43,8 @@
 
 class FetchLoader final : public ThreadableLoaderClient {
 public:
-    enum class Type { ArrayBuffer, Stream, Text };
+    FetchLoader(FetchLoaderClient&, FetchBodyConsumer*);
 
-    FetchLoader(Type, FetchLoaderClient&);
-
     RefPtr<SharedBuffer> startStreaming();
 
     void start(ScriptExecutionContext&, const FetchRequest&);
@@ -63,13 +60,10 @@
     void didFinishLoading(unsigned long, double) final;
     void didFail(const ResourceError&) final;
 
-    Type type() const { return m_type; }
-
 private:
-    Type m_type { Type::ArrayBuffer };
     FetchLoaderClient& m_client;
     RefPtr<ThreadableLoader> m_loader;
-    RefPtr<SharedBuffer> m_data;
+    FetchBodyConsumer* m_consumer;
     bool m_isStarted { false };
 };
 
@@ -76,5 +70,3 @@
 } // namespace WebCore
 
 #endif // ENABLE(FETCH_API)
-
-#endif // FetchLoader_h

Modified: trunk/Source/WebCore/Modules/fetch/FetchLoaderClient.h (203718 => 203719)


--- trunk/Source/WebCore/Modules/fetch/FetchLoaderClient.h	2016-07-26 13:26:35 UTC (rev 203718)
+++ trunk/Source/WebCore/Modules/fetch/FetchLoaderClient.h	2016-07-26 16:03:01 UTC (rev 203719)
@@ -47,8 +47,6 @@
 
     virtual void didReceiveResponse(const ResourceResponse&) { }
 
-    virtual void didFinishLoadingAsText(String&&) { }
-    virtual void didFinishLoadingAsArrayBuffer(RefPtr<JSC::ArrayBuffer>&&) { }
     virtual void didReceiveData(const char*, size_t) { }
 
     virtual void didSucceed() = 0;

Modified: trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp (203718 => 203719)


--- trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp	2016-07-26 13:26:35 UTC (rev 203718)
+++ trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp	2016-07-26 16:03:01 UTC (rev 203719)
@@ -34,6 +34,7 @@
 #include "ExceptionCode.h"
 #include "FetchRequest.h"
 #include "HTTPParsers.h"
+#include "JSBlob.h"
 #include "JSFetchResponse.h"
 #include "ScriptExecutionContext.h"
 
@@ -93,13 +94,11 @@
 {
 }
 
-RefPtr<FetchResponse> FetchResponse::clone(ScriptExecutionContext& context, ExceptionCode& ec)
+Ref<FetchResponse> FetchResponse::cloneForJS()
 {
-    if (isDisturbed()) {
-        ec = TypeError;
-        return nullptr;
-    }
-    return adoptRef(*new FetchResponse(context, FetchBody(m_body), FetchHeaders::create(headers()), ResourceResponse(m_response)));
+    ASSERT(scriptExecutionContext());
+    ASSERT(!isDisturbed());
+    return adoptRef(*new FetchResponse(*scriptExecutionContext(), FetchBody(m_body), FetchHeaders::create(headers()), ResourceResponse(m_response)));
 }
 
 void FetchResponse::fetch(ScriptExecutionContext& context, FetchRequest& request, FetchPromise&& promise)
@@ -130,6 +129,8 @@
         m_response.m_readableStreamSource = nullptr;
     }
 #endif
+    m_response.m_body.loadingSucceeded();
+
     if (m_loader->isStarted())
         m_response.m_bodyLoader = Nullopt;
     m_response.unsetPendingActivity(&m_response);
@@ -187,14 +188,9 @@
 #endif
 }
 
-void FetchResponse::BodyLoader::didFinishLoadingAsArrayBuffer(RefPtr<ArrayBuffer>&& buffer)
-{
-    m_response.body().loadedAsArrayBuffer(WTFMove(buffer));
-}
-
 bool FetchResponse::BodyLoader::start(ScriptExecutionContext& context, const FetchRequest& request)
 {
-    m_loader = std::make_unique<FetchLoader>(FetchLoader::Type::ArrayBuffer, *this);
+    m_loader = std::make_unique<FetchLoader>(*this, &m_response.m_body.consumer());
     m_loader->start(context, request);
     return m_loader->isStarted();
 }
@@ -205,7 +201,46 @@
         m_loader->stop();
 }
 
+void FetchResponse::consume(unsigned type, DeferredWrapper&& wrapper)
+{
+    ASSERT(type <= static_cast<unsigned>(FetchBodyConsumer::Type::Text));
+
+    switch (static_cast<FetchBodyConsumer::Type>(type)) {
+    case FetchBodyConsumer::Type::ArrayBuffer:
+        arrayBuffer(WTFMove(wrapper));
+        return;
+    case FetchBodyConsumer::Type::Blob:
+        blob(WTFMove(wrapper));
+        return;
+    case FetchBodyConsumer::Type::JSON:
+        json(WTFMove(wrapper));
+        return;
+    case FetchBodyConsumer::Type::Text:
+        text(WTFMove(wrapper));
+        return;
+    case FetchBodyConsumer::Type::None:
+        ASSERT_NOT_REACHED();
+        return;
+    }
+}
+
 #if ENABLE(STREAMS_API)
+void FetchResponse::startConsumingStream(unsigned type)
+{
+    m_isDisturbed = true;
+    m_consumer.setType(static_cast<FetchBodyConsumer::Type>(type));
+}
+
+void FetchResponse::consumeChunk(Ref<JSC::Uint8Array>&& chunk)
+{
+    m_consumer.append(chunk->data(), chunk->byteLength());
+}
+
+void FetchResponse::finishConsumingStream(DeferredWrapper&& promise)
+{
+    m_consumer.resolve(promise);
+}
+
 void FetchResponse::consumeBodyAsStream()
 {
     ASSERT(m_readableStreamSource);

Modified: trunk/Source/WebCore/Modules/fetch/FetchResponse.h (203718 => 203719)


--- trunk/Source/WebCore/Modules/fetch/FetchResponse.h	2016-07-26 13:26:35 UTC (rev 203718)
+++ trunk/Source/WebCore/Modules/fetch/FetchResponse.h	2016-07-26 16:03:01 UTC (rev 203719)
@@ -33,6 +33,7 @@
 #include "FetchBodyOwner.h"
 #include "FetchHeaders.h"
 #include "ResourceResponse.h"
+#include <runtime/TypedArrays.h>
 
 namespace JSC {
 class ArrayBuffer;
@@ -59,6 +60,13 @@
     using FetchPromise = DOMPromise<FetchResponse>;
     static void fetch(ScriptExecutionContext&, FetchRequest&, FetchPromise&&);
 
+    void consume(unsigned, DeferredWrapper&&);
+#if ENABLE(STREAMS_API)
+    void startConsumingStream(unsigned);
+    void consumeChunk(Ref<JSC::Uint8Array>&&);
+    void finishConsumingStream(DeferredWrapper&&);
+#endif
+
     void setStatus(int, const String&, ExceptionCode&);
     void initializeWith(JSC::ExecState&, JSC::JSValue);
 
@@ -70,7 +78,7 @@
     const String& statusText() const { return m_response.httpStatusText(); }
 
     FetchHeaders& headers() { return m_headers; }
-    RefPtr<FetchResponse> clone(ScriptExecutionContext&, ExceptionCode&);
+    Ref<FetchResponse> cloneForJS();
 
 #if ENABLE(STREAMS_API)
     ReadableStreamSource* createReadableStreamSource();
@@ -105,7 +113,6 @@
         void didFail() final;
         void didReceiveResponse(const ResourceResponse&) final;
         void didReceiveData(const char*, size_t) final;
-        void didFinishLoadingAsArrayBuffer(RefPtr<ArrayBuffer>&&) final;
 
         FetchResponse& m_response;
         Optional<FetchPromise> m_promise;
@@ -116,6 +123,8 @@
     Ref<FetchHeaders> m_headers;
     Optional<BodyLoader> m_bodyLoader;
     mutable String m_responseURL;
+
+    FetchBodyConsumer m_consumer { FetchBodyConsumer::Type::ArrayBuffer  };
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/Modules/fetch/FetchResponse.idl (203718 => 203719)


--- trunk/Source/WebCore/Modules/fetch/FetchResponse.idl	2016-07-26 13:26:35 UTC (rev 203718)
+++ trunk/Source/WebCore/Modules/fetch/FetchResponse.idl	2016-07-26 16:03:01 UTC (rev 203719)
@@ -53,11 +53,25 @@
     readonly attribute FetchHeaders headers;
     [JSBuiltin] readonly attribute ReadableStream? body;
 
-    [NewObject, CallWith=ScriptExecutionContext, RaisesException] FetchResponse clone();
+    // Copy of FetchBody IDL as we want to implement some of these as built-ins.
+    [ImplementedAs=isDisturbed] readonly attribute boolean bodyUsed;
+    [JSBuiltin] Promise arrayBuffer();
+    [JSBuiltin] Promise blob();
+    [JSBuiltin] Promise formData();
+    [JSBuiltin] Promise json();
+    [JSBuiltin] Promise text();
 
+    [JSBuiltin] FetchResponse clone();
+
+    [PrivateIdentifier, NewObject] FetchResponse cloneForJS();
+
+    [Conditional=STREAMS_API, PrivateIdentifier] void startConsumingStream(unsigned short type);
+    [Conditional=STREAMS_API, PrivateIdentifier] void consumeChunk(Uint8Array chunk);
+    [Conditional=STREAMS_API, PrivateIdentifier] Promise finishConsumingStream();
+
+    [PrivateIdentifier] Promise consume(unsigned short type);
     [PrivateIdentifier, RaisesException] void setStatus(unsigned short status, DOMString statusText);
     [CallWith=ScriptState, PrivateIdentifier] void initializeWith(any body);
     [PrivateIdentifier, NewObject] ReadableStreamSource createReadableStreamSource();
     [PrivateIdentifier] boolean isDisturbed();
 };
-FetchResponse implements FetchBody;

Modified: trunk/Source/WebCore/Modules/fetch/FetchResponse.js (203718 => 203719)


--- trunk/Source/WebCore/Modules/fetch/FetchResponse.js	2016-07-26 13:26:35 UTC (rev 203718)
+++ trunk/Source/WebCore/Modules/fetch/FetchResponse.js	2016-07-26 16:03:01 UTC (rev 203719)
@@ -48,6 +48,12 @@
     if (body !== @undefined && body !== null) {
         if (status == 101 || status == 204 || status == 205 || status == 304)
             throw new @TypeError("Response cannot have a body with the given status");
+
+        // FIXME: Use @isReadableStream once it is no longer guarded by STREAMS_API guard.
+        let isBodyReadableStream = (@isObject(body) && !!body.@underlyingSource);
+        if (isBodyReadableStream)
+          this.@body = body;
+
         this.@initializeWith(body);
     }
 
@@ -68,3 +74,77 @@
     }
     return this.@body;
 }
+
+function clone()
+{
+    if (!this instanceof @Response)
+        throw new @TypeError("Function should be called on a Response");
+
+    if (@Response.prototype.@isDisturbed.@call(this))
+        throw new @TypeError("Cannot clone a disturbed Response");
+
+    var cloned = @Response.prototype.@cloneForJS.@call(this);
+    if (this.@body) {
+        var teedReadableStreams = @teeReadableStream(this.@body, false);
+        this.@body = teedReadableStreams[0];
+        cloned.@body = teedReadableStreams[1];
+    }
+    return cloned;
+}
+
+// consume and consumeStream single parameter should be kept in sync with FetchBodyConsumer::Type.
+function arrayBuffer()
+{
+    if (!this instanceof @Response)
+        throw new @TypeError("Function should be called on a Response");
+
+    const arrayBufferConsumerType = 1;
+    if (!this.@body)
+        return @Response.prototype.@consume.@call(this, arrayBufferConsumerType);
+
+    return @consumeStream(this, arrayBufferConsumerType);
+}
+
+function blob()
+{
+    if (!this instanceof @Response)
+        throw new @TypeError("Function should be called on a Response");
+
+    const blobConsumerType = 2;
+    if (!this.@body)
+        return @Response.prototype.@consume.@call(this, blobConsumerType);
+
+    return @consumeStream(this, blobConsumerType);
+}
+
+function formData()
+{
+    if (!this instanceof @Response)
+        throw new @TypeError("Function should be called on a Response");
+
+    return @Promise.@reject("Not implemented");
+}
+
+function json()
+{
+    if (!this instanceof @Response)
+        throw new @TypeError("Function should be called on a Response");
+
+    const jsonConsumerType = 3;
+    if (!this.@body)
+        return @Response.prototype.@consume.@call(this, jsonConsumerType);
+
+    return @consumeStream(this, jsonConsumerType);
+}
+
+function text()
+{
+    if (!this instanceof @Response)
+        throw new @TypeError("Function should be called on a Response");
+
+    const textConsumerType = 4;
+    if (!this.@body)
+        return @Response.prototype.@consume.@call(this, textConsumerType);
+
+    return @consumeStream(this, textConsumerType);
+}

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (203718 => 203719)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2016-07-26 13:26:35 UTC (rev 203718)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2016-07-26 16:03:01 UTC (rev 203719)
@@ -1631,6 +1631,7 @@
 		41BF700F0FE86F61005E8DEC /* PlatformMessagePortChannel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41BF700D0FE86F61005E8DEC /* PlatformMessagePortChannel.cpp */; };
 		41BF70100FE86F61005E8DEC /* PlatformMessagePortChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = 41BF700E0FE86F61005E8DEC /* PlatformMessagePortChannel.h */; };
 		41C760B10EDE03D300C1655F /* ScriptState.h in Headers */ = {isa = PBXBuildFile; fileRef = 41C760B00EDE03D300C1655F /* ScriptState.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		41CF8BE71D46226700707DC9 /* FetchBodyConsumer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41CF8BE41D46222000707DC9 /* FetchBodyConsumer.cpp */; };
 		41D015CA0F4B5C71004A662F /* ContentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 41D015C80F4B5C71004A662F /* ContentType.h */; };
 		41D015CB0F4B5C71004A662F /* ContentType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41D015C90F4B5C71004A662F /* ContentType.cpp */; };
 		41E1B1D00FF5986900576B3B /* AbstractWorker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41E1B1CA0FF5986900576B3B /* AbstractWorker.cpp */; };
@@ -9218,6 +9219,9 @@
 		41BF700D0FE86F61005E8DEC /* PlatformMessagePortChannel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PlatformMessagePortChannel.cpp; path = default/PlatformMessagePortChannel.cpp; sourceTree = "<group>"; };
 		41BF700E0FE86F61005E8DEC /* PlatformMessagePortChannel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PlatformMessagePortChannel.h; path = default/PlatformMessagePortChannel.h; sourceTree = "<group>"; };
 		41C760B00EDE03D300C1655F /* ScriptState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptState.h; sourceTree = "<group>"; };
+		41CF8BE41D46222000707DC9 /* FetchBodyConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FetchBodyConsumer.cpp; sourceTree = "<group>"; };
+		41CF8BE51D46222000707DC9 /* FetchBodyConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FetchBodyConsumer.h; sourceTree = "<group>"; };
+		41CF8BE61D46222C00707DC9 /* FetchInternals.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode._javascript_; path = FetchInternals.js; sourceTree = "<group>"; };
 		41D015C80F4B5C71004A662F /* ContentType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContentType.h; sourceTree = "<group>"; };
 		41D015C90F4B5C71004A662F /* ContentType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ContentType.cpp; sourceTree = "<group>"; };
 		41E1B1CA0FF5986900576B3B /* AbstractWorker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AbstractWorker.cpp; sourceTree = "<group>"; };
@@ -17098,6 +17102,8 @@
 				41F54F7D1C50C4F600338488 /* FetchBody.cpp */,
 				41F54F7E1C50C4F600338488 /* FetchBody.h */,
 				41F54F7F1C50C4F600338488 /* FetchBody.idl */,
+				41CF8BE41D46222000707DC9 /* FetchBodyConsumer.cpp */,
+				41CF8BE51D46222000707DC9 /* FetchBodyConsumer.h */,
 				4147E2B31C89912600A7E715 /* FetchBodyOwner.cpp */,
 				4147E2B21C88337F00A7E715 /* FetchBodyOwner.h */,
 				41F54F821C50C4F600338488 /* FetchHeaders.cpp */,
@@ -17104,6 +17110,7 @@
 				41F54F831C50C4F600338488 /* FetchHeaders.h */,
 				41F54F841C50C4F600338488 /* FetchHeaders.idl */,
 				41F54F851C50C4F600338488 /* FetchHeaders.js */,
+				41CF8BE61D46222C00707DC9 /* FetchInternals.js */,
 				4147E2B41C89912600A7E715 /* FetchLoader.cpp */,
 				4147E2B51C89912600A7E715 /* FetchLoader.h */,
 				4147E2B61C89912600A7E715 /* FetchLoaderClient.h */,
@@ -30772,6 +30779,7 @@
 				BC06EDE30BFD6D0D00856E9D /* JSHTMLTableCellElement.cpp in Sources */,
 				BC06ED9D0BFD660600856E9D /* JSHTMLTableColElement.cpp in Sources */,
 				BC06EE040BFD71AA00856E9D /* JSHTMLTableElement.cpp in Sources */,
+				41CF8BE71D46226700707DC9 /* FetchBodyConsumer.cpp in Sources */,
 				BC06ED9F0BFD660600856E9D /* JSHTMLTableRowElement.cpp in Sources */,
 				BC06ED060BFD5BAE00856E9D /* JSHTMLTableSectionElement.cpp in Sources */,
 				D6489D25166FFCF1007C031B /* JSHTMLTemplateElement.cpp in Sources */,

Modified: trunk/Source/WebCore/bindings/js/JSDOMPromise.h (203718 => 203719)


--- trunk/Source/WebCore/bindings/js/JSDOMPromise.h	2016-07-26 13:26:35 UTC (rev 203718)
+++ trunk/Source/WebCore/bindings/js/JSDOMPromise.h	2016-07-26 16:03:01 UTC (rev 203719)
@@ -118,6 +118,8 @@
     template<class RejectResultType> typename std::enable_if<PromiseResultInspector<RejectResultType>::passByConstRef, void>::type
     reject(const RejectResultType& result) { rejectWithValue(result); }
 
+    template<class ResolveResultType> void resolveWithNewlyCreated(Ref<ResolveResultType>&&);
+
     void reject(ExceptionCode, const String& = { });
 
     JSDOMGlobalObject& globalObject() const;
@@ -181,6 +183,16 @@
     resolve(*exec, toJS(exec, m_globalObject.get(), std::forward<ResolveResultType>(result)));
 }
 
+template<class ResolveResultType>
+inline void DeferredWrapper::resolveWithNewlyCreated(Ref<ResolveResultType>&& result)
+{
+    ASSERT(m_deferred);
+    ASSERT(m_globalObject);
+    JSC::ExecState* exec = m_globalObject->globalExec();
+    JSC::JSLockHolder locker(exec);
+    resolve(*exec, toJSNewlyCreated(exec, m_globalObject.get(), WTFMove(result)));
+}
+
 template<class RejectResultType>
 inline void DeferredWrapper::rejectWithValue(RejectResultType&& result)
 {

Modified: trunk/Source/WebCore/bindings/js/WebCoreBuiltinNames.h (203718 => 203719)


--- trunk/Source/WebCore/bindings/js/WebCoreBuiltinNames.h	2016-07-26 13:26:35 UTC (rev 203718)
+++ trunk/Source/WebCore/bindings/js/WebCoreBuiltinNames.h	2016-07-26 16:03:01 UTC (rev 203719)
@@ -35,8 +35,11 @@
     macro(addTrack) \
     macro(appendFromJS) \
     macro(body) \
+    macro(cloneForJS) \
     macro(closeRequested) \
     macro(closedPromiseCapability) \
+    macro(consume) \
+    macro(consumeChunk) \
     macro(controlledReadableStream) \
     macro(controller) \
     macro(createReadableStreamSource) \
@@ -43,6 +46,7 @@
     macro(disturbed) \
     macro(fetchRequest) \
     macro(fillFromJS) \
+    macro(finishConsumingStream) \
     macro(firstReadCallback) \
     macro(getUserMediaFromJS) \
     macro(getRemoteStreams) \
@@ -72,6 +76,7 @@
     macro(setBody) \
     macro(setStatus) \
     macro(state) \
+    macro(startConsumingStream) \
     macro(started) \
     macro(startedPromise) \
     macro(storedError) \
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to