WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
Removing WebCoreJSBuiltins.cpp from CMake WebCore_DERIVED_SOURCES
bug-159804-20160726193758.patch (text/plain), 59.29 KB, created by
youenn fablet
on 2016-07-26 10:39:09 PDT
(
hide
)
Description:
Removing WebCoreJSBuiltins.cpp from CMake WebCore_DERIVED_SOURCES
Filename:
MIME Type:
Creator:
youenn fablet
Created:
2016-07-26 10:39:09 PDT
Size:
59.29 KB
patch
obsolete
>Subversion Revision: 203727 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index f04125af899accea3ce23d7feb90951b5ff1fa8c..72f3606537cdea51f5dc0c40e498a3520f3ff1b7 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,127 @@ >+2016-07-26 Youenn Fablet <youenn@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.cpp. Removing WebCoreJSBuiltins.cpp from CMake list as it is not needed. >+ * 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-26 Commit Queue <commit-queue@webkit.org> > > Unreviewed, rolling out r203719. >diff --git a/Source/WebCore/CMakeLists.txt b/Source/WebCore/CMakeLists.txt >index 6dc113f8a2c602e3f5013313736ecaa366be57fd..62a7232cd8b3df5b748fa7d7481f46a308510258 100644 >--- a/Source/WebCore/CMakeLists.txt >+++ b/Source/WebCore/CMakeLists.txt >@@ -818,6 +818,7 @@ set(WebCore_SOURCES > > Modules/fetch/DOMWindowFetch.cpp > Modules/fetch/FetchBody.cpp >+ Modules/fetch/FetchBodyConsumer.cpp > Modules/fetch/FetchBodyOwner.cpp > Modules/fetch/FetchHeaders.cpp > Modules/fetch/FetchLoader.cpp >@@ -3773,7 +3774,6 @@ add_custom_command( > DEPENDS ${BUILTINS_GENERATOR_SCRIPTS} > COMMAND ${PYTHON_EXECUTABLE} ${JavaScriptCore_SCRIPTS_DIR}/generate-js-builtins.py --wrappers-only --framework WebCore --output-directory ${DERIVED_SOURCES_WEBCORE_DIR} ${WebCore_BUILTINS_SOURCES} > VERBATIM) >-list(APPEND WebCore_DERIVED_SOURCES ${DERIVED_SOURCES_WEBCORE_DIR}/WebCoreJSBuiltins.cpp) > list(APPEND WebCore_DERIVED_SOURCES ${DERIVED_SOURCES_WEBCORE_DIR}/WebCoreJSBuiltinInternals.cpp) > list(APPEND WebCore_DERIVED_SOURCES ${DERIVED_SOURCES_WEBCORE_DIR}/WebCoreJSBuiltins.h) > list(APPEND WebCore_DERIVED_SOURCES ${DERIVED_SOURCES_WEBCORE_DIR}/WebCoreJSBuiltinInternals.h) >diff --git a/Source/WebCore/Modules/fetch/FetchBody.cpp b/Source/WebCore/Modules/fetch/FetchBody.cpp >index 8c479d5f8e062502d9570c8b9b585bcf0db44d3f..e0f5ae18035aaafc794b77b0dd7d6a2160550fd9 100644 >--- a/Source/WebCore/Modules/fetch/FetchBody.cpp >+++ b/Source/WebCore/Modules/fetch/FetchBody.cpp >@@ -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 @@ FetchBody FetchBody::extract(JSC::ExecState& state, JSC::JSValue value) > 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 @@ FetchBody FetchBody::extractFromBody(FetchBody* body) > 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 @@ void FetchBody::json(FetchBodyOwner& owner, DeferredWrapper&& promise) > 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 @@ void FetchBody::text(FetchBodyOwner& owner, DeferredWrapper&& promise) > 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 = extractFromText(); >- 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")); > } >-} >-#endif > >-void FetchBody::consumeArrayBuffer(Consumer::Type type, 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); >+ if (closeStream) >+ source.close(); > } >+#endif > >-void FetchBody::consumeText(Consumer::Type type, DeferredWrapper& promise) >+void FetchBody::consumeArrayBuffer(DeferredWrapper& promise) > { >- ASSERT(type == Consumer::Type::ArrayBuffer || type == Consumer::Type::Blob); >- >- if (type == Consumer::Type::ArrayBuffer) { >- Vector<uint8_t> data = extractFromText(); >- fulfillPromiseWithArrayBuffer(promise, data.data(), data.size()); >- return; >- } >- String contentType = Blob::normalizedContentType(extractMIMETypeFromMediaType(m_mimeType)); >- promise.resolve(Blob::create(extractFromText(), contentType)); >+ m_consumer.resolveWithData(promise, static_cast<const uint8_t*>(m_data->data()), m_data->byteLength()); > } > >-FetchLoader::Type FetchBody::loadingType(Consumer::Type type) >+void FetchBody::consumeText(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; >- }; >+ Vector<uint8_t> data = extractFromText(); >+ m_consumer.resolveWithData(promise, data.data(), data.size()); > } > >-void FetchBody::consumeBlob(FetchBodyOwner& owner, Consumer::Type type, DeferredWrapper&& promise) >+void FetchBody::consumeBlob(FetchBodyOwner& owner, 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,63 +223,21 @@ Vector<uint8_t> FetchBody::extractFromText() const > 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; >-} >- >-void FetchBody::loadedAsArrayBuffer(RefPtr<ArrayBuffer>&& buffer) >-{ >- 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; >- } >- >- 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())); >+ if (m_consumePromise) { >+ m_consumePromise->reject(0); >+ m_consumePromise = Nullopt; > } >- m_consumer = Nullopt; > } > >-void FetchBody::loadedAsText(String&& text) >+void FetchBody::loadingSucceeded() > { >- 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; >+ m_type = m_consumer.hasData() ? Type::Loaded : Type::None; >+ if (m_consumePromise) { >+ m_consumer.resolve(*m_consumePromise); >+ m_consumePromise = Nullopt; >+ } > } > > RefPtr<FormData> FetchBody::bodyForInternalRequest() const >diff --git a/Source/WebCore/Modules/fetch/FetchBody.h b/Source/WebCore/Modules/fetch/FetchBody.h >index 56f3dfdc8571c315112f2665c6ffda975a9df392..62d9e5a787d58330b664f8ac56ef24532cef6dc5 100644 >--- a/Source/WebCore/Modules/fetch/FetchBody.h >+++ b/Source/WebCore/Modules/fetch/FetchBody.h >@@ -33,6 +33,7 @@ > > #include "Blob.h" > #include "DOMFormData.h" >+#include "FetchBodyConsumer.h" > #include "FetchLoader.h" > #include "JSDOMPromise.h" > >@@ -70,35 +71,27 @@ public: > 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>&&); > FetchBody(String&&); > FetchBody(Type type) : m_type(type) { } > >- struct Consumer { >- enum class Type { Text, Blob, JSON, ArrayBuffer }; >- >- Type type; >- DeferredWrapper promise; >- }; >- void consume(FetchBodyOwner&, Consumer::Type, DeferredWrapper&&); >+ void consume(FetchBodyOwner&, 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 @@ private: > RefPtr<ArrayBuffer> m_data; > String m_text; > >- Optional<Consumer> m_consumer; >+ FetchBodyConsumer m_consumer { FetchBodyConsumer::Type::None }; >+ Optional<DeferredWrapper> m_consumePromise; > }; > > } // namespace WebCore >diff --git a/Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp b/Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..d93251bf94cd3427f679fd62eade4e8ba0023467 >--- /dev/null >+++ b/Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp >@@ -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) >diff --git a/Source/WebCore/Modules/fetch/FetchBodyConsumer.h b/Source/WebCore/Modules/fetch/FetchBodyConsumer.h >new file mode 100644 >index 0000000000000000000000000000000000000000..faa1fe7d28ac7a6cae32aec74445d98081344b3b >--- /dev/null >+++ b/Source/WebCore/Modules/fetch/FetchBodyConsumer.h >@@ -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) >diff --git a/Source/WebCore/Modules/fetch/FetchBodyOwner.cpp b/Source/WebCore/Modules/fetch/FetchBodyOwner.cpp >index 0f45794a069e2ee608b18378e3df1f4bce7353a5..964be771104da67197d3d504c69881418cc85689 100644 >--- a/Source/WebCore/Modules/fetch/FetchBodyOwner.cpp >+++ b/Source/WebCore/Modules/fetch/FetchBodyOwner.cpp >@@ -138,7 +138,7 @@ void FetchBodyOwner::text(DeferredWrapper&& promise) > 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 @@ void FetchBodyOwner::loadBlob(Blob& blob, FetchLoader::Type type) > } > > 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 @@ void FetchBodyOwner::finishBlobLoading() > 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 @@ void FetchBodyOwner::blobLoadingSucceeded() > m_readableStreamSource = nullptr; > } > #endif >- >+ m_body.loadingSucceeded(); > finishBlobLoading(); > } > >diff --git a/Source/WebCore/Modules/fetch/FetchBodyOwner.h b/Source/WebCore/Modules/fetch/FetchBodyOwner.h >index 06a212665c39fc3907d38e13f4cc133cc872c7b4..87b72f0a499f9336a40fa48633a18909223b1d96 100644 >--- a/Source/WebCore/Modules/fetch/FetchBodyOwner.h >+++ b/Source/WebCore/Modules/fetch/FetchBodyOwner.h >@@ -52,7 +52,7 @@ public: > 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 @@ protected: > > 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 @@ private: > 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; >diff --git a/Source/WebCore/Modules/fetch/FetchInternals.js b/Source/WebCore/Modules/fetch/FetchInternals.js >index 452ec763535a809ea8d8298e06935ee5b3076e4b..d75004e2f8085b15c710070015bedd1b5abb22c6 100644 >--- a/Source/WebCore/Modules/fetch/FetchInternals.js >+++ b/Source/WebCore/Modules/fetch/FetchInternals.js >@@ -51,3 +51,27 @@ function fillFetchHeaders(headers, headersInit) > @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); >+ } >+} >diff --git a/Source/WebCore/Modules/fetch/FetchLoader.cpp b/Source/WebCore/Modules/fetch/FetchLoader.cpp >index 1b23f049e67b4671c1e16a689e1db2b44ad13f80..e63bc1b2d33c32d21e49f99a57226473015262ea 100644 >--- a/Source/WebCore/Modules/fetch/FetchLoader.cpp >+++ b/Source/WebCore/Modules/fetch/FetchLoader.cpp >@@ -89,24 +89,26 @@ void FetchLoader::start(ScriptExecutionContext& context, const FetchRequest& req > 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(); > } > > 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 @@ void FetchLoader::didReceiveResponse(unsigned long, const ResourceResponse& resp > 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(); > } > >diff --git a/Source/WebCore/Modules/fetch/FetchLoader.h b/Source/WebCore/Modules/fetch/FetchLoader.h >index d473ff17451fca5c1a713fb543bd0b6a0b1de02b..dbb82fbebd559e77d1ce1b616bc6d0b4f1aef3c3 100644 >--- a/Source/WebCore/Modules/fetch/FetchLoader.h >+++ b/Source/WebCore/Modules/fetch/FetchLoader.h >@@ -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,9 +43,7 @@ class ScriptExecutionContext; > > class FetchLoader final : public ThreadableLoaderClient { > public: >- enum class Type { ArrayBuffer, Stream, Text }; >- >- FetchLoader(Type, FetchLoaderClient&); >+ FetchLoader(FetchLoaderClient&, FetchBodyConsumer*); > > RefPtr<SharedBuffer> startStreaming(); > >@@ -63,18 +60,13 @@ private: > 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 }; > }; > > } // namespace WebCore > > #endif // ENABLE(FETCH_API) >- >-#endif // FetchLoader_h >diff --git a/Source/WebCore/Modules/fetch/FetchLoaderClient.h b/Source/WebCore/Modules/fetch/FetchLoaderClient.h >index d09fad53e27e6d8ac22adb7ca9f4510278da4150..e88e99418cd9914a1ee481877d61adcb6e04eaf4 100644 >--- a/Source/WebCore/Modules/fetch/FetchLoaderClient.h >+++ b/Source/WebCore/Modules/fetch/FetchLoaderClient.h >@@ -47,8 +47,6 @@ public: > > 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; >diff --git a/Source/WebCore/Modules/fetch/FetchResponse.cpp b/Source/WebCore/Modules/fetch/FetchResponse.cpp >index c2e8abaab11a201540d8bd12850e51e70b2ea301..6738fa3183c961159112ce18cd050cb880da8403 100644 >--- a/Source/WebCore/Modules/fetch/FetchResponse.cpp >+++ b/Source/WebCore/Modules/fetch/FetchResponse.cpp >@@ -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 @@ FetchResponse::FetchResponse(ScriptExecutionContext& context, FetchBody&& body, > { > } > >-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 @@ void FetchResponse::BodyLoader::didSucceed() > 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 @@ void FetchResponse::BodyLoader::didReceiveData(const char* data, size_t size) > #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 @@ void FetchResponse::BodyLoader::stop() > 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); >diff --git a/Source/WebCore/Modules/fetch/FetchResponse.h b/Source/WebCore/Modules/fetch/FetchResponse.h >index 573c2708d8dc94dda8105b4c960c51596854204f..848625140507d80c836d71955a1b3b6fdb28b26d 100644 >--- a/Source/WebCore/Modules/fetch/FetchResponse.h >+++ b/Source/WebCore/Modules/fetch/FetchResponse.h >@@ -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 @@ public: > 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 @@ public: > 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 @@ private: > 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 @@ private: > Ref<FetchHeaders> m_headers; > Optional<BodyLoader> m_bodyLoader; > mutable String m_responseURL; >+ >+ FetchBodyConsumer m_consumer { FetchBodyConsumer::Type::ArrayBuffer }; > }; > > } // namespace WebCore >diff --git a/Source/WebCore/Modules/fetch/FetchResponse.idl b/Source/WebCore/Modules/fetch/FetchResponse.idl >index 3fb148814354ce7d1f840180bc990dfb23d0a92b..be3c2ce02937f6238f865d9219226b6fb1d1701c 100644 >--- a/Source/WebCore/Modules/fetch/FetchResponse.idl >+++ b/Source/WebCore/Modules/fetch/FetchResponse.idl >@@ -53,11 +53,25 @@ interface FetchResponse { > 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; >diff --git a/Source/WebCore/Modules/fetch/FetchResponse.js b/Source/WebCore/Modules/fetch/FetchResponse.js >index c4acc01011f4c1ee6370dc3341339db68581903e..8a4dabf1b8106bfe2b6c107cbeefe7fc3f968aa2 100644 >--- a/Source/WebCore/Modules/fetch/FetchResponse.js >+++ b/Source/WebCore/Modules/fetch/FetchResponse.js >@@ -48,6 +48,12 @@ function initializeFetchResponse(body, init) > 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 @@ function body() > } > 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); >+} >diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >index b4a5597a06808e3431fdd99d2dadcff9c44e4c16..373a93cbed8e8a983540064bcaa273c4aa9177cb 100644 >--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj >+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >@@ -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,12 +17102,15 @@ > 41F54F7D1C50C4F600338488 /* FetchBody.cpp */, > 41F54F7E1C50C4F600338488 /* FetchBody.h */, > 41F54F7F1C50C4F600338488 /* FetchBody.idl */, >+ 41CF8BE41D46222000707DC9 /* FetchBodyConsumer.cpp */, >+ 41CF8BE51D46222000707DC9 /* FetchBodyConsumer.h */, > 4147E2B31C89912600A7E715 /* FetchBodyOwner.cpp */, > 4147E2B21C88337F00A7E715 /* FetchBodyOwner.h */, > 41F54F821C50C4F600338488 /* FetchHeaders.cpp */, > 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 */, >diff --git a/Source/WebCore/bindings/js/JSDOMPromise.h b/Source/WebCore/bindings/js/JSDOMPromise.h >index 1275a32e678ddd8beca254bd1d6d4d19f024c287..4e22e334ff376ad3849bf0d10999b97bd9d9bc80 100644 >--- a/Source/WebCore/bindings/js/JSDOMPromise.h >+++ b/Source/WebCore/bindings/js/JSDOMPromise.h >@@ -118,6 +118,8 @@ public: > 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 @@ inline void DeferredWrapper::resolveWithValue(ResolveResultType&& result) > 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) > { >diff --git a/Source/WebCore/bindings/js/WebCoreBuiltinNames.h b/Source/WebCore/bindings/js/WebCoreBuiltinNames.h >index a5add94b209a2693bec351c98ffc5ce28a761be2..683902a6bed884f13a2a1b79335ed216c6be48f8 100644 >--- a/Source/WebCore/bindings/js/WebCoreBuiltinNames.h >+++ b/Source/WebCore/bindings/js/WebCoreBuiltinNames.h >@@ -35,14 +35,18 @@ namespace WebCore { > macro(addTrack) \ > macro(appendFromJS) \ > macro(body) \ >+ macro(cloneForJS) \ > macro(closeRequested) \ > macro(closedPromiseCapability) \ >+ macro(consume) \ >+ macro(consumeChunk) \ > macro(controlledReadableStream) \ > macro(controller) \ > macro(createReadableStreamSource) \ > macro(disturbed) \ > macro(fetchRequest) \ > macro(fillFromJS) \ >+ macro(finishConsumingStream) \ > macro(firstReadCallback) \ > macro(getUserMediaFromJS) \ > macro(getRemoteStreams) \ >@@ -72,6 +76,7 @@ namespace WebCore { > macro(setBody) \ > macro(setStatus) \ > macro(state) \ >+ macro(startConsumingStream) \ > macro(started) \ > macro(startedPromise) \ > macro(storedError) \ >diff --git a/LayoutTests/imported/w3c/ChangeLog b/LayoutTests/imported/w3c/ChangeLog >index cc489c9d17d92f4aebbfe204a61705f735889341..665e5f75780d2d7fadece1ec154dc629ee4d9bef 100644 >--- a/LayoutTests/imported/w3c/ChangeLog >+++ b/LayoutTests/imported/w3c/ChangeLog >@@ -1,3 +1,14 @@ >+2016-07-26 Youenn Fablet <youenn@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-26 Commit Queue <commit-queue@webkit.org> > > Unreviewed, rolling out r203719. >diff --git a/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-empty-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-empty-expected.txt >index 6704de1a442e5f1fd725b0cee22c7f0737a5e586..e9679518bd9c03094d8fffcf9fcf82dd177bc7cf 100644 >--- a/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-empty-expected.txt >+++ b/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-empty-expected.txt >@@ -3,7 +3,7 @@ PASS Consume response's body as text > 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 >diff --git a/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-expected.txt >index d088a69a8ce42a2fa0a1c92099d86a6bfa57e6d8..416a392ce6ad6cab68e271dd04a19a2ee50203ee 100644 >--- a/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-expected.txt >+++ b/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-expected.txt >@@ -3,9 +3,13 @@ PASS Consume response's body as text > 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 > >diff --git a/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume.html b/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume.html >index 02814ff5be926be738264ba91070bd2369d54691..99410cd448ab8bd64790187004efd34b1c99ab49 100644 >--- a/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume.html >+++ b/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume.html >@@ -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>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 159804
:
283761
|
284484
|
284485
|
284486
|
284492
|
284493
|
284498
|
284522
|
284592
| 284603