OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "content/browser/download/mhtml_generation_manager.h" | 5 #include "content/browser/download/mhtml_generation_manager.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 #include <queue> | 8 #include <queue> |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
11 #include "base/bind.h" | 11 #include "base/bind.h" |
12 #include "base/files/file.h" | 12 #include "base/files/file.h" |
13 #include "base/guid.h" | 13 #include "base/guid.h" |
14 #include "base/macros.h" | 14 #include "base/macros.h" |
15 #include "base/memory/ptr_util.h" | 15 #include "base/memory/ptr_util.h" |
16 #include "base/metrics/histogram_macros.h" | 16 #include "base/metrics/histogram_macros.h" |
17 #include "base/scoped_observer.h" | 17 #include "base/scoped_observer.h" |
18 #include "base/stl_util.h" | 18 #include "base/stl_util.h" |
19 #include "base/strings/string_util.h" | 19 #include "base/strings/string_util.h" |
20 #include "base/strings/stringprintf.h" | 20 #include "base/strings/stringprintf.h" |
| 21 #include "base/task_runner_util.h" |
21 #include "base/time/time.h" | 22 #include "base/time/time.h" |
22 #include "base/trace_event/trace_event.h" | 23 #include "base/trace_event/trace_event.h" |
23 #include "content/browser/bad_message.h" | 24 #include "content/browser/bad_message.h" |
| 25 #include "content/browser/download/download_task_runner.h" |
24 #include "content/browser/download/mhtml_extra_parts_impl.h" | 26 #include "content/browser/download/mhtml_extra_parts_impl.h" |
25 #include "content/browser/frame_host/frame_tree_node.h" | 27 #include "content/browser/frame_host/frame_tree_node.h" |
26 #include "content/browser/frame_host/render_frame_host_impl.h" | 28 #include "content/browser/frame_host/render_frame_host_impl.h" |
27 #include "content/common/frame_messages.h" | 29 #include "content/common/frame_messages.h" |
28 #include "content/public/browser/browser_thread.h" | 30 #include "content/public/browser/browser_thread.h" |
29 #include "content/public/browser/mhtml_extra_parts.h" | 31 #include "content/public/browser/mhtml_extra_parts.h" |
30 #include "content/public/browser/render_frame_host.h" | 32 #include "content/public/browser/render_frame_host.h" |
31 #include "content/public/browser/render_process_host.h" | 33 #include "content/public/browser/render_process_host.h" |
32 #include "content/public/browser/render_process_host_observer.h" | 34 #include "content/public/browser/render_process_host_observer.h" |
33 #include "content/public/browser/web_contents.h" | 35 #include "content/public/browser/web_contents.h" |
(...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
373 | 375 |
374 if (!browser_file_.IsValid()) { | 376 if (!browser_file_.IsValid()) { |
375 // Only update the status if that won't hide an earlier error. | 377 // Only update the status if that won't hide an earlier error. |
376 if (save_status == MhtmlSaveStatus::SUCCESS) | 378 if (save_status == MhtmlSaveStatus::SUCCESS) |
377 save_status = MhtmlSaveStatus::FILE_WRITTING_ERROR; | 379 save_status = MhtmlSaveStatus::FILE_WRITTING_ERROR; |
378 callback.Run(std::make_tuple(save_status, -1)); | 380 callback.Run(std::make_tuple(save_status, -1)); |
379 return; | 381 return; |
380 } | 382 } |
381 | 383 |
382 // If no previous error occurred the boundary should be sent. | 384 // If no previous error occurred the boundary should be sent. |
383 BrowserThread::PostTaskAndReplyWithResult( | 385 base::PostTaskAndReplyWithResult( |
384 BrowserThread::FILE, FROM_HERE, | 386 GetDownloadTaskRunner().get(), FROM_HERE, |
385 base::Bind( | 387 base::Bind( |
386 &MHTMLGenerationManager::Job::FinalizeAndCloseFileOnFileThread, | 388 &MHTMLGenerationManager::Job::FinalizeAndCloseFileOnFileThread, |
387 save_status, | 389 save_status, |
388 (save_status == MhtmlSaveStatus::SUCCESS ? mhtml_boundary_marker_ | 390 (save_status == MhtmlSaveStatus::SUCCESS ? mhtml_boundary_marker_ |
389 : std::string()), | 391 : std::string()), |
390 base::Passed(&browser_file_), extra_parts_), | 392 base::Passed(&browser_file_), extra_parts_), |
391 callback); | 393 callback); |
392 } | 394 } |
393 | 395 |
394 bool MHTMLGenerationManager::Job::IsMessageFromFrameExpected( | 396 bool MHTMLGenerationManager::Job::IsMessageFromFrameExpected( |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
431 return SendToNextRenderFrame(); | 433 return SendToNextRenderFrame(); |
432 } | 434 } |
433 | 435 |
434 // static | 436 // static |
435 std::tuple<MhtmlSaveStatus, int64_t> | 437 std::tuple<MhtmlSaveStatus, int64_t> |
436 MHTMLGenerationManager::Job::FinalizeAndCloseFileOnFileThread( | 438 MHTMLGenerationManager::Job::FinalizeAndCloseFileOnFileThread( |
437 MhtmlSaveStatus save_status, | 439 MhtmlSaveStatus save_status, |
438 const std::string& boundary, | 440 const std::string& boundary, |
439 base::File file, | 441 base::File file, |
440 const MHTMLExtraPartsImpl* extra_parts) { | 442 const MHTMLExtraPartsImpl* extra_parts) { |
441 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 443 DCHECK(GetDownloadTaskRunner()->RunsTasksInCurrentSequence()); |
442 | 444 |
443 // If no previous error occurred the boundary should have been provided. | 445 // If no previous error occurred the boundary should have been provided. |
444 if (save_status == MhtmlSaveStatus::SUCCESS) { | 446 if (save_status == MhtmlSaveStatus::SUCCESS) { |
445 TRACE_EVENT0("page-serialization", | 447 TRACE_EVENT0("page-serialization", |
446 "MHTMLGenerationManager::Job MHTML footer writing"); | 448 "MHTMLGenerationManager::Job MHTML footer writing"); |
447 DCHECK(!boundary.empty()); | 449 DCHECK(!boundary.empty()); |
448 | 450 |
449 // Write the extra data into a part of its own, if we have any. | 451 // Write the extra data into a part of its own, if we have any. |
450 if (!WriteExtraDataParts(boundary, file, extra_parts)) { | 452 if (!WriteExtraDataParts(boundary, file, extra_parts)) { |
451 save_status = MhtmlSaveStatus::FILE_WRITTING_ERROR; | 453 save_status = MhtmlSaveStatus::FILE_WRITTING_ERROR; |
(...skipping 15 matching lines...) Expand all Loading... |
467 } | 469 } |
468 | 470 |
469 return std::make_tuple(save_status, file_size); | 471 return std::make_tuple(save_status, file_size); |
470 } | 472 } |
471 | 473 |
472 // static | 474 // static |
473 bool MHTMLGenerationManager::Job::WriteExtraDataParts( | 475 bool MHTMLGenerationManager::Job::WriteExtraDataParts( |
474 const std::string& boundary, | 476 const std::string& boundary, |
475 base::File& file, | 477 base::File& file, |
476 const MHTMLExtraPartsImpl* extra_parts) { | 478 const MHTMLExtraPartsImpl* extra_parts) { |
477 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 479 DCHECK(GetDownloadTaskRunner()->RunsTasksInCurrentSequence()); |
478 // Don't write an extra data part if there is none. | 480 // Don't write an extra data part if there is none. |
479 if (extra_parts == nullptr) | 481 if (extra_parts == nullptr) |
480 return true; | 482 return true; |
481 | 483 |
482 const std::vector<MHTMLExtraDataPart>& extra_data_parts(extra_parts->parts()); | 484 const std::vector<MHTMLExtraDataPart>& extra_data_parts(extra_parts->parts()); |
483 if (extra_data_parts.empty()) | 485 if (extra_data_parts.empty()) |
484 return true; | 486 return true; |
485 | 487 |
486 std::string serialized_extra_data_parts; | 488 std::string serialized_extra_data_parts; |
487 | 489 |
(...skipping 14 matching lines...) Expand all Loading... |
502 } | 504 } |
503 | 505 |
504 // Write the string into the file. Returns false if we failed the write. | 506 // Write the string into the file. Returns false if we failed the write. |
505 return (file.WriteAtCurrentPos(serialized_extra_data_parts.data(), | 507 return (file.WriteAtCurrentPos(serialized_extra_data_parts.data(), |
506 serialized_extra_data_parts.size()) >= 0); | 508 serialized_extra_data_parts.size()) >= 0); |
507 } | 509 } |
508 | 510 |
509 // static | 511 // static |
510 bool MHTMLGenerationManager::Job::WriteFooter(const std::string& boundary, | 512 bool MHTMLGenerationManager::Job::WriteFooter(const std::string& boundary, |
511 base::File& file) { | 513 base::File& file) { |
512 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 514 DCHECK(GetDownloadTaskRunner()->RunsTasksInCurrentSequence()); |
513 std::string footer = base::StringPrintf("--%s--\r\n", boundary.c_str()); | 515 std::string footer = base::StringPrintf("--%s--\r\n", boundary.c_str()); |
514 DCHECK(base::IsStringASCII(footer)); | 516 DCHECK(base::IsStringASCII(footer)); |
515 return (file.WriteAtCurrentPos(footer.data(), footer.size()) >= 0); | 517 return (file.WriteAtCurrentPos(footer.data(), footer.size()) >= 0); |
516 } | 518 } |
517 | 519 |
518 // static | 520 // static |
519 bool MHTMLGenerationManager::Job::CloseFileIfValid(base::File& file, | 521 bool MHTMLGenerationManager::Job::CloseFileIfValid(base::File& file, |
520 int64_t* file_size) { | 522 int64_t* file_size) { |
521 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 523 DCHECK(GetDownloadTaskRunner()->RunsTasksInCurrentSequence()); |
522 DCHECK(file_size); | 524 DCHECK(file_size); |
523 if (file.IsValid()) { | 525 if (file.IsValid()) { |
524 *file_size = file.GetLength(); | 526 *file_size = file.GetLength(); |
525 file.Close(); | 527 file.Close(); |
526 return true; | 528 return true; |
527 } | 529 } |
528 | 530 |
529 return false; | 531 return false; |
530 } | 532 } |
531 | 533 |
(...skipping 10 matching lines...) Expand all Loading... |
542 const MHTMLGenerationParams& params, | 544 const MHTMLGenerationParams& params, |
543 const GenerateMHTMLCallback& callback) { | 545 const GenerateMHTMLCallback& callback) { |
544 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 546 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
545 | 547 |
546 Job* job = NewJob(web_contents, params, callback); | 548 Job* job = NewJob(web_contents, params, callback); |
547 TRACE_EVENT_NESTABLE_ASYNC_BEGIN2( | 549 TRACE_EVENT_NESTABLE_ASYNC_BEGIN2( |
548 "page-serialization", "SavingMhtmlJob", job, "url", | 550 "page-serialization", "SavingMhtmlJob", job, "url", |
549 web_contents->GetLastCommittedURL().possibly_invalid_spec(), | 551 web_contents->GetLastCommittedURL().possibly_invalid_spec(), |
550 "file", params.file_path.AsUTF8Unsafe()); | 552 "file", params.file_path.AsUTF8Unsafe()); |
551 | 553 |
552 BrowserThread::PostTaskAndReplyWithResult( | 554 base::PostTaskAndReplyWithResult( |
553 BrowserThread::FILE, FROM_HERE, | 555 GetDownloadTaskRunner().get(), FROM_HERE, |
554 base::Bind(&MHTMLGenerationManager::CreateFile, params.file_path), | 556 base::Bind(&MHTMLGenerationManager::CreateFile, params.file_path), |
555 base::Bind(&MHTMLGenerationManager::OnFileAvailable, | 557 base::Bind(&MHTMLGenerationManager::OnFileAvailable, |
556 base::Unretained(this), // Safe b/c |this| is a singleton. | 558 base::Unretained(this), // Safe b/c |this| is a singleton. |
557 job->id())); | 559 job->id())); |
558 } | 560 } |
559 | 561 |
560 void MHTMLGenerationManager::OnSerializeAsMHTMLResponse( | 562 void MHTMLGenerationManager::OnSerializeAsMHTMLResponse( |
561 RenderFrameHostImpl* sender, | 563 RenderFrameHostImpl* sender, |
562 int job_id, | 564 int job_id, |
563 MhtmlSaveStatus save_status, | 565 MhtmlSaveStatus save_status, |
(...skipping 26 matching lines...) Expand all Loading... |
590 return; | 592 return; |
591 } | 593 } |
592 | 594 |
593 // Otherwise report completion if the job is done. | 595 // Otherwise report completion if the job is done. |
594 if (job->IsDone()) | 596 if (job->IsDone()) |
595 JobFinished(job, MhtmlSaveStatus::SUCCESS); | 597 JobFinished(job, MhtmlSaveStatus::SUCCESS); |
596 } | 598 } |
597 | 599 |
598 // static | 600 // static |
599 base::File MHTMLGenerationManager::CreateFile(const base::FilePath& file_path) { | 601 base::File MHTMLGenerationManager::CreateFile(const base::FilePath& file_path) { |
600 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 602 DCHECK(GetDownloadTaskRunner()->RunsTasksInCurrentSequence()); |
601 | 603 |
602 // SECURITY NOTE: A file descriptor to the file created below will be passed | 604 // SECURITY NOTE: A file descriptor to the file created below will be passed |
603 // to multiple renderer processes which (in out-of-process iframes mode) can | 605 // to multiple renderer processes which (in out-of-process iframes mode) can |
604 // act on behalf of separate web principals. Therefore it is important to | 606 // act on behalf of separate web principals. Therefore it is important to |
605 // only allow writing to the file and forbid reading from the file (as this | 607 // only allow writing to the file and forbid reading from the file (as this |
606 // would allow reading content generated by other renderers / other web | 608 // would allow reading content generated by other renderers / other web |
607 // principals). | 609 // principals). |
608 uint32_t file_flags = base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE; | 610 uint32_t file_flags = base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE; |
609 | 611 |
610 base::File browser_file(file_path, file_flags); | 612 base::File browser_file(file_path, file_flags); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
691 return iter->second.get(); | 693 return iter->second.get(); |
692 } | 694 } |
693 | 695 |
694 void MHTMLGenerationManager::RenderProcessExited(Job* job) { | 696 void MHTMLGenerationManager::RenderProcessExited(Job* job) { |
695 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 697 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
696 DCHECK(job); | 698 DCHECK(job); |
697 JobFinished(job, MhtmlSaveStatus::RENDER_PROCESS_EXITED); | 699 JobFinished(job, MhtmlSaveStatus::RENDER_PROCESS_EXITED); |
698 } | 700 } |
699 | 701 |
700 } // namespace content | 702 } // namespace content |
OLD | NEW |