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

Side by Side Diff: third_party/WebKit/Source/modules/fetch/FetchDataLoader.cpp

Issue 2292763002: [Fetch API] Implement Request.formData and Response.formData. (Closed)
Patch Set: Handle partial delimiter prefixes correctly and really test them Created 4 years, 3 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
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "modules/fetch/FetchDataLoader.h" 5 #include "modules/fetch/FetchDataLoader.h"
6 6
7 #include "core/fileapi/Blob.h"
8 #include "core/html/FormData.h"
7 #include "core/html/parser/TextResourceDecoder.h" 9 #include "core/html/parser/TextResourceDecoder.h"
8 #include "modules/fetch/BytesConsumer.h" 10 #include "modules/fetch/BytesConsumer.h"
11 #include "modules/fetch/MultipartParser.h"
12 #include "platform/HTTPNames.h"
13 #include "platform/network/ParsedContentType.h"
9 #include "wtf/PtrUtil.h" 14 #include "wtf/PtrUtil.h"
10 #include "wtf/text/StringBuilder.h" 15 #include "wtf/text/StringBuilder.h"
11 #include "wtf/text/WTFString.h" 16 #include "wtf/text/WTFString.h"
12 #include "wtf/typed_arrays/ArrayBufferBuilder.h" 17 #include "wtf/typed_arrays/ArrayBufferBuilder.h"
13 #include <memory> 18 #include <memory>
14 19
15 namespace blink { 20 namespace blink {
16 21
17 namespace { 22 namespace {
18 23
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
154 BytesConsumer::Client::trace(visitor); 159 BytesConsumer::Client::trace(visitor);
155 } 160 }
156 161
157 private: 162 private:
158 Member<BytesConsumer> m_consumer; 163 Member<BytesConsumer> m_consumer;
159 Member<FetchDataLoader::Client> m_client; 164 Member<FetchDataLoader::Client> m_client;
160 165
161 std::unique_ptr<ArrayBufferBuilder> m_rawData; 166 std::unique_ptr<ArrayBufferBuilder> m_rawData;
162 }; 167 };
163 168
169 class FetchDataLoaderAsFormData final : public FetchDataLoader, public BytesCons umer::Client, private MultipartParser::Client {
yhirano 2016/09/07 06:00:16 Why do you use private inheritance?
e_hakkinen 2016/09/08 00:06:29 Because public inheritance is not needed. I'll use
yhirano 2016/09/12 02:20:49 Thanks, I think public is preferred (https://googl
170 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsFormData);
171
172 public:
173 explicit FetchDataLoaderAsFormData(const String& multipartBoundary)
174 : m_multipartBoundary(multipartBoundary)
175 {
176 }
177
178 void start(BytesConsumer* consumer, FetchDataLoader::Client* client) overrid e
179 {
180 DCHECK(!m_client);
181 DCHECK(!m_multipartParser);
182 DCHECK(!m_consumer);
183
184 CString multipartBoundaryCString = m_multipartBoundary.utf8();
185 Vector<char> multipartBoundaryVector;
186 multipartBoundaryVector.append(multipartBoundaryCString.data(), multipar tBoundaryCString.length());
187
188 m_client = client;
189 m_formData = FormData::create();
190 m_multipartParser = new MultipartParser(std::move(multipartBoundaryVecto r), this);
191 m_consumer = consumer;
192 m_consumer->setClient(this);
193 onStateChange();
194 }
195
196 void onStateChange() override
197 {
198 while (!m_multipartParser->isCancelled()) {
199 const char* buffer;
200 size_t available;
201 switch (m_consumer->beginRead(&buffer, &available)) {
202 case BytesConsumer::Result::Ok:
203 if (available > 0) {
204 if (!m_multipartParser->appendData(buffer, available))
205 m_client->didFetchDataLoadFailed();
yhirano 2016/09/07 06:00:16 +m_consumer->cancel();
e_hakkinen 2016/09/08 00:06:29 Done.
206 }
207 m_consumer->endRead(available);
208 break;
209 case BytesConsumer::Result::ShouldWait:
210 return;
211 case BytesConsumer::Result::Done:
212 if (m_multipartParser->finish()) {
213 m_client->didFetchDataLoadedFormData(m_formData);
214 } else {
215 m_client->didFetchDataLoadFailed();
216 }
217 return;
218 case BytesConsumer::Result::Error:
219 m_client->didFetchDataLoadFailed();
220 return;
221 }
222 }
223 }
224
225 void cancel() override
226 {
227 m_consumer->cancel();
228 m_multipartParser->cancel();
229 }
230
231 DEFINE_INLINE_TRACE()
232 {
233 visitor->trace(m_consumer);
234 visitor->trace(m_client);
235 visitor->trace(m_formData);
236 visitor->trace(m_multipartParser);
237 FetchDataLoader::trace(visitor);
238 BytesConsumer::Client::trace(visitor);
239 MultipartParser::Client::trace(visitor);
240 }
241
242 private:
243 void partHeaderFieldsInMultipartReceived(const ResourceResponse& response) o verride
244 {
245 if (!m_currentEntry.initialize(response)) {
246 m_client->didFetchDataLoadFailed();
247 // The client does not like to be notified multiple times thus stop
248 // parsing so that no more errors will be reached.
249 m_multipartParser->cancel();
yhirano 2016/09/07 06:00:16 +m_consumer->cancel();
e_hakkinen 2016/09/08 00:06:29 Done.
250 }
251 }
252
253 void partDataInMultipartReceived(const char* bytes, size_t size) override
254 {
255 m_currentEntry.appendBytes(bytes, size);
256 }
257
258 void partDataInMultipartFullyReceived() override
259 {
260 m_currentEntry.finish(m_formData);
261 }
262
263 class Entry {
264 public:
265 bool initialize(const ResourceResponse& response)
266 {
267 ParsedContentType disposition(response.httpHeaderField(HTTPNames::Co ntent_Disposition));
268 String dispositionType = disposition.mimeType();
269 m_filename = disposition.parameterValueForName("filename");
270 m_name = disposition.parameterValueForName("name");
yhirano 2016/09/07 06:00:16 I would prefer clearing members unconditionally he
e_hakkinen 2016/09/08 00:06:29 Done.
271 if (dispositionType != "form-data" || m_name.isNull())
272 return false;
273 if (!m_filename.isNull()) {
274 m_blobData = BlobData::create();
275 m_blobData->setContentType(response.httpHeaderField(HTTPNames::C ontent_Type));
276 m_stringBuilder.reset();
277 } else {
278 m_blobData.reset();
279 if (!m_decoder)
280 m_decoder = TextResourceDecoder::createAlwaysUseUTF8ForText( );
281 m_stringBuilder.reset(new StringBuilder);
282 }
283 return true;
284 }
285
286 void appendBytes(const char* bytes, size_t size)
287 {
288 if (m_blobData)
289 m_blobData->appendBytes(bytes, size);
290 if (m_stringBuilder)
291 m_stringBuilder->append(m_decoder->decode(bytes, size));
yhirano 2016/09/07 06:00:16 You need to check m_decoder->sawError.
e_hakkinen 2016/09/08 00:06:29 Done.
292 }
293
294 void finish(FormData* formData)
295 {
296 if (m_blobData) {
297 DCHECK(!m_stringBuilder);
298 auto size = m_blobData->length();
299 formData->append(m_name, Blob::create(BlobDataHandle::create(std ::move(m_blobData), size)), m_filename);
300 }
301 if (m_stringBuilder) {
302 DCHECK(!m_blobData);
303 m_stringBuilder->append(m_decoder->flush());
yhirano 2016/09/07 06:00:16 You need to check m_decoder->sawError.
e_hakkinen 2016/09/08 00:06:29 Done.
304 formData->append(m_name, m_stringBuilder->toString());
305 }
306 }
307
308 private:
309 std::unique_ptr<BlobData> m_blobData;
310 std::unique_ptr<TextResourceDecoder> m_decoder;
311 String m_filename;
312 String m_name;
313 std::unique_ptr<StringBuilder> m_stringBuilder;
314 };
315
316 Member<BytesConsumer> m_consumer;
317 Member<FetchDataLoader::Client> m_client;
318 Member<FormData> m_formData;
319 Member<MultipartParser> m_multipartParser;
320
321 Entry m_currentEntry;
322 String m_multipartBoundary;
323 };
324
164 class FetchDataLoaderAsString final : public FetchDataLoader, public BytesConsum er::Client { 325 class FetchDataLoaderAsString final : public FetchDataLoader, public BytesConsum er::Client {
165 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsString); 326 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsString);
166 public: 327 public:
167 void start(BytesConsumer* consumer, FetchDataLoader::Client* client) overrid e 328 void start(BytesConsumer* consumer, FetchDataLoader::Client* client) overrid e
168 { 329 {
169 DCHECK(!m_client); 330 DCHECK(!m_client);
170 DCHECK(!m_decoder); 331 DCHECK(!m_decoder);
171 DCHECK(!m_consumer); 332 DCHECK(!m_consumer);
172 m_client = client; 333 m_client = client;
173 m_decoder = TextResourceDecoder::createAlwaysUseUTF8ForText(); 334 m_decoder = TextResourceDecoder::createAlwaysUseUTF8ForText();
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 FetchDataLoader* FetchDataLoader::createLoaderAsBlobHandle(const String& mimeTyp e) 459 FetchDataLoader* FetchDataLoader::createLoaderAsBlobHandle(const String& mimeTyp e)
299 { 460 {
300 return new FetchDataLoaderAsBlobHandle(mimeType); 461 return new FetchDataLoaderAsBlobHandle(mimeType);
301 } 462 }
302 463
303 FetchDataLoader* FetchDataLoader::createLoaderAsArrayBuffer() 464 FetchDataLoader* FetchDataLoader::createLoaderAsArrayBuffer()
304 { 465 {
305 return new FetchDataLoaderAsArrayBuffer(); 466 return new FetchDataLoaderAsArrayBuffer();
306 } 467 }
307 468
469 FetchDataLoader* FetchDataLoader::createLoaderAsFormData(const String& multipart Boundary)
470 {
471 return new FetchDataLoaderAsFormData(multipartBoundary);
472 }
473
308 FetchDataLoader* FetchDataLoader::createLoaderAsString() 474 FetchDataLoader* FetchDataLoader::createLoaderAsString()
309 { 475 {
310 return new FetchDataLoaderAsString(); 476 return new FetchDataLoaderAsString();
311 } 477 }
312 478
313 FetchDataLoader* FetchDataLoader::createLoaderAsStream(Stream* outStream) 479 FetchDataLoader* FetchDataLoader::createLoaderAsStream(Stream* outStream)
314 { 480 {
315 return new FetchDataLoaderAsStream(outStream); 481 return new FetchDataLoaderAsStream(outStream);
316 } 482 }
317 483
318 } // namespace blink 484 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698