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 |