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

Side by Side Diff: Source/modules/fetch/FetchFormDataConsumerHandle.cpp

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

Powered by Google App Engine
This is Rietveld 408576698