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

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: More global-interface-listing*-expected.txt, urlencoded-parser-expected.txt 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 { consumer_->Cancel(); }
217
218 DEFINE_INLINE_TRACE() {
219 visitor->Trace(consumer_);
220 visitor->Trace(client_);
221 FetchDataLoader::Trace(visitor);
222 BytesConsumer::Client::Trace(visitor);
223 }
224
225 private:
226 Member<BytesConsumer> consumer_;
227 Member<FetchDataLoader::Client> client_;
228 };
229
230 class FetchDataLoaderAsFormData final : public FetchDataLoader,
231 public BytesConsumer::Client,
232 public MultipartParser::Client {
233 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsFormData);
234
235 public:
236 explicit FetchDataLoaderAsFormData(const String& multipart_boundary)
237 : multipart_boundary_(multipart_boundary) {}
238
239 void Start(BytesConsumer* consumer,
240 FetchDataLoader::Client* client) override {
241 DCHECK(!client_);
242 DCHECK(!consumer_);
243 DCHECK(!form_data_);
244 DCHECK(!multipart_parser_);
245
246 const CString multipart_boundary_utf8 = multipart_boundary_.Utf8();
247 Vector<char> multipart_boundary_vector;
248 multipart_boundary_vector.Append(multipart_boundary_utf8.data(),
249 multipart_boundary_utf8.length());
250
251 client_ = client;
252 form_data_ = FormData::Create();
253 multipart_parser_ =
254 new MultipartParser(std::move(multipart_boundary_vector), this);
255 consumer_ = consumer;
256 consumer_->SetClient(this);
257 OnStateChange();
258 }
259
260 void OnStateChange() override {
261 while (true) {
262 const char* buffer;
263 size_t available;
264 auto result = consumer_->BeginRead(&buffer, &available);
265 if (result == BytesConsumer::Result::kShouldWait)
266 return;
267 if (result == BytesConsumer::Result::kOk) {
268 const bool buffer_appended =
269 multipart_parser_->AppendData(buffer, available);
270 const bool multipart_receive_failed = multipart_parser_->IsCancelled();
271 result = consumer_->EndRead(available);
272 if (!buffer_appended || multipart_receive_failed)
273 result = BytesConsumer::Result::kError;
274 }
275 switch (result) {
276 case BytesConsumer::Result::kOk:
277 break;
278 case BytesConsumer::Result::kShouldWait:
279 NOTREACHED();
280 return;
281 case BytesConsumer::Result::kDone:
282 if (multipart_parser_->Finish()) {
283 DCHECK(!multipart_parser_->IsCancelled());
284 client_->DidFetchDataLoadedFormData(form_data_);
285 } else {
286 client_->DidFetchDataLoadFailed();
287 }
288 return;
289 case BytesConsumer::Result::kError:
290 client_->DidFetchDataLoadFailed();
291 return;
292 }
293 }
294 }
295
296 void Cancel() override {
297 consumer_->Cancel();
298 multipart_parser_->Cancel();
299 }
300
301 DEFINE_INLINE_TRACE() {
302 visitor->Trace(consumer_);
303 visitor->Trace(client_);
304 visitor->Trace(form_data_);
305 visitor->Trace(multipart_parser_);
306 FetchDataLoader::Trace(visitor);
307 BytesConsumer::Client::Trace(visitor);
308 MultipartParser::Client::Trace(visitor);
309 }
310
311 private:
312 void PartHeaderFieldsInMultipartReceived(
313 const HTTPHeaderMap& header_fields) override {
314 if (!current_entry_.Initialize(header_fields))
315 multipart_parser_->Cancel();
316 }
317
318 void PartDataInMultipartReceived(const char* bytes, size_t size) override {
319 if (!current_entry_.AppendBytes(bytes, size))
320 multipart_parser_->Cancel();
321 }
322
323 void PartDataInMultipartFullyReceived() override {
324 if (!current_entry_.Finish(form_data_))
325 multipart_parser_->Cancel();
326 }
327
328 class Entry {
329 public:
330 bool Initialize(const HTTPHeaderMap& header_fields) {
331 // TODO(e_hakkinen): Use a proper Content-Disposition parser instead of
332 // converting content disposition to a faked content type and parsing
333 // that.
334 const String fakePrefix = "x-fake/";
335 const ParsedContentType disposition(
336 fakePrefix + header_fields.Get(HTTPNames::Content_Disposition));
337 // The faked MIME type without the faked prefix is a proper disposition
338 // type.
339 const String disposition_type =
340 disposition.MimeType().Substring(fakePrefix.length());
341 filename_ = disposition.ParameterValueForName("filename");
342 name_ = disposition.ParameterValueForName("name");
343 blob_data_.reset();
344 string_builder_.reset();
345 if (disposition_type != "form-data" || name_.IsNull())
346 return false;
347 if (!filename_.IsNull()) {
348 blob_data_ = BlobData::Create();
349 const AtomicString& content_type =
350 header_fields.Get(HTTPNames::Content_Type);
351 blob_data_->SetContentType(content_type.IsNull() ? "text/plain"
352 : content_type);
353 } else {
354 if (!string_decoder_)
355 string_decoder_ = TextResourceDecoder::CreateAlwaysUseUTF8ForText();
356 string_builder_.reset(new StringBuilder);
357 }
358 return true;
359 }
360
361 bool AppendBytes(const char* bytes, size_t size) {
362 if (blob_data_)
363 blob_data_->AppendBytes(bytes, size);
364 if (string_builder_) {
365 string_builder_->Append(string_decoder_->Decode(bytes, size));
366 if (string_decoder_->SawError())
367 return false;
368 }
369 return true;
370 }
371
372 bool Finish(FormData* form_data) {
373 if (blob_data_) {
374 DCHECK(!string_builder_);
375 const auto size = blob_data_->length();
376 File* file =
377 File::Create(filename_, InvalidFileTime(),
378 BlobDataHandle::Create(std::move(blob_data_), size));
379 form_data->append(name_, file, filename_);
380 return true;
381 }
382 DCHECK(!blob_data_);
383 DCHECK(string_builder_);
384 string_builder_->Append(string_decoder_->Flush());
385 if (string_decoder_->SawError())
386 return false;
387 form_data->append(name_, string_builder_->ToString());
388 return true;
389 }
390
391 private:
392 std::unique_ptr<BlobData> blob_data_;
393 String filename_;
394 String name_;
395 std::unique_ptr<StringBuilder> string_builder_;
396 std::unique_ptr<TextResourceDecoder> string_decoder_;
397 };
398
399 Member<BytesConsumer> consumer_;
400 Member<FetchDataLoader::Client> client_;
401 Member<FormData> form_data_;
402 Member<MultipartParser> multipart_parser_;
403
404 Entry current_entry_;
405 String multipart_boundary_;
406 };
407
173 class FetchDataLoaderAsString final : public FetchDataLoader, 408 class FetchDataLoaderAsString final : public FetchDataLoader,
174 public BytesConsumer::Client { 409 public BytesConsumer::Client {
175 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsString); 410 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsString);
176 411
177 public: 412 public:
178 void Start(BytesConsumer* consumer, 413 void Start(BytesConsumer* consumer,
179 FetchDataLoader::Client* client) override { 414 FetchDataLoader::Client* client) override {
180 DCHECK(!client_); 415 DCHECK(!client_);
181 DCHECK(!decoder_); 416 DCHECK(!decoder_);
182 DCHECK(!consumer_); 417 DCHECK(!consumer_);
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 569
335 FetchDataLoader* FetchDataLoader::CreateLoaderAsBlobHandle( 570 FetchDataLoader* FetchDataLoader::CreateLoaderAsBlobHandle(
336 const String& mime_type) { 571 const String& mime_type) {
337 return new FetchDataLoaderAsBlobHandle(mime_type); 572 return new FetchDataLoaderAsBlobHandle(mime_type);
338 } 573 }
339 574
340 FetchDataLoader* FetchDataLoader::CreateLoaderAsArrayBuffer() { 575 FetchDataLoader* FetchDataLoader::CreateLoaderAsArrayBuffer() {
341 return new FetchDataLoaderAsArrayBuffer(); 576 return new FetchDataLoaderAsArrayBuffer();
342 } 577 }
343 578
579 FetchDataLoader* FetchDataLoader::CreateLoaderAsFailure() {
580 return new FetchDataLoaderAsFailure();
581 }
582
583 FetchDataLoader* FetchDataLoader::CreateLoaderAsFormData(
584 const String& multipartBoundary) {
585 return new FetchDataLoaderAsFormData(multipartBoundary);
586 }
587
344 FetchDataLoader* FetchDataLoader::CreateLoaderAsString() { 588 FetchDataLoader* FetchDataLoader::CreateLoaderAsString() {
345 return new FetchDataLoaderAsString(); 589 return new FetchDataLoaderAsString();
346 } 590 }
347 591
348 FetchDataLoader* FetchDataLoader::CreateLoaderAsDataPipe( 592 FetchDataLoader* FetchDataLoader::CreateLoaderAsDataPipe(
349 mojo::ScopedDataPipeProducerHandle out_data_pipe) { 593 mojo::ScopedDataPipeProducerHandle out_data_pipe) {
350 return new FetchDataLoaderAsDataPipe(std::move(out_data_pipe)); 594 return new FetchDataLoaderAsDataPipe(std::move(out_data_pipe));
351 } 595 }
352 596
353 } // namespace blink 597 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698