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

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

Issue 2292763002: [Fetch API] Implement Request.formData and Response.formData. (Closed)
Patch Set: Created 3 years, 11 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 cb76438f1b76c3acc2f85c3bd824085cf010fa9e..b8f0c953c6ffe9a2341abe277295092128c8f019 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/File.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 @@ class FetchDataLoaderAsArrayBuffer final : public FetchDataLoader,
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_consumer);
+ DCHECK(!m_formData);
+ DCHECK(!m_multipartParser);
+
+ const CString multipartBoundaryCString = m_multipartBoundary.utf8();
yhirano 2017/01/11 08:54:03 Is this variable needed? Isn't it enough to run |m
e_hakkinen 2017/05/02 23:38:56 |Utf8()| is not a getter but a conversion function
+ 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) {
+ const bool bufferAppended =
+ m_multipartParser->appendData(buffer, available);
+ const bool multipartReceiveFailed = m_multipartParser->isCancelled();
+ result = m_consumer->endRead(available);
+ if (!bufferAppended || multipartReceiveFailed)
+ result = BytesConsumer::Result::Error;
+ }
+ switch (result) {
+ case BytesConsumer::Result::Ok:
+ break;
+ case BytesConsumer::Result::ShouldWait:
+ NOTREACHED();
+ return;
+ case BytesConsumer::Result::Done:
+ if (m_multipartParser->finish()) {
+ DCHECK(!m_multipartParser->isCancelled());
+ m_client->didFetchDataLoadedFormData(m_formData);
+ return;
+ }
+ // Fall throught.
yhirano 2017/01/11 08:54:03 Can you write m_client->didFetchDataLoadFailed() h
e_hakkinen 2017/05/02 23:38:56 Done.
+ 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 HTTPHeaderMap& headerFields) override {
+ if (!m_currentEntry.initialize(headerFields))
+ m_multipartParser->cancel();
yhirano 2017/01/11 08:54:03 Shouldn't be this cancel() (i.e., this->cancel())?
e_hakkinen 2017/05/02 23:38:56 No, it should not. This member function is called
+ }
+
+ 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 HTTPHeaderMap& headerFields) {
+ const ParsedContentType disposition(
+ headerFields.get(HTTPNames::Content_Disposition));
+ const 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();
+ const AtomicString& contentType =
+ headerFields.get(HTTPNames::Content_Type);
+ m_blobData->setContentType(contentType.isNull() ? "text/plain"
+ : contentType);
+ } 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);
+ const auto size = m_blobData->length();
+ File* file =
+ File::create(m_filename, invalidFileTime(),
+ BlobDataHandle::create(std::move(m_blobData), size));
+ formData->append(m_name, file, 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);
@@ -316,6 +491,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