Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1396)

Unified Diff: Source/modules/fetch/Body.cpp

Issue 1233573002: [Fetch API] Remove DrainingBuffer. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/modules/fetch/Body.h ('k') | Source/modules/fetch/BodyStreamBuffer.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/modules/fetch/Body.cpp
diff --git a/Source/modules/fetch/Body.cpp b/Source/modules/fetch/Body.cpp
index 902ed48e0465637cdb9ae9a48e8bff993139f3a0..18b88f1041d43cf147f43194e3c372ebf20d94ce 100644
--- a/Source/modules/fetch/Body.cpp
+++ b/Source/modules/fetch/Body.cpp
@@ -15,194 +15,94 @@
#include "core/dom/ExceptionCode.h"
#include "core/fileapi/Blob.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"
+#include "modules/fetch/FetchDataLoader.h"
+#include "wtf/PassRefPtr.h"
+#include "wtf/RefPtr.h"
namespace blink {
-class Body::ReadableStreamSource : public GarbageCollectedFinalized<Body::ReadableStreamSource>, public UnderlyingSource, public WebDataConsumerHandle::Client, public BodyStreamBuffer::DrainingStreamNotificationClient {
- USING_GARBAGE_COLLECTED_MIXIN(ReadableStreamSource);
+namespace {
+
+class BodyConsumerBase : public GarbageCollectedFinalized<BodyConsumerBase>, public FetchDataLoader::Client {
+ WTF_MAKE_NONCOPYABLE(BodyConsumerBase);
+ USING_GARBAGE_COLLECTED_MIXIN(BodyConsumerBase);
public:
- ReadableStreamSource(ExecutionContext* executionContext, BodyStreamBuffer* buffer)
- : m_bodyStreamBuffer(buffer)
- , m_streamNeedsMore(false)
-#if ENABLE(ASSERT)
- , m_drained(false)
- , m_isCloseCalled(false)
- , m_isErrorCalled(false)
-#endif
+ explicit BodyConsumerBase(PassRefPtrWillBeRawPtr<ScriptPromiseResolver> resolver) : m_resolver(resolver) {}
+ PassRefPtrWillBeRawPtr<ScriptPromiseResolver> resolver() { return m_resolver; }
+ void didFetchDataLoadFailed() override
{
- if (m_bodyStreamBuffer)
- obtainReader();
+ ScriptState::Scope scope(resolver()->scriptState());
+ m_resolver->reject(V8ThrowException::createTypeError(resolver()->scriptState()->isolate(), "Failed to fetch"));
}
- ~ReadableStreamSource() override { }
-
- void startStream(ReadableByteStream* stream)
- {
- m_stream = stream;
- stream->didSourceStart();
- if (!m_bodyStreamBuffer)
- close();
- }
- // Creates a new BodyStreamBuffer to drain the data.
- PassOwnPtr<DrainingBodyStreamBuffer> createDrainingStream()
+ DEFINE_INLINE_TRACE()
{
- if (!m_bodyStreamBuffer)
- return nullptr;
-
-#if ENABLE(ASSERT)
- ASSERT(!m_drained);
- m_drained = true;
- ASSERT(!(m_stream->stateInternal() == ReadableByteStream::Closed && !m_isCloseCalled));
- ASSERT(!(m_stream->stateInternal() == ReadableByteStream::Errored && !m_isErrorCalled));
-#endif
-
- m_reader.clear();
- return DrainingBodyStreamBuffer::create(m_bodyStreamBuffer, this);
+ visitor->trace(m_resolver);
+ FetchDataLoader::Client::trace(visitor);
}
- DEFINE_INLINE_VIRTUAL_TRACE()
- {
- visitor->trace(m_bodyStreamBuffer);
- visitor->trace(m_stream);
- UnderlyingSource::trace(visitor);
- DrainingStreamNotificationClient::trace(visitor);
- }
+private:
+ RefPtrWillBeMember<ScriptPromiseResolver> m_resolver;
+};
- void close()
- {
- m_reader.clear();
- m_stream->close();
- if (m_bodyStreamBuffer)
- m_bodyStreamBuffer = BodyStreamBuffer::createEmpty();
-#if ENABLE(ASSERT)
- m_isCloseCalled = true;
-#endif
- }
+class BodyBlobConsumer final : public BodyConsumerBase {
+ WTF_MAKE_NONCOPYABLE(BodyBlobConsumer);
+public:
+ explicit BodyBlobConsumer(PassRefPtrWillBeRawPtr<ScriptPromiseResolver> resolver) : BodyConsumerBase(resolver) {}
- void error()
+ void didFetchDataLoadedBlobHandle(PassRefPtr<BlobDataHandle> blobDataHandle) override
{
- m_reader.clear();
- m_stream->error(DOMException::create(NetworkError, "network error"));
- if (m_bodyStreamBuffer)
- m_bodyStreamBuffer = BodyStreamBuffer::create(createFetchDataConsumerHandleFromWebHandle(createUnexpectedErrorDataConsumerHandle()));
-#if ENABLE(ASSERT)
- m_isErrorCalled = true;
-#endif
+ resolver()->resolve(Blob::create(blobDataHandle));
}
+};
-private:
- void obtainReader()
- {
- m_reader = m_bodyStreamBuffer->handle()->obtainReader(this);
- }
+class BodyArrayBufferConsumer final : public BodyConsumerBase {
+ WTF_MAKE_NONCOPYABLE(BodyArrayBufferConsumer);
+public:
+ explicit BodyArrayBufferConsumer(PassRefPtrWillBeRawPtr<ScriptPromiseResolver> resolver) : BodyConsumerBase(resolver) {}
- void didFetchDataLoadFinishedFromDrainingStream()
+ void didFetchDataLoadedArrayBuffer(PassRefPtr<DOMArrayBuffer> arrayBuffer) override
{
- ASSERT(m_bodyStreamBuffer);
- ASSERT(m_drained);
-
-#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();
+ resolver()->resolve(arrayBuffer);
}
+};
- void didGetReadable() override
- {
- 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;
- }
- }
-
- processData();
- }
+class BodyTextConsumer final : public BodyConsumerBase {
+ WTF_MAKE_NONCOPYABLE(BodyTextConsumer);
+public:
+ explicit BodyTextConsumer(PassRefPtrWillBeRawPtr<ScriptPromiseResolver> resolver) : BodyConsumerBase(resolver) {}
- // UnderlyingSource functions.
- void pullSource() override
+ void didFetchDataLoadedString(const String& string) override
{
- ASSERT(!m_streamNeedsMore);
- m_streamNeedsMore = true;
-
- ASSERT(!m_drained);
-
- processData();
+ resolver()->resolve(string);
}
+};
- ScriptPromise cancelSource(ScriptState* scriptState, ScriptValue reason) override
- {
- close();
- return ScriptPromise::cast(scriptState, v8::Undefined(scriptState->isolate()));
- }
+class BodyJsonConsumer final : public BodyConsumerBase {
+ WTF_MAKE_NONCOPYABLE(BodyJsonConsumer);
+public:
+ explicit BodyJsonConsumer(PassRefPtrWillBeRawPtr<ScriptPromiseResolver> resolver) : BodyConsumerBase(resolver) {}
- // Reads data and writes the data to |m_stream|, as long as data are
- // available and the stream has pending reads.
- void processData()
+ void didFetchDataLoadedString(const String& string) override
{
- 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;
- }
- }
+ if (!resolver()->executionContext() || resolver()->executionContext()->activeDOMObjectsAreStopped())
+ return;
+ ScriptState::Scope scope(resolver()->scriptState());
+ v8::Isolate* isolate = resolver()->scriptState()->isolate();
+ v8::Local<v8::String> inputString = v8String(isolate, string);
+ v8::TryCatch trycatch;
+ v8::Local<v8::Value> parsed;
+ if (v8Call(v8::JSON::Parse(isolate, inputString), parsed, trycatch))
+ resolver()->resolve(parsed);
+ else
+ resolver()->reject(trycatch.Exception());
}
-
- // Source of data.
- Member<BodyStreamBuffer> m_bodyStreamBuffer;
- OwnPtr<FetchDataConsumerHandle::Reader> m_reader;
-
- Member<ReadableByteStream> m_stream;
- bool m_streamNeedsMore;
-#if ENABLE(ASSERT)
- bool m_drained;
- bool m_isCloseCalled;
- bool m_isErrorCalled;
-#endif
};
-ScriptPromise Body::readAsync(ScriptState* scriptState, ResponseType type)
+} // namespace
+
+ScriptPromise Body::arrayBuffer(ScriptState* scriptState)
{
if (bodyUsed())
return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), "Already read"));
@@ -213,256 +113,82 @@ ScriptPromise Body::readAsync(ScriptState* scriptState, ResponseType type)
// first check the ExecutionContext and return immediately if it's already
// gone (which means that the V8::TerminateExecution() signal has been sent
// to this worker thread).
- ExecutionContext* executionContext = scriptState->executionContext();
- if (!executionContext)
+ if (!scriptState->executionContext())
return ScriptPromise();
- lockBody();
- m_responseType = type;
-
- ASSERT(!m_resolver);
- m_resolver = ScriptPromiseResolver::create(scriptState);
- ScriptPromise promise = m_resolver->promise();
-
- if (m_stream->stateInternal() == ReadableStream::Closed) {
- resolveWithEmptyDataSynchronously();
- } else if (m_stream->stateInternal() == ReadableStream::Errored) {
- m_resolver->reject(m_stream->storedException());
- m_resolver.clear();
- } else {
- readAsyncFromDrainingBodyStreamBuffer(createDrainingStream(), mimeType());
- }
+ RefPtrWillBeRawPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
+ ScriptPromise promise = resolver->promise();
+ bodyBuffer()->startLoading(scriptState->executionContext(), FetchDataLoader::createLoaderAsArrayBuffer(), new BodyArrayBufferConsumer(resolver));
return promise;
}
-void Body::resolveWithEmptyDataSynchronously()
-{
- // 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();
-}
-
-void Body::readAsyncFromDrainingBodyStreamBuffer(PassOwnPtr<DrainingBodyStreamBuffer> buffer, const String& mimeType)
+ScriptPromise Body::blob(ScriptState* scriptState)
{
- 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;
+ if (bodyUsed())
+ return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), "Already read"));
- case ResponseAsFormData:
- // FIXME: Implement this.
- ASSERT_NOT_REACHED();
- return;
+ // See above comment.
+ if (!scriptState->executionContext())
+ return ScriptPromise();
- default:
- ASSERT_NOT_REACHED();
- return;
- }
+ RefPtrWillBeRawPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
+ ScriptPromise promise = resolver->promise();
+ bodyBuffer()->startLoading(scriptState->executionContext(), FetchDataLoader::createLoaderAsBlobHandle(mimeType()), new BodyBlobConsumer(resolver));
+ return promise;
- buffer->startLoading(fetchDataLoader, this);
}
-ScriptPromise Body::arrayBuffer(ScriptState* scriptState)
-{
- return readAsync(scriptState, ResponseAsArrayBuffer);
-}
-
-ScriptPromise Body::blob(ScriptState* scriptState)
+ScriptPromise Body::json(ScriptState* scriptState)
{
- return readAsync(scriptState, ResponseAsBlob);
-}
+ if (bodyUsed())
+ return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), "Already read"));
-ScriptPromise Body::formData(ScriptState* scriptState)
-{
- return readAsync(scriptState, ResponseAsFormData);
-}
+ // See above comment.
+ if (!scriptState->executionContext())
+ return ScriptPromise();
-ScriptPromise Body::json(ScriptState* scriptState)
-{
- return readAsync(scriptState, ResponseAsJSON);
+ RefPtrWillBeRawPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
+ ScriptPromise promise = resolver->promise();
+ bodyBuffer()->startLoading(scriptState->executionContext(), FetchDataLoader::createLoaderAsString(), new BodyJsonConsumer(resolver));
+ return promise;
}
ScriptPromise Body::text(ScriptState* scriptState)
{
- return readAsync(scriptState, ResponseAsText);
-}
-
-ReadableByteStream* Body::body()
-{
- UseCounter::count(executionContext(), UseCounter::FetchBodyStream);
- return m_stream;
-}
+ if (bodyUsed())
+ return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), "Already read"));
-bool Body::bodyUsed() const
-{
- return m_bodyUsed || m_stream->isLocked();
-}
+ // See above comment.
+ if (!scriptState->executionContext())
+ return ScriptPromise();
-void Body::lockBody(LockBodyOption option)
-{
- ASSERT(!bodyUsed());
- if (option == PassBody)
- m_bodyUsed = true;
- ASSERT(!m_stream->isLocked());
- TrackExceptionState exceptionState;
- m_stream->getBytesReader(executionContext(), exceptionState);
- ASSERT(!exceptionState.hadException());
+ RefPtrWillBeRawPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
+ ScriptPromise promise = resolver->promise();
+ bodyBuffer()->startLoading(scriptState->executionContext(), FetchDataLoader::createLoaderAsString(), new BodyTextConsumer(resolver));
+ return promise;
}
-void Body::setBody(BodyStreamBuffer* buffer)
+ReadableByteStream* Body::body()
{
- m_streamSource = new ReadableStreamSource(executionContext(), buffer);
- m_stream = new ReadableByteStream(m_streamSource, new ReadableByteStream::StrictStrategy);
- m_streamSource->startStream(m_stream);
+ UseCounter::count(executionContext(), UseCounter::FetchBodyStream);
+ return bodyBuffer()->stream();
}
-PassOwnPtr<DrainingBodyStreamBuffer> Body::createDrainingStream()
+bool Body::bodyUsed()
{
- return m_streamSource->createDrainingStream();
+ return m_bodyPassed || body()->isLocked();
}
bool Body::hasPendingActivity() const
{
if (executionContext()->activeDOMObjectsAreStopped())
return false;
- if (m_resolver)
- return true;
- if (m_stream->isLocked())
- return true;
- return false;
-}
-
-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, nullptr))
- , m_stream(new ReadableByteStream(m_streamSource, new ReadableByteStream::StrictStrategy))
-{
- m_streamSource->startStream(m_stream);
-}
-
-void Body::resolveJSON(const String& string)
-{
- ASSERT(m_responseType == ResponseAsJSON);
- ScriptState::Scope scope(m_resolver->scriptState());
- v8::Isolate* isolate = m_resolver->scriptState()->isolate();
- v8::Local<v8::String> inputString = v8String(isolate, string);
- v8::TryCatch trycatch;
- v8::Local<v8::Value> parsed;
- if (v8Call(v8::JSON::Parse(isolate, inputString), parsed, trycatch))
- m_resolver->resolve(parsed);
- else
- m_resolver->reject(trycatch.Exception());
-}
-
-// FetchDataLoader::Client functions.
-void Body::didFetchDataLoadFailed()
-{
- if (!executionContext() || executionContext()->activeDOMObjectsAreStopped())
- return;
-
- 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();
- }
-}
-
-void Body::didFetchDataLoadedBlobHandle(PassRefPtr<BlobDataHandle> blobDataHandle)
-{
- if (!executionContext() || executionContext()->activeDOMObjectsAreStopped())
- return;
-
- ASSERT(m_responseType == ResponseAsBlob);
- m_resolver->resolve(Blob::create(blobDataHandle));
- m_resolver.clear();
+ return bodyBuffer()->hasPendingActivity();
}
-void Body::didFetchDataLoadedArrayBuffer(PassRefPtr<DOMArrayBuffer> arrayBuffer)
+Body::Body(ExecutionContext* context) : ActiveDOMObject(context), m_bodyPassed(false)
{
- if (!executionContext() || executionContext()->activeDOMObjectsAreStopped())
- return;
-
- ASSERT(m_responseType == ResponseAsArrayBuffer);
- m_resolver->resolve(arrayBuffer);
- m_resolver.clear();
-}
-
-void Body::didFetchDataLoadedString(const String& str)
-{
- if (!executionContext() || executionContext()->activeDOMObjectsAreStopped())
- return;
-
- switch (m_responseType) {
- case ResponseAsJSON:
- resolveJSON(str);
- break;
- case ResponseAsText:
- m_resolver->resolve(str);
- break;
- default:
- ASSERT_NOT_REACHED();
- }
-
- m_resolver.clear();
+ suspendIfNeeded();
}
} // namespace blink
« no previous file with comments | « Source/modules/fetch/Body.h ('k') | Source/modules/fetch/BodyStreamBuffer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698