Support caching of Response with a ReadableStream body
https://bugs.webkit.org/show_bug.cgi?id=176462

Patch by Youenn Fablet <youenn@apple.com> on 2017-09-06
Reviewed by Alex Christensen.

LayoutTests/imported/w3c:

* web-platform-tests/service-workers/cache-storage/worker/cache-put.https-expected.txt:

Source/WebCore:

Tests: http/wpt/cache-storage/cache-put-stream.https.any.html
       http/wpt/cache-storage/cache-put-stream.https.any.worker.html

Making FetchResponse use more of ReadableStream:
- Cloning of its body is done through ReadableStream.
- Computation of disturbed and locked is done through ReadableStream.
- Storing of the ReadableStream body given at constructor time is done in FetchBody for FetchResponse.
This allows making FetchResponse closer to FetchRequest.
This also allows to correctly compute disturbed and locked in clone cases.

Adding the ability to consume a Response ReadableStream body as a SharedBuffer.
Using that ability in DOMCache.

* Modules/cache/DOMCache.cpp:
(WebCore::DOMCache::putWithResponseData):
(WebCore::DOMCache::put):
* Modules/cache/DOMCache.h:
* Modules/fetch/FetchBody.h:
(WebCore::FetchBody::readableStream const):
* Modules/fetch/FetchBodyConsumer.cpp:
(WebCore::FetchBodyConsumer::extract):
* Modules/fetch/FetchBodyConsumer.h:
* Modules/fetch/FetchBodyOwner.cpp:
(WebCore::FetchBodyOwner::isDisturbed const):
(WebCore::FetchBodyOwner::isDisturbedOrLocked const):
* Modules/fetch/FetchBodyOwner.h:
(WebCore::FetchBodyOwner::hasReadableStreamBody const):
* Modules/fetch/FetchBodySource.cpp:
* Modules/fetch/FetchBodySource.h:
* Modules/fetch/FetchResponse.cpp:
(WebCore::FetchResponse::consumeBodyFromReadableStream):
(WebCore::FetchResponse::consumeBodyWhenLoaded):
(WebCore::FetchResponse::consumeBodyAsStream):
* Modules/fetch/FetchResponse.h:
* Modules/fetch/FetchResponse.idl:
* Modules/fetch/FetchResponse.js:
(initializeFetchResponse):
(clone):
* bindings/js/ReadableStream.cpp:
(WebCore::callFunction):
(WebCore::ReadableStream::pipeTo):
(WebCore::ReadableStream::tee):
(WebCore::checkReadableStream):
(WebCore::ReadableStream::isLocked const):
(WebCore::ReadableStream::isDisturbed const):
(WebCore::ReadableStream::isDisturbed):
* bindings/js/ReadableStream.h:
* bindings/js/ReadableStreamDefaultController.cpp:
* bindings/js/ReadableStreamDefaultController.h:
* bindings/js/WebCoreBuiltinNames.h:
* testing/Internals.cpp:
(WebCore::Internals::isReadableStreamDisturbed):

LayoutTests:

* TestExpectations: Removing flakiness expectation for cache-put tests.
* http/wpt/cache-storage/cache-put-stream.https.any-expected.txt: Added.
* http/wpt/cache-storage/cache-put-stream.https.any.html: Added.
* http/wpt/cache-storage/cache-put-stream.https.any.js: Added.
(cache_test.):
(cache_test):
(string_appeared_here.cache_test.return.reader.read.then.):
(string_appeared_here.cache_test):
* http/wpt/cache-storage/cache-put-stream.https.any.worker-expected.txt: Added.
* http/wpt/cache-storage/cache-put-stream.https.any.worker.html: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@221704 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/bindings/js/ReadableStream.cpp b/Source/WebCore/bindings/js/ReadableStream.cpp
index cf48697..d16105e 100644
--- a/Source/WebCore/bindings/js/ReadableStream.cpp
+++ b/Source/WebCore/bindings/js/ReadableStream.cpp
@@ -55,6 +55,17 @@
     return create(globalObject, *newReadableStream);
 }
 
+static inline JSC::JSValue callFunction(JSC::ExecState& state, JSC::JSValue jsFunction, JSC::JSValue thisValue, const JSC::ArgList& arguments)
+{
+    auto scope = DECLARE_CATCH_SCOPE(state.vm());
+    JSC::CallData callData;
+    auto callType = JSC::getCallData(jsFunction, callData);
+    ASSERT(callType != JSC::CallType::None);
+    auto result = call(&state, jsFunction, callType, callData, thisValue, arguments);
+    scope.assertNoException();
+    return result;
+}
+
 void ReadableStream::pipeTo(ReadableStreamSink& sink)
 {
     auto& state = *m_globalObject->globalExec();
@@ -64,13 +75,10 @@
     auto readableStreamPipeTo = m_globalObject->get(&state, privateName);
     ASSERT(readableStreamPipeTo.isFunction());
 
-    CallData callData;
-    CallType callType = getCallData(readableStreamPipeTo, callData);
-    ASSERT(callType != JSC::CallType::None);
     MarkedArgumentBuffer arguments;
     arguments.append(readableStream());
     arguments.append(toJS(&state, m_globalObject.get(), sink));
-    JSC::call(&state, readableStreamPipeTo, callType, callData, JSC::jsUndefined(), arguments);
+    callFunction(state, readableStreamPipeTo, JSC::jsUndefined(), arguments);
 }
 
 std::pair<Ref<ReadableStream>, Ref<ReadableStream>> ReadableStream::tee()
@@ -82,13 +90,10 @@
     auto readableStreamTee = m_globalObject->get(&state, privateName);
     ASSERT(readableStreamTee.isFunction());
 
-    CallData callData;
-    CallType callType = getCallData(readableStreamTee, callData);
-    ASSERT(callType != JSC::CallType::None);
     MarkedArgumentBuffer arguments;
     arguments.append(readableStream());
     arguments.append(JSC::jsBoolean(true));
-    JSValue returnedValue = JSC::call(&state, readableStreamTee, callType, callData, JSC::jsUndefined(), arguments);
+    auto returnedValue = callFunction(state, readableStreamTee, JSC::jsUndefined(), arguments);
 
     auto results = Detail::SequenceConverter<IDLInterface<ReadableStream>>::convert(state, returnedValue);
 
@@ -96,4 +101,33 @@
     return std::make_pair(results[0].releaseNonNull(), results[1].releaseNonNull());
 }
 
+static inline bool checkReadableStream(JSDOMGlobalObject& globalObject, JSReadableStream* readableStream, JSC::JSValue function)
+{
+    auto& state = *globalObject.globalExec();
+
+    ASSERT(function);
+    JSC::MarkedArgumentBuffer arguments;
+    arguments.append(readableStream);
+    return callFunction(state, function, JSC::jsUndefined(), arguments).isTrue();
+}
+
+bool ReadableStream::isLocked() const
+{
+    return checkReadableStream(*globalObject(), readableStream(), globalObject()->builtinInternalFunctions().readableStreamInternals().m_isReadableStreamLockedFunction.get());
+}
+
+bool ReadableStream::isDisturbed() const
+{
+    return checkReadableStream(*globalObject(), readableStream(), globalObject()->builtinInternalFunctions().readableStreamInternals().m_isReadableStreamDisturbedFunction.get());
+}
+
+bool ReadableStream::isDisturbed(ExecState& state, JSValue value)
+{
+    auto& vm = state.vm();
+    auto& globalObject = *jsDynamicDowncast<JSDOMGlobalObject*>(vm, state.lexicalGlobalObject());
+    auto* readableStream = jsDynamicDowncast<JSReadableStream*>(vm, value);
+
+    return checkReadableStream(globalObject, readableStream, globalObject.builtinInternalFunctions().readableStreamInternals().m_isReadableStreamDisturbedFunction.get());
+}
+
 }