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