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

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

Issue 1265413002: Introduce FetchFormDataConsumerHandle. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Add (const void*, size_t) creation function 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 class FetchFormDataConsumerHandle::Context : public ThreadSafeRefCounted<Context > {
24 WTF_MAKE_NONCOPYABLE(Context);
25 public:
26 virtual ~Context() {}
27 virtual PassOwnPtr<FetchDataConsumerHandle::Reader> obtainReader(Client*) = 0;
28
29 protected:
30 explicit Context() {}
31 };
32
33 class FetchFormDataConsumerHandle::SimpleContext final : public Context {
34 class ReaderImpl;
35 public:
36 static PassRefPtr<SimpleContext> create(const String& body) { return adoptRe f(new SimpleContext(body)); }
37 static PassRefPtr<SimpleContext> create(const void* data, size_t size) { ret urn adoptRef(new SimpleContext(data, size)); }
38 static PassRefPtr<SimpleContext> create(PassRefPtr<FormData> body) { return adoptRef(new SimpleContext(body)); }
39
40 PassOwnPtr<Reader> obtainReader(Client* client) override
41 {
42 // For memory barrier.
43 Mutex m;
44 MutexLocker locker(m);
hiroshige 2015/08/11 09:35:01 BTW if we need memory barrier here, should we also
yhirano 2015/08/11 11:36:01 If a user obtains and releases a reader on one thr
45 return ReaderImpl::create(this, client);
46 }
47
48 PassRefPtr<FormData> drainFormData()
hiroshige 2015/08/11 09:35:01 IIUC: 1. If flatten() is called before drainFormDa
yhirano 2015/08/11 11:36:01 Done.
49 {
50 ASSERT(!m_formData || m_formData->hasOneRef());
51 return m_formData.release();
52 }
53
54 Result read(void* data, size_t size, Flags flags, size_t* readSize)
55 {
56 *readSize = 0;
57 if (size == 0) {
58 if (!m_formData && m_flattenFormData.size() == m_flattenFormDataOffs et)
59 return WebDataConsumerHandle::Done;
60 return WebDataConsumerHandle::Ok;
61 }
62 flatten();
63
hiroshige 2015/08/11 09:35:01 How about adding "RELEASE_ASSERT(m_flattenFormData
yhirano 2015/08/11 11:36:01 Done.
64 *readSize = std::min(size, m_flattenFormData.size() - m_flattenFormDataO ffset);
65 if (*readSize == 0)
66 return WebDataConsumerHandle::Done;
67 memcpy(data, &m_flattenFormData[m_flattenFormDataOffset], *readSize);
68 m_flattenFormDataOffset += *readSize;
69 return WebDataConsumerHandle::Ok;
70 }
71
72 Result beginRead(const void** buffer, Flags flags, size_t* available)
73 {
74 *buffer = nullptr;
75 *available = 0;
76
77 flatten();
78 if (m_flattenFormData.size() == m_flattenFormDataOffset)
79 return WebDataConsumerHandle::Done;
hiroshige 2015/08/11 09:35:01 ditto.
yhirano 2015/08/11 11:36:01 Done.
80 *buffer = &m_flattenFormData[m_flattenFormDataOffset];
81 *available = m_flattenFormData.size() - m_flattenFormDataOffset;
82 return WebDataConsumerHandle::Ok;
83 }
84
85 Result endRead(size_t read)
86 {
hiroshige 2015/08/11 09:35:01 Please add: RELEASE_ASSERT(m_flattenFormData.s
yhirano 2015/08/11 11:36:01 Done.
87 m_flattenFormDataOffset += read;
88 return WebDataConsumerHandle::Ok;
89 }
90
91 private:
92 class ReaderImpl final : public FetchDataConsumerHandle::Reader {
93 WTF_MAKE_NONCOPYABLE(ReaderImpl);
94 public:
95 static PassOwnPtr<ReaderImpl> create(PassRefPtr<SimpleContext> context, Client* client) { return adoptPtr(new ReaderImpl(context, client)); }
96 Result read(void* data, size_t size, Flags flags, size_t* readSize) over ride
97 {
98 return m_context->read(data, size, flags, readSize);
99 }
100 Result beginRead(const void** buffer, Flags flags, size_t* available) ov erride
101 {
102 return m_context->beginRead(buffer, flags, available);
103 }
104 Result endRead(size_t read) override
105 {
106 return m_context->endRead(read);
107 }
108 PassRefPtr<FormData> drainAsFormData() override
109 {
110 return m_context->drainFormData();
111 }
112
113 private:
114 ReaderImpl(PassRefPtr<SimpleContext> context, Client* client) : m_contex t(context), m_notifier(client) {}
115
116 RefPtr<SimpleContext> m_context;
117 NotifyOnReaderCreationHelper m_notifier;
118 };
119
120 explicit SimpleContext(const String& body)
121 : m_formData(FormData::create(UTF8Encoding().encode(body, WTF::EntitiesF orUnencodables)))
122 , m_flattenFormDataOffset(0) {}
123 explicit SimpleContext(const void* data, size_t size)
124 : m_formData(FormData::create(data, size))
125 , m_flattenFormDataOffset(0) {}
126 explicit SimpleContext(PassRefPtr<FormData> body)
127 : m_formData(body->deepCopy())
128 , m_flattenFormDataOffset(0) {}
129
130 void flatten()
131 {
132 if (!m_formData) {
133 // It is already drained or flatten.
134 return;
135 }
136 ASSERT(m_formData->hasOneRef());
137 m_formData->flatten(m_flattenFormData);
138 m_formData = nullptr;
139 }
140
141 RefPtr<FormData> m_formData;
142 Vector<char> m_flattenFormData;
143 size_t m_flattenFormDataOffset;
144 };
145
146 class FetchFormDataConsumerHandle::ComplexContext final : public Context {
147 class ReaderImpl;
148 public:
149 static PassRefPtr<ComplexContext> create(ExecutionContext* executionContext,
150 PassRefPtr<FormData> formData,
151 FetchBlobDataConsumerHandle::LoaderFactory* factory)
152 {
153 return adoptRef(new ComplexContext(executionContext, formData, factory)) ;
154 }
155
156 PassOwnPtr<FetchFormDataConsumerHandle::Reader> obtainReader(Client* client) override
157 {
158 // For memory barrier.
159 Mutex m;
160 MutexLocker locker(m);
161 return ReaderImpl::create(this, client);
162 }
163
164 private:
165 class ReaderImpl final : public FetchDataConsumerHandle::Reader {
166 WTF_MAKE_NONCOPYABLE(ReaderImpl);
167 public:
168 static PassOwnPtr<ReaderImpl> create(PassRefPtr<ComplexContext> context, Client* client) { return adoptPtr(new ReaderImpl(context, client)); }
169 Result read(void* data, size_t size, Flags flags, size_t* readSize) over ride
170 {
171 Result r = m_reader->read(data, size, flags, readSize);
172 if (!((r == Ok && *readSize == 0) || r == ShouldWait)) {
173 m_context->drainFormData();
174 }
175 return r;
176 }
177 Result beginRead(const void** buffer, Flags flags, size_t* available) ov erride
178 {
179 Result r = m_reader->beginRead(buffer, flags, available);
180 if (r != ShouldWait) {
181 m_context->drainFormData();
182 }
183 return r;
184 }
185 Result endRead(size_t read) override
186 {
187 return m_reader->endRead(read);
188 }
189 PassRefPtr<BlobDataHandle> drainAsBlobDataHandle(BlobSizePolicy policy) override
190 {
191 m_context->drainFormData();
192 return m_reader->drainAsBlobDataHandle();
193 }
194 PassRefPtr<FormData> drainAsFormData() override
195 {
196 // Drain from the internal reader to sync the state.
197 m_reader->drainAsFormData();
198 return m_context->drainFormData();
199 }
200 private:
201 ReaderImpl(PassRefPtr<ComplexContext> context, Client* client) : m_conte xt(context), m_reader(m_context->m_handle->obtainReader(client)) {}
202
203 RefPtr<ComplexContext> m_context;
204 OwnPtr<FetchDataConsumerHandle::Reader> m_reader;
205 };
206
207 explicit ComplexContext(ExecutionContext* executionContext, PassRefPtr<FormD ata> body, FetchBlobDataConsumerHandle::LoaderFactory* factory)
208 : m_formData(body->deepCopy())
209 {
210 OwnPtr<BlobData> blobData = BlobData::create();
211 for (const auto& element : m_formData->elements()) {
212 switch (element.m_type) {
213 case FormDataElement::data:
214 blobData->appendBytes(element.m_data.data(), element.m_data.size ());
215 break;
216 case FormDataElement::encodedFile:
217 blobData->appendFile(element.m_filename, element.m_fileStart, el ement.m_fileLength, element.m_expectedFileModificationTime);
218 break;
219 case FormDataElement::encodedBlob:
220 if (element.m_optionalBlobDataHandle)
221 blobData->appendBlob(element.m_optionalBlobDataHandle, 0, el ement.m_optionalBlobDataHandle->size());
222 break;
223 case FormDataElement::encodedFileSystemURL:
224 blobData->appendFileSystemURL(element.m_fileSystemURL, element.m _fileStart, element.m_fileLength, element.m_expectedFileModificationTime);
hiroshige 2015/08/11 10:19:04 This is not thread-safe, because appendFileSystemU
yhirano 2015/08/11 11:36:01 Nice catch! done.
225 break;
226 }
227 }
228 // Here we handle m_formData->boundary() as a C-style string. See
229 // FormDataBuilder::generateUniqueBoundaryString.
230 blobData->setContentType(AtomicString("multipart/form-data; boundary=", AtomicString::ConstructFromLiteral) + m_formData->boundary().data());
231 auto size = blobData->length();
232 if (factory) {
233 // For testing
234 m_handle = FetchBlobDataConsumerHandle::create(executionContext, Blo bDataHandle::create(blobData.release(), size), factory);
235 } else {
236 m_handle = FetchBlobDataConsumerHandle::create(executionContext, Blo bDataHandle::create(blobData.release(), size));
237 }
238 }
239 PassRefPtr<FormData> drainFormData()
240 {
241 ASSERT(!m_formData || m_formData->hasOneRef());
242 return m_formData.release();
243 }
244
245 RefPtr<FormData> m_formData;
246 OwnPtr<FetchDataConsumerHandle> m_handle;
247 };
248
249 FetchFormDataConsumerHandle::FetchFormDataConsumerHandle(const String& body) : m _context(SimpleContext::create(body)) {}
250 FetchFormDataConsumerHandle::FetchFormDataConsumerHandle(const void* data, size_ t size) : m_context(SimpleContext::create(data, size)) {}
251 FetchFormDataConsumerHandle::FetchFormDataConsumerHandle(ExecutionContext* execu tionContext,
252 PassRefPtr<FormData> body,
253 FetchBlobDataConsumerHandle::LoaderFactory* loaderFactory)
254 {
255 if (isSimple(body.get())) {
256 m_context = SimpleContext::create(body);
257 } else {
258 m_context = ComplexContext::create(executionContext, body, loaderFactory );
259 }
260 }
261 FetchFormDataConsumerHandle::~FetchFormDataConsumerHandle() {}
262
263 FetchDataConsumerHandle::Reader* FetchFormDataConsumerHandle::obtainReaderIntern al(Client* client)
264 {
265 return m_context->obtainReader(client).leakPtr();
266 }
267
268 bool FetchFormDataConsumerHandle::isSimple(const FormData* formData)
269 {
270 for (const auto& element : formData->elements()) {
271 if (element.m_type != FormDataElement::data)
272 return false;
273 }
274 return true;
275 }
276
277 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698