OLD | NEW |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |