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 "modules/fetch/FetchFormDataConsumerHandle.h" | |
6 | |
7 #include "modules/fetch/DataConsumerHandleUtil.h" | |
8 #include "modules/fetch/FetchBlobDataConsumerHandle.h" | |
9 #include "wtf/PtrUtil.h" | |
10 #include "wtf/ThreadingPrimitives.h" | |
11 #include "wtf/Vector.h" | |
12 #include "wtf/text/TextCodec.h" | |
13 #include "wtf/text/TextEncoding.h" | |
14 #include "wtf/text/WTFString.h" | |
15 #include <memory> | |
16 #include <utility> | |
17 | |
18 namespace blink { | |
19 | |
20 using Result = FetchDataConsumerHandle::Result; | |
21 | |
22 namespace { | |
23 | |
24 bool isSimple(const EncodedFormData* formData) | |
25 { | |
26 for (const auto& element : formData->elements()) { | |
27 if (element.m_type != FormDataElement::data) | |
28 return false; | |
29 } | |
30 return true; | |
31 } | |
32 | |
33 } // namespace | |
34 | |
35 class FetchFormDataConsumerHandle::Context : public ThreadSafeRefCounted<Context
> { | |
36 WTF_MAKE_NONCOPYABLE(Context); | |
37 public: | |
38 virtual ~Context() {} | |
39 virtual std::unique_ptr<FetchDataConsumerHandle::Reader> obtainReader(Client
*) = 0; | |
40 | |
41 protected: | |
42 explicit Context() {} | |
43 }; | |
44 | |
45 class FetchFormDataConsumerHandle::SimpleContext final : public Context { | |
46 class ReaderImpl; | |
47 public: | |
48 static PassRefPtr<SimpleContext> create(const String& body) { return adoptRe
f(new SimpleContext(body)); } | |
49 static PassRefPtr<SimpleContext> create(const void* data, size_t size) { ret
urn adoptRef(new SimpleContext(data, size)); } | |
50 static PassRefPtr<SimpleContext> create(PassRefPtr<EncodedFormData> body) {
return adoptRef(new SimpleContext(std::move(body))); } | |
51 | |
52 std::unique_ptr<Reader> obtainReader(Client* client) override | |
53 { | |
54 // For memory barrier. | |
55 Mutex m; | |
56 MutexLocker locker(m); | |
57 return ReaderImpl::create(this, client); | |
58 } | |
59 | |
60 PassRefPtr<BlobDataHandle> drainAsBlobDataHandle() | |
61 { | |
62 if (!m_formData) | |
63 return nullptr; | |
64 flatten(); | |
65 std::unique_ptr<BlobData> blobData = BlobData::create(); | |
66 blobData->appendBytes(m_flattenFormData.data(), m_flattenFormData.size()
); | |
67 m_flattenFormData.clear(); | |
68 auto length = blobData->length(); | |
69 return BlobDataHandle::create(std::move(blobData), length); | |
70 } | |
71 | |
72 PassRefPtr<EncodedFormData> drainFormData() | |
73 { | |
74 ASSERT(!m_formData || m_formData->isSafeToSendToAnotherThread()); | |
75 return m_formData.release(); | |
76 } | |
77 | |
78 Result read(void* data, size_t size, Flags flags, size_t* readSize) | |
79 { | |
80 *readSize = 0; | |
81 if (size == 0 && m_formData) | |
82 return WebDataConsumerHandle::Ok; | |
83 | |
84 flatten(); | |
85 RELEASE_ASSERT(m_flattenFormDataOffset <= m_flattenFormData.size()); | |
86 | |
87 *readSize = std::min(size, m_flattenFormData.size() - m_flattenFormDataO
ffset); | |
88 if (*readSize == 0) | |
89 return WebDataConsumerHandle::Done; | |
90 memcpy(data, &m_flattenFormData[m_flattenFormDataOffset], *readSize); | |
91 m_flattenFormDataOffset += *readSize; | |
92 RELEASE_ASSERT(m_flattenFormDataOffset <= m_flattenFormData.size()); | |
93 | |
94 return WebDataConsumerHandle::Ok; | |
95 } | |
96 | |
97 Result beginRead(const void** buffer, Flags flags, size_t* available) | |
98 { | |
99 *buffer = nullptr; | |
100 *available = 0; | |
101 | |
102 flatten(); | |
103 RELEASE_ASSERT(m_flattenFormDataOffset <= m_flattenFormData.size()); | |
104 | |
105 if (m_flattenFormData.size() == m_flattenFormDataOffset) | |
106 return WebDataConsumerHandle::Done; | |
107 *buffer = &m_flattenFormData[m_flattenFormDataOffset]; | |
108 *available = m_flattenFormData.size() - m_flattenFormDataOffset; | |
109 return WebDataConsumerHandle::Ok; | |
110 } | |
111 | |
112 Result endRead(size_t read) | |
113 { | |
114 RELEASE_ASSERT(m_flattenFormDataOffset <= m_flattenFormData.size()); | |
115 RELEASE_ASSERT(read <= m_flattenFormData.size() - m_flattenFormDataOffse
t); | |
116 m_flattenFormDataOffset += read; | |
117 | |
118 return WebDataConsumerHandle::Ok; | |
119 } | |
120 | |
121 private: | |
122 class ReaderImpl final : public FetchDataConsumerHandle::Reader { | |
123 WTF_MAKE_NONCOPYABLE(ReaderImpl); | |
124 public: | |
125 static std::unique_ptr<ReaderImpl> create(PassRefPtr<SimpleContext> cont
ext, Client* client) { return wrapUnique(new ReaderImpl(std::move(context), clie
nt)); } | |
126 Result read(void* data, size_t size, Flags flags, size_t* readSize) over
ride | |
127 { | |
128 return m_context->read(data, size, flags, readSize); | |
129 } | |
130 Result beginRead(const void** buffer, Flags flags, size_t* available) ov
erride | |
131 { | |
132 return m_context->beginRead(buffer, flags, available); | |
133 } | |
134 Result endRead(size_t read) override | |
135 { | |
136 return m_context->endRead(read); | |
137 } | |
138 PassRefPtr<BlobDataHandle> drainAsBlobDataHandle(BlobSizePolicy) overrid
e | |
139 { | |
140 // A "simple" FormData always has a finite known size. | |
141 return m_context->drainAsBlobDataHandle(); | |
142 } | |
143 PassRefPtr<EncodedFormData> drainAsFormData() override | |
144 { | |
145 return m_context->drainFormData(); | |
146 } | |
147 | |
148 private: | |
149 ReaderImpl(PassRefPtr<SimpleContext> context, Client* client) : m_contex
t(context), m_notifier(client) {} | |
150 | |
151 RefPtr<SimpleContext> m_context; | |
152 NotifyOnReaderCreationHelper m_notifier; | |
153 }; | |
154 | |
155 explicit SimpleContext(const String& body) | |
156 : m_formData(EncodedFormData::create(UTF8Encoding().encode(body, WTF::En
titiesForUnencodables))) | |
157 , m_flattenFormDataOffset(0) {} | |
158 SimpleContext(const void* data, size_t size) : m_formData(EncodedFormData::c
reate(data, size)) , m_flattenFormDataOffset(0) {} | |
159 explicit SimpleContext(PassRefPtr<EncodedFormData> body) : m_formData(body->
deepCopy()) , m_flattenFormDataOffset(0) {} | |
160 | |
161 void flatten() | |
162 { | |
163 if (!m_formData) { | |
164 // It is already drained or flatten. | |
165 return; | |
166 } | |
167 ASSERT(m_formData->isSafeToSendToAnotherThread()); | |
168 m_formData->flatten(m_flattenFormData); | |
169 m_formData = nullptr; | |
170 } | |
171 | |
172 // either one of |m_formData| and |m_flattenFormData| is usable at a time. | |
173 RefPtr<EncodedFormData> m_formData; | |
174 Vector<char> m_flattenFormData; | |
175 size_t m_flattenFormDataOffset; | |
176 }; | |
177 | |
178 class FetchFormDataConsumerHandle::ComplexContext final : public Context { | |
179 class ReaderImpl; | |
180 public: | |
181 static PassRefPtr<ComplexContext> create(ExecutionContext* executionContext, | |
182 PassRefPtr<EncodedFormData> formData, | |
183 FetchBlobDataConsumerHandle::LoaderFactory* factory) | |
184 { | |
185 return adoptRef(new ComplexContext(executionContext, std::move(formData)
, factory)); | |
186 } | |
187 | |
188 std::unique_ptr<FetchFormDataConsumerHandle::Reader> obtainReader(Client* cl
ient) override | |
189 { | |
190 // For memory barrier. | |
191 Mutex m; | |
192 MutexLocker locker(m); | |
193 return ReaderImpl::create(this, client); | |
194 } | |
195 | |
196 private: | |
197 class ReaderImpl final : public FetchDataConsumerHandle::Reader { | |
198 WTF_MAKE_NONCOPYABLE(ReaderImpl); | |
199 public: | |
200 static std::unique_ptr<ReaderImpl> create(PassRefPtr<ComplexContext> con
text, Client* client) { return wrapUnique(new ReaderImpl(std::move(context), cli
ent)); } | |
201 Result read(void* data, size_t size, Flags flags, size_t* readSize) over
ride | |
202 { | |
203 Result r = m_reader->read(data, size, flags, readSize); | |
204 if (!(size == 0 && (r == Ok || r == ShouldWait))) { | |
205 m_context->drainFormData(); | |
206 } | |
207 return r; | |
208 } | |
209 Result beginRead(const void** buffer, Flags flags, size_t* available) ov
erride | |
210 { | |
211 m_context->drainFormData(); | |
212 return m_reader->beginRead(buffer, flags, available); | |
213 } | |
214 Result endRead(size_t read) override | |
215 { | |
216 return m_reader->endRead(read); | |
217 } | |
218 PassRefPtr<BlobDataHandle> drainAsBlobDataHandle(BlobSizePolicy policy)
override | |
219 { | |
220 RefPtr<BlobDataHandle> handle = m_reader->drainAsBlobDataHandle(poli
cy); | |
221 if (handle) { | |
222 m_context->drainFormData(); | |
223 } | |
224 return handle.release(); | |
225 } | |
226 PassRefPtr<EncodedFormData> drainAsFormData() override | |
227 { | |
228 RefPtr<EncodedFormData> formData = m_context->drainFormData(); | |
229 if (formData) { | |
230 // Drain blob from the underlying handle to mark data as read. | |
231 RefPtr<BlobDataHandle> handle = m_reader->drainAsBlobDataHandle(
AllowBlobWithInvalidSize); | |
232 // Here we assume we can always get the valid handle. That is | |
233 // in fact not specified at FetchDataConsumerHandle level, but | |
234 // |m_context->m_handle| is a FetchBlobDataConsumerHandle. | |
235 ASSERT(handle); | |
236 } | |
237 return formData.release(); | |
238 } | |
239 private: | |
240 ReaderImpl(PassRefPtr<ComplexContext> context, Client* client) : m_conte
xt(context), m_reader(m_context->m_handle->obtainFetchDataReader(client)) {} | |
241 | |
242 RefPtr<ComplexContext> m_context; | |
243 std::unique_ptr<FetchDataConsumerHandle::Reader> m_reader; | |
244 }; | |
245 | |
246 ComplexContext(ExecutionContext* executionContext, PassRefPtr<EncodedFormDat
a> body, FetchBlobDataConsumerHandle::LoaderFactory* factory) | |
247 { | |
248 std::unique_ptr<BlobData> blobData = BlobData::create(); | |
249 for (const auto& element : body->elements()) { | |
250 switch (element.m_type) { | |
251 case FormDataElement::data: | |
252 blobData->appendBytes(element.m_data.data(), element.m_data.size
()); | |
253 break; | |
254 case FormDataElement::encodedFile: | |
255 blobData->appendFile(element.m_filename, element.m_fileStart, el
ement.m_fileLength, element.m_expectedFileModificationTime); | |
256 break; | |
257 case FormDataElement::encodedBlob: | |
258 if (element.m_optionalBlobDataHandle) | |
259 blobData->appendBlob(element.m_optionalBlobDataHandle, 0, el
ement.m_optionalBlobDataHandle->size()); | |
260 break; | |
261 case FormDataElement::encodedFileSystemURL: | |
262 blobData->appendFileSystemURL(element.m_fileSystemURL, element.m
_fileStart, element.m_fileLength, element.m_expectedFileModificationTime); | |
263 break; | |
264 } | |
265 } | |
266 // Here we handle body->boundary() as a C-style string. See | |
267 // FormDataEncoder::generateUniqueBoundaryString. | |
268 blobData->setContentType(AtomicString("multipart/form-data; boundary=")
+ body->boundary().data()); | |
269 auto size = blobData->length(); | |
270 if (factory) { | |
271 // For testing | |
272 m_handle = FetchBlobDataConsumerHandle::create(executionContext, Blo
bDataHandle::create(std::move(blobData), size), factory); | |
273 } else { | |
274 m_handle = FetchBlobDataConsumerHandle::create(executionContext, Blo
bDataHandle::create(std::move(blobData), size)); | |
275 } | |
276 // It is important to initialize |m_formData| here, because even | |
277 // read-only operations may make the form data unsharable with implicit | |
278 // ref-counting. | |
279 m_formData = body->deepCopy(); | |
280 } | |
281 PassRefPtr<EncodedFormData> drainFormData() | |
282 { | |
283 ASSERT(!m_formData || m_formData->isSafeToSendToAnotherThread()); | |
284 return m_formData.release(); | |
285 } | |
286 | |
287 RefPtr<EncodedFormData> m_formData; | |
288 std::unique_ptr<FetchDataConsumerHandle> m_handle; | |
289 }; | |
290 | |
291 std::unique_ptr<FetchDataConsumerHandle> FetchFormDataConsumerHandle::create(con
st String& body) | |
292 { | |
293 return wrapUnique(new FetchFormDataConsumerHandle(body)); | |
294 } | |
295 std::unique_ptr<FetchDataConsumerHandle> FetchFormDataConsumerHandle::create(DOM
ArrayBuffer* body) | |
296 { | |
297 return wrapUnique(new FetchFormDataConsumerHandle(body->data(), body->byteLe
ngth())); | |
298 } | |
299 std::unique_ptr<FetchDataConsumerHandle> FetchFormDataConsumerHandle::create(DOM
ArrayBufferView* body) | |
300 { | |
301 return wrapUnique(new FetchFormDataConsumerHandle(body->baseAddress(), body-
>byteLength())); | |
302 } | |
303 std::unique_ptr<FetchDataConsumerHandle> FetchFormDataConsumerHandle::create(con
st void* data, size_t size) | |
304 { | |
305 return wrapUnique(new FetchFormDataConsumerHandle(data, size)); | |
306 } | |
307 std::unique_ptr<FetchDataConsumerHandle> FetchFormDataConsumerHandle::create(Exe
cutionContext* executionContext, PassRefPtr<EncodedFormData> body) | |
308 { | |
309 return wrapUnique(new FetchFormDataConsumerHandle(executionContext, std::mov
e(body))); | |
310 } | |
311 std::unique_ptr<FetchDataConsumerHandle> FetchFormDataConsumerHandle::createForT
est( | |
312 ExecutionContext* executionContext, | |
313 PassRefPtr<EncodedFormData> body, | |
314 FetchBlobDataConsumerHandle::LoaderFactory* loaderFactory) | |
315 { | |
316 return wrapUnique(new FetchFormDataConsumerHandle(executionContext, std::mov
e(body), loaderFactory)); | |
317 } | |
318 | |
319 FetchFormDataConsumerHandle::FetchFormDataConsumerHandle(const String& body) : m
_context(SimpleContext::create(body)) {} | |
320 FetchFormDataConsumerHandle::FetchFormDataConsumerHandle(const void* data, size_
t size) : m_context(SimpleContext::create(data, size)) {} | |
321 FetchFormDataConsumerHandle::FetchFormDataConsumerHandle(ExecutionContext* execu
tionContext, | |
322 PassRefPtr<EncodedFormData> body, | |
323 FetchBlobDataConsumerHandle::LoaderFactory* loaderFactory) | |
324 { | |
325 if (isSimple(body.get())) { | |
326 m_context = SimpleContext::create(std::move(body)); | |
327 } else { | |
328 m_context = ComplexContext::create(executionContext, std::move(body), lo
aderFactory); | |
329 } | |
330 } | |
331 FetchFormDataConsumerHandle::~FetchFormDataConsumerHandle() {} | |
332 | |
333 std::unique_ptr<FetchDataConsumerHandle::Reader> FetchFormDataConsumerHandle::ob
tainFetchDataReader(Client* client) | |
334 { | |
335 return m_context->obtainReader(client); | |
336 } | |
337 | |
338 } // namespace blink | |
OLD | NEW |