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

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

Issue 2292763002: [Fetch API] Implement Request.formData and Response.formData. (Closed)
Patch Set: Handle partial delimiter prefixes correctly and really test them 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 47a95f29a2286e508e112ffa053ebabe0ab204f6..23e0733aba8289e9abb58a88d5256a087102f5a2 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"
@@ -161,6 +166,162 @@ private:
std::unique_ptr<ArrayBufferBuilder> m_rawData;
};
+class FetchDataLoaderAsFormData final : public FetchDataLoader, public BytesConsumer::Client, private MultipartParser::Client {
yhirano 2016/09/07 06:00:16 Why do you use private inheritance?
e_hakkinen 2016/09/08 00:06:29 Because public inheritance is not needed. I'll use
yhirano 2016/09/12 02:20:49 Thanks, I think public is preferred (https://googl
+ 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();
+ 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 (!m_multipartParser->isCancelled()) {
+ const char* buffer;
+ size_t available;
+ switch (m_consumer->beginRead(&buffer, &available)) {
+ case BytesConsumer::Result::Ok:
+ if (available > 0) {
+ if (!m_multipartParser->appendData(buffer, available))
+ m_client->didFetchDataLoadFailed();
yhirano 2016/09/07 06:00:16 +m_consumer->cancel();
e_hakkinen 2016/09/08 00:06:29 Done.
+ }
+ m_consumer->endRead(available);
+ break;
+ case BytesConsumer::Result::ShouldWait:
+ return;
+ case BytesConsumer::Result::Done:
+ if (m_multipartParser->finish()) {
+ m_client->didFetchDataLoadedFormData(m_formData);
+ } else {
+ m_client->didFetchDataLoadFailed();
+ }
+ return;
+ case BytesConsumer::Result::Error:
+ 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_client->didFetchDataLoadFailed();
+ // The client does not like to be notified multiple times thus stop
+ // parsing so that no more errors will be reached.
+ m_multipartParser->cancel();
yhirano 2016/09/07 06:00:16 +m_consumer->cancel();
e_hakkinen 2016/09/08 00:06:29 Done.
+ }
+ }
+
+ void partDataInMultipartReceived(const char* bytes, size_t size) override
+ {
+ m_currentEntry.appendBytes(bytes, size);
+ }
+
+ void partDataInMultipartFullyReceived() override
+ {
+ m_currentEntry.finish(m_formData);
+ }
+
+ class Entry {
+ public:
+ bool initialize(const ResourceResponse& response)
+ {
+ ParsedContentType disposition(response.httpHeaderField(HTTPNames::Content_Disposition));
+ String dispositionType = disposition.mimeType();
+ m_filename = disposition.parameterValueForName("filename");
+ m_name = disposition.parameterValueForName("name");
yhirano 2016/09/07 06:00:16 I would prefer clearing members unconditionally he
e_hakkinen 2016/09/08 00:06:29 Done.
+ 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));
+ m_stringBuilder.reset();
+ } else {
+ m_blobData.reset();
+ if (!m_decoder)
+ m_decoder = TextResourceDecoder::createAlwaysUseUTF8ForText();
+ m_stringBuilder.reset(new StringBuilder);
+ }
+ return true;
+ }
+
+ void 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));
yhirano 2016/09/07 06:00:16 You need to check m_decoder->sawError.
e_hakkinen 2016/09/08 00:06:29 Done.
+ }
+
+ void finish(FormData* formData)
+ {
+ if (m_blobData) {
+ DCHECK(!m_stringBuilder);
+ auto size = m_blobData->length();
+ 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());
yhirano 2016/09/07 06:00:16 You need to check m_decoder->sawError.
e_hakkinen 2016/09/08 00:06:29 Done.
+ formData->append(m_name, m_stringBuilder->toString());
+ }
+ }
+
+ 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:
@@ -305,6 +466,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