| Index: Source/modules/fetch/Body.cpp
|
| diff --git a/Source/modules/fetch/Body.cpp b/Source/modules/fetch/Body.cpp
|
| index 0be313e412339d2df44a9ff3303435e9b7786011..5f4032b524508644fb6e3d888ed6fd01052b0913 100644
|
| --- a/Source/modules/fetch/Body.cpp
|
| +++ b/Source/modules/fetch/Body.cpp
|
| @@ -12,77 +12,41 @@
|
| #include "bindings/core/v8/V8ThrowException.h"
|
| #include "core/dom/DOMArrayBuffer.h"
|
| #include "core/dom/DOMTypedArray.h"
|
| +#include "core/dom/ExceptionCode.h"
|
| #include "core/fileapi/Blob.h"
|
| -#include "core/fileapi/FileReaderLoader.h"
|
| -#include "core/fileapi/FileReaderLoaderClient.h"
|
| #include "core/frame/UseCounter.h"
|
| #include "core/streams/ReadableByteStream.h"
|
| #include "core/streams/ReadableByteStreamReader.h"
|
| #include "core/streams/UnderlyingSource.h"
|
| #include "modules/fetch/BodyStreamBuffer.h"
|
| +#include "modules/fetch/DataConsumerHandleUtil.h"
|
| +#include "modules/fetch/FetchBlobDataConsumerHandle.h"
|
|
|
| namespace blink {
|
|
|
| -class Body::BlobHandleReceiver final : public BodyStreamBuffer::BlobHandleCreatorClient {
|
| -public:
|
| - explicit BlobHandleReceiver(Body* body)
|
| - : m_body(body)
|
| - {
|
| - }
|
| - void didCreateBlobHandle(PassRefPtr<BlobDataHandle> handle) override
|
| - {
|
| - ASSERT(m_body);
|
| - m_body->readAsyncFromBlob(handle);
|
| - m_body = nullptr;
|
| - }
|
| - void didFail(DOMException* exception) override
|
| - {
|
| - ASSERT(m_body);
|
| - m_body->didBlobHandleReceiveError(exception);
|
| - m_body = nullptr;
|
| - }
|
| - DEFINE_INLINE_VIRTUAL_TRACE()
|
| - {
|
| - BodyStreamBuffer::BlobHandleCreatorClient::trace(visitor);
|
| - visitor->trace(m_body);
|
| - }
|
| -private:
|
| - Member<Body> m_body;
|
| -};
|
| -
|
| // This class is an ActiveDOMObject subclass only for holding the
|
| // ExecutionContext used in |pullSource|.
|
| -class Body::ReadableStreamSource : public BodyStreamBuffer::Observer, public UnderlyingSource, public FileReaderLoaderClient, public ActiveDOMObject {
|
| +class Body::ReadableStreamSource : public GarbageCollectedFinalized<Body::ReadableStreamSource>, public UnderlyingSource, public WebDataConsumerHandle::Client, public BodyStreamBuffer::DrainingStreamNotificationClient, public ActiveDOMObject {
|
| USING_GARBAGE_COLLECTED_MIXIN(ReadableStreamSource);
|
| public:
|
| enum State {
|
| - Initial,
|
| Streaming,
|
| Closed,
|
| Errored,
|
| };
|
| - ReadableStreamSource(ExecutionContext* executionContext, PassRefPtr<BlobDataHandle> handle)
|
| - : ActiveDOMObject(executionContext)
|
| - , m_blobDataHandle(handle ? handle : BlobDataHandle::create(BlobData::create(), 0))
|
| - , m_state(Initial)
|
| - {
|
| - suspendIfNeeded();
|
| - }
|
|
|
| ReadableStreamSource(ExecutionContext* executionContext, BodyStreamBuffer* buffer)
|
| : ActiveDOMObject(executionContext)
|
| , m_bodyStreamBuffer(buffer)
|
| - , m_state(Initial)
|
| - {
|
| - suspendIfNeeded();
|
| - }
|
| -
|
| - explicit ReadableStreamSource(ExecutionContext* executionContext)
|
| - : ActiveDOMObject(executionContext)
|
| - , m_blobDataHandle(BlobDataHandle::create(BlobData::create(), 0))
|
| - , m_state(Initial)
|
| + , m_state(Streaming)
|
| + , m_streamNeedsMore(false)
|
| +#if ENABLE(ASSERT)
|
| + , m_drained(false)
|
| +#endif
|
| {
|
| suspendIfNeeded();
|
| + if (m_bodyStreamBuffer)
|
| + obtainReader();
|
| }
|
|
|
| ~ReadableStreamSource() override { }
|
| @@ -95,42 +59,32 @@ public:
|
| stream->didSourceStart();
|
| }
|
| // Creates a new BodyStreamBuffer to drain the data.
|
| - BodyStreamBuffer* createDrainingStream()
|
| + PassOwnPtr<DrainingBodyStreamBuffer> createDrainingStream()
|
| {
|
| - ASSERT(m_state != Initial);
|
| + if (!m_bodyStreamBuffer)
|
| + return nullptr;
|
|
|
| - auto drainingStreamBuffer = new BodyStreamBuffer(new Canceller(this));
|
| if (m_stream->stateInternal() == ReadableByteStream::Closed) {
|
| - drainingStreamBuffer->close();
|
| - return drainingStreamBuffer;
|
| + return DrainingBodyStreamBuffer::create(BodyStreamBuffer::createEmpty(), nullptr);
|
| }
|
| if (m_stream->stateInternal() == ReadableByteStream::Errored) {
|
| - drainingStreamBuffer->error(exception());
|
| - return drainingStreamBuffer;
|
| - }
|
| -
|
| - ASSERT(!m_drainingStreamBuffer);
|
| - // Take back the data in |m_stream|.
|
| - Deque<std::pair<RefPtr<DOMArrayBufferView>, size_t>> tmp_queue;
|
| - ASSERT(m_stream->stateInternal() == ReadableStream::Readable);
|
| - m_stream->readInternal(tmp_queue);
|
| - while (!tmp_queue.isEmpty()) {
|
| - std::pair<RefPtr<DOMArrayBufferView>, size_t> data = tmp_queue.takeFirst();
|
| - drainingStreamBuffer->write(data.first->buffer());
|
| + return DrainingBodyStreamBuffer::create(BodyStreamBuffer::create(createFetchDataConsumerHandleFromWebHandle(createUnexpectedErrorDataConsumerHandle())), nullptr);
|
| }
|
| - if (m_state == Closed)
|
| - drainingStreamBuffer->close();
|
|
|
| - m_drainingStreamBuffer = drainingStreamBuffer;
|
| - return m_drainingStreamBuffer;
|
| + ASSERT(!m_drained);
|
| +#if ENABLE(ASSERT)
|
| + m_drained = true;
|
| +#endif
|
| + m_reader.clear();
|
| + return DrainingBodyStreamBuffer::create(m_bodyStreamBuffer, this);
|
| }
|
| +
|
| DEFINE_INLINE_VIRTUAL_TRACE()
|
| {
|
| visitor->trace(m_bodyStreamBuffer);
|
| - visitor->trace(m_drainingStreamBuffer);
|
| visitor->trace(m_stream);
|
| - BodyStreamBuffer::Observer::trace(visitor);
|
| UnderlyingSource::trace(visitor);
|
| + DrainingStreamNotificationClient::trace(visitor);
|
| ActiveDOMObject::trace(visitor);
|
| }
|
|
|
| @@ -143,145 +97,118 @@ public:
|
| return;
|
| }
|
| m_state = Closed;
|
| - if (m_drainingStreamBuffer)
|
| - m_drainingStreamBuffer->close();
|
| + m_reader.clear();
|
| m_stream->close();
|
| }
|
| void error()
|
| {
|
| m_state = Errored;
|
| - if (m_drainingStreamBuffer)
|
| - m_drainingStreamBuffer->error(exception());
|
| - m_stream->error(exception());
|
| + m_reader.clear();
|
| + m_stream->error(DOMException::create(NetworkError, "network error"));
|
| }
|
|
|
| -private:
|
| - class Canceller : public BodyStreamBuffer::Canceller {
|
| - public:
|
| - Canceller(ReadableStreamSource* source) : m_source(source) { }
|
| - void cancel() override
|
| - {
|
| - m_source->cancel();
|
| - }
|
| -
|
| - DEFINE_INLINE_VIRTUAL_TRACE()
|
| - {
|
| - visitor->trace(m_source);
|
| - BodyStreamBuffer::Canceller::trace(visitor);
|
| - }
|
| -
|
| - private:
|
| - Member<ReadableStreamSource> m_source;
|
| - };
|
| -
|
| - // UnderlyingSource functions.
|
| - void pullSource() override
|
| + void obtainReader()
|
| {
|
| - // Note that one |pull| is called only when |read| is called on the
|
| - // associated ReadableByteStreamReader because we create a stream with
|
| - // StrictStrategy.
|
| - if (m_state == Initial) {
|
| - m_state = Streaming;
|
| - if (m_bodyStreamBuffer) {
|
| - m_bodyStreamBuffer->registerObserver(this);
|
| - onWrite();
|
| - if (m_bodyStreamBuffer->hasError())
|
| - return onError();
|
| - if (m_bodyStreamBuffer->isClosed())
|
| - return onClose();
|
| - } else {
|
| - FileReaderLoader::ReadType readType = FileReaderLoader::ReadAsArrayBuffer;
|
| - m_loader = adoptPtr(new FileReaderLoader(readType, this));
|
| - m_loader->start(executionContext(), m_blobDataHandle);
|
| - }
|
| - }
|
| + m_reader = m_bodyStreamBuffer->handle()->obtainReader(this);
|
| }
|
|
|
| - ScriptPromise cancelSource(ScriptState* scriptState, ScriptValue reason) override
|
| +private:
|
| + void didFetchDataLoadFinishedFromDrainingStream()
|
| {
|
| - cancel();
|
| - return ScriptPromise::cast(scriptState, v8::Undefined(scriptState->isolate()));
|
| + ASSERT(m_bodyStreamBuffer);
|
| +
|
| +#if ENABLE(ASSERT)
|
| + m_drained = false;
|
| +#endif
|
| + obtainReader();
|
| + // We have to call didGetReadable() now to call close()/error() if
|
| + // necessary.
|
| + // didGetReadable() would be called asynchronously, but it is too late.
|
| + didGetReadable();
|
| }
|
|
|
| - // BodyStreamBuffer::Observer functions.
|
| - void onWrite() override
|
| + void didGetReadable() override
|
| {
|
| - ASSERT(m_state == Streaming);
|
| - while (RefPtr<DOMArrayBuffer> buf = m_bodyStreamBuffer->read()) {
|
| - write(buf);
|
| + if (!m_streamNeedsMore) {
|
| + // Perform zero-length read to call close()/error() early.
|
| + size_t readSize;
|
| + WebDataConsumerHandle::Result result = m_reader->read(nullptr, 0, WebDataConsumerHandle::FlagNone, &readSize);
|
| + switch (result) {
|
| + case WebDataConsumerHandle::Ok:
|
| + case WebDataConsumerHandle::ShouldWait:
|
| + return;
|
| + case WebDataConsumerHandle::Done:
|
| + close();
|
| + return;
|
| + case WebDataConsumerHandle::Busy:
|
| + case WebDataConsumerHandle::ResourceExhausted:
|
| + case WebDataConsumerHandle::UnexpectedError:
|
| + error();
|
| + return;
|
| + }
|
| }
|
| - }
|
| - void onClose() override
|
| - {
|
| - ASSERT(m_state == Streaming);
|
| - close();
|
| - m_bodyStreamBuffer->unregisterObserver();
|
| - }
|
| - void onError() override
|
| - {
|
| - ASSERT(m_state == Streaming);
|
| - error();
|
| - m_bodyStreamBuffer->unregisterObserver();
|
| - }
|
|
|
| - // FileReaderLoaderClient functions.
|
| - void didStartLoading() override { }
|
| - void didReceiveData() override { }
|
| - void didFinishLoading() override
|
| - {
|
| - ASSERT(m_state == Streaming);
|
| - write(m_loader->arrayBufferResult());
|
| - close();
|
| - }
|
| - void didFail(FileError::ErrorCode) override
|
| - {
|
| - ASSERT(m_state == Streaming);
|
| - error();
|
| + processData();
|
| }
|
|
|
| - void write(PassRefPtr<DOMArrayBuffer> buf)
|
| + // UnderlyingSource functions.
|
| + void pullSource() override
|
| {
|
| - if (m_drainingStreamBuffer) {
|
| - m_drainingStreamBuffer->write(buf);
|
| - } else {
|
| - auto size = buf->byteLength();
|
| - m_stream->enqueue(DOMUint8Array::create(buf, 0, size));
|
| - }
|
| + ASSERT(!m_streamNeedsMore);
|
| + m_streamNeedsMore = true;
|
| +
|
| + ASSERT(!m_drained);
|
| +
|
| + processData();
|
| }
|
| - void cancel()
|
| +
|
| + ScriptPromise cancelSource(ScriptState* scriptState, ScriptValue reason) override
|
| {
|
| - if (m_bodyStreamBuffer) {
|
| - m_bodyStreamBuffer->cancel();
|
| - // We should not close the stream here, because it is canceller's
|
| - // responsibility.
|
| - } else {
|
| - if (m_loader)
|
| - m_loader->cancel();
|
| - close();
|
| - }
|
| + close();
|
| + return ScriptPromise::cast(scriptState, v8::Undefined(scriptState->isolate()));
|
| }
|
|
|
| - DOMException* exception()
|
| + // Reads data and writes the data to |m_stream|, as long as data are
|
| + // available and the stream has pending reads.
|
| + void processData()
|
| {
|
| - if (m_state != Errored)
|
| - return nullptr;
|
| - if (m_bodyStreamBuffer) {
|
| - ASSERT(m_bodyStreamBuffer->exception());
|
| - return m_bodyStreamBuffer->exception();
|
| + ASSERT(m_reader);
|
| + while (m_streamNeedsMore) {
|
| + const void* buffer;
|
| + size_t available;
|
| + WebDataConsumerHandle::Result result = m_reader->beginRead(&buffer, WebDataConsumerHandle::FlagNone, &available);
|
| + switch (result) {
|
| + case WebDataConsumerHandle::Ok:
|
| + m_streamNeedsMore = m_stream->enqueue(DOMUint8Array::create(static_cast<const unsigned char*>(buffer), available));
|
| + m_reader->endRead(available);
|
| + break;
|
| +
|
| + case WebDataConsumerHandle::Done:
|
| + close();
|
| + return;
|
| +
|
| + case WebDataConsumerHandle::ShouldWait:
|
| + return;
|
| +
|
| + case WebDataConsumerHandle::Busy:
|
| + case WebDataConsumerHandle::ResourceExhausted:
|
| + case WebDataConsumerHandle::UnexpectedError:
|
| + error();
|
| + return;
|
| + }
|
| }
|
| - return DOMException::create(NetworkError, "network error");
|
| }
|
|
|
| - // Set when the data container of the Body is a BodyStreamBuffer.
|
| + // Source of data.
|
| Member<BodyStreamBuffer> m_bodyStreamBuffer;
|
| - // Set when the data container of the Body is a BlobDataHandle.
|
| - RefPtr<BlobDataHandle> m_blobDataHandle;
|
| - // Used to read the data from BlobDataHandle.
|
| - OwnPtr<FileReaderLoader> m_loader;
|
| - // Created when createDrainingStream is called to drain the data.
|
| - Member<BodyStreamBuffer> m_drainingStreamBuffer;
|
| + OwnPtr<FetchDataConsumerHandle::Reader> m_reader;
|
| +
|
| Member<ReadableByteStream> m_stream;
|
| State m_state;
|
| + bool m_streamNeedsMore;
|
| +#if ENABLE(ASSERT)
|
| + bool m_drained;
|
| +#endif
|
| };
|
|
|
| ScriptPromise Body::readAsync(ScriptState* scriptState, ResponseType type)
|
| @@ -307,94 +234,84 @@ ScriptPromise Body::readAsync(ScriptState* scriptState, ResponseType type)
|
| ScriptPromise promise = m_resolver->promise();
|
|
|
| if (m_stream->stateInternal() == ReadableStream::Closed) {
|
| - // We resolve the resolver manually in order not to use member
|
| - // variables.
|
| - switch (m_responseType) {
|
| - case ResponseAsArrayBuffer:
|
| - m_resolver->resolve(DOMArrayBuffer::create(nullptr, 0));
|
| - break;
|
| - case ResponseAsBlob: {
|
| - OwnPtr<BlobData> blobData = BlobData::create();
|
| - blobData->setContentType(mimeType());
|
| - m_resolver->resolve(Blob::create(BlobDataHandle::create(blobData.release(), 0)));
|
| - break;
|
| - }
|
| - case ResponseAsText:
|
| - m_resolver->resolve(String());
|
| - break;
|
| - case ResponseAsFormData:
|
| - // TODO(yhirano): Implement this.
|
| - ASSERT_NOT_REACHED();
|
| - break;
|
| - case ResponseAsJSON: {
|
| - ScriptState::Scope scope(m_resolver->scriptState());
|
| - m_resolver->reject(V8ThrowException::createSyntaxError(m_resolver->scriptState()->isolate(), "Unexpected end of input"));
|
| - break;
|
| - }
|
| - case ResponseUnknown:
|
| - ASSERT_NOT_REACHED();
|
| - break;
|
| - }
|
| - m_resolver.clear();
|
| + resolveWithEmptyDataSynchronously();
|
| } else if (m_stream->stateInternal() == ReadableStream::Errored) {
|
| m_resolver->reject(m_stream->storedException());
|
| m_resolver.clear();
|
| - } else if (isBodyConsumed()) {
|
| - m_streamSource->createDrainingStream()->readAllAndCreateBlobHandle(mimeType(), new BlobHandleReceiver(this));
|
| - } else if (buffer()) {
|
| - buffer()->readAllAndCreateBlobHandle(mimeType(), new BlobHandleReceiver(this));
|
| } else {
|
| - readAsyncFromBlob(blobDataHandle());
|
| + readAsyncFromDrainingBodyStreamBuffer(createDrainingStream(), mimeType());
|
| }
|
| return promise;
|
| }
|
|
|
| -void Body::readAsyncFromBlob(PassRefPtr<BlobDataHandle> handle)
|
| +void Body::resolveWithEmptyDataSynchronously()
|
| {
|
| - FileReaderLoader::ReadType readType = FileReaderLoader::ReadAsText;
|
| - RefPtr<BlobDataHandle> blobHandle = handle;
|
| - if (!blobHandle)
|
| - blobHandle = BlobDataHandle::create(BlobData::create(), 0);
|
| + // We resolve the resolver manually in order not to use member
|
| + // variables.
|
| switch (m_responseType) {
|
| case ResponseAsArrayBuffer:
|
| - readType = FileReaderLoader::ReadAsArrayBuffer;
|
| + m_resolver->resolve(DOMArrayBuffer::create(nullptr, 0));
|
| break;
|
| - case ResponseAsBlob:
|
| - if (blobHandle->size() != kuint64max) {
|
| - // If the size of |blobHandle| is set correctly, creates Blob from
|
| - // it.
|
| - if (blobHandle->type() != mimeType()) {
|
| - // A new BlobDataHandle is created to override the Blob's type.
|
| - m_resolver->resolve(Blob::create(BlobDataHandle::create(blobHandle->uuid(), mimeType(), blobHandle->size())));
|
| - } else {
|
| - m_resolver->resolve(Blob::create(blobHandle));
|
| - }
|
| - m_stream->close();
|
| - m_resolver.clear();
|
| - return;
|
| - }
|
| - // If the size is not set, read as ArrayBuffer and create a new blob to
|
| - // get the size.
|
| - // FIXME: This workaround is not good for performance.
|
| - // When we will stop using Blob as a base system of Body to support
|
| - // stream, this problem should be solved.
|
| - readType = FileReaderLoader::ReadAsArrayBuffer;
|
| + case ResponseAsBlob: {
|
| + OwnPtr<BlobData> blobData = BlobData::create();
|
| + blobData->setContentType(mimeType());
|
| + m_resolver->resolve(Blob::create(BlobDataHandle::create(blobData.release(), 0)));
|
| + break;
|
| + }
|
| + case ResponseAsText:
|
| + m_resolver->resolve(String());
|
| break;
|
| case ResponseAsFormData:
|
| - // FIXME: Implement this.
|
| + // TODO(yhirano): Implement this.
|
| + ASSERT_NOT_REACHED();
|
| + break;
|
| + case ResponseAsJSON: {
|
| + ScriptState::Scope scope(m_resolver->scriptState());
|
| + m_resolver->reject(V8ThrowException::createSyntaxError(m_resolver->scriptState()->isolate(), "Unexpected end of input"));
|
| + break;
|
| + }
|
| + case ResponseUnknown:
|
| ASSERT_NOT_REACHED();
|
| break;
|
| + }
|
| + m_resolver.clear();
|
| +}
|
| +
|
| +void Body::readAsyncFromDrainingBodyStreamBuffer(PassOwnPtr<DrainingBodyStreamBuffer> buffer, const String& mimeType)
|
| +{
|
| + if (!buffer) {
|
| + resolveWithEmptyDataSynchronously();
|
| + m_streamSource->close();
|
| + return;
|
| + }
|
| +
|
| + FetchDataLoader* fetchDataLoader = nullptr;
|
| +
|
| + switch (m_responseType) {
|
| + case ResponseAsArrayBuffer:
|
| + fetchDataLoader = FetchDataLoader::createLoaderAsArrayBuffer();
|
| + break;
|
| +
|
| case ResponseAsJSON:
|
| case ResponseAsText:
|
| + fetchDataLoader = FetchDataLoader::createLoaderAsString();
|
| + break;
|
| +
|
| + case ResponseAsBlob:
|
| + fetchDataLoader = FetchDataLoader::createLoaderAsBlobHandle(mimeType);
|
| break;
|
| +
|
| + case ResponseAsFormData:
|
| + // FIXME: Implement this.
|
| + ASSERT_NOT_REACHED();
|
| + return;
|
| +
|
| default:
|
| ASSERT_NOT_REACHED();
|
| + return;
|
| }
|
|
|
| - m_loader = adoptPtr(new FileReaderLoader(readType, this));
|
| - m_loader->start(m_resolver->scriptState()->executionContext(), blobHandle);
|
| -
|
| - return;
|
| + buffer->startLoading(fetchDataLoader, this);
|
| }
|
|
|
| ScriptPromise Body::arrayBuffer(ScriptState* scriptState)
|
| @@ -444,41 +361,20 @@ void Body::lockBody(LockBodyOption option)
|
| ASSERT(!exceptionState.hadException());
|
| }
|
|
|
| -bool Body::isBodyConsumed() const
|
| +void Body::setBody(BodyStreamBuffer* buffer)
|
| {
|
| - if (m_streamSource->state() != m_streamSource->Initial) {
|
| - // Some data is pulled from the source.
|
| - return true;
|
| - }
|
| - if (m_stream->stateInternal() == ReadableStream::Closed) {
|
| - // Return true if the blob handle is originally not empty.
|
| - RefPtr<BlobDataHandle> handle = blobDataHandle();
|
| - return handle && handle->size();
|
| - }
|
| - if (m_stream->stateInternal() == ReadableStream::Errored) {
|
| - // The stream is errored. That means an effort to read data was made.
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -void Body::setBody(ReadableStreamSource* source)
|
| -{
|
| - m_streamSource = source;
|
| + m_streamSource = new ReadableStreamSource(executionContext(), buffer);
|
| m_stream = new ReadableByteStream(m_streamSource, new ReadableByteStream::StrictStrategy);
|
| m_streamSource->startStream(m_stream);
|
| }
|
|
|
| -BodyStreamBuffer* Body::createDrainingStream()
|
| +PassOwnPtr<DrainingBodyStreamBuffer> Body::createDrainingStream()
|
| {
|
| return m_streamSource->createDrainingStream();
|
| }
|
|
|
| void Body::stop()
|
| {
|
| - // Canceling the load will call didFail which will remove the resolver.
|
| - if (m_loader)
|
| - m_loader->cancel();
|
| }
|
|
|
| bool Body::hasPendingActivity() const
|
| @@ -492,29 +388,20 @@ bool Body::hasPendingActivity() const
|
| return false;
|
| }
|
|
|
| -Body::ReadableStreamSource* Body::createBodySource(PassRefPtr<BlobDataHandle> handle)
|
| -{
|
| - return new ReadableStreamSource(executionContext(), handle);
|
| -}
|
| -
|
| -Body::ReadableStreamSource* Body::createBodySource(BodyStreamBuffer* buffer)
|
| -{
|
| - return new ReadableStreamSource(executionContext(), buffer);
|
| -}
|
| -
|
| DEFINE_TRACE(Body)
|
| {
|
| visitor->trace(m_resolver);
|
| visitor->trace(m_stream);
|
| visitor->trace(m_streamSource);
|
| ActiveDOMObject::trace(visitor);
|
| + FetchDataLoader::Client::trace(visitor);
|
| }
|
|
|
| Body::Body(ExecutionContext* context)
|
| : ActiveDOMObject(context)
|
| , m_bodyUsed(false)
|
| , m_responseType(ResponseType::ResponseUnknown)
|
| - , m_streamSource(new ReadableStreamSource(context))
|
| + , m_streamSource(new ReadableStreamSource(context, nullptr))
|
| , m_stream(new ReadableByteStream(m_streamSource, new ReadableByteStream::StrictStrategy))
|
| {
|
| m_streamSource->startStream(m_stream);
|
| @@ -534,63 +421,60 @@ void Body::resolveJSON(const String& string)
|
| m_resolver->reject(trycatch.Exception());
|
| }
|
|
|
| -// FileReaderLoaderClient functions.
|
| -void Body::didStartLoading() { }
|
| -void Body::didReceiveData() { }
|
| -void Body::didFinishLoading()
|
| +// FetchDataLoader::Client functions.
|
| +void Body::didFetchDataLoadFailed()
|
| {
|
| if (!executionContext() || executionContext()->activeDOMObjectsAreStopped())
|
| return;
|
|
|
| - switch (m_responseType) {
|
| - case ResponseAsArrayBuffer:
|
| - m_resolver->resolve(m_loader->arrayBufferResult());
|
| - break;
|
| - case ResponseAsBlob: {
|
| - ASSERT(blobDataHandle()->size() == kuint64max);
|
| - OwnPtr<BlobData> blobData = BlobData::create();
|
| - RefPtr<DOMArrayBuffer> buffer = m_loader->arrayBufferResult();
|
| - blobData->appendBytes(buffer->data(), buffer->byteLength());
|
| - blobData->setContentType(mimeType());
|
| - const size_t length = blobData->length();
|
| - m_resolver->resolve(Blob::create(BlobDataHandle::create(blobData.release(), length)));
|
| - break;
|
| - }
|
| - case ResponseAsFormData:
|
| - ASSERT_NOT_REACHED();
|
| - break;
|
| - case ResponseAsJSON:
|
| - resolveJSON(m_loader->stringResult());
|
| - break;
|
| - case ResponseAsText:
|
| - m_resolver->resolve(m_loader->stringResult());
|
| - break;
|
| - default:
|
| - ASSERT_NOT_REACHED();
|
| + if (m_resolver) {
|
| + if (!m_resolver->executionContext() || m_resolver->executionContext()->activeDOMObjectsAreStopped()) {
|
| + m_resolver.clear();
|
| + return;
|
| + }
|
| + ScriptState* state = m_resolver->scriptState();
|
| + ScriptState::Scope scope(state);
|
| + m_resolver->reject(V8ThrowException::createTypeError(state->isolate(), "Failed to fetch"));
|
| + m_resolver.clear();
|
| }
|
| - m_streamSource->close();
|
| +}
|
| +
|
| +void Body::didFetchDataLoadedBlobHandle(PassRefPtr<BlobDataHandle> blobDataHandle)
|
| +{
|
| + if (!executionContext() || executionContext()->activeDOMObjectsAreStopped())
|
| + return;
|
| +
|
| + ASSERT(m_responseType == ResponseAsBlob);
|
| + m_resolver->resolve(Blob::create(blobDataHandle));
|
| m_resolver.clear();
|
| }
|
|
|
| -void Body::didFail(FileError::ErrorCode code)
|
| +void Body::didFetchDataLoadedArrayBuffer(PassRefPtr<DOMArrayBuffer> arrayBuffer)
|
| {
|
| if (!executionContext() || executionContext()->activeDOMObjectsAreStopped())
|
| return;
|
|
|
| - m_streamSource->error();
|
| - if (m_resolver) {
|
| - // FIXME: We should reject the promise.
|
| - m_resolver->resolve("");
|
| - m_resolver.clear();
|
| - }
|
| + ASSERT(m_responseType == ResponseAsArrayBuffer);
|
| + m_resolver->resolve(arrayBuffer);
|
| + m_resolver.clear();
|
| }
|
|
|
| -void Body::didBlobHandleReceiveError(DOMException* exception)
|
| +void Body::didFetchDataLoadedString(const String& str)
|
| {
|
| - if (!m_resolver)
|
| + if (!executionContext() || executionContext()->activeDOMObjectsAreStopped())
|
| return;
|
| - m_streamSource->error();
|
| - m_resolver->reject(exception);
|
| +
|
| + switch (m_responseType) {
|
| + case ResponseAsJSON:
|
| + resolveJSON(str);
|
| + break;
|
| + case ResponseAsText:
|
| + m_resolver->resolve(str);
|
| + break;
|
| + default:
|
| + ASSERT_NOT_REACHED();
|
| + }
|
| +
|
| m_resolver.clear();
|
| }
|
|
|
|
|