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

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

Issue 1265413002: Introduce FetchFormDataConsumerHandle. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 5 years, 4 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
Index: Source/modules/fetch/FetchFormDataConsumerHandle.cpp
diff --git a/Source/modules/fetch/FetchFormDataConsumerHandle.cpp b/Source/modules/fetch/FetchFormDataConsumerHandle.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ec269b770b1586dc99f9d9e076cec07ad0bb4bbf
--- /dev/null
+++ b/Source/modules/fetch/FetchFormDataConsumerHandle.cpp
@@ -0,0 +1,322 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "modules/fetch/FetchFormDataConsumerHandle.h"
+
+#include "modules/fetch/DataConsumerHandleUtil.h"
+#include "modules/fetch/FetchBlobDataConsumerHandle.h"
+#include "wtf/ThreadSafeRefCounted.h"
+#include "wtf/ThreadingPrimitives.h"
+#include "wtf/Vector.h"
+#include "wtf/text/TextCodec.h"
+#include "wtf/text/TextEncoding.h"
+#include "wtf/text/WTFString.h"
+
+#include <utility>
+
+namespace blink {
+
+using Result = FetchDataConsumerHandle::Result;
+
+namespace {
+
+bool isSimple(const FormData* formData)
+{
+ for (const auto& element : formData->elements()) {
+ if (element.m_type != FormDataElement::data)
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+class FetchFormDataConsumerHandle::Context : public ThreadSafeRefCounted<Context> {
+ WTF_MAKE_NONCOPYABLE(Context);
+public:
+ virtual ~Context() {}
+ virtual PassOwnPtr<FetchDataConsumerHandle::Reader> obtainReader(Client*) = 0;
+
+protected:
+ explicit Context() {}
+};
+
+class FetchFormDataConsumerHandle::SimpleContext final : public Context {
+ class ReaderImpl;
+public:
+ static PassRefPtr<SimpleContext> create(const String& body) { return adoptRef(new SimpleContext(body)); }
+ static PassRefPtr<SimpleContext> create(const void* data, size_t size) { return adoptRef(new SimpleContext(data, size)); }
+ static PassRefPtr<SimpleContext> create(PassRefPtr<FormData> body) { return adoptRef(new SimpleContext(body)); }
+
+ PassOwnPtr<Reader> obtainReader(Client* client) override
+ {
+ // For memory barrier.
+ Mutex m;
+ MutexLocker locker(m);
+ return ReaderImpl::create(this, client);
+ }
+
+ PassRefPtr<FormData> drainFormData()
+ {
+ ASSERT(!m_formData || m_formData->isSafeToSendToAnotherThread());
+ return m_formData.release();
+ }
+
+ Result read(void* data, size_t size, Flags flags, size_t* readSize)
+ {
+ *readSize = 0;
+ if (size == 0 && m_formData)
+ return WebDataConsumerHandle::Ok;
+
+ flatten();
+ RELEASE_ASSERT(m_flattenFormDataOffset <= m_flattenFormData.size());
+
+ *readSize = std::min(size, m_flattenFormData.size() - m_flattenFormDataOffset);
+ if (*readSize == 0)
+ return WebDataConsumerHandle::Done;
+ memcpy(data, &m_flattenFormData[m_flattenFormDataOffset], *readSize);
+ m_flattenFormDataOffset += *readSize;
+ RELEASE_ASSERT(m_flattenFormDataOffset <= m_flattenFormData.size());
+
+ return WebDataConsumerHandle::Ok;
+ }
+
+ Result beginRead(const void** buffer, Flags flags, size_t* available)
+ {
+ *buffer = nullptr;
+ *available = 0;
+
+ flatten();
+ RELEASE_ASSERT(m_flattenFormDataOffset <= m_flattenFormData.size());
+
+ if (m_flattenFormData.size() == m_flattenFormDataOffset)
+ return WebDataConsumerHandle::Done;
+ *buffer = &m_flattenFormData[m_flattenFormDataOffset];
+ *available = m_flattenFormData.size() - m_flattenFormDataOffset;
+ return WebDataConsumerHandle::Ok;
+ }
+
+ Result endRead(size_t read)
+ {
+ RELEASE_ASSERT(m_flattenFormDataOffset <= m_flattenFormData.size());
+ RELEASE_ASSERT(read <= m_flattenFormData.size() - m_flattenFormDataOffset);
+ m_flattenFormDataOffset += read;
+
+ return WebDataConsumerHandle::Ok;
+ }
+
+private:
+ class ReaderImpl final : public FetchDataConsumerHandle::Reader {
+ WTF_MAKE_NONCOPYABLE(ReaderImpl);
+ public:
+ static PassOwnPtr<ReaderImpl> create(PassRefPtr<SimpleContext> context, Client* client) { return adoptPtr(new ReaderImpl(context, client)); }
+ Result read(void* data, size_t size, Flags flags, size_t* readSize) override
+ {
+ return m_context->read(data, size, flags, readSize);
+ }
+ Result beginRead(const void** buffer, Flags flags, size_t* available) override
+ {
+ return m_context->beginRead(buffer, flags, available);
+ }
+ Result endRead(size_t read) override
+ {
+ return m_context->endRead(read);
+ }
+ PassRefPtr<FormData> drainAsFormData() override
+ {
+ return m_context->drainFormData();
+ }
+
+ private:
+ ReaderImpl(PassRefPtr<SimpleContext> context, Client* client) : m_context(context), m_notifier(client) {}
+
+ RefPtr<SimpleContext> m_context;
+ NotifyOnReaderCreationHelper m_notifier;
+ };
+
+ explicit SimpleContext(const String& body)
+ : m_formData(FormData::create(UTF8Encoding().encode(body, WTF::EntitiesForUnencodables)))
+ , m_flattenFormDataOffset(0) {}
+ explicit SimpleContext(const void* data, size_t size) : m_formData(FormData::create(data, size)) , m_flattenFormDataOffset(0) {}
+ explicit SimpleContext(PassRefPtr<FormData> body) : m_formData(body->deepCopy()) , m_flattenFormDataOffset(0) {}
+
+ void flatten()
+ {
+ if (!m_formData) {
+ // It is already drained or flatten.
+ return;
+ }
+ ASSERT(m_formData->isSafeToSendToAnotherThread());
+ m_formData->flatten(m_flattenFormData);
+ m_formData = nullptr;
+ }
+
+ // either one of |m_formData| and |m_flattenFormData| is usable at a time.
+ RefPtr<FormData> m_formData;
+ Vector<char> m_flattenFormData;
+ size_t m_flattenFormDataOffset;
+};
+
+class FetchFormDataConsumerHandle::ComplexContext final : public Context {
+ class ReaderImpl;
+public:
+ static PassRefPtr<ComplexContext> create(ExecutionContext* executionContext,
+ PassRefPtr<FormData> formData,
+ FetchBlobDataConsumerHandle::LoaderFactory* factory)
+ {
+ return adoptRef(new ComplexContext(executionContext, formData, factory));
+ }
+
+ PassOwnPtr<FetchFormDataConsumerHandle::Reader> obtainReader(Client* client) override
+ {
+ // For memory barrier.
+ Mutex m;
+ MutexLocker locker(m);
+ return ReaderImpl::create(this, client);
+ }
+
+private:
+ class ReaderImpl final : public FetchDataConsumerHandle::Reader {
+ WTF_MAKE_NONCOPYABLE(ReaderImpl);
+ public:
+ static PassOwnPtr<ReaderImpl> create(PassRefPtr<ComplexContext> context, Client* client) { return adoptPtr(new ReaderImpl(context, client)); }
+ Result read(void* data, size_t size, Flags flags, size_t* readSize) override
+ {
+ Result r = m_reader->read(data, size, flags, readSize);
+ if (!(size == 0 && (r == Ok || r == ShouldWait))) {
+ m_context->drainFormData();
+ }
+ return r;
+ }
+ Result beginRead(const void** buffer, Flags flags, size_t* available) override
+ {
+ m_context->drainFormData();
+ return m_reader->beginRead(buffer, flags, available);
+ }
+ Result endRead(size_t read) override
+ {
+ return m_reader->endRead(read);
+ }
+ PassRefPtr<BlobDataHandle> drainAsBlobDataHandle(BlobSizePolicy policy) override
+ {
+ RefPtr<BlobDataHandle> handle = m_reader->drainAsBlobDataHandle(policy);
+ if (handle) {
+ m_context->drainFormData();
+ }
+ return handle.release();
+ }
+ PassRefPtr<FormData> drainAsFormData() override
+ {
+ RefPtr<FormData> formData = m_context->drainFormData();
+ if (formData) {
+ // Drain blob from the underlying handle to mark data as read.
+ RefPtr<BlobDataHandle> handle = m_reader->drainAsBlobDataHandle(AllowBlobWithInvalidSize);
+ // Here we assume we can always get the valid handle. That is
+ // in fact not specified at FetchDataConsumerHandle level, but
+ // |m_context->m_handle| is a FetchBlobDataConsumerHandle.
+ ASSERT(handle);
+ }
+ return formData.release();
+ }
+ private:
+ ReaderImpl(PassRefPtr<ComplexContext> context, Client* client) : m_context(context), m_reader(m_context->m_handle->obtainReader(client)) {}
+
+ RefPtr<ComplexContext> m_context;
+ OwnPtr<FetchDataConsumerHandle::Reader> m_reader;
+ };
+
+ explicit ComplexContext(ExecutionContext* executionContext, PassRefPtr<FormData> body, FetchBlobDataConsumerHandle::LoaderFactory* factory)
+ {
+ OwnPtr<BlobData> blobData = BlobData::create();
+ for (const auto& element : body->elements()) {
+ switch (element.m_type) {
+ case FormDataElement::data:
+ blobData->appendBytes(element.m_data.data(), element.m_data.size());
+ break;
+ case FormDataElement::encodedFile:
+ blobData->appendFile(element.m_filename, element.m_fileStart, element.m_fileLength, element.m_expectedFileModificationTime);
+ break;
+ case FormDataElement::encodedBlob:
+ if (element.m_optionalBlobDataHandle)
+ blobData->appendBlob(element.m_optionalBlobDataHandle, 0, element.m_optionalBlobDataHandle->size());
+ break;
+ case FormDataElement::encodedFileSystemURL:
+ blobData->appendFileSystemURL(element.m_fileSystemURL, element.m_fileStart, element.m_fileLength, element.m_expectedFileModificationTime);
+ break;
+ }
+ }
+ // Here we handle body->boundary() as a C-style string. See
+ // FormDataBuilder::generateUniqueBoundaryString.
+ blobData->setContentType(AtomicString("multipart/form-data; boundary=", AtomicString::ConstructFromLiteral) + body->boundary().data());
+ auto size = blobData->length();
+ if (factory) {
+ // For testing
+ m_handle = FetchBlobDataConsumerHandle::create(executionContext, BlobDataHandle::create(blobData.release(), size), factory);
+ } else {
+ m_handle = FetchBlobDataConsumerHandle::create(executionContext, BlobDataHandle::create(blobData.release(), size));
+ }
+ // It is important to initialize |m_formData| here, because even
+ // read-only operations may make the form data unsharable with implicit
+ // ref-counting.
+ m_formData = body->deepCopy();
+ }
+ PassRefPtr<FormData> drainFormData()
+ {
+ ASSERT(!m_formData || m_formData->isSafeToSendToAnotherThread());
+ return m_formData.release();
+ }
+
+ RefPtr<FormData> m_formData;
+ OwnPtr<FetchDataConsumerHandle> m_handle;
+};
+
+PassOwnPtr<FetchDataConsumerHandle> FetchFormDataConsumerHandle::create(const String& body)
+{
+ return adoptPtr(new FetchFormDataConsumerHandle(body));
+}
+PassOwnPtr<FetchDataConsumerHandle> FetchFormDataConsumerHandle::create(PassRefPtr<DOMArrayBuffer> body)
+{
+ return adoptPtr(new FetchFormDataConsumerHandle(body->data(), body->byteLength()));
+}
+PassOwnPtr<FetchDataConsumerHandle> FetchFormDataConsumerHandle::create(PassRefPtr<DOMArrayBufferView> body)
+{
+ return adoptPtr(new FetchFormDataConsumerHandle(body->baseAddress(), body->byteLength()));
+}
+PassOwnPtr<FetchDataConsumerHandle> FetchFormDataConsumerHandle::create(const void* data, size_t size)
+{
+ return adoptPtr(new FetchFormDataConsumerHandle(data, size));
+}
+PassOwnPtr<FetchDataConsumerHandle> FetchFormDataConsumerHandle::create(ExecutionContext* executionContext, PassRefPtr<FormData> body)
+{
+ return adoptPtr(new FetchFormDataConsumerHandle(executionContext, body));
+}
+PassOwnPtr<FetchDataConsumerHandle> FetchFormDataConsumerHandle::createForTest(
+ ExecutionContext* executionContext,
+ PassRefPtr<FormData> body,
+ FetchBlobDataConsumerHandle::LoaderFactory* loaderFactory)
+{
+ return adoptPtr(new FetchFormDataConsumerHandle(executionContext, body, loaderFactory));
+}
+
+FetchFormDataConsumerHandle::FetchFormDataConsumerHandle(const String& body) : m_context(SimpleContext::create(body)) {}
+FetchFormDataConsumerHandle::FetchFormDataConsumerHandle(const void* data, size_t size) : m_context(SimpleContext::create(data, size)) {}
+FetchFormDataConsumerHandle::FetchFormDataConsumerHandle(ExecutionContext* executionContext,
+ PassRefPtr<FormData> body,
+ FetchBlobDataConsumerHandle::LoaderFactory* loaderFactory)
+{
+ if (isSimple(body.get())) {
+ m_context = SimpleContext::create(body);
+ } else {
+ m_context = ComplexContext::create(executionContext, body, loaderFactory);
+ }
+}
+FetchFormDataConsumerHandle::~FetchFormDataConsumerHandle() {}
+
+FetchDataConsumerHandle::Reader* FetchFormDataConsumerHandle::obtainReaderInternal(Client* client)
+{
+ return m_context->obtainReader(client).leakPtr();
+}
+
+} // namespace blink
« no previous file with comments | « Source/modules/fetch/FetchFormDataConsumerHandle.h ('k') | Source/modules/fetch/FetchFormDataConsumerHandleTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698