Chromium Code Reviews| 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 { | |
| 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 Loading... | |
| 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 |
| OLD | NEW |