Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "config.h" | |
| 6 #include "modules/fetch/FetchFormDataConsumerHandle.h" | |
| 7 | |
| 8 #include "core/dom/DOMArrayBuffer.h" | |
| 9 #include "modules/fetch/DataConsumerHandleUtil.h" | |
| 10 #include "modules/fetch/FetchBlobDataConsumerHandle.h" | |
| 11 #include "platform/network/FormData.h" | |
| 12 #include "wtf/ThreadSafeRefCounted.h" | |
| 13 #include "wtf/ThreadingPrimitives.h" | |
| 14 #include "wtf/Vector.h" | |
| 15 #include "wtf/text/TextCodec.h" | |
| 16 #include "wtf/text/TextEncoding.h" | |
| 17 #include "wtf/text/WTFString.h" | |
| 18 | |
| 19 #include <utility> | |
| 20 | |
| 21 namespace blink { | |
| 22 | |
| 23 using Result = FetchDataConsumerHandle::Result; | |
| 24 | |
| 25 class FetchFormDataConsumerHandle::Context final : public ThreadSafeRefCounted<C ontext> { | |
| 26 WTF_MAKE_NONCOPYABLE(Context); | |
| 27 public: | |
| 28 static PassRefPtr<Context> create(const String& body) { return adoptRef(new Context(body)); } | |
| 29 static PassRefPtr<Context> create(PassRefPtr<DOMArrayBuffer> body) { return adoptRef(new Context(body)); } | |
| 30 static PassRefPtr<Context> create(ExecutionContext* executionContext, PassRe fPtr<FormData> body, FetchBlobDataConsumerHandle::LoaderFactory* factory) | |
| 31 { | |
| 32 return adoptRef(new Context(executionContext, body, factory)); | |
| 33 } | |
| 34 | |
| 35 void obtainReader(Client* client) | |
| 36 { | |
| 37 if (m_handleForComplexFormData) { | |
|
hiroshige
2015/08/10 13:27:03
Switching by |m_handleForComplexFormData| seems co
yhirano
2015/08/11 06:08:43
I split Context into SimpleContext and ComplexCont
| |
| 38 m_readerForComplexFormData = m_handleForComplexFormData->obtainReade r(client); | |
| 39 } | |
| 40 } | |
| 41 | |
| 42 void releaseReader() | |
| 43 { | |
| 44 m_readerForComplexFormData = nullptr; | |
| 45 } | |
| 46 | |
| 47 Result read(void* data, size_t size, Flags flags, size_t* readSize) | |
| 48 { | |
| 49 if (m_readerForComplexFormData) { | |
| 50 Result r = m_readerForComplexFormData->read(data, size, flags, readS ize); | |
| 51 if (!((r == WebDataConsumerHandle::Ok && *readSize == 0) || r == Web DataConsumerHandle::ShouldWait)) { | |
| 52 // Something is read, so the form data should be disposed. | |
| 53 m_formData = nullptr; | |
| 54 } | |
| 55 return r; | |
| 56 } | |
| 57 | |
| 58 *readSize = 0; | |
| 59 if (size == 0) { | |
| 60 if (!m_formData && m_flattenFormData.size() == m_flattenFormDataOffs et) | |
| 61 return WebDataConsumerHandle::Done; | |
| 62 return WebDataConsumerHandle::Ok; | |
| 63 } | |
| 64 flatten(); | |
| 65 | |
| 66 *readSize = std::min(size, m_flattenFormData.size() - m_flattenFormDataO ffset); | |
| 67 if (*readSize == 0) | |
| 68 return WebDataConsumerHandle::Done; | |
| 69 memcpy(data, &m_flattenFormData[m_flattenFormDataOffset], *readSize); | |
| 70 m_flattenFormDataOffset += *readSize; | |
| 71 return WebDataConsumerHandle::Ok; | |
| 72 } | |
| 73 | |
| 74 Result beginRead(const void** buffer, Flags flags, size_t* available) | |
| 75 { | |
| 76 if (m_readerForComplexFormData) { | |
| 77 Result r = m_readerForComplexFormData->beginRead(buffer, flags, avai lable); | |
| 78 if (r != WebDataConsumerHandle::ShouldWait) { | |
| 79 // Something is read, so the form data should be disposed. | |
| 80 m_formData = nullptr; | |
| 81 } | |
| 82 return r; | |
| 83 } | |
| 84 | |
| 85 *buffer = nullptr; | |
| 86 *available = 0; | |
| 87 | |
| 88 flatten(); | |
| 89 if (m_flattenFormData.size() == m_flattenFormDataOffset) | |
| 90 return WebDataConsumerHandle::Done; | |
| 91 *buffer = &m_flattenFormData[m_flattenFormDataOffset]; | |
| 92 *available = m_flattenFormData.size() - m_flattenFormDataOffset; | |
| 93 return WebDataConsumerHandle::Ok; | |
| 94 } | |
| 95 | |
| 96 Result endRead(size_t read) | |
| 97 { | |
| 98 if (m_readerForComplexFormData) | |
| 99 return m_readerForComplexFormData->endRead(read); | |
| 100 | |
| 101 m_flattenFormDataOffset += read; | |
| 102 return WebDataConsumerHandle::Ok; | |
| 103 } | |
| 104 | |
| 105 PassRefPtr<FormData> drainFormData() | |
| 106 { | |
| 107 if (!m_formData) | |
| 108 return nullptr; | |
| 109 | |
| 110 ASSERT(m_formData->hasOneRef()); | |
| 111 if (m_readerForComplexFormData) { | |
| 112 // Note that m_formData must be null in a two-phase read and hence | |
| 113 // we can release the reader here. | |
| 114 m_readerForComplexFormData = nullptr; | |
| 115 m_handleForComplexFormData = nullptr; | |
| 116 } | |
| 117 ASSERT(!m_handleForComplexFormData); | |
| 118 return m_formData.release(); | |
| 119 } | |
| 120 | |
| 121 private: | |
| 122 explicit Context(const String& body) | |
| 123 : m_formData(FormData::create(UTF8Encoding().encode(body, WTF::EntitiesF orUnencodables))) | |
| 124 , m_flattenFormDataOffset(0) {} | |
| 125 explicit Context(PassRefPtr<DOMArrayBuffer> body) | |
| 126 : m_formData(FormData::create(body->data(), body->byteLength())) | |
| 127 , m_flattenFormDataOffset(0) {} | |
| 128 explicit Context(ExecutionContext* executionContext, PassRefPtr<FormData> bo dy, FetchBlobDataConsumerHandle::LoaderFactory* factory) | |
| 129 : m_formData(body->deepCopy()) | |
| 130 , m_flattenFormDataOffset(0) | |
| 131 { | |
| 132 for (const auto& element : m_formData->elements()) { | |
| 133 if (element.m_type != FormDataElement::data) { | |
| 134 // Non data type is found, so we need to use | |
| 135 // FetchBlobDataConsumerHandle. | |
| 136 createDataConsumerHandleForComplexFormData(executionContext, fac tory); | |
| 137 break; | |
| 138 } | |
| 139 } | |
| 140 } | |
| 141 | |
| 142 void createDataConsumerHandleForComplexFormData(ExecutionContext* executionC ontext, FetchBlobDataConsumerHandle::LoaderFactory* factory) | |
| 143 { | |
| 144 OwnPtr<BlobData> blobData = BlobData::create(); | |
| 145 for (const auto& element : m_formData->elements()) { | |
| 146 switch (element.m_type) { | |
| 147 case FormDataElement::data: { | |
|
hiroshige
2015/08/10 13:27:03
nit: can we remove "{" here and "}" in L150?
yhirano
2015/08/11 06:08:43
Done.
| |
| 148 blobData->appendBytes(element.m_data.data(), element.m_data.size ()); | |
| 149 break; | |
| 150 } | |
| 151 case FormDataElement::encodedFile: | |
| 152 blobData->appendFile(element.m_filename, element.m_fileStart, el ement.m_fileLength, element.m_expectedFileModificationTime); | |
| 153 break; | |
| 154 case FormDataElement::encodedBlob: | |
| 155 if (element.m_optionalBlobDataHandle) | |
| 156 blobData->appendBlob(element.m_optionalBlobDataHandle, 0, el ement.m_optionalBlobDataHandle->size()); | |
| 157 break; | |
| 158 case FormDataElement::encodedFileSystemURL: | |
| 159 blobData->appendFileSystemURL(element.m_fileSystemURL, element.m _fileStart, element.m_fileLength, element.m_expectedFileModificationTime); | |
| 160 break; | |
| 161 } | |
| 162 } | |
| 163 blobData->setContentType("multipart/form-data; boundary=" + String(m_for mData->boundary().data(), m_formData->boundary().size())); | |
| 164 auto size = blobData->length(); | |
| 165 if (factory) { | |
| 166 // For testing | |
| 167 m_handleForComplexFormData = FetchBlobDataConsumerHandle::create(exe cutionContext, BlobDataHandle::create(blobData.release(), size), factory); | |
| 168 } else { | |
| 169 m_handleForComplexFormData = FetchBlobDataConsumerHandle::create(exe cutionContext, BlobDataHandle::create(blobData.release(), size)); | |
| 170 } | |
| 171 } | |
| 172 | |
| 173 void flatten() | |
| 174 { | |
| 175 ASSERT(!m_handleForComplexFormData); | |
| 176 if (!m_formData) { | |
| 177 // It's already flatten or drained. | |
| 178 return; | |
| 179 } | |
| 180 m_formData->flatten(m_flattenFormData); | |
| 181 m_formData = nullptr; | |
| 182 } | |
| 183 | |
| 184 // Note this data is not shared by anyone and hence it is safe to pass | |
| 185 // around the data between threads. | |
| 186 RefPtr<FormData> m_formData; | |
| 187 Vector<char> m_flattenFormData; | |
| 188 size_t m_flattenFormDataOffset; | |
| 189 OwnPtr<WebDataConsumerHandle> m_handleForComplexFormData; | |
| 190 OwnPtr<WebDataConsumerHandle::Reader> m_readerForComplexFormData; | |
| 191 }; | |
| 192 | |
| 193 class FetchFormDataConsumerHandle::ReaderImpl final : public FetchDataConsumerHa ndle::Reader { | |
| 194 WTF_MAKE_NONCOPYABLE(ReaderImpl); | |
| 195 public: | |
| 196 ReaderImpl(PassRefPtr<Context> context, Client* client) | |
| 197 : m_context(context) | |
| 198 , m_notifier(client) | |
| 199 { | |
| 200 // For memory barrier. | |
| 201 Mutex m; | |
| 202 MutexLocker locker(m); | |
| 203 m_context->obtainReader(client); | |
| 204 } | |
| 205 ~ReaderImpl() override | |
| 206 { | |
| 207 // For memory barrier. | |
| 208 Mutex m; | |
| 209 MutexLocker locker(m); | |
| 210 m_context->releaseReader(); | |
| 211 } | |
| 212 | |
| 213 Result read(void* data, size_t size, Flags flags, size_t* readSize) override | |
| 214 { | |
| 215 return m_context->read(data, size, flags, readSize); | |
| 216 } | |
| 217 Result beginRead(const void** buffer, Flags flags, size_t* available) overri de | |
| 218 { | |
| 219 return m_context->beginRead(buffer, flags, available); | |
| 220 } | |
| 221 Result endRead(size_t read) override | |
| 222 { | |
| 223 return m_context->endRead(read); | |
| 224 } | |
| 225 PassRefPtr<FormData> drainAsFormData() override | |
| 226 { | |
| 227 return m_context->drainFormData(); | |
| 228 } | |
| 229 | |
| 230 private: | |
| 231 RefPtr<Context> m_context; | |
| 232 NotifyOnReaderCreationHelper m_notifier; | |
| 233 }; | |
| 234 | |
| 235 FetchFormDataConsumerHandle::FetchFormDataConsumerHandle(const String& body) : m _context(Context::create(body)) {} | |
| 236 FetchFormDataConsumerHandle::FetchFormDataConsumerHandle(PassRefPtr<DOMArrayBuff er> body) : m_context(Context::create(body)) {} | |
| 237 FetchFormDataConsumerHandle::FetchFormDataConsumerHandle(ExecutionContext* execu tionContext, | |
| 238 PassRefPtr<FormData> body, | |
| 239 FetchBlobDataConsumerHandle::LoaderFactory* loaderFactory) | |
| 240 : m_context(Context::create(executionContext, body, loaderFactory)) | |
| 241 { | |
| 242 } | |
| 243 FetchFormDataConsumerHandle::~FetchFormDataConsumerHandle() {} | |
| 244 | |
| 245 FetchDataConsumerHandle::Reader* FetchFormDataConsumerHandle::obtainReaderIntern al(Client* client) | |
| 246 { | |
| 247 return new ReaderImpl(m_context, client); | |
| 248 } | |
| 249 | |
| 250 } // namespace blink | |
| OLD | NEW |