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

Unified Diff: third_party/WebKit/Source/modules/fetch/FetchDataLoader.cpp

Issue 2292763002: [Fetch API] Implement Request.formData and Response.formData. (Closed)
Patch Set: Created 4 years, 3 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: third_party/WebKit/Source/modules/fetch/FetchDataLoader.cpp
diff --git a/third_party/WebKit/Source/modules/fetch/FetchDataLoader.cpp b/third_party/WebKit/Source/modules/fetch/FetchDataLoader.cpp
index 1c2e04da558ed62ec689bb10c226fd58dd62e337..566724aa35787f35072ce509316df8d7aa2b1437 100644
--- a/third_party/WebKit/Source/modules/fetch/FetchDataLoader.cpp
+++ b/third_party/WebKit/Source/modules/fetch/FetchDataLoader.cpp
@@ -4,8 +4,13 @@
#include "modules/fetch/FetchDataLoader.h"
+#include "core/fileapi/Blob.h"
+#include "core/html/FormData.h"
#include "core/html/parser/TextResourceDecoder.h"
#include "modules/fetch/BytesConsumer.h"
+#include "modules/fetch/MultipartParser.h"
+#include "platform/HTTPNames.h"
+#include "platform/network/ParsedContentType.h"
#include "wtf/PtrUtil.h"
#include "wtf/text/StringBuilder.h"
#include "wtf/text/WTFString.h"
@@ -168,6 +173,176 @@ private:
std::unique_ptr<ArrayBufferBuilder> m_rawData;
};
+class FetchDataLoaderAsFormData final : public FetchDataLoader, public BytesConsumer::Client, public MultipartParser::Client {
+ USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsFormData);
+
+public:
+ explicit FetchDataLoaderAsFormData(const String& multipartBoundary)
+ : m_multipartBoundary(multipartBoundary)
+ {
+ }
+
+ void start(BytesConsumer* consumer, FetchDataLoader::Client* client) override
+ {
+ DCHECK(!m_client);
+ DCHECK(!m_multipartParser);
+ DCHECK(!m_consumer);
+
+ CString multipartBoundaryCString = m_multipartBoundary.utf8();
horo 2016/09/27 10:45:49 nit: const
e_hakkinen 2016/09/28 15:15:04 Done.
+ Vector<char> multipartBoundaryVector;
+ multipartBoundaryVector.append(multipartBoundaryCString.data(), multipartBoundaryCString.length());
+
+ m_client = client;
+ m_formData = FormData::create();
+ m_multipartParser = new MultipartParser(std::move(multipartBoundaryVector), this);
+ m_consumer = consumer;
+ m_consumer->setClient(this);
+ onStateChange();
+ }
+
+ void onStateChange() override
+ {
+ while (true) {
+ const char* buffer;
+ size_t available;
+ auto result = m_consumer->beginRead(&buffer, &available);
+ if (result == BytesConsumer::Result::ShouldWait)
+ return;
+ if (result == BytesConsumer::Result::Ok) {
+ bool bufferAppended = m_multipartParser->appendData(buffer, available);
horo 2016/09/27 10:45:49 nit: const
e_hakkinen 2016/09/28 15:15:04 Done.
+ bool multipartReceiveFailed = m_multipartParser->isCancelled();
horo 2016/09/27 10:45:49 nit: const
e_hakkinen 2016/09/28 15:15:04 Done.
+ result = m_consumer->endRead(available);
+ if (!bufferAppended || multipartReceiveFailed)
+ result = BytesConsumer::Result::Error;
+ }
+ if (result == BytesConsumer::Result::Done) {
+ if (m_multipartParser->finish()) {
yhirano 2016/09/26 10:59:34 Why don't you move this section into the below swi
e_hakkinen 2016/09/28 15:15:04 Maybe done. I am not if I understood correctly wha
+ DCHECK(!m_multipartParser->isCancelled());
+ m_client->didFetchDataLoadedFormData(m_formData);
+ return;
+ }
+ result = BytesConsumer::Result::Error;
+ }
+ switch (result) {
+ case BytesConsumer::Result::Ok:
+ break;
+ case BytesConsumer::Result::ShouldWait:
+ case BytesConsumer::Result::Done:
+ NOTREACHED();
+ return;
+ case BytesConsumer::Result::Error:
+ cancel();
+ m_client->didFetchDataLoadFailed();
+ return;
+ }
+ }
+ }
+
+ void cancel() override
+ {
+ m_consumer->cancel();
+ m_multipartParser->cancel();
+ }
+
+ DEFINE_INLINE_TRACE()
+ {
+ visitor->trace(m_consumer);
+ visitor->trace(m_client);
+ visitor->trace(m_formData);
+ visitor->trace(m_multipartParser);
+ FetchDataLoader::trace(visitor);
+ BytesConsumer::Client::trace(visitor);
+ MultipartParser::Client::trace(visitor);
+ }
+
+private:
+ void partHeaderFieldsInMultipartReceived(const ResourceResponse& response) override
+ {
+ if (!m_currentEntry.initialize(response))
+ m_multipartParser->cancel();
+ }
+
+ void partDataInMultipartReceived(const char* bytes, size_t size) override
+ {
+ if (!m_currentEntry.appendBytes(bytes, size))
+ m_multipartParser->cancel();
+ }
+
+ void partDataInMultipartFullyReceived() override
+ {
+ if (!m_currentEntry.finish(m_formData))
+ m_multipartParser->cancel();
+ }
+
+ class Entry {
+ public:
+ bool initialize(const ResourceResponse& response)
+ {
+ ParsedContentType disposition(response.httpHeaderField(HTTPNames::Content_Disposition));
horo 2016/09/27 10:45:50 nit: const
e_hakkinen 2016/09/28 15:15:04 Done.
+ String dispositionType = disposition.mimeType();
horo 2016/09/27 10:45:49 nit: const
e_hakkinen 2016/09/28 15:15:04 Done.
+ m_filename = disposition.parameterValueForName("filename");
+ m_name = disposition.parameterValueForName("name");
+ m_blobData.reset();
+ m_stringBuilder.reset();
+ if (dispositionType != "form-data" || m_name.isNull())
+ return false;
+ if (!m_filename.isNull()) {
+ m_blobData = BlobData::create();
+ m_blobData->setContentType(response.httpHeaderField(HTTPNames::Content_Type));
+ } else {
yhirano 2016/09/26 10:59:34 You're assuming that each part which doesn't have
e_hakkinen 2016/09/28 15:15:04 I am not sure as https://fetch.spec.whatwg.org/#co
yhirano 2016/09/29 08:30:09 If the spec is unclear, I think it's a good idea t
+ if (!m_decoder)
+ m_decoder = TextResourceDecoder::createAlwaysUseUTF8ForText();
yhirano 2016/09/26 10:59:34 Is always using utf-8 appropriate? https://tools.i
e_hakkinen 2016/09/28 15:15:04 I think so. The https://fetch.spec.whatwg.org/#co
+ m_stringBuilder.reset(new StringBuilder);
+ }
+ return true;
+ }
+
+ bool appendBytes(const char* bytes, size_t size)
+ {
+ if (m_blobData)
+ m_blobData->appendBytes(bytes, size);
+ if (m_stringBuilder) {
+ m_stringBuilder->append(m_decoder->decode(bytes, size));
+ if (m_decoder->sawError())
+ return false;
+ }
+ return true;
+ }
+
+ bool finish(FormData* formData)
+ {
+ if (m_blobData) {
+ DCHECK(!m_stringBuilder);
+ auto size = m_blobData->length();
horo 2016/09/27 10:45:49 nit: const
e_hakkinen 2016/09/28 15:15:04 Done.
+ formData->append(m_name, Blob::create(BlobDataHandle::create(std::move(m_blobData), size)), m_filename);
+ }
+ if (m_stringBuilder) {
+ DCHECK(!m_blobData);
+ m_stringBuilder->append(m_decoder->flush());
+ if (m_decoder->sawError())
+ return false;
+ formData->append(m_name, m_stringBuilder->toString());
+ }
+ return true;
+ }
+
+ private:
+ std::unique_ptr<BlobData> m_blobData;
+ std::unique_ptr<TextResourceDecoder> m_decoder;
+ String m_filename;
+ String m_name;
+ std::unique_ptr<StringBuilder> m_stringBuilder;
+ };
+
+ Member<BytesConsumer> m_consumer;
+ Member<FetchDataLoader::Client> m_client;
+ Member<FormData> m_formData;
+ Member<MultipartParser> m_multipartParser;
+
+ Entry m_currentEntry;
+ String m_multipartBoundary;
+};
+
class FetchDataLoaderAsString final : public FetchDataLoader, public BytesConsumer::Client {
USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsString);
public:
@@ -319,6 +494,11 @@ FetchDataLoader* FetchDataLoader::createLoaderAsArrayBuffer()
return new FetchDataLoaderAsArrayBuffer();
}
+FetchDataLoader* FetchDataLoader::createLoaderAsFormData(const String& multipartBoundary)
+{
+ return new FetchDataLoaderAsFormData(multipartBoundary);
+}
+
FetchDataLoader* FetchDataLoader::createLoaderAsString()
{
return new FetchDataLoaderAsString();

Powered by Google App Engine
This is Rietveld 408576698