Changeset 203719 in webkit


Ignore:
Timestamp:
Jul 26, 2016 9:03:01 AM (8 years ago)
Author:
commit-queue@webkit.org
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 <youenn@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:
Location:
trunk
Files:
1 added
21 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r203713 r203719  
     12016-07-26  Youenn Fablet  <youenn@apple.com>
     2
     3        [Fetch API] Response constructor should be able to take a ReadableStream as body
     4        https://bugs.webkit.org/show_bug.cgi?id=159804
     5
     6        Reviewed by Alex Christensen.
     7
     8        * web-platform-tests/fetch/api/response/response-consume-empty-expected.txt:
     9        * web-platform-tests/fetch/api/response/response-consume-expected.txt:
     10        * web-platform-tests/fetch/api/response/response-consume.html: Updating test to exercice Response coonstructor with a ReadableStream.
     11
    1122016-07-25  Chris Dumez  <cdumez@apple.com>
    213
  • trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-empty-expected.txt

    r198151 r203719  
    44PASS Consume response's body as arrayBuffer
    55PASS Consume response's body as json
    6 FAIL Consume response's body as formData promise_test: Unhandled rejection with value: undefined
     6FAIL Consume response's body as formData promise_test: Unhandled rejection with value: "Not implemented"
    77PASS Consume empty blob response body as arrayBuffer
    88PASS Consume empty text response body as arrayBuffer
  • trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-expected.txt

    r198133 r203719  
    44PASS Consume response's body as arrayBuffer
    55PASS Consume response's body as json
    6 FAIL Consume response's body as formData promise_test: Unhandled rejection with value: undefined
     6FAIL Consume response's body as formData promise_test: Unhandled rejection with value: "Not implemented"
    77PASS Consume blob response's body as blob
    88PASS Consume blob response's body as text
    99PASS Consume blob response's body as json
    1010PASS Consume blob response's body as arrayBuffer
     11PASS Consume stream response's body as blob
     12PASS Consume stream response's body as text
     13PASS Consume stream response's body as json
     14PASS Consume stream response's body as arrayBuffer
    1115
  • trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume.html

    r198888 r203719  
    9393    checkBlobResponseBody(blob, textData, "arrayBuffer", checkBodyArrayBuffer);
    9494
     95    function checkReadableStreamResponseBody(streamData, bodyType, checkFunction) {
     96      promise_test(function(test) {
     97        var stream = new ReadableStream({
     98          start: function(controller) {
     99            controller.enqueue((stringToArray(streamData)));
     100            controller.close();
     101          }
     102        });
     103        var response = new Response(stream);
     104        assert_false(response.bodyUsed, "bodyUsed is false at init");
     105        return checkFunction(response, streamData);
     106      }, "Consume stream response's body as " + bodyType);
     107    }
     108
     109    checkReadableStreamResponseBody(textData, "blob", checkBodyBlob);
     110    checkReadableStreamResponseBody(textData, "text", checkBodyText);
     111    checkReadableStreamResponseBody(textData, "json", checkBodyJSON);
     112    checkReadableStreamResponseBody(textData, "arrayBuffer", checkBodyArrayBuffer);
     113
    95114    </script>
    96115  </body>
  • trunk/Source/WebCore/CMakeLists.txt

    r203702 r203719  
    819819    Modules/fetch/DOMWindowFetch.cpp
    820820    Modules/fetch/FetchBody.cpp
     821    Modules/fetch/FetchBodyConsumer.cpp
    821822    Modules/fetch/FetchBodyOwner.cpp
    822823    Modules/fetch/FetchHeaders.cpp
  • trunk/Source/WebCore/ChangeLog

    r203717 r203719  
     12016-07-26  Youenn Fablet  <youenn@apple.com>
     2
     3        [Fetch API] Response constructor should be able to take a ReadableStream as body
     4        https://bugs.webkit.org/show_bug.cgi?id=159804
     5
     6        Reviewed by Alex Christensen.
     7
     8        Covered by existing and updated tests.
     9
     10        Introduced FetchBodyConsumer to encapsulate the code responsible to adapt FetchBody internal data to the requests made by user scripts.
     11        This refactoring eases the handling of internal data coming from ReadableStream.
     12
     13        FetchLoader is now delegating conversion from the data to its m_consumer field.
     14        If m_consumer is null, FetchLoader calls FetchLoaderClient::didReceiveData (streaming reception mode).
     15        Clients of FetchLoader needs to pass a FetchBodyConsumer to the FetchLoader to do the data adaptation at loader creation time.
     16
     17        Added support for body data passed as a ReadableStream to Response.
     18        This requires to set @body internal slot of the Response object in the constructor initialization JS built-in.
     19
     20        To actually use that data, Body accessors are also implemented as JS built-in for Response.
     21        Since there is no need to do so for Request, FetchResponse is no longer marked as implementing FetchBody but all
     22        FetchBody IDL description is inlined in FetchResponse.idl.
     23
     24        For each body accessor (arrayBuffer, blob, json, text), the corresponding JS built-in checks whether @body internal slot is set.
     25        If that is not the case, regular handling is done through a new private method called @consume.
     26        If @body internal slot is set, chunks are pumped from the ReadableStream using ReadableStream internal built-ins functions.
     27        Data handling is done in C++ through the private methods @startConsumingStream, @consumeChunk and @finishConsumingStream.
     28
     29        To support cloning of Response with bodies, clone method is also implemented as a JS built-in.
     30        Main clone is done through @cloneFoJS private method implemented in C++.
     31        JS built-in clone code does the teeing of the ReadableStream using ReadableStream JS built-in internal functions.
     32
     33        Introducing a new ReadableStream type for FetchBody to cope with body being stored in a ReadableStream.
     34
     35        Introducing a new Loaded type for FetchBody to cope with body being stored in the FetchBodyConsumer owned by FetchBody.
     36        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.
     37        At the end of a load, the data remains in FetchBodyConsumer and the body is marked as Loaded.
     38        If the user wants to get the data after data finished being loaded, FetchBodyConsumer will do the required conversions.
     39
     40        Introducing DeferredWrapper::resolveWithNewValue to handle the case of resolving promises with new objects.
     41        This allows directly using toJSNewlyCreated instead of toJS.
     42
     43        * CMakeLists.txt: Adding FetchBodyConsumer.
     44        * Modules/fetch/FetchBody.cpp: Moving data adaptation code to FetchBodyConsumer.
     45        (WebCore::FetchBody::extract):
     46        (WebCore::FetchBody::arrayBuffer):
     47        (WebCore::FetchBody::blob): Setting contentType in FetchBodyConsumer to handle proper creation of blob.
     48        (WebCore::FetchBody::json):
     49        (WebCore::FetchBody::text):
     50        (WebCore::FetchBody::consume): Refactoring and added case of Loaded bodies.
     51        (WebCore::FetchBody::consumeAsStream): Ditto.
     52        (WebCore::FetchBody::consumeArrayBuffer):
     53        (WebCore::FetchBody::consumeText):
     54        (WebCore::FetchBody::consumeBlob):
     55        (WebCore::FetchBody::loadingFailed):
     56        (WebCore::FetchBody::loadingSucceeded):
     57        (WebCore::FetchBody::loadingType): Deleted.
     58        (WebCore::blobFromArrayBuffer): Deleted.
     59        (WebCore::FetchBody::fulfillTextPromise): Deleted.
     60        (WebCore::FetchBody::loadedAsArrayBuffer): Deleted.
     61        (WebCore::FetchBody::loadedAsText): Deleted.
     62        * Modules/fetch/FetchBody.h:
     63        (WebCore::FetchBody::consumer):
     64        * Modules/fetch/FetchBodyConsumer.cpp: Added, responsible of data adaptation.
     65        (WebCore::blobFromData):
     66        (WebCore::FetchBodyConsumer::resolveWithData):
     67        (WebCore::FetchBodyConsumer::resolve):
     68        (WebCore::FetchBodyConsumer::append):
     69        (WebCore::FetchBodyConsumer::takeData):
     70        (WebCore::FetchBodyConsumer::takeAsArrayBuffer):
     71        (WebCore::FetchBodyConsumer::takeAsBlob):
     72        (WebCore::FetchBodyConsumer::takeAsText):
     73        * Modules/fetch/FetchBodyConsumer.h: Added.
     74        (WebCore::FetchBodyConsumer::FetchBodyConsumer):
     75        (WebCore::FetchBodyConsumer::setContentType):
     76        (WebCore::FetchBodyConsumer::setType):
     77        (WebCore::FetchBodyConsumer::type):
     78        (WebCore::FetchBodyConsumer::clean):
     79        (WebCore::FetchBodyConsumer::hasData):
     80        * Modules/fetch/FetchBodyOwner.cpp:
     81        (WebCore::FetchBodyOwner::loadBlob):
     82        (WebCore::FetchBodyOwner::blobLoadingSucceeded):
     83        (WebCore::FetchBodyOwner::loadedBlobAsText): Deleted.
     84        * Modules/fetch/FetchBodyOwner.h:
     85        (WebCore::FetchBodyOwner::loadedBlobAsArrayBuffer): Deleted.
     86        * Modules/fetch/FetchInternals.js:
     87        (consumeStream): Pump ReadableStream data and send it to FetchResponse to be converted according user need.
     88        * Modules/fetch/FetchLoader.cpp:
     89        (WebCore::FetchLoader::FetchLoader): FetchLoader is simplified as it has two nodes: consumer mode in which case
     90        data is sent to the consumer and no-consumer mode in which case data is passed to loader client. The second mode
     91        is used to conveyy data to ReadableStream source.
     92        (WebCore::FetchLoader::stop):
     93        (WebCore::FetchLoader::startStreaming):
     94        (WebCore::FetchLoader::didReceiveData):
     95        (WebCore::FetchLoader::didFinishLoading): Deleted.
     96        * Modules/fetch/FetchLoader.h:
     97        * Modules/fetch/FetchLoaderClient.h:
     98        (WebCore::FetchLoaderClient::didFinishLoadingAsText): Deleted.
     99        (WebCore::FetchLoaderClient::didFinishLoadingAsArrayBuffer): Deleted.
     100        * Modules/fetch/FetchResponse.cpp:
     101        (WebCore::FetchResponse::cloneForJS):
     102        (WebCore::FetchResponse::BodyLoader::didSucceed):
     103        (WebCore::FetchResponse::BodyLoader::start):
     104        (WebCore::FetchResponse::consume): Introduced to consume data stored in body and not in ReadableStream.
     105        (WebCore::FetchResponse::startConsumingStream): Introduced to start process of consuming data stored in the ReadableStream.
     106        (WebCore::FetchResponse::consumeChunk): Reception of ReadableStream data.
     107        (WebCore::FetchResponse::finishConsumingStream): Doing the final conversion.
     108        (WebCore::FetchResponse::clone): Deleted.
     109        (WebCore::FetchResponse::BodyLoader::didFinishLoadingAsArrayBuffer): Deleted.
     110        * Modules/fetch/FetchResponse.h:
     111        * Modules/fetch/FetchResponse.idl: Inlining of FetchBody methods/attributes and adding private methods.
     112        * Modules/fetch/FetchResponse.js:
     113        (initializeFetchResponse):
     114        (clone):
     115        (arrayBuffer):
     116        (blob):
     117        (formData):
     118        (json):
     119        (text):
     120        * WebCore.xcodeproj/project.pbxproj:
     121        * bindings/js/JSDOMPromise.h:
     122        (WebCore::DeferredWrapper::resolveWithNewValue):
     123        * bindings/js/WebCoreBuiltinNames.h:
     124
    11252016-07-25  Sergio Villar Senin  <svillar@igalia.com>
    2126
  • trunk/Source/WebCore/Modules/fetch/FetchBody.cpp

    r203637 r203719  
    4040#include "JSBlob.h"
    4141#include "JSDOMFormData.h"
     42#include "JSReadableStream.h"
    4243#include "ReadableStreamSource.h"
    4344
    4445namespace WebCore {
    45 
    46 static Ref<Blob> blobFromArrayBuffer(ArrayBuffer*, const String&);
    4746
    4847FetchBody::FetchBody(Ref<Blob>&& blob)
     
    7675    if (value.isString())
    7776        return FetchBody(value.toWTFString(&state));
     77    if (value.inherits(JSReadableStream::info()))
     78        return { Type::ReadableStream };
    7879    return { };
    7980}
     
    9091{
    9192    ASSERT(m_type != Type::None);
    92     consume(owner, Consumer::Type::ArrayBuffer, WTFMove(promise));
     93    m_consumer.setType(FetchBodyConsumer::Type::ArrayBuffer);
     94    consume(owner, WTFMove(promise));
    9395}
    9496
     
    9698{
    9799    ASSERT(m_type != Type::None);
    98     consume(owner, Consumer::Type::Blob, WTFMove(promise));
     100    m_consumer.setType(FetchBodyConsumer::Type::Blob);
     101    m_consumer.setContentType(Blob::normalizedContentType(extractMIMETypeFromMediaType(m_mimeType)));
     102    consume(owner, WTFMove(promise));
    99103}
    100104
     
    107111        return;
    108112    }
    109     consume(owner, Consumer::Type::JSON, WTFMove(promise));
     113    m_consumer.setType(FetchBodyConsumer::Type::JSON);
     114    consume(owner, WTFMove(promise));
    110115}
    111116
     
    118123        return;
    119124    }
    120     consume(owner, Consumer::Type::Text, WTFMove(promise));
    121 }
    122 
    123 void FetchBody::consume(FetchBodyOwner& owner, Consumer::Type type, DeferredWrapper&& promise)
    124 {
    125     if (m_type == Type::ArrayBuffer) {
    126         consumeArrayBuffer(type, promise);
    127         return;
    128     }
    129     if (m_type == Type::Text) {
    130         consumeText(type, promise);
    131         return;
    132     }
    133     if (m_type == Type::Blob) {
    134         consumeBlob(owner, type, WTFMove(promise));
    135         return;
    136     }
    137     if (m_type == Type::Loading) {
    138         // FIXME: We should be able to change the loading type to text if consumer type is JSON or Text.
    139         m_consumer = Consumer({type, WTFMove(promise)});
    140         return;
    141     }
    142 
    143     // FIXME: Support other types.
    144     promise.reject(0);
     125    m_consumer.setType(FetchBodyConsumer::Type::Text);
     126    consume(owner, WTFMove(promise));
     127}
     128
     129void FetchBody::consume(FetchBodyOwner& owner, DeferredWrapper&& promise)
     130{
     131    // This should be handled by FetchBodyOwner
     132    ASSERT(m_type != Type::None);
     133    // This should be handled by JS built-ins
     134    ASSERT(m_type != Type::ReadableStream);
     135
     136    switch (m_type) {
     137    case Type::ArrayBuffer:
     138        consumeArrayBuffer(promise);
     139        return;
     140    case Type::Text:
     141        consumeText(promise);
     142        return;
     143    case Type::Blob:
     144        consumeBlob(owner, WTFMove(promise));
     145        return;
     146    case Type::Loading:
     147        m_consumePromise = WTFMove(promise);
     148        return;
     149    case Type::Loaded:
     150        m_consumer.resolve(promise);
     151        return;
     152    default:
     153        // FIXME: Support other types.
     154        promise.reject(0);
     155    }
    145156}
    146157
     
    148159void FetchBody::consumeAsStream(FetchBodyOwner& owner, FetchResponseSource& source)
    149160{
     161    // This should be handled by FetchResponse
    150162    ASSERT(m_type != Type::Loading);
    151 
     163    // This should be handled by JS built-ins
     164    ASSERT(m_type != Type::ReadableStream);
     165
     166    bool closeStream = false;
    152167    switch (m_type) {
    153168    case Type::ArrayBuffer:
    154169        ASSERT(m_data);
    155         if (source.enqueue(RefPtr<JSC::ArrayBuffer>(m_data)))
    156             source.close();
    157         return;
     170        closeStream = source.enqueue(RefPtr<JSC::ArrayBuffer>(m_data));
     171        break;
    158172    case Type::Text: {
    159173        Vector<uint8_t> data = extractFromText();
    160         if (source.enqueue(ArrayBuffer::tryCreate(data.data(), data.size())))
    161             source.close();
    162         return;
     174        closeStream = source.enqueue(ArrayBuffer::tryCreate(data.data(), data.size()));
     175        break;
    163176    }
    164177    case Type::Blob:
    165178        ASSERT(m_blob);
    166         owner.loadBlob(*m_blob, FetchLoader::Type::Stream);
    167         return;
     179        owner.loadBlob(*m_blob, nullptr);
     180        break;
    168181    case Type::None:
    169         source.close();
    170         return;
     182        closeStream = true;
     183        break;
     184    case Type::Loaded: {
     185        closeStream = source.enqueue(m_consumer.takeAsArrayBuffer());
     186        break;
     187    }
    171188    default:
    172189        source.error(ASCIILiteral("not implemented"));
    173190    }
     191
     192    if (closeStream)
     193        source.close();
    174194}
    175195#endif
    176196
    177 void FetchBody::consumeArrayBuffer(Consumer::Type type, DeferredWrapper& promise)
    178 {
    179     if (type == Consumer::Type::ArrayBuffer) {
    180         fulfillPromiseWithArrayBuffer(promise, m_data.get());
    181         return;
    182     }
    183     if (type == Consumer::Type::Blob) {
    184         promise.resolve(blobFromArrayBuffer(m_data.get(), Blob::normalizedContentType(extractMIMETypeFromMediaType(m_mimeType))));
    185         return;
    186     }
    187 
    188     ASSERT(type == Consumer::Type::Text || type == Consumer::Type::JSON);
    189     // FIXME: Do we need TextResourceDecoder to create a String to decode UTF-8 data.
    190     fulfillTextPromise(type, TextResourceDecoder::create(ASCIILiteral("text/plain"), "UTF-8")->decodeAndFlush(static_cast<const char*>(m_data->data()), m_data->byteLength()), promise);
    191 }
    192 
    193 void FetchBody::consumeText(Consumer::Type type, DeferredWrapper& promise)
    194 {
    195     ASSERT(type == Consumer::Type::ArrayBuffer || type == Consumer::Type::Blob);
    196 
    197     if (type == Consumer::Type::ArrayBuffer) {
    198         Vector<uint8_t> data = extractFromText();
    199         fulfillPromiseWithArrayBuffer(promise, data.data(), data.size());
    200         return;
    201     }
    202     String contentType = Blob::normalizedContentType(extractMIMETypeFromMediaType(m_mimeType));
    203     promise.resolve(Blob::create(extractFromText(), contentType));
    204 }
    205 
    206 FetchLoader::Type FetchBody::loadingType(Consumer::Type type)
    207 {
    208     switch (type) {
    209     case Consumer::Type::JSON:
    210     case Consumer::Type::Text:
    211         return FetchLoader::Type::Text;
    212     case Consumer::Type::Blob:
    213     case Consumer::Type::ArrayBuffer:
    214         return FetchLoader::Type::ArrayBuffer;
    215     default:
    216         ASSERT_NOT_REACHED();
    217         return FetchLoader::Type::ArrayBuffer;
    218     };
    219 }
    220 
    221 void FetchBody::consumeBlob(FetchBodyOwner& owner, Consumer::Type type, DeferredWrapper&& promise)
     197void FetchBody::consumeArrayBuffer(DeferredWrapper& promise)
     198{
     199    m_consumer.resolveWithData(promise, static_cast<const uint8_t*>(m_data->data()), m_data->byteLength());
     200}
     201
     202void FetchBody::consumeText(DeferredWrapper& promise)
     203{
     204    Vector<uint8_t> data = extractFromText();
     205    m_consumer.resolveWithData(promise, data.data(), data.size());
     206}
     207
     208void FetchBody::consumeBlob(FetchBodyOwner& owner, DeferredWrapper&& promise)
    222209{
    223210    ASSERT(m_blob);
    224211
    225     m_consumer = Consumer({type, WTFMove(promise)});
    226     owner.loadBlob(*m_blob, loadingType(type));
     212    m_consumePromise = WTFMove(promise);
     213    owner.loadBlob(*m_blob, &m_consumer);
    227214}
    228215
     
    237224}
    238225
    239 static inline Ref<Blob> blobFromArrayBuffer(ArrayBuffer* buffer, const String& contentType)
    240 {
    241     if (!buffer)
    242         return Blob::create(Vector<uint8_t>(), contentType);
    243 
    244     // FIXME: We should try to move buffer to Blob without doing this copy.
    245     Vector<uint8_t> value(buffer->byteLength());
    246     memcpy(value.data(), buffer->data(), buffer->byteLength());
    247     return Blob::create(WTFMove(value), contentType);
    248 }
    249 
    250 void FetchBody::fulfillTextPromise(FetchBody::Consumer::Type type, const String& text, DeferredWrapper& promise)
    251 {
    252     ASSERT(type == Consumer::Type::Text || type == Consumer::Type::JSON);
    253     if (type == FetchBody::Consumer::Type::Text)
    254         promise.resolve(text);
    255     else
    256         fulfillPromiseWithJSON(promise, text);
    257 }
    258 
    259226void FetchBody::loadingFailed()
    260227{
    261     ASSERT(m_consumer);
    262     m_consumer->promise.reject(0);
    263     m_consumer = Nullopt;
    264 }
    265 
    266 void FetchBody::loadedAsArrayBuffer(RefPtr<ArrayBuffer>&& buffer)
    267 {
    268     if (m_type == Type::Loading) {
    269         m_type = Type::ArrayBuffer;
    270         m_data = buffer;
    271         if (m_consumer) {
    272             consumeArrayBuffer(m_consumer->type, m_consumer->promise);
    273             m_consumer = Nullopt;
    274         }
    275         return;
    276     }
    277 
    278     ASSERT(m_consumer);
    279     ASSERT(m_consumer->type == Consumer::Type::Blob || m_consumer->type == Consumer::Type::ArrayBuffer);
    280     if (m_consumer->type == Consumer::Type::ArrayBuffer)
    281         fulfillPromiseWithArrayBuffer(m_consumer->promise, buffer.get());
    282     else {
    283         ASSERT(m_blob);
    284         m_consumer->promise.resolve(blobFromArrayBuffer(buffer.get(), m_blob->type()));
    285     }
    286     m_consumer = Nullopt;
    287 }
    288 
    289 void FetchBody::loadedAsText(String&& text)
    290 {
    291     ASSERT(m_consumer);
    292     ASSERT(m_consumer->type == Consumer::Type::Text || m_consumer->type == Consumer::Type::JSON);
    293 
    294     fulfillTextPromise(m_consumer->type, text, m_consumer->promise);
    295     m_consumer = Nullopt;
     228    if (m_consumePromise) {
     229        m_consumePromise->reject(0);
     230        m_consumePromise = Nullopt;
     231    }
     232}
     233
     234void FetchBody::loadingSucceeded()
     235{
     236    m_type = m_consumer.hasData() ? Type::Loaded : Type::None;
     237    if (m_consumePromise) {
     238        m_consumer.resolve(*m_consumePromise);
     239        m_consumePromise = Nullopt;
     240    }
    296241}
    297242
  • trunk/Source/WebCore/Modules/fetch/FetchBody.h

    r201013 r203719  
    3434#include "Blob.h"
    3535#include "DOMFormData.h"
     36#include "FetchBodyConsumer.h"
    3637#include "FetchLoader.h"
    3738#include "JSDOMPromise.h"
     
    7172
    7273    void loadingFailed();
    73     void loadedAsArrayBuffer(RefPtr<ArrayBuffer>&&);
    74     void loadedAsText(String&&);
     74    void loadingSucceeded();
    7575
    7676    RefPtr<FormData> bodyForInternalRequest() const;
    7777
    78     enum class Type { None, ArrayBuffer, Loading, Text, Blob, FormData };
     78    enum class Type { None, ArrayBuffer, Blob, FormData, Text, Loading, Loaded, ReadableStream };
    7979    Type type() const { return m_type; }
     80
     81    FetchBodyConsumer& consumer() { return m_consumer; }
    8082
    8183private:
     
    8587    FetchBody(Type type) : m_type(type) { }
    8688
    87     struct Consumer {
    88         enum class Type { Text, Blob, JSON, ArrayBuffer };
    89 
    90         Type type;
    91         DeferredWrapper promise;
    92     };
    93     void consume(FetchBodyOwner&, Consumer::Type, DeferredWrapper&&);
     89    void consume(FetchBodyOwner&, DeferredWrapper&&);
    9490
    9591    Vector<uint8_t> extractFromText() const;
    96     void consumeArrayBuffer(Consumer::Type, DeferredWrapper&);
    97     void consumeText(Consumer::Type, DeferredWrapper&);
    98     void consumeBlob(FetchBodyOwner&, Consumer::Type, DeferredWrapper&&);
    99     static FetchLoader::Type loadingType(Consumer::Type);
    100     static void fulfillTextPromise(FetchBody::Consumer::Type, const String&, DeferredWrapper&);
    101     static void fulfillArrayBufferPromise(FetchBody::Consumer::Type, const String&, DeferredWrapper&);
     92    void consumeArrayBuffer(DeferredWrapper&);
     93    void consumeText(DeferredWrapper&);
     94    void consumeBlob(FetchBodyOwner&, DeferredWrapper&&);
    10295
    10396    Type m_type { Type::None };
     
    110103    String m_text;
    111104
    112     Optional<Consumer> m_consumer;
     105    FetchBodyConsumer m_consumer { FetchBodyConsumer::Type::None };
     106    Optional<DeferredWrapper> m_consumePromise;
    113107};
    114108
  • trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.h

    r203718 r203719  
    11/*
    2  * Copyright (C) 2016 Canon Inc.
     2 * Copyright (C) 2016 Apple Inc.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    1111 *     notice, this list of conditions and the following disclaimer in the
    1212 *     documentation and/or other materials provided with the distribution.
    13  * 3.  Neither the name of Canon Inc. nor the names of
     13 * 3.  Neither the name of Apple Inc. nor the names of
    1414 *     its contributors may be used to endorse or promote products derived
    1515 *     from this software without specific prior written permission.
    1616 *
    17  * THIS SOFTWARE IS PROVIDED BY CANON INC. AND ITS CONTRIBUTORS "AS IS" AND ANY
     17 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS "AS IS" AND ANY
    1818 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    1919 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    20  * DISCLAIMED. IN NO EVENT SHALL CANON INC. AND ITS CONTRIBUTORS BE LIABLE FOR
     20 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. AND ITS CONTRIBUTORS BE LIABLE FOR
    2121 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    2222 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     
    2727 */
    2828
    29 #ifndef FetchLoaderClient_h
    30 #define FetchLoaderClient_h
     29#pragma once
    3130
    3231#if ENABLE(FETCH_API)
    3332
    34 #include <wtf/Forward.h>
    35 
    36 namespace JSC {
    37 class ArrayBuffer;
    38 }
     33#include "SharedBuffer.h"
    3934
    4035namespace WebCore {
    4136
    42 class ResourceResponse;
     37class Blob;
     38class DeferredWrapper;
    4339
    44 class FetchLoaderClient {
     40class FetchBodyConsumer {
    4541public:
    46     virtual ~FetchLoaderClient() { }
     42    // Type is used in FetchResponse.js and should be kept synchronized with it.
     43    enum class Type { None, ArrayBuffer, Blob, JSON, Text };
    4744
    48     virtual void didReceiveResponse(const ResourceResponse&) { }
     45    FetchBodyConsumer(Type type) : m_type(type) { }
    4946
    50     virtual void didFinishLoadingAsText(String&&) { }
    51     virtual void didFinishLoadingAsArrayBuffer(RefPtr<JSC::ArrayBuffer>&&) { }
    52     virtual void didReceiveData(const char*, size_t) { }
     47    void append(const char* data, unsigned);
     48    void append(const unsigned char* data, unsigned);
    5349
    54     virtual void didSucceed() = 0;
    55     virtual void didFail() = 0;
     50    RefPtr<SharedBuffer> takeData();
     51    RefPtr<JSC::ArrayBuffer> takeAsArrayBuffer();
     52    Ref<Blob> takeAsBlob();
     53    String takeAsText();
     54
     55    void setContentType(const String& contentType) { m_contentType = contentType; }
     56    void setType(Type type) { m_type = type; }
     57
     58    void clean() { m_buffer = nullptr; }
     59
     60    void resolve(DeferredWrapper&);
     61    void resolveWithData(DeferredWrapper&, const unsigned char*, unsigned);
     62
     63    bool hasData() const { return !!m_buffer; }
     64
     65private:
     66    Type m_type;
     67    String m_contentType;
     68    RefPtr<SharedBuffer> m_buffer;
    5669};
    5770
     
    5972
    6073#endif // ENABLE(FETCH_API)
    61 
    62 #endif // FetchLoaderClient_h
  • trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.cpp

    r203637 r203719  
    139139}
    140140
    141 void FetchBodyOwner::loadBlob(Blob& blob, FetchLoader::Type type)
     141void FetchBodyOwner::loadBlob(Blob& blob, FetchBodyConsumer* consumer)
    142142{
    143143    // Can only be called once for a body instance.
     
    151151
    152152    m_blobLoader = { *this };
    153     m_blobLoader->loader = std::make_unique<FetchLoader>(type, *m_blobLoader);
     153    m_blobLoader->loader = std::make_unique<FetchLoader>(*m_blobLoader, consumer);
    154154
    155155    m_blobLoader->loader->start(*scriptExecutionContext(), blob);
     
    170170}
    171171
    172 void FetchBodyOwner::loadedBlobAsText(String&& text)
    173 {
    174     m_body.loadedAsText(WTFMove(text));
    175 }
    176 
    177172void FetchBodyOwner::blobLoadingSucceeded()
    178173{
     
    185180    }
    186181#endif
    187 
     182    m_body.loadingSucceeded();
    188183    finishBlobLoading();
    189184}
  • trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.h

    r199641 r203719  
    5353    void text(DeferredWrapper&&);
    5454
    55     void loadBlob(Blob&, FetchLoader::Type);
     55    void loadBlob(Blob&, FetchBodyConsumer*);
    5656
    5757    bool isActive() const { return !!m_blobLoader; }
     
    6868private:
    6969    // Blob loading routines
    70     void loadedBlobAsText(String&&);
    71     void loadedBlobAsArrayBuffer(RefPtr<ArrayBuffer>&& buffer) { m_body.loadedAsArrayBuffer(WTFMove(buffer)); }
    7270    void blobChunk(const char*, size_t);
    7371    void blobLoadingSucceeded();
     
    7977
    8078        // FetchLoaderClient API
    81         void didFinishLoadingAsText(String&& text) final { owner.loadedBlobAsText(WTFMove(text)); }
    82         void didFinishLoadingAsArrayBuffer(RefPtr<ArrayBuffer>&& buffer) final { owner.loadedBlobAsArrayBuffer(WTFMove(buffer)); }
    8379        void didReceiveResponse(const ResourceResponse&) final;
    8480        void didReceiveData(const char* data, size_t size) final { owner.blobChunk(data, size); }
  • trunk/Source/WebCore/Modules/fetch/FetchInternals.js

    r203445 r203719  
    5252    }
    5353}
     54
     55function consumeStream(response, type)
     56{
     57    @assert(response instanceof @Response);
     58    @assert(response.@body instanceof @ReadableStream);
     59
     60    if (@isReadableStreamDisturbed(response.@body))
     61        return @Promise.@reject(new @TypeError("Cannot consume a disturbed Response body ReadableStream"));
     62
     63    try {
     64        let reader = new @ReadableStreamReader(response.@body);
     65
     66        @Response.prototype.@startConsumingStream.@call(response, type);
     67        let pull = (result) => {
     68            if (result.done)
     69                return @Response.prototype.@finishConsumingStream.@call(response);
     70            @Response.prototype.@consumeChunk.@call(response, result.value);
     71            return @Promise.prototype.@then.@call(@readFromReadableStreamReader(reader), pull);
     72        }
     73        return @Promise.prototype.@then.@call(@readFromReadableStreamReader(reader), pull);
     74    } catch(e) {
     75        return @Promise.@reject(e);
     76    }
     77}
  • trunk/Source/WebCore/Modules/fetch/FetchLoader.cpp

    r203490 r203719  
    9090}
    9191
    92 FetchLoader::FetchLoader(Type type, FetchLoaderClient& client)
    93     : m_type(type)
    94     , m_client(client)
     92FetchLoader::FetchLoader(FetchLoaderClient& client, FetchBodyConsumer* consumer)
     93    : m_client(client)
     94    , m_consumer(consumer)
    9595{
    9696}
     
    9898void FetchLoader::stop()
    9999{
    100     m_data = nullptr;
     100    if (m_consumer)
     101        m_consumer->clean();
    101102    if (m_loader)
    102103        m_loader->cancel();
     
    105106RefPtr<SharedBuffer> FetchLoader::startStreaming()
    106107{
    107     ASSERT(m_type == Type::ArrayBuffer);
    108     m_type = Type::Stream;
    109     return WTFMove(m_data);
     108    ASSERT(m_consumer);
     109    auto firstChunk = m_consumer->takeData();
     110    m_consumer = nullptr;
     111    return firstChunk;
    110112}
    111113
     
    115117}
    116118
    117 // FIXME: We should make text and blob creation more efficient.
    118 // We might also want to merge this class with FileReaderLoader.
    119119void FetchLoader::didReceiveData(const char* value, int size)
    120120{
    121     if (m_type == Type::Stream) {
     121    if (!m_consumer) {
    122122        m_client.didReceiveData(value, size);
    123123        return;
    124124    }
    125     if (!m_data) {
    126         m_data = SharedBuffer::create(value, size);
    127         return;
    128     }
    129     m_data->append(value, size);
     125    m_consumer->append(value, size);
    130126}
    131127
    132128void FetchLoader::didFinishLoading(unsigned long, double)
    133129{
    134     if (m_type == Type::ArrayBuffer)
    135         m_client.didFinishLoadingAsArrayBuffer(m_data ? m_data->createArrayBuffer() : ArrayBuffer::tryCreate(nullptr, 0));
    136     else if (m_type == Type::Text)
    137         m_client.didFinishLoadingAsText(m_data ? TextResourceDecoder::create(ASCIILiteral("text/plain"), "UTF-8")->decodeAndFlush(m_data->data(), m_data->size()): String());
    138     m_data = nullptr;
    139 
    140130    m_client.didSucceed();
    141131}
  • trunk/Source/WebCore/Modules/fetch/FetchLoader.h

    r202480 r203719  
    2727 */
    2828
    29 #ifndef FetchLoader_h
    30 #define FetchLoader_h
     29#pragma once
    3130
    3231#if ENABLE(FETCH_API)
    3332
    34 #include "SharedBuffer.h"
     33#include "FetchBodyConsumer.h"
    3534#include "ThreadableLoader.h"
    3635#include "ThreadableLoaderClient.h"
     
    4544class FetchLoader final : public ThreadableLoaderClient {
    4645public:
    47     enum class Type { ArrayBuffer, Stream, Text };
    48 
    49     FetchLoader(Type, FetchLoaderClient&);
     46    FetchLoader(FetchLoaderClient&, FetchBodyConsumer*);
    5047
    5148    RefPtr<SharedBuffer> startStreaming();
     
    6461    void didFail(const ResourceError&) final;
    6562
    66     Type type() const { return m_type; }
    67 
    6863private:
    69     Type m_type { Type::ArrayBuffer };
    7064    FetchLoaderClient& m_client;
    7165    RefPtr<ThreadableLoader> m_loader;
    72     RefPtr<SharedBuffer> m_data;
     66    FetchBodyConsumer* m_consumer;
    7367    bool m_isStarted { false };
    7468};
     
    7771
    7872#endif // ENABLE(FETCH_API)
    79 
    80 #endif // FetchLoader_h
  • trunk/Source/WebCore/Modules/fetch/FetchLoaderClient.h

    r199641 r203719  
    4848    virtual void didReceiveResponse(const ResourceResponse&) { }
    4949
    50     virtual void didFinishLoadingAsText(String&&) { }
    51     virtual void didFinishLoadingAsArrayBuffer(RefPtr<JSC::ArrayBuffer>&&) { }
    5250    virtual void didReceiveData(const char*, size_t) { }
    5351
  • trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp

    r203675 r203719  
    3535#include "FetchRequest.h"
    3636#include "HTTPParsers.h"
     37#include "JSBlob.h"
    3738#include "JSFetchResponse.h"
    3839#include "ScriptExecutionContext.h"
     
    9495}
    9596
    96 RefPtr<FetchResponse> FetchResponse::clone(ScriptExecutionContext& context, ExceptionCode& ec)
    97 {
    98     if (isDisturbed()) {
    99         ec = TypeError;
    100         return nullptr;
    101     }
    102     return adoptRef(*new FetchResponse(context, FetchBody(m_body), FetchHeaders::create(headers()), ResourceResponse(m_response)));
     97Ref<FetchResponse> FetchResponse::cloneForJS()
     98{
     99    ASSERT(scriptExecutionContext());
     100    ASSERT(!isDisturbed());
     101    return adoptRef(*new FetchResponse(*scriptExecutionContext(), FetchBody(m_body), FetchHeaders::create(headers()), ResourceResponse(m_response)));
    103102}
    104103
     
    131130    }
    132131#endif
     132    m_response.m_body.loadingSucceeded();
     133
    133134    if (m_loader->isStarted())
    134135        m_response.m_bodyLoader = Nullopt;
     
    188189}
    189190
    190 void FetchResponse::BodyLoader::didFinishLoadingAsArrayBuffer(RefPtr<ArrayBuffer>&& buffer)
    191 {
    192     m_response.body().loadedAsArrayBuffer(WTFMove(buffer));
    193 }
    194 
    195191bool FetchResponse::BodyLoader::start(ScriptExecutionContext& context, const FetchRequest& request)
    196192{
    197     m_loader = std::make_unique<FetchLoader>(FetchLoader::Type::ArrayBuffer, *this);
     193    m_loader = std::make_unique<FetchLoader>(*this, &m_response.m_body.consumer());
    198194    m_loader->start(context, request);
    199195    return m_loader->isStarted();
     
    206202}
    207203
     204void FetchResponse::consume(unsigned type, DeferredWrapper&& wrapper)
     205{
     206    ASSERT(type <= static_cast<unsigned>(FetchBodyConsumer::Type::Text));
     207
     208    switch (static_cast<FetchBodyConsumer::Type>(type)) {
     209    case FetchBodyConsumer::Type::ArrayBuffer:
     210        arrayBuffer(WTFMove(wrapper));
     211        return;
     212    case FetchBodyConsumer::Type::Blob:
     213        blob(WTFMove(wrapper));
     214        return;
     215    case FetchBodyConsumer::Type::JSON:
     216        json(WTFMove(wrapper));
     217        return;
     218    case FetchBodyConsumer::Type::Text:
     219        text(WTFMove(wrapper));
     220        return;
     221    case FetchBodyConsumer::Type::None:
     222        ASSERT_NOT_REACHED();
     223        return;
     224    }
     225}
     226
    208227#if ENABLE(STREAMS_API)
     228void FetchResponse::startConsumingStream(unsigned type)
     229{
     230    m_isDisturbed = true;
     231    m_consumer.setType(static_cast<FetchBodyConsumer::Type>(type));
     232}
     233
     234void FetchResponse::consumeChunk(Ref<JSC::Uint8Array>&& chunk)
     235{
     236    m_consumer.append(chunk->data(), chunk->byteLength());
     237}
     238
     239void FetchResponse::finishConsumingStream(DeferredWrapper&& promise)
     240{
     241    m_consumer.resolve(promise);
     242}
     243
    209244void FetchResponse::consumeBodyAsStream()
    210245{
  • trunk/Source/WebCore/Modules/fetch/FetchResponse.h

    r203675 r203719  
    3434#include "FetchHeaders.h"
    3535#include "ResourceResponse.h"
     36#include <runtime/TypedArrays.h>
    3637
    3738namespace JSC {
     
    6061    static void fetch(ScriptExecutionContext&, FetchRequest&, FetchPromise&&);
    6162
     63    void consume(unsigned, DeferredWrapper&&);
     64#if ENABLE(STREAMS_API)
     65    void startConsumingStream(unsigned);
     66    void consumeChunk(Ref<JSC::Uint8Array>&&);
     67    void finishConsumingStream(DeferredWrapper&&);
     68#endif
     69
    6270    void setStatus(int, const String&, ExceptionCode&);
    6371    void initializeWith(JSC::ExecState&, JSC::JSValue);
     
    7179
    7280    FetchHeaders& headers() { return m_headers; }
    73     RefPtr<FetchResponse> clone(ScriptExecutionContext&, ExceptionCode&);
     81    Ref<FetchResponse> cloneForJS();
    7482
    7583#if ENABLE(STREAMS_API)
     
    106114        void didReceiveResponse(const ResourceResponse&) final;
    107115        void didReceiveData(const char*, size_t) final;
    108         void didFinishLoadingAsArrayBuffer(RefPtr<ArrayBuffer>&&) final;
    109116
    110117        FetchResponse& m_response;
     
    117124    Optional<BodyLoader> m_bodyLoader;
    118125    mutable String m_responseURL;
     126
     127    FetchBodyConsumer m_consumer { FetchBodyConsumer::Type::ArrayBuffer  };
    119128};
    120129
  • trunk/Source/WebCore/Modules/fetch/FetchResponse.idl

    r203632 r203719  
    5454    [JSBuiltin] readonly attribute ReadableStream? body;
    5555
    56     [NewObject, CallWith=ScriptExecutionContext, RaisesException] FetchResponse clone();
     56    // Copy of FetchBody IDL as we want to implement some of these as built-ins.
     57    [ImplementedAs=isDisturbed] readonly attribute boolean bodyUsed;
     58    [JSBuiltin] Promise arrayBuffer();
     59    [JSBuiltin] Promise blob();
     60    [JSBuiltin] Promise formData();
     61    [JSBuiltin] Promise json();
     62    [JSBuiltin] Promise text();
    5763
     64    [JSBuiltin] FetchResponse clone();
     65
     66    [PrivateIdentifier, NewObject] FetchResponse cloneForJS();
     67
     68    [Conditional=STREAMS_API, PrivateIdentifier] void startConsumingStream(unsigned short type);
     69    [Conditional=STREAMS_API, PrivateIdentifier] void consumeChunk(Uint8Array chunk);
     70    [Conditional=STREAMS_API, PrivateIdentifier] Promise finishConsumingStream();
     71
     72    [PrivateIdentifier] Promise consume(unsigned short type);
    5873    [PrivateIdentifier, RaisesException] void setStatus(unsigned short status, DOMString statusText);
    5974    [CallWith=ScriptState, PrivateIdentifier] void initializeWith(any body);
     
    6176    [PrivateIdentifier] boolean isDisturbed();
    6277};
    63 FetchResponse implements FetchBody;
  • trunk/Source/WebCore/Modules/fetch/FetchResponse.js

    r203632 r203719  
    4949        if (status == 101 || status == 204 || status == 205 || status == 304)
    5050            throw new @TypeError("Response cannot have a body with the given status");
     51
     52        // FIXME: Use @isReadableStream once it is no longer guarded by STREAMS_API guard.
     53        let isBodyReadableStream = (@isObject(body) && !!body.@underlyingSource);
     54        if (isBodyReadableStream)
     55          this.@body = body;
     56
    5157        this.@initializeWith(body);
    5258    }
     
    6975    return this.@body;
    7076}
     77
     78function clone()
     79{
     80    if (!this instanceof @Response)
     81        throw new @TypeError("Function should be called on a Response");
     82
     83    if (@Response.prototype.@isDisturbed.@call(this))
     84        throw new @TypeError("Cannot clone a disturbed Response");
     85
     86    var cloned = @Response.prototype.@cloneForJS.@call(this);
     87    if (this.@body) {
     88        var teedReadableStreams = @teeReadableStream(this.@body, false);
     89        this.@body = teedReadableStreams[0];
     90        cloned.@body = teedReadableStreams[1];
     91    }
     92    return cloned;
     93}
     94
     95// consume and consumeStream single parameter should be kept in sync with FetchBodyConsumer::Type.
     96function arrayBuffer()
     97{
     98    if (!this instanceof @Response)
     99        throw new @TypeError("Function should be called on a Response");
     100
     101    const arrayBufferConsumerType = 1;
     102    if (!this.@body)
     103        return @Response.prototype.@consume.@call(this, arrayBufferConsumerType);
     104
     105    return @consumeStream(this, arrayBufferConsumerType);
     106}
     107
     108function blob()
     109{
     110    if (!this instanceof @Response)
     111        throw new @TypeError("Function should be called on a Response");
     112
     113    const blobConsumerType = 2;
     114    if (!this.@body)
     115        return @Response.prototype.@consume.@call(this, blobConsumerType);
     116
     117    return @consumeStream(this, blobConsumerType);
     118}
     119
     120function formData()
     121{
     122    if (!this instanceof @Response)
     123        throw new @TypeError("Function should be called on a Response");
     124
     125    return @Promise.@reject("Not implemented");
     126}
     127
     128function json()
     129{
     130    if (!this instanceof @Response)
     131        throw new @TypeError("Function should be called on a Response");
     132
     133    const jsonConsumerType = 3;
     134    if (!this.@body)
     135        return @Response.prototype.@consume.@call(this, jsonConsumerType);
     136
     137    return @consumeStream(this, jsonConsumerType);
     138}
     139
     140function text()
     141{
     142    if (!this instanceof @Response)
     143        throw new @TypeError("Function should be called on a Response");
     144
     145    const textConsumerType = 4;
     146    if (!this.@body)
     147        return @Response.prototype.@consume.@call(this, textConsumerType);
     148
     149    return @consumeStream(this, textConsumerType);
     150}
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r203702 r203719  
    16321632                41BF70100FE86F61005E8DEC /* PlatformMessagePortChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = 41BF700E0FE86F61005E8DEC /* PlatformMessagePortChannel.h */; };
    16331633                41C760B10EDE03D300C1655F /* ScriptState.h in Headers */ = {isa = PBXBuildFile; fileRef = 41C760B00EDE03D300C1655F /* ScriptState.h */; settings = {ATTRIBUTES = (Private, ); }; };
     1634                41CF8BE71D46226700707DC9 /* FetchBodyConsumer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41CF8BE41D46222000707DC9 /* FetchBodyConsumer.cpp */; };
    16341635                41D015CA0F4B5C71004A662F /* ContentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 41D015C80F4B5C71004A662F /* ContentType.h */; };
    16351636                41D015CB0F4B5C71004A662F /* ContentType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41D015C90F4B5C71004A662F /* ContentType.cpp */; };
     
    92199220                41BF700E0FE86F61005E8DEC /* PlatformMessagePortChannel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PlatformMessagePortChannel.h; path = default/PlatformMessagePortChannel.h; sourceTree = "<group>"; };
    92209221                41C760B00EDE03D300C1655F /* ScriptState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptState.h; sourceTree = "<group>"; };
     9222                41CF8BE41D46222000707DC9 /* FetchBodyConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FetchBodyConsumer.cpp; sourceTree = "<group>"; };
     9223                41CF8BE51D46222000707DC9 /* FetchBodyConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FetchBodyConsumer.h; sourceTree = "<group>"; };
     9224                41CF8BE61D46222C00707DC9 /* FetchInternals.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = FetchInternals.js; sourceTree = "<group>"; };
    92219225                41D015C80F4B5C71004A662F /* ContentType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContentType.h; sourceTree = "<group>"; };
    92229226                41D015C90F4B5C71004A662F /* ContentType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ContentType.cpp; sourceTree = "<group>"; };
     
    1709917103                                41F54F7E1C50C4F600338488 /* FetchBody.h */,
    1710017104                                41F54F7F1C50C4F600338488 /* FetchBody.idl */,
     17105                                41CF8BE41D46222000707DC9 /* FetchBodyConsumer.cpp */,
     17106                                41CF8BE51D46222000707DC9 /* FetchBodyConsumer.h */,
    1710117107                                4147E2B31C89912600A7E715 /* FetchBodyOwner.cpp */,
    1710217108                                4147E2B21C88337F00A7E715 /* FetchBodyOwner.h */,
     
    1710517111                                41F54F841C50C4F600338488 /* FetchHeaders.idl */,
    1710617112                                41F54F851C50C4F600338488 /* FetchHeaders.js */,
     17113                                41CF8BE61D46222C00707DC9 /* FetchInternals.js */,
    1710717114                                4147E2B41C89912600A7E715 /* FetchLoader.cpp */,
    1710817115                                4147E2B51C89912600A7E715 /* FetchLoader.h */,
     
    3077330780                                BC06ED9D0BFD660600856E9D /* JSHTMLTableColElement.cpp in Sources */,
    3077430781                                BC06EE040BFD71AA00856E9D /* JSHTMLTableElement.cpp in Sources */,
     30782                                41CF8BE71D46226700707DC9 /* FetchBodyConsumer.cpp in Sources */,
    3077530783                                BC06ED9F0BFD660600856E9D /* JSHTMLTableRowElement.cpp in Sources */,
    3077630784                                BC06ED060BFD5BAE00856E9D /* JSHTMLTableSectionElement.cpp in Sources */,
  • trunk/Source/WebCore/bindings/js/JSDOMPromise.h

    r201394 r203719  
    119119    reject(const RejectResultType& result) { rejectWithValue(result); }
    120120
     121    template<class ResolveResultType> void resolveWithNewlyCreated(Ref<ResolveResultType>&&);
     122
    121123    void reject(ExceptionCode, const String& = { });
    122124
     
    182184}
    183185
     186template<class ResolveResultType>
     187inline void DeferredWrapper::resolveWithNewlyCreated(Ref<ResolveResultType>&& result)
     188{
     189    ASSERT(m_deferred);
     190    ASSERT(m_globalObject);
     191    JSC::ExecState* exec = m_globalObject->globalExec();
     192    JSC::JSLockHolder locker(exec);
     193    resolve(*exec, toJSNewlyCreated(exec, m_globalObject.get(), WTFMove(result)));
     194}
     195
    184196template<class RejectResultType>
    185197inline void DeferredWrapper::rejectWithValue(RejectResultType&& result)
  • trunk/Source/WebCore/bindings/js/WebCoreBuiltinNames.h

    r203675 r203719  
    3636    macro(appendFromJS) \
    3737    macro(body) \
     38    macro(cloneForJS) \
    3839    macro(closeRequested) \
    3940    macro(closedPromiseCapability) \
     41    macro(consume) \
     42    macro(consumeChunk) \
    4043    macro(controlledReadableStream) \
    4144    macro(controller) \
     
    4447    macro(fetchRequest) \
    4548    macro(fillFromJS) \
     49    macro(finishConsumingStream) \
    4650    macro(firstReadCallback) \
    4751    macro(getUserMediaFromJS) \
     
    7377    macro(setStatus) \
    7478    macro(state) \
     79    macro(startConsumingStream) \
    7580    macro(started) \
    7681    macro(startedPromise) \
Note: See TracChangeset for help on using the changeset viewer.