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

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

Issue 2292763002: [Fetch API] Implement Request.formData and Response.formData. (Closed)
Patch Set: Parse functions etc 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..f4c7c79f4a7e411bdd14a0cb34c65ba4836570b3 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,178 @@ private:
std::unique_ptr<ArrayBufferBuilder> m_rawData;
};
+class FetchDataLoaderAsFormData final : public FetchDataLoader, public BytesConsumer::Client, public MultipartParser::Client {
yhirano 2016/09/21 09:02:57 Please add unittests.
e_hakkinen 2016/09/22 22:27:15 Done.
+ 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))
+ failed();
yhirano 2016/09/21 09:02:57 BytesConsumer::cancel cannot be called in a two-ph
e_hakkinen 2016/09/22 22:27:15 Done.
+ }
+ if (m_consumer->endRead(available) != BytesConsumer::Result::Ok) {
yhirano 2016/09/21 09:02:57 I recently changed BytesConsumer::endRead so that
e_hakkinen 2016/09/22 22:27:16 Done.
+ m_client->didFetchDataLoadFailed();
yhirano 2016/09/21 09:02:57 failed()?
e_hakkinen 2016/09/22 22:27:16 Yeah, but there is not really need for failed() to
+ return;
+ }
+ 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 failed()
+ {
+ m_client->didFetchDataLoadFailed();
+ // The client does not like to be notified multiple times thus stop
+ // parsing so that no more errors will be reached.
+ cancel();
+ }
+
+ void partHeaderFieldsInMultipartReceived(const ResourceResponse& response) override
+ {
+ if (!m_currentEntry.initialize(response))
+ failed();
+ }
+
+ void partDataInMultipartReceived(const char* bytes, size_t size) override
+ {
+ if (!m_currentEntry.appendBytes(bytes, size))
+ failed();
+ }
+
+ void partDataInMultipartFullyReceived() override
+ {
+ if (!m_currentEntry.finish(m_formData))
+ failed();
+ }
+
+ 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");
+ 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 {
+ if (!m_decoder)
+ m_decoder = TextResourceDecoder::createAlwaysUseUTF8ForText();
+ 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();
+ 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 +496,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