Index: third_party/WebKit/Source/modules/fetch/Body.cpp |
diff --git a/third_party/WebKit/Source/modules/fetch/Body.cpp b/third_party/WebKit/Source/modules/fetch/Body.cpp |
index eadb58918aa3af3a61704ea7edd98e57d9b4183b..670ea27b1e45ca179c84449e2b08beb0cad2f913 100644 |
--- a/third_party/WebKit/Source/modules/fetch/Body.cpp |
+++ b/third_party/WebKit/Source/modules/fetch/Body.cpp |
@@ -4,6 +4,7 @@ |
#include "modules/fetch/Body.h" |
+#include "bindings/core/v8/ExceptionState.h" |
#include "bindings/core/v8/ScriptPromiseResolver.h" |
#include "bindings/core/v8/ScriptState.h" |
#include "bindings/core/v8/V8ArrayBuffer.h" |
@@ -13,6 +14,9 @@ |
#include "core/dom/ExceptionCode.h" |
#include "core/fileapi/Blob.h" |
#include "core/frame/UseCounter.h" |
+#include "core/streams/ReadableStreamController.h" |
+#include "core/streams/ReadableStreamOperations.h" |
+#include "core/streams/UnderlyingSourceBase.h" |
#include "modules/fetch/BodyStreamBuffer.h" |
#include "modules/fetch/FetchDataLoader.h" |
#include "public/platform/WebDataConsumerHandle.h" |
@@ -100,6 +104,59 @@ |
} |
}; |
+class UnderlyingSourceFromDataConsumerHandle final : public UnderlyingSourceBase, public WebDataConsumerHandle::Client { |
+ EAGERLY_FINALIZE(); |
+ DECLARE_EAGER_FINALIZATION_OPERATOR_NEW(); |
+public: |
+ UnderlyingSourceFromDataConsumerHandle(ScriptState* scriptState, PassOwnPtr<WebDataConsumerHandle> handle) |
+ : UnderlyingSourceBase(scriptState) |
+ , m_scriptState(scriptState) |
+ , m_reader(handle->obtainReader(this)) |
+ { |
+ } |
+ |
+ ScriptPromise pull(ScriptState* scriptState) override |
+ { |
+ didGetReadable(); |
+ return ScriptPromise::castUndefined(scriptState); |
+ } |
+ |
+ ScriptPromise cancel(ScriptState* scriptState, ScriptValue reason) override |
+ { |
+ m_reader = nullptr; |
+ return ScriptPromise::castUndefined(scriptState); |
+ } |
+ |
+ void didGetReadable() override |
+ { |
+ while (controller()->desiredSize() > 0) { |
+ size_t available = 0; |
+ const void* buffer = nullptr; |
+ WebDataConsumerHandle::Result result = m_reader->beginRead(&buffer, WebDataConsumerHandle::FlagNone, &available); |
+ if (result == WebDataConsumerHandle::Ok) { |
+ RefPtr<ArrayBuffer> arrayBuffer = ArrayBuffer::create(available, 1); |
+ memcpy(arrayBuffer->data(), buffer, available); |
+ m_reader->endRead(available); |
+ controller()->enqueue(DOMUint8Array::create(arrayBuffer.release(), 0, available)); |
+ } else if (result == WebDataConsumerHandle::ShouldWait) { |
+ break; |
+ } else if (result == WebDataConsumerHandle::Done) { |
+ m_reader = nullptr; |
+ controller()->close(); |
+ break; |
+ } else { |
+ m_reader = nullptr; |
+ controller()->error(V8ThrowException::createTypeError(m_scriptState->isolate(), "Network error")); |
+ break; |
+ } |
+ } |
+ } |
+ |
+private: |
+ RefPtr<ScriptState> m_scriptState; |
+ OwnPtr<WebDataConsumerHandle::Reader> m_reader; |
+}; |
+ |
} // namespace |
ScriptPromise Body::arrayBuffer(ScriptState* scriptState) |
@@ -120,7 +177,7 @@ |
ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
promise = resolver->promise(); |
if (bodyBuffer()) { |
- bodyBuffer()->startLoading(FetchDataLoader::createLoaderAsArrayBuffer(), new BodyArrayBufferConsumer(resolver)); |
+ bodyBuffer()->startLoading(scriptState->getExecutionContext(), FetchDataLoader::createLoaderAsArrayBuffer(), new BodyArrayBufferConsumer(resolver)); |
} else { |
resolver->resolve(DOMArrayBuffer::create(0u, 1)); |
} |
@@ -140,7 +197,7 @@ |
ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
promise = resolver->promise(); |
if (bodyBuffer()) { |
- bodyBuffer()->startLoading(FetchDataLoader::createLoaderAsBlobHandle(mimeType()), new BodyBlobConsumer(resolver)); |
+ bodyBuffer()->startLoading(scriptState->getExecutionContext(), FetchDataLoader::createLoaderAsBlobHandle(mimeType()), new BodyBlobConsumer(resolver)); |
} else { |
OwnPtr<BlobData> blobData = BlobData::create(); |
blobData->setContentType(mimeType()); |
@@ -163,7 +220,7 @@ |
ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
promise = resolver->promise(); |
if (bodyBuffer()) { |
- bodyBuffer()->startLoading(FetchDataLoader::createLoaderAsString(), new BodyJsonConsumer(resolver)); |
+ bodyBuffer()->startLoading(scriptState->getExecutionContext(), FetchDataLoader::createLoaderAsString(), new BodyJsonConsumer(resolver)); |
} else { |
resolver->reject(V8ThrowException::createSyntaxError(scriptState->isolate(), "Unexpected end of input")); |
} |
@@ -183,21 +240,32 @@ |
ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
promise = resolver->promise(); |
if (bodyBuffer()) { |
- bodyBuffer()->startLoading(FetchDataLoader::createLoaderAsString(), new BodyTextConsumer(resolver)); |
+ bodyBuffer()->startLoading(scriptState->getExecutionContext(), FetchDataLoader::createLoaderAsString(), new BodyTextConsumer(resolver)); |
} else { |
resolver->resolve(String()); |
} |
return promise; |
} |
-ScriptValue Body::bodyWithUseCounter(ScriptState* scriptState) |
+ReadableByteStream* Body::body() |
+{ |
+ return bodyBuffer() ? bodyBuffer()->stream() : nullptr; |
+} |
+ |
+ReadableByteStream* Body::bodyWithUseCounter() |
{ |
UseCounter::count(getExecutionContext(), UseCounter::FetchBodyStream); |
- if (!bodyBuffer()) |
- return ScriptValue::createNull(scriptState); |
- ScriptValue stream = bodyBuffer()->stream(); |
- ASSERT(stream.getScriptState() == scriptState); |
- return stream; |
+ return body(); |
+} |
+ |
+ScriptValue Body::v8ExtraStreamBody(ScriptState* scriptState) |
+{ |
+ if (bodyUsed() || isBodyLocked() || !bodyBuffer()) |
+ return ScriptValue(scriptState, v8::Undefined(scriptState->isolate())); |
+ OwnPtr<FetchDataConsumerHandle> handle = bodyBuffer()->releaseHandle(scriptState->getExecutionContext()); |
+ return ReadableStreamOperations::createReadableStream(scriptState, |
+ new UnderlyingSourceFromDataConsumerHandle(scriptState, handle.release()), |
+ ScriptValue(scriptState, v8::Undefined(scriptState->isolate()))); |
} |
bool Body::bodyUsed() |