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

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: LayoutTests, FetchDataLoader Created 3 years, 7 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 <memory> 7 #include <memory>
8 #include "core/fileapi/File.h"
9 #include "core/html/FormData.h"
8 #include "core/html/parser/TextResourceDecoder.h" 10 #include "core/html/parser/TextResourceDecoder.h"
9 #include "modules/fetch/BytesConsumer.h" 11 #include "modules/fetch/BytesConsumer.h"
12 #include "modules/fetch/MultipartParser.h"
10 #include "mojo/public/cpp/system/simple_watcher.h" 13 #include "mojo/public/cpp/system/simple_watcher.h"
14 #include "platform/HTTPNames.h"
15 #include "platform/network/ParsedContentType.h"
11 #include "platform/wtf/Functional.h" 16 #include "platform/wtf/Functional.h"
12 #include "platform/wtf/PtrUtil.h" 17 #include "platform/wtf/PtrUtil.h"
13 #include "platform/wtf/text/StringBuilder.h" 18 #include "platform/wtf/text/StringBuilder.h"
14 #include "platform/wtf/text/WTFString.h" 19 #include "platform/wtf/text/WTFString.h"
15 #include "platform/wtf/typed_arrays/ArrayBufferBuilder.h" 20 #include "platform/wtf/typed_arrays/ArrayBufferBuilder.h"
16 21
17 namespace blink { 22 namespace blink {
18 23
19 namespace { 24 namespace {
20 25
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 BytesConsumer::Client::Trace(visitor); 168 BytesConsumer::Client::Trace(visitor);
164 } 169 }
165 170
166 private: 171 private:
167 Member<BytesConsumer> consumer_; 172 Member<BytesConsumer> consumer_;
168 Member<FetchDataLoader::Client> client_; 173 Member<FetchDataLoader::Client> client_;
169 174
170 std::unique_ptr<ArrayBufferBuilder> raw_data_; 175 std::unique_ptr<ArrayBufferBuilder> raw_data_;
171 }; 176 };
172 177
178 class FetchDataLoaderAsFailure final : public FetchDataLoader,
179 public BytesConsumer::Client {
180 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsFailure);
181
182 public:
183 void Start(BytesConsumer* consumer,
184 FetchDataLoader::Client* client) override {
185 DCHECK(!client_);
186 DCHECK(!consumer_);
187 client_ = client;
188 consumer_ = consumer;
189 consumer_->SetClient(this);
190 OnStateChange();
191 }
192
193 void OnStateChange() override {
194 while (true) {
195 const char* buffer;
196 size_t available;
197 auto result = consumer_->BeginRead(&buffer, &available);
198 if (result == BytesConsumer::Result::kShouldWait)
199 return;
200 if (result == BytesConsumer::Result::kOk)
201 result = consumer_->EndRead(available);
202 switch (result) {
203 case BytesConsumer::Result::kOk:
204 break;
205 case BytesConsumer::Result::kShouldWait:
206 NOTREACHED();
207 return;
208 case BytesConsumer::Result::kDone:
209 case BytesConsumer::Result::kError:
210 client_->DidFetchDataLoadFailed();
211 return;
212 }
213 }
214 }
215
216 void Cancel() override {
217 consumer_->Cancel();
218 }
219
220 DEFINE_INLINE_TRACE() {
221 visitor->Trace(consumer_);
222 visitor->Trace(client_);
223 FetchDataLoader::Trace(visitor);
224 BytesConsumer::Client::Trace(visitor);
225 }
226
227 private:
228 Member<BytesConsumer> consumer_;
229 Member<FetchDataLoader::Client> client_;
230 };
231
232 class FetchDataLoaderAsFormData final : public FetchDataLoader,
233 public BytesConsumer::Client,
234 public MultipartParser::Client {
235 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsFormData);
236
237 public:
238 explicit FetchDataLoaderAsFormData(const String& multipart_boundary)
239 : multipart_boundary_(multipart_boundary) {}
240
241 void Start(BytesConsumer* consumer,
242 FetchDataLoader::Client* client) override {
243 DCHECK(!client_);
244 DCHECK(!consumer_);
245 DCHECK(!form_data_);
246 DCHECK(!multipart_parser_);
247
248 const CString multipart_boundary_utf8 = multipart_boundary_.Utf8();
249 Vector<char> multipart_boundary_vector;
250 multipart_boundary_vector.Append(multipart_boundary_utf8.data(),
251 multipart_boundary_utf8.length());
252
253 client_ = client;
254 form_data_ = FormData::Create();
255 multipart_parser_ =
256 new MultipartParser(std::move(multipart_boundary_vector), this);
257 consumer_ = consumer;
258 consumer_->SetClient(this);
259 OnStateChange();
260 }
261
262 void OnStateChange() override {
263 while (true) {
264 const char* buffer;
265 size_t available;
266 auto result = consumer_->BeginRead(&buffer, &available);
267 if (result == BytesConsumer::Result::kShouldWait)
268 return;
269 if (result == BytesConsumer::Result::kOk) {
270 const bool buffer_appended =
271 multipart_parser_->AppendData(buffer, available);
272 const bool multipart_receive_failed = multipart_parser_->IsCancelled();
273 result = consumer_->EndRead(available);
274 if (!buffer_appended || multipart_receive_failed)
275 result = BytesConsumer::Result::kError;
276 }
277 switch (result) {
278 case BytesConsumer::Result::kOk:
279 break;
280 case BytesConsumer::Result::kShouldWait:
281 NOTREACHED();
282 return;
283 case BytesConsumer::Result::kDone:
284 if (multipart_parser_->Finish()) {
285 DCHECK(!multipart_parser_->IsCancelled());
286 client_->DidFetchDataLoadedFormData(form_data_);
287 } else {
288 client_->DidFetchDataLoadFailed();
289 }
290 return;
291 case BytesConsumer::Result::kError:
292 client_->DidFetchDataLoadFailed();
293 return;
294 }
295 }
296 }
297
298 void Cancel() override {
299 consumer_->Cancel();
300 multipart_parser_->Cancel();
301 }
302
303 DEFINE_INLINE_TRACE() {
304 visitor->Trace(consumer_);
305 visitor->Trace(client_);
306 visitor->Trace(form_data_);
307 visitor->Trace(multipart_parser_);
308 FetchDataLoader::Trace(visitor);
309 BytesConsumer::Client::Trace(visitor);
310 MultipartParser::Client::Trace(visitor);
311 }
312
313 private:
314 void PartHeaderFieldsInMultipartReceived(
315 const HTTPHeaderMap& header_fields) override {
316 if (!current_entry_.Initialize(header_fields))
317 multipart_parser_->Cancel();
318 }
319
320 void PartDataInMultipartReceived(const char* bytes, size_t size) override {
321 if (!current_entry_.AppendBytes(bytes, size))
322 multipart_parser_->Cancel();
323 }
324
325 void PartDataInMultipartFullyReceived() override {
326 if (!current_entry_.Finish(form_data_))
327 multipart_parser_->Cancel();
328 }
329
330 class Entry {
331 public:
332 bool Initialize(const HTTPHeaderMap& header_fields) {
333 // TODO(e_hakkinen): Use a proper Content-Disposition parser instead of
334 // converting content disposition to a faked content type and parsing
335 // that.
336 const String fakePrefix = "x-fake/";
337 const ParsedContentType disposition(
338 fakePrefix + header_fields.Get(HTTPNames::Content_Disposition));
339 // The faked MIME type without the faked prefix is a proper disposition
340 // type.
341 const String disposition_type =
342 disposition.MimeType().Substring(fakePrefix.length());
343 filename_ = disposition.ParameterValueForName("filename");
344 name_ = disposition.ParameterValueForName("name");
345 blob_data_.reset();
346 string_builder_.reset();
347 if (disposition_type != "form-data" || name_.IsNull())
348 return false;
349 if (!filename_.IsNull()) {
350 blob_data_ = BlobData::Create();
351 const AtomicString& content_type =
352 header_fields.Get(HTTPNames::Content_Type);
353 blob_data_->SetContentType(content_type.IsNull() ? "text/plain"
354 : content_type);
355 } else {
356 if (!string_decoder_)
357 string_decoder_ = TextResourceDecoder::CreateAlwaysUseUTF8ForText();
358 string_builder_.reset(new StringBuilder);
359 }
360 return true;
361 }
362
363 bool AppendBytes(const char* bytes, size_t size) {
364 if (blob_data_)
365 blob_data_->AppendBytes(bytes, size);
366 if (string_builder_) {
367 string_builder_->Append(string_decoder_->Decode(bytes, size));
368 if (string_decoder_->SawError())
369 return false;
370 }
371 return true;
372 }
373
374 bool Finish(FormData* form_data) {
375 if (blob_data_) {
376 DCHECK(!string_builder_);
377 const auto size = blob_data_->length();
378 File* file =
379 File::Create(filename_, InvalidFileTime(),
380 BlobDataHandle::Create(std::move(blob_data_), size));
381 form_data->append(name_, file, filename_);
yhirano 2017/05/15 11:54:48 Please put return true; here, and...
e_hakkinen 2017/05/17 09:46:59 Done.
382 }
383 if (string_builder_) {
yhirano 2017/05/15 11:54:48 please put DCHECK(string_builder_) here.
e_hakkinen 2017/05/17 09:46:59 Done.
384 DCHECK(!blob_data_);
385 string_builder_->Append(string_decoder_->Flush());
386 if (string_decoder_->SawError())
387 return false;
388 form_data->append(name_, string_builder_->ToString());
389 }
390 return true;
391 }
392
393 private:
394 std::unique_ptr<BlobData> blob_data_;
395 String filename_;
396 String name_;
397 std::unique_ptr<StringBuilder> string_builder_;
398 std::unique_ptr<TextResourceDecoder> string_decoder_;
399 };
400
401 Member<BytesConsumer> consumer_;
402 Member<FetchDataLoader::Client> client_;
403 Member<FormData> form_data_;
404 Member<MultipartParser> multipart_parser_;
405
406 Entry current_entry_;
407 String multipart_boundary_;
408 };
409
173 class FetchDataLoaderAsString final : public FetchDataLoader, 410 class FetchDataLoaderAsString final : public FetchDataLoader,
174 public BytesConsumer::Client { 411 public BytesConsumer::Client {
175 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsString); 412 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsString);
176 413
177 public: 414 public:
178 void Start(BytesConsumer* consumer, 415 void Start(BytesConsumer* consumer,
179 FetchDataLoader::Client* client) override { 416 FetchDataLoader::Client* client) override {
180 DCHECK(!client_); 417 DCHECK(!client_);
181 DCHECK(!decoder_); 418 DCHECK(!decoder_);
182 DCHECK(!consumer_); 419 DCHECK(!consumer_);
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 571
335 FetchDataLoader* FetchDataLoader::CreateLoaderAsBlobHandle( 572 FetchDataLoader* FetchDataLoader::CreateLoaderAsBlobHandle(
336 const String& mime_type) { 573 const String& mime_type) {
337 return new FetchDataLoaderAsBlobHandle(mime_type); 574 return new FetchDataLoaderAsBlobHandle(mime_type);
338 } 575 }
339 576
340 FetchDataLoader* FetchDataLoader::CreateLoaderAsArrayBuffer() { 577 FetchDataLoader* FetchDataLoader::CreateLoaderAsArrayBuffer() {
341 return new FetchDataLoaderAsArrayBuffer(); 578 return new FetchDataLoaderAsArrayBuffer();
342 } 579 }
343 580
581 FetchDataLoader* FetchDataLoader::CreateLoaderAsFailure() {
582 return new FetchDataLoaderAsFailure();
583 }
584
585
586 FetchDataLoader* FetchDataLoader::CreateLoaderAsFormData(
587 const String& multipartBoundary) {
588 return new FetchDataLoaderAsFormData(multipartBoundary);
589 }
590
344 FetchDataLoader* FetchDataLoader::CreateLoaderAsString() { 591 FetchDataLoader* FetchDataLoader::CreateLoaderAsString() {
345 return new FetchDataLoaderAsString(); 592 return new FetchDataLoaderAsString();
346 } 593 }
347 594
348 FetchDataLoader* FetchDataLoader::CreateLoaderAsDataPipe( 595 FetchDataLoader* FetchDataLoader::CreateLoaderAsDataPipe(
349 mojo::ScopedDataPipeProducerHandle out_data_pipe) { 596 mojo::ScopedDataPipeProducerHandle out_data_pipe) {
350 return new FetchDataLoaderAsDataPipe(std::move(out_data_pipe)); 597 return new FetchDataLoaderAsDataPipe(std::move(out_data_pipe));
351 } 598 }
352 599
353 } // namespace blink 600 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698