| Index: Source/modules/fetch/Body.cpp
|
| diff --git a/Source/modules/fetch/Body.cpp b/Source/modules/fetch/Body.cpp
|
| index f80644561fcbefd072de728387f62a7356355637..1d2eee792357cbb3de06c69532c07e2201a50b27 100644
|
| --- a/Source/modules/fetch/Body.cpp
|
| +++ b/Source/modules/fetch/Body.cpp
|
| @@ -110,6 +110,27 @@ public:
|
| UnderlyingSource::trace(visitor);
|
| }
|
|
|
| + void close()
|
| + {
|
| + if (m_state == Closed) {
|
| + // It is possible to call |close| from the source side (such
|
| + // as blob loading finish) and from the consumer side (such as
|
| + // calling |cancel|). Thus we should ignore it here.
|
| + return;
|
| + }
|
| + m_state = Closed;
|
| + if (m_drainingStreamBuffer)
|
| + m_drainingStreamBuffer->close();
|
| + m_stream->close();
|
| + }
|
| + void error()
|
| + {
|
| + m_state = Errored;
|
| + if (m_drainingStreamBuffer)
|
| + m_drainingStreamBuffer->error(exception());
|
| + m_stream->error(exception());
|
| + }
|
| +
|
| private:
|
| class Canceller : public BodyStreamBuffer::Canceller {
|
| public:
|
| @@ -207,20 +228,6 @@ private:
|
| m_stream->enqueue(DOMUint8Array::create(buf, 0, size));
|
| }
|
| }
|
| - void close()
|
| - {
|
| - m_state = Closed;
|
| - if (m_drainingStreamBuffer)
|
| - m_drainingStreamBuffer->close();
|
| - m_stream->close();
|
| - }
|
| - void error()
|
| - {
|
| - m_state = Errored;
|
| - if (m_drainingStreamBuffer)
|
| - m_drainingStreamBuffer->error(exception());
|
| - m_stream->error(exception());
|
| - }
|
| void cancel()
|
| {
|
| if (m_bodyStreamBuffer) {
|
| @@ -273,14 +280,47 @@ ScriptPromise Body::readAsync(ScriptState* scriptState, ResponseType type)
|
| if (!executionContext)
|
| return ScriptPromise();
|
|
|
| - lockBody(PassBody);
|
| + lockBody();
|
| m_responseType = type;
|
|
|
| ASSERT(!m_resolver);
|
| m_resolver = ScriptPromiseResolver::create(scriptState);
|
| ScriptPromise promise = m_resolver->promise();
|
|
|
| - if (streamAccessed()) {
|
| + 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();
|
| + } 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));
|
| @@ -384,9 +424,22 @@ void Body::lockBody(LockBodyOption option)
|
| ASSERT(!exceptionState.hadException());
|
| }
|
|
|
| -bool Body::streamAccessed() const
|
| +bool Body::isBodyConsumed() const
|
| {
|
| - return m_streamSource->state() != m_streamSource->Initial;
|
| + 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::refreshBody()
|
| @@ -485,7 +538,7 @@ void Body::didFinishLoading()
|
| default:
|
| ASSERT_NOT_REACHED();
|
| }
|
| - m_stream->close();
|
| + m_streamSource->close();
|
| m_resolver.clear();
|
| }
|
|
|
| @@ -494,7 +547,7 @@ void Body::didFail(FileError::ErrorCode code)
|
| if (!executionContext() || executionContext()->activeDOMObjectsAreStopped())
|
| return;
|
|
|
| - m_stream->error(DOMException::create(NetworkError, "network error"));
|
| + m_streamSource->error();
|
| if (m_resolver) {
|
| // FIXME: We should reject the promise.
|
| m_resolver->resolve("");
|
| @@ -506,7 +559,7 @@ void Body::didBlobHandleReceiveError(PassRefPtrWillBeRawPtr<DOMException> except
|
| {
|
| if (!m_resolver)
|
| return;
|
| - m_stream->error(DOMException::create(NetworkError, "network error"));
|
| + m_streamSource->error();
|
| m_resolver->reject(exception);
|
| m_resolver.clear();
|
| }
|
|
|