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

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: Rebase, LayoutTests updates 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 FetchDataLoaderAsFormData final : public FetchDataLoader,
179 public BytesConsumer::Client,
180 public MultipartParser::Client {
181 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsFormData);
182
183 public:
184 explicit FetchDataLoaderAsFormData(const String& multipart_boundary)
185 : multipart_boundary_(multipart_boundary) {}
186
187 void Start(BytesConsumer* consumer,
188 FetchDataLoader::Client* client) override {
189 DCHECK(!client_);
190 DCHECK(!consumer_);
191 DCHECK(!form_data_);
192 DCHECK(!multipart_parser_);
193
194 const CString multipart_boundary_utf8 = multipart_boundary_.Utf8();
195 Vector<char> multipart_boundary_vector;
196 multipart_boundary_vector.Append(multipart_boundary_utf8.data(),
197 multipart_boundary_utf8.length());
198
199 client_ = client;
200 form_data_ = FormData::Create();
201 multipart_parser_ =
202 new MultipartParser(std::move(multipart_boundary_vector), this);
203 consumer_ = consumer;
204 consumer_->SetClient(this);
205 OnStateChange();
206 }
207
208 void OnStateChange() override {
209 while (true) {
210 const char* buffer;
211 size_t available;
212 auto result = consumer_->BeginRead(&buffer, &available);
213 if (result == BytesConsumer::Result::kShouldWait)
214 return;
215 if (result == BytesConsumer::Result::kOk) {
216 const bool buffer_appended =
217 multipart_parser_->AppendData(buffer, available);
218 const bool multipart_receive_failed = multipart_parser_->IsCancelled();
219 result = consumer_->EndRead(available);
220 if (!buffer_appended || multipart_receive_failed)
221 result = BytesConsumer::Result::kError;
222 }
223 switch (result) {
224 case BytesConsumer::Result::kOk:
225 break;
226 case BytesConsumer::Result::kShouldWait:
227 NOTREACHED();
228 return;
229 case BytesConsumer::Result::kDone:
230 if (multipart_parser_->Finish()) {
231 DCHECK(!multipart_parser_->IsCancelled());
232 client_->DidFetchDataLoadedFormData(form_data_);
233 } else {
234 client_->DidFetchDataLoadFailed();
235 }
236 return;
237 case BytesConsumer::Result::kError:
238 client_->DidFetchDataLoadFailed();
239 return;
240 }
241 }
242 }
243
244 void Cancel() override {
245 consumer_->Cancel();
246 multipart_parser_->Cancel();
247 }
248
249 DEFINE_INLINE_TRACE() {
250 visitor->Trace(consumer_);
251 visitor->Trace(client_);
252 visitor->Trace(form_data_);
253 visitor->Trace(multipart_parser_);
254 FetchDataLoader::Trace(visitor);
255 BytesConsumer::Client::Trace(visitor);
256 MultipartParser::Client::Trace(visitor);
257 }
258
259 private:
260 void PartHeaderFieldsInMultipartReceived(
261 const HTTPHeaderMap& header_fields) override {
262 if (!current_entry_.Initialize(header_fields))
263 multipart_parser_->Cancel();
264 }
265
266 void PartDataInMultipartReceived(const char* bytes, size_t size) override {
267 if (!current_entry_.AppendBytes(bytes, size))
268 multipart_parser_->Cancel();
269 }
270
271 void PartDataInMultipartFullyReceived() override {
272 if (!current_entry_.Finish(form_data_))
273 multipart_parser_->Cancel();
274 }
275
276 class Entry {
277 public:
278 bool Initialize(const HTTPHeaderMap& header_fields) {
279 // TODO(e_hakkinen): Use a proper Content-Disposition parser instead of
280 // converting content disposition to a faked content type and parsing
281 // that.
282 const String fakePrefix = "x-fake/";
283 const ParsedContentType disposition(
284 fakePrefix + header_fields.Get(HTTPNames::Content_Disposition));
285 // The faked MIME type without the faked prefix is a proper disposition
286 // type.
287 const String disposition_type =
288 disposition.MimeType().Substring(fakePrefix.length());
289 filename_ = disposition.ParameterValueForName("filename");
290 name_ = disposition.ParameterValueForName("name");
291 blob_data_.reset();
292 string_builder_.reset();
293 if (disposition_type != "form-data" || name_.IsNull())
294 return false;
295 if (!filename_.IsNull()) {
296 blob_data_ = BlobData::Create();
297 const AtomicString& content_type =
298 header_fields.Get(HTTPNames::Content_Type);
299 blob_data_->SetContentType(content_type.IsNull() ? "text/plain"
300 : content_type);
301 } else {
302 if (!string_decoder_)
303 string_decoder_ = TextResourceDecoder::CreateAlwaysUseUTF8ForText();
304 string_builder_.reset(new StringBuilder);
305 }
306 return true;
307 }
308
309 bool AppendBytes(const char* bytes, size_t size) {
310 if (blob_data_)
311 blob_data_->AppendBytes(bytes, size);
312 if (string_builder_) {
313 string_builder_->Append(string_decoder_->Decode(bytes, size));
314 if (string_decoder_->SawError())
315 return false;
316 }
317 return true;
318 }
319
320 bool Finish(FormData* form_data) {
321 if (blob_data_) {
322 DCHECK(!string_builder_);
323 const auto size = blob_data_->length();
324 File* file =
325 File::Create(filename_, InvalidFileTime(),
326 BlobDataHandle::Create(std::move(blob_data_), size));
327 form_data->append(name_, file, filename_);
328 }
329 if (string_builder_) {
330 DCHECK(!blob_data_);
331 string_builder_->Append(string_decoder_->Flush());
332 if (string_decoder_->SawError())
333 return false;
334 form_data->append(name_, string_builder_->ToString());
335 }
336 return true;
337 }
338
339 private:
340 std::unique_ptr<BlobData> blob_data_;
341 String filename_;
342 String name_;
343 std::unique_ptr<StringBuilder> string_builder_;
344 std::unique_ptr<TextResourceDecoder> string_decoder_;
345 };
346
347 Member<BytesConsumer> consumer_;
348 Member<FetchDataLoader::Client> client_;
349 Member<FormData> form_data_;
350 Member<MultipartParser> multipart_parser_;
351
352 Entry current_entry_;
353 String multipart_boundary_;
354 };
355
173 class FetchDataLoaderAsString final : public FetchDataLoader, 356 class FetchDataLoaderAsString final : public FetchDataLoader,
174 public BytesConsumer::Client { 357 public BytesConsumer::Client {
175 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsString); 358 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsString);
176 359
177 public: 360 public:
178 void Start(BytesConsumer* consumer, 361 void Start(BytesConsumer* consumer,
179 FetchDataLoader::Client* client) override { 362 FetchDataLoader::Client* client) override {
180 DCHECK(!client_); 363 DCHECK(!client_);
181 DCHECK(!decoder_); 364 DCHECK(!decoder_);
182 DCHECK(!consumer_); 365 DCHECK(!consumer_);
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 517
335 FetchDataLoader* FetchDataLoader::CreateLoaderAsBlobHandle( 518 FetchDataLoader* FetchDataLoader::CreateLoaderAsBlobHandle(
336 const String& mime_type) { 519 const String& mime_type) {
337 return new FetchDataLoaderAsBlobHandle(mime_type); 520 return new FetchDataLoaderAsBlobHandle(mime_type);
338 } 521 }
339 522
340 FetchDataLoader* FetchDataLoader::CreateLoaderAsArrayBuffer() { 523 FetchDataLoader* FetchDataLoader::CreateLoaderAsArrayBuffer() {
341 return new FetchDataLoaderAsArrayBuffer(); 524 return new FetchDataLoaderAsArrayBuffer();
342 } 525 }
343 526
527 FetchDataLoader* FetchDataLoader::CreateLoaderAsFormData(
528 const String& multipartBoundary) {
529 return new FetchDataLoaderAsFormData(multipartBoundary);
530 }
531
344 FetchDataLoader* FetchDataLoader::CreateLoaderAsString() { 532 FetchDataLoader* FetchDataLoader::CreateLoaderAsString() {
345 return new FetchDataLoaderAsString(); 533 return new FetchDataLoaderAsString();
346 } 534 }
347 535
348 FetchDataLoader* FetchDataLoader::CreateLoaderAsDataPipe( 536 FetchDataLoader* FetchDataLoader::CreateLoaderAsDataPipe(
349 mojo::ScopedDataPipeProducerHandle out_data_pipe) { 537 mojo::ScopedDataPipeProducerHandle out_data_pipe) {
350 return new FetchDataLoaderAsDataPipe(std::move(out_data_pipe)); 538 return new FetchDataLoaderAsDataPipe(std::move(out_data_pipe));
351 } 539 }
352 540
353 } // namespace blink 541 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698