| 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 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/file_path.h" | 10 #include "base/file_path.h" |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 134 user_canceled_(false), | 134 user_canceled_(false), |
| 135 disk_error_occurred_(false), | 135 disk_error_occurred_(false), |
| 136 save_type_(save_type), | 136 save_type_(save_type), |
| 137 all_save_items_count_(0), | 137 all_save_items_count_(0), |
| 138 wait_state_(INITIALIZE), | 138 wait_state_(INITIALIZE), |
| 139 contents_id_(web_contents->GetRenderProcessHost()->GetID()), | 139 contents_id_(web_contents->GetRenderProcessHost()->GetID()), |
| 140 unique_id_(g_save_package_id++), | 140 unique_id_(g_save_package_id++), |
| 141 wrote_to_completed_file_(false), | 141 wrote_to_completed_file_(false), |
| 142 wrote_to_failed_file_(false) { | 142 wrote_to_failed_file_(false) { |
| 143 DCHECK(page_url_.is_valid()); | 143 DCHECK(page_url_.is_valid()); |
| 144 DCHECK(save_type_ == content::SAVE_PAGE_TYPE_AS_ONLY_HTML || | 144 DCHECK((save_type_ == content::SAVE_PAGE_TYPE_AS_ONLY_HTML) || |
| 145 save_type_ == content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML); | 145 (save_type_ == content::SAVE_PAGE_TYPE_AS_MHTML) || |
| 146 (save_type_ == content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML)); |
| 146 DCHECK(!saved_main_file_path_.empty() && | 147 DCHECK(!saved_main_file_path_.empty() && |
| 147 saved_main_file_path_.value().length() <= kMaxFilePathLength); | 148 saved_main_file_path_.value().length() <= kMaxFilePathLength); |
| 148 DCHECK(!saved_main_directory_path_.empty() && | 149 DCHECK(!saved_main_directory_path_.empty() && |
| 149 saved_main_directory_path_.value().length() < kMaxFilePathLength); | 150 saved_main_directory_path_.value().length() < kMaxFilePathLength); |
| 150 InternalInit(); | 151 InternalInit(); |
| 151 } | 152 } |
| 152 | 153 |
| 153 SavePackage::SavePackage(WebContents* web_contents) | 154 SavePackage::SavePackage(WebContents* web_contents) |
| 154 : content::WebContentsObserver(web_contents), | 155 : content::WebContentsObserver(web_contents), |
| 155 file_manager_(NULL), | 156 file_manager_(NULL), |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 258 | 259 |
| 259 file_manager_ = rdh->save_file_manager(); | 260 file_manager_ = rdh->save_file_manager(); |
| 260 DCHECK(file_manager_); | 261 DCHECK(file_manager_); |
| 261 | 262 |
| 262 download_manager_ = web_contents()->GetBrowserContext()->GetDownloadManager(); | 263 download_manager_ = web_contents()->GetBrowserContext()->GetDownloadManager(); |
| 263 DCHECK(download_manager_); | 264 DCHECK(download_manager_); |
| 264 | 265 |
| 265 download_stats::RecordSavePackageEvent(download_stats::SAVE_PACKAGE_STARTED); | 266 download_stats::RecordSavePackageEvent(download_stats::SAVE_PACKAGE_STARTED); |
| 266 } | 267 } |
| 267 | 268 |
| 268 bool SavePackage::Init() { | 269 bool SavePackage::Init( |
| 270 content::SaveFileDownloadCreatedCallback download_created_callback) { |
| 269 // Set proper running state. | 271 // Set proper running state. |
| 270 if (wait_state_ != INITIALIZE) | 272 if (wait_state_ != INITIALIZE) |
| 271 return false; | 273 return false; |
| 272 | 274 |
| 273 wait_state_ = START_PROCESS; | 275 wait_state_ = START_PROCESS; |
| 274 | 276 |
| 275 // Initialize the request context and resource dispatcher. | 277 // Initialize the request context and resource dispatcher. |
| 276 content::BrowserContext* browser_context = | 278 content::BrowserContext* browser_context = |
| 277 web_contents()->GetBrowserContext(); | 279 web_contents()->GetBrowserContext(); |
| 278 if (!browser_context) { | 280 if (!browser_context) { |
| 279 NOTREACHED(); | 281 NOTREACHED(); |
| 280 return false; | 282 return false; |
| 281 } | 283 } |
| 282 | 284 |
| 283 // The download manager keeps ownership but adds us as an observer. | 285 // The download manager keeps ownership but adds us as an observer. |
| 284 download_ = download_manager_->CreateSavePackageDownloadItem( | 286 download_ = download_manager_->CreateSavePackageDownloadItem( |
| 285 saved_main_file_path_, page_url_, | 287 saved_main_file_path_, |
| 286 browser_context->IsOffTheRecord(), this); | 288 page_url_, |
| 289 browser_context->IsOffTheRecord(), |
| 290 ((save_type_ == content::SAVE_PAGE_TYPE_AS_MHTML) ? |
| 291 "multipart/related" : "text/html"), |
| 292 this); |
| 293 if (!download_created_callback.is_null()) |
| 294 download_created_callback.Run(download_); |
| 287 | 295 |
| 288 // Check save type and process the save page job. | 296 // Check save type and process the save page job. |
| 289 if (save_type_ == content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML) { | 297 if (save_type_ == content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML) { |
| 290 // Get directory | 298 // Get directory |
| 291 DCHECK(!saved_main_directory_path_.empty()); | 299 DCHECK(!saved_main_directory_path_.empty()); |
| 292 GetAllSavableResourceLinksForCurrentPage(); | 300 GetAllSavableResourceLinksForCurrentPage(); |
| 301 } else if (save_type_ == content::SAVE_PAGE_TYPE_AS_MHTML) { |
| 302 download_->SetTotalBytes(1); |
| 303 web_contents()->GenerateMHTML(saved_main_file_path_, base::Bind( |
| 304 &SavePackage::OnMHTMLGenerated, this)); |
| 293 } else { | 305 } else { |
| 294 wait_state_ = NET_FILES; | 306 wait_state_ = NET_FILES; |
| 295 SaveFileCreateInfo::SaveFileSource save_source = page_url_.SchemeIsFile() ? | 307 SaveFileCreateInfo::SaveFileSource save_source = page_url_.SchemeIsFile() ? |
| 296 SaveFileCreateInfo::SAVE_FILE_FROM_FILE : | 308 SaveFileCreateInfo::SAVE_FILE_FROM_FILE : |
| 297 SaveFileCreateInfo::SAVE_FILE_FROM_NET; | 309 SaveFileCreateInfo::SAVE_FILE_FROM_NET; |
| 298 SaveItem* save_item = new SaveItem(page_url_, | 310 SaveItem* save_item = new SaveItem(page_url_, |
| 299 GURL(), | 311 GURL(), |
| 300 this, | 312 this, |
| 301 save_source); | 313 save_source); |
| 302 // Add this item to waiting list. | 314 // Add this item to waiting list. |
| 303 waiting_item_queue_.push(save_item); | 315 waiting_item_queue_.push(save_item); |
| 304 all_save_items_count_ = 1; | 316 all_save_items_count_ = 1; |
| 305 download_->SetTotalBytes(1); | 317 download_->SetTotalBytes(1); |
| 306 | 318 |
| 307 DoSavingProcess(); | 319 DoSavingProcess(); |
| 308 } | 320 } |
| 309 | 321 |
| 310 return true; | 322 return true; |
| 311 } | 323 } |
| 312 | 324 |
| 325 void SavePackage::OnMHTMLGenerated(const FilePath& path, int64 size) { |
| 326 if (size <= 0) { |
| 327 Cancel(false); |
| 328 } else { |
| 329 download_->UpdateProgress(1, 0, ""); |
| 330 wrote_to_completed_file_ = true; |
| 331 Finish(); |
| 332 } |
| 333 } |
| 334 |
| 313 // On POSIX, the length of |pure_file_name| + |file_name_ext| is further | 335 // On POSIX, the length of |pure_file_name| + |file_name_ext| is further |
| 314 // restricted by NAME_MAX. The maximum allowed path looks like: | 336 // restricted by NAME_MAX. The maximum allowed path looks like: |
| 315 // '/path/to/save_dir' + '/' + NAME_MAX. | 337 // '/path/to/save_dir' + '/' + NAME_MAX. |
| 316 uint32 SavePackage::GetMaxPathLengthForDirectory(const FilePath& base_dir) { | 338 uint32 SavePackage::GetMaxPathLengthForDirectory(const FilePath& base_dir) { |
| 317 #if defined(OS_POSIX) | 339 #if defined(OS_POSIX) |
| 318 return std::min(kMaxFilePathLength, | 340 return std::min(kMaxFilePathLength, |
| 319 static_cast<uint32>(base_dir.value().length()) + | 341 static_cast<uint32>(base_dir.value().length()) + |
| 320 NAME_MAX + 1); | 342 NAME_MAX + 1); |
| 321 #else | 343 #else |
| 322 return kMaxFilePathLength; | 344 return kMaxFilePathLength; |
| (...skipping 375 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 698 it != saved_failed_items_.end(); ++it) | 720 it != saved_failed_items_.end(); ++it) |
| 699 save_ids.push_back(it->second->save_id()); | 721 save_ids.push_back(it->second->save_id()); |
| 700 | 722 |
| 701 BrowserThread::PostTask( | 723 BrowserThread::PostTask( |
| 702 BrowserThread::FILE, FROM_HERE, | 724 BrowserThread::FILE, FROM_HERE, |
| 703 base::Bind(&SaveFileManager::RemoveSavedFileFromFileMap, | 725 base::Bind(&SaveFileManager::RemoveSavedFileFromFileMap, |
| 704 file_manager_, | 726 file_manager_, |
| 705 save_ids)); | 727 save_ids)); |
| 706 | 728 |
| 707 if (download_) { | 729 if (download_) { |
| 708 download_->OnAllDataSaved(all_save_items_count_, | 730 download_->OnAllDataSaved( |
| 709 DownloadItem::kEmptyFileHash); | 731 ((save_type_ != content::SAVE_PAGE_TYPE_AS_MHTML) ? |
| 732 all_save_items_count_ : 1), |
| 733 DownloadItem::kEmptyFileHash); |
| 710 download_->MarkAsComplete(); | 734 download_->MarkAsComplete(); |
| 711 FinalizeDownloadEntry(); | 735 FinalizeDownloadEntry(); |
| 712 } | 736 } |
| 713 } | 737 } |
| 714 | 738 |
| 715 // Called for updating end state. | 739 // Called for updating end state. |
| 716 void SavePackage::SaveFinished(int32 save_id, int64 size, bool is_success) { | 740 void SavePackage::SaveFinished(int32 save_id, int64 size, bool is_success) { |
| 717 // Because we might have canceled this saving job before, | 741 // Because we might have canceled this saving job before, |
| 718 // so we might not find corresponding SaveItem. Just ignore it. | 742 // so we might not find corresponding SaveItem. Just ignore it. |
| 719 SaveItem* save_item = LookupItemInProcessBySaveId(save_id); | 743 SaveItem* save_item = LookupItemInProcessBySaveId(save_id); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 767 | 791 |
| 768 save_item->Finish(0, false); | 792 save_item->Finish(0, false); |
| 769 | 793 |
| 770 PutInProgressItemToSavedMap(save_item); | 794 PutInProgressItemToSavedMap(save_item); |
| 771 | 795 |
| 772 // Inform the DownloadItem to update UI. | 796 // Inform the DownloadItem to update UI. |
| 773 // We use the received bytes as number of saved files. | 797 // We use the received bytes as number of saved files. |
| 774 if (download_) | 798 if (download_) |
| 775 download_->UpdateProgress(completed_count(), CurrentSpeed(), ""); | 799 download_->UpdateProgress(completed_count(), CurrentSpeed(), ""); |
| 776 | 800 |
| 777 if (save_type_ == content::SAVE_PAGE_TYPE_AS_ONLY_HTML || | 801 if ((save_type_ == content::SAVE_PAGE_TYPE_AS_ONLY_HTML) || |
| 778 save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM) { | 802 (save_type_ == content::SAVE_PAGE_TYPE_AS_MHTML) || |
| 803 (save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM)) { |
| 779 // We got error when saving page. Treat it as disk error. | 804 // We got error when saving page. Treat it as disk error. |
| 780 Cancel(true); | 805 Cancel(true); |
| 781 } | 806 } |
| 782 | 807 |
| 783 if (canceled()) { | 808 if (canceled()) { |
| 784 DCHECK(finished_); | 809 DCHECK(finished_); |
| 785 return; | 810 return; |
| 786 } | 811 } |
| 787 | 812 |
| 788 // Continue processing the save page job. | 813 // Continue processing the save page job. |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 874 wait_state_ = HTML_DATA; | 899 wait_state_ = HTML_DATA; |
| 875 // All non-HTML resources have been finished, start all remaining | 900 // All non-HTML resources have been finished, start all remaining |
| 876 // HTML files. | 901 // HTML files. |
| 877 SaveNextFile(true); | 902 SaveNextFile(true); |
| 878 } | 903 } |
| 879 } else if (in_process_count()) { | 904 } else if (in_process_count()) { |
| 880 // Continue asking for HTML data. | 905 // Continue asking for HTML data. |
| 881 DCHECK(wait_state_ == HTML_DATA); | 906 DCHECK(wait_state_ == HTML_DATA); |
| 882 } | 907 } |
| 883 } else { | 908 } else { |
| 884 // Save as HTML only. | 909 // Save as HTML only or MHTML. |
| 885 DCHECK(wait_state_ == NET_FILES); | 910 DCHECK(wait_state_ == NET_FILES); |
| 886 DCHECK(save_type_ == content::SAVE_PAGE_TYPE_AS_ONLY_HTML); | 911 DCHECK((save_type_ == content::SAVE_PAGE_TYPE_AS_ONLY_HTML) || |
| 912 (save_type_ == content::SAVE_PAGE_TYPE_AS_MHTML)); |
| 887 if (waiting_item_queue_.size()) { | 913 if (waiting_item_queue_.size()) { |
| 888 DCHECK(all_save_items_count_ == waiting_item_queue_.size()); | 914 DCHECK(all_save_items_count_ == waiting_item_queue_.size()); |
| 889 SaveNextFile(false); | 915 SaveNextFile(false); |
| 890 } | 916 } |
| 891 } | 917 } |
| 892 } | 918 } |
| 893 | 919 |
| 894 bool SavePackage::OnMessageReceived(const IPC::Message& message) { | 920 bool SavePackage::OnMessageReceived(const IPC::Message& message) { |
| 895 bool handled = true; | 921 bool handled = true; |
| 896 IPC_BEGIN_MESSAGE_MAP(SavePackage, message) | 922 IPC_BEGIN_MESSAGE_MAP(SavePackage, message) |
| (...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1260 // The WebContents which owns this SavePackage may have disappeared during | 1286 // The WebContents which owns this SavePackage may have disappeared during |
| 1261 // the UI->FILE->UI thread hop of | 1287 // the UI->FILE->UI thread hop of |
| 1262 // GetSaveInfo->CreateDirectoryOnFileThread->ContinueGetSaveInfo. | 1288 // GetSaveInfo->CreateDirectoryOnFileThread->ContinueGetSaveInfo. |
| 1263 if (!web_contents()) | 1289 if (!web_contents()) |
| 1264 return; | 1290 return; |
| 1265 | 1291 |
| 1266 FilePath::StringType default_extension; | 1292 FilePath::StringType default_extension; |
| 1267 if (can_save_as_complete) | 1293 if (can_save_as_complete) |
| 1268 default_extension = kDefaultHtmlExtension; | 1294 default_extension = kDefaultHtmlExtension; |
| 1269 | 1295 |
| 1270 // On ChromeOS, OnPathPicked is not invoked; SavePackageFilePickerChromeOS | |
| 1271 // handles the the save. | |
| 1272 download_manager_->delegate()->ChooseSavePath( | 1296 download_manager_->delegate()->ChooseSavePath( |
| 1273 web_contents(), suggested_path, default_extension, can_save_as_complete, | 1297 web_contents(), suggested_path, default_extension, can_save_as_complete, |
| 1274 base::Bind(&SavePackage::OnPathPicked, AsWeakPtr())); | 1298 base::Bind(&SavePackage::OnPathPicked, AsWeakPtr())); |
| 1275 } | 1299 } |
| 1276 | 1300 |
| 1277 void SavePackage::OnPathPicked(const FilePath& final_name, | 1301 void SavePackage::OnPathPicked( |
| 1278 content::SavePageType type) { | 1302 const FilePath& final_name, |
| 1303 content::SavePageType type, |
| 1304 content::SaveFileDownloadCreatedCallback download_created_callback) { |
| 1279 // Ensure the filename is safe. | 1305 // Ensure the filename is safe. |
| 1280 saved_main_file_path_ = final_name; | 1306 saved_main_file_path_ = final_name; |
| 1281 // TODO(asanka): This call may block on IO and shouldn't be made | 1307 // TODO(asanka): This call may block on IO and shouldn't be made |
| 1282 // from the UI thread. See http://crbug.com/61827. | 1308 // from the UI thread. See http://crbug.com/61827. |
| 1283 net::GenerateSafeFileName(web_contents()->GetContentsMimeType(), false, | 1309 net::GenerateSafeFileName(web_contents()->GetContentsMimeType(), false, |
| 1284 &saved_main_file_path_); | 1310 &saved_main_file_path_); |
| 1285 | 1311 |
| 1286 saved_main_directory_path_ = saved_main_file_path_.DirName(); | 1312 saved_main_directory_path_ = saved_main_file_path_.DirName(); |
| 1287 save_type_ = type; | 1313 save_type_ = type; |
| 1288 if (save_type_ == content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML) { | 1314 if (save_type_ == content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML) { |
| 1289 // Make new directory for saving complete file. | 1315 // Make new directory for saving complete file. |
| 1290 saved_main_directory_path_ = saved_main_directory_path_.Append( | 1316 saved_main_directory_path_ = saved_main_directory_path_.Append( |
| 1291 saved_main_file_path_.RemoveExtension().BaseName().value() + | 1317 saved_main_file_path_.RemoveExtension().BaseName().value() + |
| 1292 FILE_PATH_LITERAL("_files")); | 1318 FILE_PATH_LITERAL("_files")); |
| 1293 } | 1319 } |
| 1294 | 1320 |
| 1295 Init(); | 1321 Init(download_created_callback); |
| 1296 } | 1322 } |
| 1297 | 1323 |
| 1298 void SavePackage::StopObservation() { | 1324 void SavePackage::StopObservation() { |
| 1299 DCHECK(download_); | 1325 DCHECK(download_); |
| 1300 DCHECK(download_manager_); | 1326 DCHECK(download_manager_); |
| 1301 | 1327 |
| 1302 download_->RemoveObserver(this); | 1328 download_->RemoveObserver(this); |
| 1303 download_ = NULL; | 1329 download_ = NULL; |
| 1304 download_manager_ = NULL; | 1330 download_manager_ = NULL; |
| 1305 } | 1331 } |
| 1306 | 1332 |
| 1307 void SavePackage::OnDownloadUpdated(DownloadItem* download) { | 1333 void SavePackage::OnDownloadUpdated(DownloadItem* download) { |
| 1308 DCHECK(download_); | 1334 DCHECK(download_); |
| 1309 DCHECK(download_ == download); | 1335 DCHECK(download_ == download); |
| 1310 DCHECK(download_manager_); | 1336 DCHECK(download_manager_); |
| 1311 | 1337 |
| 1312 // Check for removal. | 1338 // Check for removal. |
| 1313 if (download->GetState() == DownloadItem::REMOVING) | 1339 if (download->GetState() == DownloadItem::REMOVING) |
| 1314 StopObservation(); | 1340 StopObservation(); |
| 1315 } | 1341 } |
| 1316 | 1342 |
| 1317 void SavePackage::FinalizeDownloadEntry() { | 1343 void SavePackage::FinalizeDownloadEntry() { |
| 1318 DCHECK(download_); | 1344 DCHECK(download_); |
| 1319 DCHECK(download_manager_); | 1345 DCHECK(download_manager_); |
| 1320 | 1346 |
| 1321 download_manager_->SavePageDownloadFinished(download_); | 1347 download_manager_->SavePageDownloadFinished(download_); |
| 1322 StopObservation(); | 1348 StopObservation(); |
| 1323 } | 1349 } |
| OLD | NEW |