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/save_package.h" | 5 #include "content/browser/download/save_package.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
51 #include "net/base/io_buffer.h" | 51 #include "net/base/io_buffer.h" |
52 #include "net/base/mime_util.h" | 52 #include "net/base/mime_util.h" |
53 #include "net/url_request/url_request_context.h" | 53 #include "net/url_request/url_request_context.h" |
54 #include "url/url_constants.h" | 54 #include "url/url_constants.h" |
55 | 55 |
56 using base::Time; | 56 using base::Time; |
57 | 57 |
58 namespace content { | 58 namespace content { |
59 namespace { | 59 namespace { |
60 | 60 |
61 // A counter for uniquely identifying each save package. | 61 // Generates unique ids for SavePackage::unique_id_ field. |
62 int g_save_package_id = 0; | 62 SavePackageId GetNextSavePackageId() { |
| 63 static int g_save_package_id = 0; |
| 64 return SavePackageId::FromUnsafeValue(g_save_package_id++); |
| 65 } |
63 | 66 |
64 // Default name which will be used when we can not get proper name from | 67 // Default name which will be used when we can not get proper name from |
65 // resource URL. | 68 // resource URL. |
66 const char kDefaultSaveName[] = "saved_resource"; | 69 const char kDefaultSaveName[] = "saved_resource"; |
67 | 70 |
68 // Maximum number of file ordinal number. I think it's big enough for resolving | 71 // Maximum number of file ordinal number. I think it's big enough for resolving |
69 // name-conflict files which has same base file name. | 72 // name-conflict files which has same base file name. |
70 const int32_t kMaxFileOrdinalNumber = 9999; | 73 const int32_t kMaxFileOrdinalNumber = 9999; |
71 | 74 |
72 // Maximum length for file path. Since Windows have MAX_PATH limitation for | 75 // Maximum length for file path. Since Windows have MAX_PATH limitation for |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
155 title_(web_contents->GetTitle()), | 158 title_(web_contents->GetTitle()), |
156 start_tick_(base::TimeTicks::Now()), | 159 start_tick_(base::TimeTicks::Now()), |
157 finished_(false), | 160 finished_(false), |
158 mhtml_finishing_(false), | 161 mhtml_finishing_(false), |
159 user_canceled_(false), | 162 user_canceled_(false), |
160 disk_error_occurred_(false), | 163 disk_error_occurred_(false), |
161 save_type_(save_type), | 164 save_type_(save_type), |
162 all_save_items_count_(0), | 165 all_save_items_count_(0), |
163 file_name_set_(&base::FilePath::CompareLessIgnoreCase), | 166 file_name_set_(&base::FilePath::CompareLessIgnoreCase), |
164 wait_state_(INITIALIZE), | 167 wait_state_(INITIALIZE), |
165 unique_id_(g_save_package_id++), | 168 unique_id_(GetNextSavePackageId()), |
166 wrote_to_completed_file_(false), | 169 wrote_to_completed_file_(false), |
167 wrote_to_failed_file_(false) { | 170 wrote_to_failed_file_(false) { |
168 DCHECK(page_url_.is_valid()); | 171 DCHECK(page_url_.is_valid()); |
169 DCHECK((save_type_ == SAVE_PAGE_TYPE_AS_ONLY_HTML) || | 172 DCHECK((save_type_ == SAVE_PAGE_TYPE_AS_ONLY_HTML) || |
170 (save_type_ == SAVE_PAGE_TYPE_AS_MHTML) || | 173 (save_type_ == SAVE_PAGE_TYPE_AS_MHTML) || |
171 (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML)) | 174 (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML)) |
172 << save_type_; | 175 << save_type_; |
173 DCHECK(!saved_main_file_path_.empty() && | 176 DCHECK(!saved_main_file_path_.empty() && |
174 saved_main_file_path_.value().length() <= kMaxFilePathLength); | 177 saved_main_file_path_.value().length() <= kMaxFilePathLength); |
175 DCHECK(!saved_main_directory_path_.empty() && | 178 DCHECK(!saved_main_directory_path_.empty() && |
(...skipping 11 matching lines...) Expand all Loading... |
187 title_(web_contents->GetTitle()), | 190 title_(web_contents->GetTitle()), |
188 start_tick_(base::TimeTicks::Now()), | 191 start_tick_(base::TimeTicks::Now()), |
189 finished_(false), | 192 finished_(false), |
190 mhtml_finishing_(false), | 193 mhtml_finishing_(false), |
191 user_canceled_(false), | 194 user_canceled_(false), |
192 disk_error_occurred_(false), | 195 disk_error_occurred_(false), |
193 save_type_(SAVE_PAGE_TYPE_UNKNOWN), | 196 save_type_(SAVE_PAGE_TYPE_UNKNOWN), |
194 all_save_items_count_(0), | 197 all_save_items_count_(0), |
195 file_name_set_(&base::FilePath::CompareLessIgnoreCase), | 198 file_name_set_(&base::FilePath::CompareLessIgnoreCase), |
196 wait_state_(INITIALIZE), | 199 wait_state_(INITIALIZE), |
197 unique_id_(g_save_package_id++), | 200 unique_id_(GetNextSavePackageId()), |
198 wrote_to_completed_file_(false), | 201 wrote_to_completed_file_(false), |
199 wrote_to_failed_file_(false) { | 202 wrote_to_failed_file_(false) { |
200 DCHECK(page_url_.is_valid()); | 203 DCHECK(page_url_.is_valid()); |
201 InternalInit(); | 204 InternalInit(); |
202 } | 205 } |
203 | 206 |
204 // This is for testing use. Set |finished_| as true because we don't want | 207 // This is for testing use. Set |finished_| as true because we don't want |
205 // method Cancel to be be called in destructor in test mode. | 208 // method Cancel to be be called in destructor in test mode. |
206 // We also don't call InternalInit(). | 209 // We also don't call InternalInit(). |
207 SavePackage::SavePackage(WebContents* web_contents, | 210 SavePackage::SavePackage(WebContents* web_contents, |
208 const base::FilePath& file_full_path, | 211 const base::FilePath& file_full_path, |
209 const base::FilePath& directory_full_path) | 212 const base::FilePath& directory_full_path) |
210 : WebContentsObserver(web_contents), | 213 : WebContentsObserver(web_contents), |
211 number_of_frames_pending_response_(0), | 214 number_of_frames_pending_response_(0), |
212 file_manager_(NULL), | 215 file_manager_(NULL), |
213 download_manager_(NULL), | 216 download_manager_(NULL), |
214 download_(NULL), | 217 download_(NULL), |
215 saved_main_file_path_(file_full_path), | 218 saved_main_file_path_(file_full_path), |
216 saved_main_directory_path_(directory_full_path), | 219 saved_main_directory_path_(directory_full_path), |
217 start_tick_(base::TimeTicks::Now()), | 220 start_tick_(base::TimeTicks::Now()), |
218 finished_(true), | 221 finished_(true), |
219 mhtml_finishing_(false), | 222 mhtml_finishing_(false), |
220 user_canceled_(false), | 223 user_canceled_(false), |
221 disk_error_occurred_(false), | 224 disk_error_occurred_(false), |
222 save_type_(SAVE_PAGE_TYPE_UNKNOWN), | 225 save_type_(SAVE_PAGE_TYPE_UNKNOWN), |
223 all_save_items_count_(0), | 226 all_save_items_count_(0), |
224 file_name_set_(&base::FilePath::CompareLessIgnoreCase), | 227 file_name_set_(&base::FilePath::CompareLessIgnoreCase), |
225 wait_state_(INITIALIZE), | 228 wait_state_(INITIALIZE), |
226 unique_id_(g_save_package_id++), | 229 unique_id_(GetNextSavePackageId()), |
227 wrote_to_completed_file_(false), | 230 wrote_to_completed_file_(false), |
228 wrote_to_failed_file_(false) {} | 231 wrote_to_failed_file_(false) {} |
229 | 232 |
230 SavePackage::~SavePackage() { | 233 SavePackage::~SavePackage() { |
231 // Stop receiving saving job's updates | 234 // Stop receiving saving job's updates |
232 if (!finished_ && !canceled()) { | 235 if (!finished_ && !canceled()) { |
233 // Unexpected quit. | 236 // Unexpected quit. |
234 Cancel(true); | 237 Cancel(true); |
235 } | 238 } |
236 | 239 |
(...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
620 | 623 |
621 // Check whether we begin to require serialized HTML data. | 624 // Check whether we begin to require serialized HTML data. |
622 if (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML && | 625 if (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML && |
623 wait_state_ == HTML_DATA) { | 626 wait_state_ == HTML_DATA) { |
624 // Inform backend to serialize the all frames' DOM and send serialized | 627 // Inform backend to serialize the all frames' DOM and send serialized |
625 // HTML data back. | 628 // HTML data back. |
626 GetSerializedHtmlWithLocalLinks(); | 629 GetSerializedHtmlWithLocalLinks(); |
627 } | 630 } |
628 } | 631 } |
629 | 632 |
630 SaveItem* SavePackage::LookupSaveItemInProcess(int32_t save_item_id) { | 633 SaveItem* SavePackage::LookupSaveItemInProcess(SaveItemId save_item_id) { |
631 auto it = in_progress_items_.find(save_item_id); | 634 auto it = in_progress_items_.find(save_item_id); |
632 if (it != in_progress_items_.end()) { | 635 if (it != in_progress_items_.end()) { |
633 SaveItem* save_item = it->second; | 636 SaveItem* save_item = it->second; |
634 DCHECK_EQ(SaveItem::IN_PROGRESS, save_item->state()); | 637 DCHECK_EQ(SaveItem::IN_PROGRESS, save_item->state()); |
635 return save_item; | 638 return save_item; |
636 } | 639 } |
637 return nullptr; | 640 return nullptr; |
638 } | 641 } |
639 | 642 |
640 void SavePackage::PutInProgressItemToSavedMap(SaveItem* save_item) { | 643 void SavePackage::PutInProgressItemToSavedMap(SaveItem* save_item) { |
641 SaveItemIdMap::iterator it = in_progress_items_.find(save_item->id()); | 644 SaveItemIdMap::iterator it = in_progress_items_.find(save_item->id()); |
642 DCHECK(it != in_progress_items_.end()); | 645 DCHECK(it != in_progress_items_.end()); |
643 DCHECK(save_item == it->second); | 646 DCHECK(save_item == it->second); |
644 in_progress_items_.erase(it); | 647 in_progress_items_.erase(it); |
645 | 648 |
646 if (save_item->success()) { | 649 if (save_item->success()) { |
647 // Add it to saved_success_items_. | 650 // Add it to saved_success_items_. |
648 DCHECK(saved_success_items_.find(save_item->id()) == | 651 DCHECK(saved_success_items_.find(save_item->id()) == |
649 saved_success_items_.end()); | 652 saved_success_items_.end()); |
650 saved_success_items_[save_item->id()] = save_item; | 653 saved_success_items_[save_item->id()] = save_item; |
651 } else { | 654 } else { |
652 // Add it to saved_failed_items_. | 655 // Add it to saved_failed_items_. |
653 DCHECK(saved_failed_items_.find(save_item->id()) == | 656 DCHECK(saved_failed_items_.find(save_item->id()) == |
654 saved_failed_items_.end()); | 657 saved_failed_items_.end()); |
655 saved_failed_items_[save_item->id()] = save_item; | 658 saved_failed_items_[save_item->id()] = save_item; |
656 } | 659 } |
657 } | 660 } |
658 | 661 |
659 // Called for updating saving state. | 662 // Called for updating saving state. |
660 bool SavePackage::UpdateSaveProgress(int32_t save_item_id, | 663 bool SavePackage::UpdateSaveProgress(SaveItemId save_item_id, |
661 int64_t size, | 664 int64_t size, |
662 bool write_success) { | 665 bool write_success) { |
663 // Because we might have canceled this saving job before, | 666 // Because we might have canceled this saving job before, |
664 // so we might not find corresponding SaveItem. | 667 // so we might not find corresponding SaveItem. |
665 SaveItem* save_item = LookupSaveItemInProcess(save_item_id); | 668 SaveItem* save_item = LookupSaveItemInProcess(save_item_id); |
666 if (!save_item) | 669 if (!save_item) |
667 return false; | 670 return false; |
668 | 671 |
669 save_item->Update(size); | 672 save_item->Update(size); |
670 | 673 |
671 // If we got disk error, cancel whole save page job. | 674 // If we got disk error, cancel whole save page job. |
672 if (!write_success) { | 675 if (!write_success) { |
673 // Cancel job with reason of disk error. | 676 // Cancel job with reason of disk error. |
674 Cancel(false); | 677 Cancel(false); |
675 } | 678 } |
676 return true; | 679 return true; |
677 } | 680 } |
678 | 681 |
679 // Stop all page saving jobs that are in progress and instruct the file thread | 682 // Stop all page saving jobs that are in progress and instruct the file thread |
680 // to delete all saved files. | 683 // to delete all saved files. |
681 void SavePackage::Stop() { | 684 void SavePackage::Stop() { |
682 // If we haven't moved out of the initial state, there's nothing to cancel and | 685 // If we haven't moved out of the initial state, there's nothing to cancel and |
683 // there won't be valid pointers for file_manager_ or download_. | 686 // there won't be valid pointers for file_manager_ or download_. |
684 if (wait_state_ == INITIALIZE) | 687 if (wait_state_ == INITIALIZE) |
685 return; | 688 return; |
686 | 689 |
687 // When stopping, if it still has some items in in_progress, cancel them. | 690 // When stopping, if it still has some items in in_progress, cancel them. |
688 DCHECK(canceled()); | 691 DCHECK(canceled()); |
689 if (in_process_count()) { | 692 if (in_process_count()) { |
690 SaveItemIdMap::iterator it = in_progress_items_.begin(); | 693 for (const auto& it : in_progress_items_) { |
691 for (; it != in_progress_items_.end(); ++it) { | 694 SaveItem* save_item = it.second; |
692 SaveItem* save_item = it->second; | |
693 DCHECK_EQ(SaveItem::IN_PROGRESS, save_item->state()); | 695 DCHECK_EQ(SaveItem::IN_PROGRESS, save_item->state()); |
694 save_item->Cancel(); | 696 save_item->Cancel(); |
695 } | 697 } |
696 // Remove all in progress item to saved map. For failed items, they will | 698 // Remove all in progress item to saved map. For failed items, they will |
697 // be put into saved_failed_items_, for successful item, they will be put | 699 // be put into saved_failed_items_, for successful item, they will be put |
698 // into saved_success_items_. | 700 // into saved_success_items_. |
699 while (in_process_count()) | 701 while (in_process_count()) |
700 PutInProgressItemToSavedMap(in_progress_items_.begin()->second); | 702 PutInProgressItemToSavedMap(in_progress_items_.begin()->second); |
701 } | 703 } |
702 | 704 |
703 // This vector contains the save ids of the save files which SaveFileManager | 705 // This vector contains the save ids of the save files which SaveFileManager |
704 // needs to remove from its save_file_map_. | 706 // needs to remove from its save_file_map_. |
705 std::vector<int> save_item_ids; | 707 std::vector<SaveItemId> save_item_ids; |
706 for (const auto& it : saved_success_items_) | 708 for (const auto& it : saved_success_items_) |
707 save_item_ids.push_back(it.first); | 709 save_item_ids.push_back(it.first); |
708 for (const auto& it : saved_failed_items_) | 710 for (const auto& it : saved_failed_items_) |
709 save_item_ids.push_back(it.first); | 711 save_item_ids.push_back(it.first); |
710 | 712 |
711 BrowserThread::PostTask( | 713 BrowserThread::PostTask( |
712 BrowserThread::FILE, FROM_HERE, | 714 BrowserThread::FILE, FROM_HERE, |
713 base::Bind(&SaveFileManager::RemoveSavedFileFromFileMap, file_manager_, | 715 base::Bind(&SaveFileManager::RemoveSavedFileFromFileMap, file_manager_, |
714 save_item_ids)); | 716 save_item_ids)); |
715 | 717 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
760 | 762 |
761 // Record any errors that occurred. | 763 // Record any errors that occurred. |
762 if (wrote_to_completed_file_) | 764 if (wrote_to_completed_file_) |
763 RecordSavePackageEvent(SAVE_PACKAGE_WRITE_TO_COMPLETED); | 765 RecordSavePackageEvent(SAVE_PACKAGE_WRITE_TO_COMPLETED); |
764 | 766 |
765 if (wrote_to_failed_file_) | 767 if (wrote_to_failed_file_) |
766 RecordSavePackageEvent(SAVE_PACKAGE_WRITE_TO_FAILED); | 768 RecordSavePackageEvent(SAVE_PACKAGE_WRITE_TO_FAILED); |
767 | 769 |
768 // This vector contains the save ids of the save files which SaveFileManager | 770 // This vector contains the save ids of the save files which SaveFileManager |
769 // needs to remove from its save_file_map_. | 771 // needs to remove from its save_file_map_. |
770 std::vector<int> list_of_failed_save_item_ids; | 772 std::vector<SaveItemId> list_of_failed_save_item_ids; |
771 for (const auto& it : saved_failed_items_) { | 773 for (const auto& it : saved_failed_items_) { |
772 SaveItem* save_item = it.second; | 774 SaveItem* save_item = it.second; |
773 DCHECK_EQ(it.first, save_item->id()); | 775 DCHECK_EQ(it.first, save_item->id()); |
774 list_of_failed_save_item_ids.push_back(save_item->id()); | 776 list_of_failed_save_item_ids.push_back(save_item->id()); |
775 } | 777 } |
776 | 778 |
777 BrowserThread::PostTask( | 779 BrowserThread::PostTask( |
778 BrowserThread::FILE, FROM_HERE, | 780 BrowserThread::FILE, FROM_HERE, |
779 base::Bind(&SaveFileManager::RemoveSavedFileFromFileMap, file_manager_, | 781 base::Bind(&SaveFileManager::RemoveSavedFileFromFileMap, file_manager_, |
780 list_of_failed_save_item_ids)); | 782 list_of_failed_save_item_ids)); |
781 | 783 |
782 if (download_) { | 784 if (download_) { |
783 // Hack to avoid touching download_ after user cancel. | 785 // Hack to avoid touching download_ after user cancel. |
784 // TODO(rdsmith/benjhayden): Integrate canceling on DownloadItem | 786 // TODO(rdsmith/benjhayden): Integrate canceling on DownloadItem |
785 // with SavePackage flow. | 787 // with SavePackage flow. |
786 if (download_->GetState() == DownloadItem::IN_PROGRESS) { | 788 if (download_->GetState() == DownloadItem::IN_PROGRESS) { |
787 if (save_type_ != SAVE_PAGE_TYPE_AS_MHTML) { | 789 if (save_type_ != SAVE_PAGE_TYPE_AS_MHTML) { |
788 download_->DestinationUpdate( | 790 download_->DestinationUpdate( |
789 all_save_items_count_, CurrentSpeed(), std::string()); | 791 all_save_items_count_, CurrentSpeed(), std::string()); |
790 download_->OnAllDataSaved(DownloadItem::kEmptyFileHash); | 792 download_->OnAllDataSaved(DownloadItem::kEmptyFileHash); |
791 } | 793 } |
792 download_->MarkAsComplete(); | 794 download_->MarkAsComplete(); |
793 } | 795 } |
794 FinalizeDownloadEntry(); | 796 FinalizeDownloadEntry(); |
795 } | 797 } |
796 } | 798 } |
797 | 799 |
798 // Called for updating end state. | 800 // Called for updating end state. |
799 void SavePackage::SaveFinished(int32_t save_item_id, | 801 void SavePackage::SaveFinished(SaveItemId save_item_id, |
800 int64_t size, | 802 int64_t size, |
801 bool is_success) { | 803 bool is_success) { |
802 // Because we might have canceled this saving job before, | 804 // Because we might have canceled this saving job before, |
803 // so we might not find corresponding SaveItem. Just ignore it. | 805 // so we might not find corresponding SaveItem. Just ignore it. |
804 SaveItem* save_item = LookupSaveItemInProcess(save_item_id); | 806 SaveItem* save_item = LookupSaveItemInProcess(save_item_id); |
805 if (!save_item) | 807 if (!save_item) |
806 return; | 808 return; |
807 | 809 |
808 // Let SaveItem set end state. | 810 // Let SaveItem set end state. |
809 save_item->Finish(size, is_success); | 811 save_item->Finish(size, is_success); |
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1037 if (it == frame_tree_node_id_to_save_item_.end()) { | 1039 if (it == frame_tree_node_id_to_save_item_.end()) { |
1038 // Sanitization of renderer IPC - we will have no save item only if | 1040 // Sanitization of renderer IPC - we will have no save item only if |
1039 // the renderer misbehaves and sends OnSerializedHtmlFragment IPC without | 1041 // the renderer misbehaves and sends OnSerializedHtmlFragment IPC without |
1040 // being asked to. | 1042 // being asked to. |
1041 NOTREACHED(); | 1043 NOTREACHED(); |
1042 return; | 1044 return; |
1043 } | 1045 } |
1044 SaveItem* save_item = it->second; | 1046 SaveItem* save_item = it->second; |
1045 DCHECK_EQ(SaveFileCreateInfo::SAVE_FILE_FROM_DOM, save_item->save_source()); | 1047 DCHECK_EQ(SaveFileCreateInfo::SAVE_FILE_FROM_DOM, save_item->save_source()); |
1046 if (save_item->state() != SaveItem::IN_PROGRESS) { | 1048 if (save_item->state() != SaveItem::IN_PROGRESS) { |
1047 for (SavedItemMap::iterator saved_it = saved_success_items_.begin(); | 1049 for (const auto& saved_it : saved_success_items_) { |
1048 saved_it != saved_success_items_.end(); ++saved_it) { | 1050 if (saved_it.second->url() == save_item->url()) { |
1049 if (saved_it->second->url() == save_item->url()) { | |
1050 wrote_to_completed_file_ = true; | 1051 wrote_to_completed_file_ = true; |
1051 break; | 1052 break; |
1052 } | 1053 } |
1053 } | 1054 } |
1054 | 1055 |
1055 auto it2 = saved_failed_items_.find(save_item->id()); | 1056 auto it2 = saved_failed_items_.find(save_item->id()); |
1056 if (it2 != saved_failed_items_.end()) | 1057 if (it2 != saved_failed_items_.end()) |
1057 wrote_to_failed_file_ = true; | 1058 wrote_to_failed_file_ = true; |
1058 | 1059 |
1059 return; | 1060 return; |
(...skipping 434 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1494 | 1495 |
1495 void SavePackage::FinalizeDownloadEntry() { | 1496 void SavePackage::FinalizeDownloadEntry() { |
1496 DCHECK(download_); | 1497 DCHECK(download_); |
1497 DCHECK(download_manager_); | 1498 DCHECK(download_manager_); |
1498 | 1499 |
1499 download_manager_->OnSavePackageSuccessfullyFinished(download_); | 1500 download_manager_->OnSavePackageSuccessfullyFinished(download_); |
1500 StopObservation(); | 1501 StopObservation(); |
1501 } | 1502 } |
1502 | 1503 |
1503 } // namespace content | 1504 } // namespace content |
OLD | NEW |