Chromium Code Reviews| 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/files/file_path.h" | 10 #include "base/files/file_path.h" |
| 11 #include "base/files/file_util.h" | 11 #include "base/files/file_util.h" |
| 12 #include "base/i18n/file_util_icu.h" | 12 #include "base/i18n/file_util_icu.h" |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/message_loop/message_loop.h" | 14 #include "base/message_loop/message_loop.h" |
| 15 #include "base/stl_util.h" | 15 #include "base/stl_util.h" |
| 16 #include "base/strings/string_piece.h" | 16 #include "base/strings/string_piece.h" |
| 17 #include "base/strings/string_split.h" | 17 #include "base/strings/string_split.h" |
| 18 #include "base/strings/sys_string_conversions.h" | 18 #include "base/strings/sys_string_conversions.h" |
| 19 #include "base/strings/utf_string_conversions.h" | 19 #include "base/strings/utf_string_conversions.h" |
| 20 #include "base/threading/thread.h" | 20 #include "base/threading/thread.h" |
| 21 #include "components/url_formatter/url_formatter.h" | 21 #include "components/url_formatter/url_formatter.h" |
| 22 #include "content/browser/download/download_item_impl.h" | 22 #include "content/browser/download/download_item_impl.h" |
| 23 #include "content/browser/download/download_manager_impl.h" | 23 #include "content/browser/download/download_manager_impl.h" |
| 24 #include "content/browser/download/download_stats.h" | 24 #include "content/browser/download/download_stats.h" |
| 25 #include "content/browser/download/save_file.h" | 25 #include "content/browser/download/save_file.h" |
| 26 #include "content/browser/download/save_file_manager.h" | 26 #include "content/browser/download/save_file_manager.h" |
| 27 #include "content/browser/download/save_item.h" | 27 #include "content/browser/download/save_item.h" |
| 28 #include "content/browser/frame_host/frame_tree.h" | |
| 29 #include "content/browser/frame_host/frame_tree_node.h" | |
| 28 #include "content/browser/loader/resource_dispatcher_host_impl.h" | 30 #include "content/browser/loader/resource_dispatcher_host_impl.h" |
| 29 #include "content/browser/renderer_host/render_process_host_impl.h" | 31 #include "content/browser/renderer_host/render_process_host_impl.h" |
| 30 #include "content/browser/renderer_host/render_view_host_delegate.h" | 32 #include "content/browser/renderer_host/render_view_host_delegate.h" |
| 31 #include "content/browser/renderer_host/render_view_host_impl.h" | 33 #include "content/browser/renderer_host/render_view_host_impl.h" |
| 34 #include "content/browser/web_contents/web_contents_impl.h" | |
| 32 #include "content/common/frame_messages.h" | 35 #include "content/common/frame_messages.h" |
| 33 #include "content/common/view_messages.h" | |
| 34 #include "content/public/browser/browser_context.h" | 36 #include "content/public/browser/browser_context.h" |
| 35 #include "content/public/browser/browser_thread.h" | 37 #include "content/public/browser/browser_thread.h" |
| 36 #include "content/public/browser/content_browser_client.h" | 38 #include "content/public/browser/content_browser_client.h" |
| 37 #include "content/public/browser/download_manager_delegate.h" | 39 #include "content/public/browser/download_manager_delegate.h" |
| 38 #include "content/public/browser/navigation_entry.h" | 40 #include "content/public/browser/navigation_entry.h" |
| 39 #include "content/public/browser/notification_service.h" | 41 #include "content/public/browser/notification_service.h" |
| 40 #include "content/public/browser/notification_types.h" | 42 #include "content/public/browser/notification_types.h" |
| 41 #include "content/public/browser/render_frame_host.h" | 43 #include "content/public/browser/render_frame_host.h" |
| 42 #include "content/public/browser/resource_context.h" | 44 #include "content/public/browser/resource_context.h" |
| 43 #include "content/public/browser/web_contents.h" | 45 #include "content/public/browser/web_contents.h" |
| 44 #include "net/base/filename_util.h" | 46 #include "net/base/filename_util.h" |
| 45 #include "net/base/io_buffer.h" | 47 #include "net/base/io_buffer.h" |
| 46 #include "net/base/mime_util.h" | 48 #include "net/base/mime_util.h" |
| 47 #include "net/url_request/url_request_context.h" | 49 #include "net/url_request/url_request_context.h" |
| 48 #include "third_party/WebKit/public/web/WebPageSerializerClient.h" | |
| 49 #include "url/url_constants.h" | 50 #include "url/url_constants.h" |
| 50 | 51 |
| 51 using base::Time; | 52 using base::Time; |
| 52 using blink::WebPageSerializerClient; | |
| 53 | 53 |
| 54 namespace content { | 54 namespace content { |
| 55 namespace { | 55 namespace { |
| 56 | 56 |
| 57 // A counter for uniquely identifying each save package. | 57 // A counter for uniquely identifying each save package. |
| 58 int g_save_package_id = 0; | 58 int g_save_package_id = 0; |
| 59 | 59 |
| 60 // Default name which will be used when we can not get proper name from | 60 // Default name which will be used when we can not get proper name from |
| 61 // resource URL. | 61 // resource URL. |
| 62 const char kDefaultSaveName[] = "saved_resource"; | 62 const char kDefaultSaveName[] = "saved_resource"; |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 232 Cancel(true); | 232 Cancel(true); |
| 233 } | 233 } |
| 234 | 234 |
| 235 // We should no longer be observing the DownloadItem at this point. | 235 // We should no longer be observing the DownloadItem at this point. |
| 236 CHECK(!download_); | 236 CHECK(!download_); |
| 237 | 237 |
| 238 DCHECK(all_save_items_count_ == (waiting_item_queue_.size() + | 238 DCHECK(all_save_items_count_ == (waiting_item_queue_.size() + |
| 239 completed_count() + | 239 completed_count() + |
| 240 in_process_count())); | 240 in_process_count())); |
| 241 // Free all SaveItems. | 241 // Free all SaveItems. |
| 242 while (!waiting_item_queue_.empty()) { | 242 STLDeleteElements(&waiting_item_queue_); |
| 243 // We still have some items which are waiting for start to save. | 243 STLDeleteValues(&in_progress_items_); |
| 244 SaveItem* save_item = waiting_item_queue_.front(); | |
| 245 waiting_item_queue_.pop(); | |
| 246 delete save_item; | |
| 247 } | |
| 248 | |
| 249 STLDeleteValues(&saved_success_items_); | 244 STLDeleteValues(&saved_success_items_); |
| 250 STLDeleteValues(&in_progress_items_); | |
| 251 STLDeleteValues(&saved_failed_items_); | 245 STLDeleteValues(&saved_failed_items_); |
| 252 | 246 |
| 253 file_manager_ = NULL; | 247 file_manager_ = NULL; |
| 254 } | 248 } |
| 255 | 249 |
| 256 GURL SavePackage::GetUrlToBeSaved() { | 250 GURL SavePackage::GetUrlToBeSaved() { |
| 257 // Instead of using web_contents_.GetURL here, we use url() (which is the | 251 // Instead of using web_contents_.GetURL here, we use url() (which is the |
| 258 // "real" url of the page) from the NavigationEntry because it reflects its | 252 // "real" url of the page) from the NavigationEntry because it reflects its |
| 259 // origin rather than the displayed one (returned by GetURL) which may be | 253 // origin rather than the displayed one (returned by GetURL) which may be |
| 260 // different (like having "view-source:" on the front). | 254 // different (like having "view-source:" on the front). |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 342 GetSavableResourceLinks(); | 336 GetSavableResourceLinks(); |
| 343 } else if (save_type_ == SAVE_PAGE_TYPE_AS_MHTML) { | 337 } else if (save_type_ == SAVE_PAGE_TYPE_AS_MHTML) { |
| 344 web_contents()->GenerateMHTML(saved_main_file_path_, base::Bind( | 338 web_contents()->GenerateMHTML(saved_main_file_path_, base::Bind( |
| 345 &SavePackage::OnMHTMLGenerated, this)); | 339 &SavePackage::OnMHTMLGenerated, this)); |
| 346 } else { | 340 } else { |
| 347 DCHECK_EQ(SAVE_PAGE_TYPE_AS_ONLY_HTML, save_type_) << save_type_; | 341 DCHECK_EQ(SAVE_PAGE_TYPE_AS_ONLY_HTML, save_type_) << save_type_; |
| 348 wait_state_ = NET_FILES; | 342 wait_state_ = NET_FILES; |
| 349 SaveFileCreateInfo::SaveFileSource save_source = page_url_.SchemeIsFile() ? | 343 SaveFileCreateInfo::SaveFileSource save_source = page_url_.SchemeIsFile() ? |
| 350 SaveFileCreateInfo::SAVE_FILE_FROM_FILE : | 344 SaveFileCreateInfo::SAVE_FILE_FROM_FILE : |
| 351 SaveFileCreateInfo::SAVE_FILE_FROM_NET; | 345 SaveFileCreateInfo::SAVE_FILE_FROM_NET; |
| 352 SaveItem* save_item = new SaveItem(page_url_, | 346 SaveItem* save_item = new SaveItem(page_url_, this, save_source); |
| 353 Referrer(), | |
| 354 this, | |
| 355 save_source); | |
| 356 // Add this item to waiting list. | 347 // Add this item to waiting list. |
| 357 waiting_item_queue_.push(save_item); | 348 waiting_item_queue_.push_back(save_item); |
| 358 all_save_items_count_ = 1; | 349 all_save_items_count_ = 1; |
| 359 download_->SetTotalBytes(1); | 350 download_->SetTotalBytes(1); |
| 360 | 351 |
| 361 DoSavingProcess(); | 352 DoSavingProcess(); |
| 362 } | 353 } |
| 363 } | 354 } |
| 364 | 355 |
| 365 void SavePackage::OnMHTMLGenerated(int64 size) { | 356 void SavePackage::OnMHTMLGenerated(int64 size) { |
| 366 if (size <= 0) { | 357 if (size <= 0) { |
| 367 Cancel(false); | 358 Cancel(false); |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 628 // HTML data back. | 619 // HTML data back. |
| 629 GetSerializedHtmlWithLocalLinks(); | 620 GetSerializedHtmlWithLocalLinks(); |
| 630 } | 621 } |
| 631 } | 622 } |
| 632 | 623 |
| 633 SaveItem* SavePackage::LookupItemInProcessBySaveId(int32 save_id) { | 624 SaveItem* SavePackage::LookupItemInProcessBySaveId(int32 save_id) { |
| 634 if (in_process_count()) { | 625 if (in_process_count()) { |
| 635 for (SaveUrlItemMap::iterator it = in_progress_items_.begin(); | 626 for (SaveUrlItemMap::iterator it = in_progress_items_.begin(); |
| 636 it != in_progress_items_.end(); ++it) { | 627 it != in_progress_items_.end(); ++it) { |
| 637 SaveItem* save_item = it->second; | 628 SaveItem* save_item = it->second; |
| 638 DCHECK(save_item->state() == SaveItem::IN_PROGRESS); | 629 DCHECK(save_item->state() == SaveItem::IN_PROGRESS || |
| 630 save_item->state() == SaveItem::COMPLETING); | |
| 639 if (save_item->save_id() == save_id) | 631 if (save_item->save_id() == save_id) |
| 640 return save_item; | 632 return save_item; |
| 641 } | 633 } |
| 642 } | 634 } |
| 643 return NULL; | 635 return NULL; |
| 644 } | 636 } |
| 645 | 637 |
| 646 void SavePackage::PutInProgressItemToSavedMap(SaveItem* save_item) { | 638 void SavePackage::PutInProgressItemToSavedMap(SaveItem* save_item) { |
| 647 SaveUrlItemMap::iterator it = in_progress_items_.find( | 639 SaveUrlItemMap::iterator it = in_progress_items_.find( |
| 648 save_item->url().spec()); | 640 save_item->url().spec()); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 690 // there won't be valid pointers for file_manager_ or download_. | 682 // there won't be valid pointers for file_manager_ or download_. |
| 691 if (wait_state_ == INITIALIZE) | 683 if (wait_state_ == INITIALIZE) |
| 692 return; | 684 return; |
| 693 | 685 |
| 694 // When stopping, if it still has some items in in_progress, cancel them. | 686 // When stopping, if it still has some items in in_progress, cancel them. |
| 695 DCHECK(canceled()); | 687 DCHECK(canceled()); |
| 696 if (in_process_count()) { | 688 if (in_process_count()) { |
| 697 SaveUrlItemMap::iterator it = in_progress_items_.begin(); | 689 SaveUrlItemMap::iterator it = in_progress_items_.begin(); |
| 698 for (; it != in_progress_items_.end(); ++it) { | 690 for (; it != in_progress_items_.end(); ++it) { |
| 699 SaveItem* save_item = it->second; | 691 SaveItem* save_item = it->second; |
| 700 DCHECK(save_item->state() == SaveItem::IN_PROGRESS); | 692 DCHECK(save_item->state() == SaveItem::IN_PROGRESS || |
| 693 save_item->state() == SaveItem::COMPLETING); | |
| 701 save_item->Cancel(); | 694 save_item->Cancel(); |
| 702 } | 695 } |
| 703 // Remove all in progress item to saved map. For failed items, they will | 696 // Remove all in progress item to saved map. For failed items, they will |
| 704 // be put into saved_failed_items_, for successful item, they will be put | 697 // be put into saved_failed_items_, for successful item, they will be put |
| 705 // into saved_success_items_. | 698 // into saved_success_items_. |
| 706 while (in_process_count()) | 699 while (in_process_count()) |
| 707 PutInProgressItemToSavedMap(in_progress_items_.begin()->second); | 700 PutInProgressItemToSavedMap(in_progress_items_.begin()->second); |
| 708 } | 701 } |
| 709 | 702 |
| 710 // This vector contains the save ids of the save files which SaveFileManager | 703 // This vector contains the save ids of the save files which SaveFileManager |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 918 // SaveFileManager, which will dispatch it to different approach according to | 911 // SaveFileManager, which will dispatch it to different approach according to |
| 919 // the save source. Parameter process_all_remaining_items indicates whether | 912 // the save source. Parameter process_all_remaining_items indicates whether |
| 920 // we need to save all remaining items. | 913 // we need to save all remaining items. |
| 921 void SavePackage::SaveNextFile(bool process_all_remaining_items) { | 914 void SavePackage::SaveNextFile(bool process_all_remaining_items) { |
| 922 DCHECK(web_contents()); | 915 DCHECK(web_contents()); |
| 923 DCHECK(waiting_item_queue_.size()); | 916 DCHECK(waiting_item_queue_.size()); |
| 924 | 917 |
| 925 do { | 918 do { |
| 926 // Pop SaveItem from waiting list. | 919 // Pop SaveItem from waiting list. |
| 927 SaveItem* save_item = waiting_item_queue_.front(); | 920 SaveItem* save_item = waiting_item_queue_.front(); |
| 928 waiting_item_queue_.pop(); | 921 waiting_item_queue_.pop_front(); |
| 929 | 922 |
| 930 // Add the item to in_progress_items_. | 923 // Add the item to in_progress_items_. |
| 931 SaveUrlItemMap::iterator it = in_progress_items_.find( | 924 SaveUrlItemMap::iterator it = in_progress_items_.find( |
| 932 save_item->url().spec()); | 925 save_item->url().spec()); |
| 933 DCHECK(it == in_progress_items_.end()); | 926 DCHECK(it == in_progress_items_.end()); |
| 934 in_progress_items_[save_item->url().spec()] = save_item; | 927 in_progress_items_[save_item->url().spec()] = save_item; |
| 935 save_item->Start(); | 928 save_item->Start(); |
| 936 file_manager_->SaveURL(save_item->url(), | 929 file_manager_->SaveURL(save_item->url(), |
| 937 save_item->referrer(), | 930 save_item->referrer(), |
| 938 web_contents()->GetRenderProcessHost()->GetID(), | 931 web_contents()->GetRenderProcessHost()->GetID(), |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 999 if (waiting_item_queue_.size()) { | 992 if (waiting_item_queue_.size()) { |
| 1000 DCHECK(all_save_items_count_ == waiting_item_queue_.size()); | 993 DCHECK(all_save_items_count_ == waiting_item_queue_.size()); |
| 1001 SaveNextFile(false); | 994 SaveNextFile(false); |
| 1002 } | 995 } |
| 1003 } | 996 } |
| 1004 } | 997 } |
| 1005 | 998 |
| 1006 bool SavePackage::OnMessageReceived(const IPC::Message& message, | 999 bool SavePackage::OnMessageReceived(const IPC::Message& message, |
| 1007 RenderFrameHost* render_frame_host) { | 1000 RenderFrameHost* render_frame_host) { |
| 1008 bool handled = true; | 1001 bool handled = true; |
| 1009 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(SavePackage, message, render_frame_host) | 1002 auto* sender = static_cast<RenderFrameHostImpl*>(render_frame_host); |
| 1003 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(SavePackage, message, sender) | |
| 1010 IPC_MESSAGE_HANDLER(FrameHostMsg_SavableResourceLinksResponse, | 1004 IPC_MESSAGE_HANDLER(FrameHostMsg_SavableResourceLinksResponse, |
| 1011 OnSavableResourceLinksResponse) | 1005 OnSavableResourceLinksResponse) |
| 1012 IPC_MESSAGE_HANDLER(FrameHostMsg_SavableResourceLinksError, | 1006 IPC_MESSAGE_HANDLER(FrameHostMsg_SavableResourceLinksError, |
| 1013 OnSavableResourceLinksError) | 1007 OnSavableResourceLinksError) |
| 1014 IPC_MESSAGE_HANDLER(FrameHostMsg_SerializedHtmlWithLocalLinksResponse, | 1008 IPC_MESSAGE_HANDLER(FrameHostMsg_SerializedHtmlFragment, |
| 1015 OnSerializedHtmlWithLocalLinksResponse) | 1009 OnSerializedHtmlFragment) |
| 1010 IPC_MESSAGE_HANDLER(FrameHostMsg_SerializedLocalPathForChildFrame, | |
| 1011 OnSerializedLocalPathForChildFrame) | |
| 1012 IPC_MESSAGE_HANDLER(FrameHostMsg_SerializedLocalPathForSavableResource, | |
| 1013 OnSerializedLocalPathForSavableResource) | |
| 1014 IPC_MESSAGE_HANDLER(FrameHostMsg_SerializedEndOfFrame, | |
| 1015 OnSerializedEndOfFrame) | |
| 1016 IPC_MESSAGE_UNHANDLED(handled = false) | 1016 IPC_MESSAGE_UNHANDLED(handled = false) |
| 1017 IPC_END_MESSAGE_MAP() | 1017 IPC_END_MESSAGE_MAP() |
| 1018 return handled; | 1018 return handled; |
| 1019 } | 1019 } |
| 1020 | 1020 |
| 1021 // After finishing all SaveItems which need to get data from net. | 1021 // After finishing all SaveItems which need to get data from net. |
| 1022 // We collect all URLs which have local storage and send the | 1022 // We collect all URLs which have local storage and send the |
| 1023 // map:(originalURL:currentLocalPath) to render process (backend). | 1023 // map:(originalURL:currentLocalPath) to render process (backend). |
| 1024 // Then render process will serialize DOM and send data to us. | 1024 // Then render process will serialize DOM and send data to us. |
| 1025 void SavePackage::GetSerializedHtmlWithLocalLinks() { | 1025 void SavePackage::GetSerializedHtmlWithLocalLinks() { |
| 1026 if (wait_state_ != HTML_DATA) | 1026 if (wait_state_ != HTML_DATA) |
| 1027 return; | 1027 return; |
| 1028 std::vector<GURL> saved_links; | |
| 1029 std::vector<base::FilePath> saved_file_paths; | |
| 1030 int successful_started_items_count = 0; | 1028 int successful_started_items_count = 0; |
| 1031 | 1029 |
| 1032 // Collect all saved items which have local storage. | 1030 // Count all saved items which have local storage. |
| 1033 // First collect the status of all the resource files and check whether they | 1031 for (const auto& it : in_progress_items_) { |
| 1034 // have created local files although they have not been completely saved. | 1032 DCHECK_EQ(SaveFileCreateInfo::SAVE_FILE_FROM_DOM, it.second->save_source()); |
| 1035 // If yes, the file can be saved. Otherwise, there is a disk error, so we | 1033 if (it.second->has_final_name()) |
| 1036 // need to cancel the page saving job. | |
| 1037 for (SaveUrlItemMap::iterator it = in_progress_items_.begin(); | |
| 1038 it != in_progress_items_.end(); ++it) { | |
| 1039 DCHECK(it->second->save_source() == | |
| 1040 SaveFileCreateInfo::SAVE_FILE_FROM_DOM); | |
| 1041 if (it->second->has_final_name()) | |
| 1042 successful_started_items_count++; | 1034 successful_started_items_count++; |
| 1043 saved_links.push_back(it->second->url()); | |
| 1044 saved_file_paths.push_back(it->second->file_name()); | |
| 1045 } | 1035 } |
| 1046 | 1036 |
| 1047 // If not all file of HTML resource have been started, then wait. | 1037 // If not all file of HTML resource have been started, then wait. |
| 1048 if (successful_started_items_count != in_process_count()) | 1038 if (successful_started_items_count != in_process_count()) |
| 1049 return; | 1039 return; |
| 1050 | 1040 |
| 1051 // Collect all saved success items. | |
| 1052 for (SavedItemMap::iterator it = saved_success_items_.begin(); | |
| 1053 it != saved_success_items_.end(); ++it) { | |
| 1054 DCHECK(it->second->has_final_name()); | |
| 1055 saved_links.push_back(it->second->url()); | |
| 1056 saved_file_paths.push_back(it->second->file_name()); | |
| 1057 } | |
| 1058 | |
| 1059 // Get the relative directory name. | |
| 1060 base::FilePath relative_dir_name = saved_main_directory_path_.BaseName(); | |
| 1061 | |
| 1062 // Ask all frames for their serialized data. | 1041 // Ask all frames for their serialized data. |
| 1063 DCHECK_EQ(0, number_of_frames_pending_response_); | 1042 DCHECK_EQ(0, number_of_frames_pending_response_); |
| 1064 web_contents()->ForEachFrame(base::Bind( | 1043 web_contents()->ForEachFrame(base::Bind( |
| 1065 &SavePackage::GetSerializedHtmlWithLocalLinksForFrame, | 1044 &SavePackage::GetSerializedHtmlWithLocalLinksForFrame, |
| 1066 base::Unretained(this), // Safe, because ForEachFrame is synchronous. | 1045 base::Unretained(this))); // Safe, because ForEachFrame is synchronous. |
| 1067 saved_links, saved_file_paths, relative_dir_name)); | |
| 1068 DCHECK_LT(0, number_of_frames_pending_response_); | 1046 DCHECK_LT(0, number_of_frames_pending_response_); |
| 1069 } | 1047 } |
| 1070 | 1048 |
| 1071 void SavePackage::GetSerializedHtmlWithLocalLinksForFrame( | 1049 void SavePackage::GetSerializedHtmlWithLocalLinksForFrame( |
| 1072 const std::vector<GURL>& saved_links, | |
| 1073 const std::vector<base::FilePath>& saved_file_paths, | |
| 1074 const base::FilePath& relative_dir_name, | |
| 1075 RenderFrameHost* target) { | 1050 RenderFrameHost* target) { |
| 1076 number_of_frames_pending_response_++; | 1051 number_of_frames_pending_response_++; |
| 1077 target->Send(new FrameMsg_GetSerializedHtmlWithLocalLinks( | 1052 target->Send( |
| 1078 target->GetRoutingID(), saved_links, saved_file_paths, | 1053 new FrameMsg_GetSerializedHtmlWithLocalLinks(target->GetRoutingID())); |
| 1079 relative_dir_name)); | |
| 1080 } | 1054 } |
| 1081 | 1055 |
| 1082 // Process the serialized HTML content data of a specified frame | 1056 void SavePackage::OnSerializedHtmlFragment(RenderFrameHostImpl* sender, |
| 1083 // retrieved from the renderer process. | 1057 const std::string& data) { |
| 1084 void SavePackage::OnSerializedHtmlWithLocalLinksResponse( | |
| 1085 RenderFrameHost* sender, | |
| 1086 const GURL& frame_url, | |
| 1087 const std::string& data, | |
| 1088 int32 status) { | |
| 1089 WebPageSerializerClient::PageSerializationStatus flag = | |
| 1090 static_cast<WebPageSerializerClient::PageSerializationStatus>(status); | |
| 1091 | |
| 1092 // When calling WebPageSerializer::serialize in non-recursive mode, the | |
| 1093 // AllFramesAreFinished is redundant - it is sent by each frame right after | |
| 1094 // CurrentFrameIsFinished. Therefore we ignore AllFramesAreFinished and | |
| 1095 // instead track pending frames in |number_of_frames_pending_response_|. | |
| 1096 if (flag == WebPageSerializerClient::AllFramesAreFinished) | |
| 1097 return; | |
| 1098 | |
| 1099 // Check current state. | |
| 1100 if (wait_state_ != HTML_DATA) | 1058 if (wait_state_ != HTML_DATA) |
| 1101 return; | 1059 return; |
| 1102 | 1060 |
| 1103 int id = contents_id(); | 1061 int frame_tree_node_id = sender->frame_tree_node()->frame_tree_node_id(); |
| 1104 | 1062 auto it = frame_tree_node_id_to_save_item_.find(frame_tree_node_id); |
| 1105 SaveUrlItemMap::iterator it = in_progress_items_.find(frame_url.spec()); | 1063 if (it == frame_tree_node_id_to_save_item_.end()) { |
| 1106 if (it == in_progress_items_.end()) { | 1064 // Sanitization of renderer IPC - we will have no save item if |
| 1107 for (SavedItemMap::iterator saved_it = saved_success_items_.begin(); | 1065 // 1) the renderer misbehaves and sends OnSerializedHtmlFragment IPC without |
| 1108 saved_it != saved_success_items_.end(); ++saved_it) { | 1066 // being asked to. |
| 1109 if (saved_it->second->url() == frame_url) { | 1067 // 2) if a new frame gets created between OnSavableResourceLinksResponse |
| 1110 wrote_to_completed_file_ = true; | 1068 // and GetSerializedHtmlWithLocalLinksForFrame (crbug.com/541354). |
| 1111 break; | 1069 return; |
| 1112 } | 1070 } |
| 1113 } | 1071 SaveItem* save_item = it->second; |
| 1114 | 1072 if (save_item->state() != SaveItem::IN_PROGRESS) { |
| 1115 it = saved_failed_items_.find(frame_url.spec()); | 1073 LogWriteToAlreadyCompletedOrFailedSaveItem(save_item); |
| 1116 if (it != saved_failed_items_.end()) | |
| 1117 wrote_to_failed_file_ = true; | |
| 1118 | |
| 1119 return; | 1074 return; |
| 1120 } | 1075 } |
| 1121 | 1076 |
| 1122 SaveItem* save_item = it->second; | |
| 1123 DCHECK(save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM); | 1077 DCHECK(save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM); |
| 1124 | |
| 1125 if (!data.empty()) { | 1078 if (!data.empty()) { |
| 1126 // Prepare buffer for saving HTML data. | 1079 // Prepare buffer for saving HTML data. |
| 1127 scoped_refptr<net::IOBuffer> new_data(new net::IOBuffer(data.size())); | 1080 scoped_refptr<net::IOBuffer> new_data(new net::IOBuffer(data.size())); |
| 1128 memcpy(new_data->data(), data.data(), data.size()); | 1081 memcpy(new_data->data(), data.data(), data.size()); |
| 1129 | 1082 |
| 1130 // Call write file functionality in file thread. | 1083 // Call write file functionality in file thread. |
| 1131 BrowserThread::PostTask( | 1084 BrowserThread::PostTask( |
| 1132 BrowserThread::FILE, FROM_HERE, | 1085 BrowserThread::FILE, FROM_HERE, |
| 1133 base::Bind(&SaveFileManager::UpdateSaveProgress, | 1086 base::Bind(&SaveFileManager::UpdateSaveProgress, file_manager_, |
| 1134 file_manager_, | 1087 save_item->save_id(), new_data, |
| 1135 save_item->save_id(), | |
| 1136 new_data, | |
| 1137 static_cast<int>(data.size()))); | 1088 static_cast<int>(data.size()))); |
| 1138 } | 1089 } |
| 1090 } | |
| 1091 | |
| 1092 void SavePackage::OnSerializedLocalPathForChildFrame( | |
| 1093 RenderFrameHostImpl* sender, | |
| 1094 int render_frame_or_proxy_routing_id) { | |
| 1095 if (wait_state_ != HTML_DATA) | |
| 1096 return; | |
| 1097 | |
| 1098 FrameTreeNode* frame_tree_node = | |
| 1099 sender->frame_tree_node()->frame_tree()->FindByRoutingID( | |
| 1100 sender->GetProcess()->GetID(), render_frame_or_proxy_routing_id); | |
| 1101 if (!frame_tree_node) | |
| 1102 return; | |
| 1103 if (frame_tree_node->parent() != sender->frame_tree_node()) | |
| 1104 return; | |
| 1105 | |
| 1106 auto it = frame_tree_node_id_to_save_item_.find( | |
| 1107 frame_tree_node->frame_tree_node_id()); | |
| 1108 SaveItem* save_item = | |
| 1109 it != frame_tree_node_id_to_save_item_.end() ? it->second : nullptr; | |
| 1110 SerializeLocalPathForSaveItem(sender, save_item, | |
| 1111 frame_tree_node->current_url()); | |
| 1112 } | |
| 1113 | |
| 1114 void SavePackage::OnSerializedLocalPathForSavableResource( | |
| 1115 RenderFrameHostImpl* sender, | |
| 1116 const GURL& savable_resource) { | |
| 1117 if (wait_state_ != HTML_DATA) | |
| 1118 return; | |
| 1119 if (!savable_resource.is_valid()) | |
| 1120 return; | |
| 1121 | |
| 1122 auto it = url_to_save_item_.find(savable_resource); | |
| 1123 SaveItem* save_item = it != url_to_save_item_.end() ? it->second : nullptr; | |
| 1124 SerializeLocalPathForSaveItem(sender, save_item, savable_resource); | |
| 1125 } | |
| 1126 | |
| 1127 void SavePackage::OnSerializedEndOfFrame(RenderFrameHostImpl* sender) { | |
| 1128 if (wait_state_ != HTML_DATA) | |
| 1129 return; | |
| 1130 | |
| 1131 int frame_tree_node_id = sender->frame_tree_node()->frame_tree_node_id(); | |
| 1132 auto it = frame_tree_node_id_to_save_item_.find(frame_tree_node_id); | |
| 1133 if (it == frame_tree_node_id_to_save_item_.end()) | |
| 1134 return; | |
| 1135 SaveItem* save_item = it->second; | |
| 1136 if (save_item->state() != SaveItem::IN_PROGRESS) { | |
| 1137 LogWriteToAlreadyCompletedOrFailedSaveItem(save_item); | |
| 1138 return; | |
| 1139 } | |
| 1140 save_item->MarkAsCompleting(); | |
| 1141 | |
| 1142 int id = contents_id(); | |
| 1139 | 1143 |
| 1140 // Current frame is completed saving, call finish in file thread. | 1144 // Current frame is completed saving, call finish in file thread. |
| 1141 if (flag == WebPageSerializerClient::CurrentFrameIsFinished) { | 1145 DVLOG(20) << " " << __FUNCTION__ << "()" |
| 1142 DVLOG(20) << " " << __FUNCTION__ << "()" | 1146 << " save_id = " << save_item->save_id() << " url = \"" |
| 1143 << " save_id = " << save_item->save_id() | 1147 << save_item->url().spec() << "\""; |
| 1144 << " url = \"" << save_item->url().spec() << "\""; | 1148 BrowserThread::PostTask( |
| 1145 BrowserThread::PostTask( | 1149 BrowserThread::FILE, FROM_HERE, |
| 1146 BrowserThread::FILE, FROM_HERE, | 1150 base::Bind(&SaveFileManager::SaveFinished, file_manager_, |
| 1147 base::Bind(&SaveFileManager::SaveFinished, | 1151 save_item->save_id(), save_item->url(), id, true)); |
| 1148 file_manager_, | 1152 number_of_frames_pending_response_--; |
| 1149 save_item->save_id(), | 1153 DCHECK_LE(0, number_of_frames_pending_response_); |
| 1150 save_item->url(), | |
| 1151 id, | |
| 1152 true)); | |
| 1153 number_of_frames_pending_response_--; | |
| 1154 DCHECK_LE(0, number_of_frames_pending_response_); | |
| 1155 } | |
| 1156 | 1154 |
| 1157 // If all frames are finished saving, we need to close the remaining | 1155 // If the all frames are finished saving, we need to close the |
| 1158 // SaveItems. | 1156 // remaining SaveItems. |
| 1159 if (number_of_frames_pending_response_ == 0) { | 1157 if (number_of_frames_pending_response_ == 0) { |
| 1160 for (SaveUrlItemMap::iterator it = in_progress_items_.begin(); | 1158 for (const auto& pair : in_progress_items_) { |
| 1161 it != in_progress_items_.end(); ++it) { | |
| 1162 DVLOG(20) << " " << __FUNCTION__ << "()" | 1159 DVLOG(20) << " " << __FUNCTION__ << "()" |
| 1163 << " save_id = " << it->second->save_id() << " url = \"" | 1160 << " save_id = " << pair.second->save_id() << " url = \"" |
| 1164 << it->second->url().spec() << "\""; | 1161 << pair.second->url().spec() << "\""; |
| 1165 BrowserThread::PostTask( | 1162 BrowserThread::PostTask( |
| 1166 BrowserThread::FILE, FROM_HERE, | 1163 BrowserThread::FILE, FROM_HERE, |
| 1167 base::Bind(&SaveFileManager::SaveFinished, file_manager_, | 1164 base::Bind(&SaveFileManager::SaveFinished, file_manager_, |
| 1168 it->second->save_id(), it->second->url(), id, true)); | 1165 pair.second->save_id(), pair.second->url(), id, true)); |
| 1169 } | 1166 } |
| 1170 } | 1167 } |
| 1171 } | 1168 } |
| 1172 | 1169 |
| 1170 void SavePackage::SerializeLocalPathForSaveItem(RenderFrameHostImpl* sender, | |
| 1171 SaveItem* save_item, | |
| 1172 const GURL& fallback_url) { | |
| 1173 std::string attr_value; | |
| 1174 if (save_item) { | |
| 1175 base::FilePath relative_path = | |
| 1176 base::FilePath(FILE_PATH_LITERAL(".")) | |
| 1177 .Append(saved_main_directory_path_.BaseName()) | |
| 1178 .Append(save_item->file_name()) | |
| 1179 .NormalizePathSeparatorsTo(FILE_PATH_LITERAL('/')); | |
| 1180 attr_value = relative_path.AsUTF8Unsafe(); | |
| 1181 } else { | |
| 1182 // Use |fallback_url| if we didn't see the referenced item when gathering | |
| 1183 // savable resources in an earlier step (i.e. because the page being saved | |
| 1184 // changes during the save - crbug.com/541354). | |
| 1185 attr_value = fallback_url.spec(); | |
| 1186 } | |
| 1187 | |
| 1188 // TODO(lukasza): Escape attr_value (" + &). | |
|
ncarter (slow)
2015/10/12 23:31:48
Responding to your comments in the earlier thread,
Łukasz Anforowicz
2015/10/21 22:50:35
Daniel pointed out net::EscapeForHTML. I am not s
| |
| 1189 OnSerializedHtmlFragment(sender, attr_value); | |
| 1190 } | |
| 1191 | |
| 1192 void SavePackage::LogWriteToAlreadyCompletedOrFailedSaveItem( | |
| 1193 SaveItem* save_item) { | |
| 1194 auto already_completed_it = | |
| 1195 std::find_if(saved_success_items_.begin(), saved_success_items_.end(), | |
| 1196 [save_item](const SavedItemMap::value_type& v) { | |
| 1197 return v.second->url() == save_item->url(); | |
| 1198 }); | |
| 1199 if (already_completed_it != saved_success_items_.end()) | |
| 1200 wrote_to_completed_file_ = true; | |
| 1201 | |
| 1202 auto failed_it = | |
| 1203 std::find_if(saved_failed_items_.begin(), saved_failed_items_.end(), | |
| 1204 [save_item](const SaveUrlItemMap::value_type& v) { | |
| 1205 DCHECK(v.second->has_final_name()); | |
| 1206 return v.second->url() == save_item->url(); | |
| 1207 }); | |
| 1208 if (failed_it != saved_failed_items_.end()) | |
| 1209 wrote_to_failed_file_ = true; | |
| 1210 } | |
| 1211 | |
| 1173 // Ask for all savable resource links from backend, include main frame and | 1212 // Ask for all savable resource links from backend, include main frame and |
| 1174 // sub-frame. | 1213 // sub-frame. |
| 1175 void SavePackage::GetSavableResourceLinks() { | 1214 void SavePackage::GetSavableResourceLinks() { |
| 1176 if (wait_state_ != START_PROCESS) | 1215 if (wait_state_ != START_PROCESS) |
| 1177 return; | 1216 return; |
| 1178 | 1217 |
| 1179 wait_state_ = RESOURCES_LIST; | 1218 wait_state_ = RESOURCES_LIST; |
| 1180 | 1219 |
| 1181 DCHECK_EQ(0, number_of_frames_pending_response_); | 1220 DCHECK_EQ(0, number_of_frames_pending_response_); |
| 1182 web_contents()->ForEachFrame(base::Bind( | 1221 web_contents()->ForEachFrame(base::Bind( |
| 1183 &SavePackage::GetSavableResourceLinksForFrame, | 1222 &SavePackage::GetSavableResourceLinksForFrame, |
| 1184 base::Unretained(this))); // Safe, because ForEachFrame is synchronous. | 1223 base::Unretained(this))); // Safe, because ForEachFrame is synchronous. |
| 1185 DCHECK_LT(0, number_of_frames_pending_response_); | 1224 DCHECK_LT(0, number_of_frames_pending_response_); |
| 1186 } | 1225 } |
| 1187 | 1226 |
| 1188 void SavePackage::GetSavableResourceLinksForFrame(RenderFrameHost* target) { | 1227 void SavePackage::GetSavableResourceLinksForFrame(RenderFrameHost* target) { |
| 1189 number_of_frames_pending_response_++; | 1228 number_of_frames_pending_response_++; |
| 1190 target->Send(new FrameMsg_GetSavableResourceLinks(target->GetRoutingID())); | 1229 target->Send(new FrameMsg_GetSavableResourceLinks(target->GetRoutingID())); |
| 1191 } | 1230 } |
| 1192 | 1231 |
| 1193 void SavePackage::OnSavableResourceLinksResponse( | 1232 void SavePackage::OnSavableResourceLinksResponse( |
| 1194 RenderFrameHost* sender, | 1233 RenderFrameHostImpl* sender, |
| 1195 const GURL& frame_url, | 1234 const GURL& frame_url, |
| 1196 const std::vector<GURL>& resources_list, | 1235 const std::vector<GURL>& resources_list, |
| 1197 const std::vector<Referrer>& referrers_list) { | 1236 const std::vector<Referrer>& referrers_list) { |
| 1198 if (wait_state_ != RESOURCES_LIST) | 1237 if (wait_state_ != RESOURCES_LIST) |
| 1199 return; | 1238 return; |
| 1200 | 1239 |
| 1201 if (resources_list.size() != referrers_list.size()) | 1240 if (resources_list.size() != referrers_list.size()) |
| 1202 return; | 1241 return; |
| 1203 | 1242 |
| 1204 // Add all sub-resources to wait list. | 1243 // Add all sub-resources to wait list. |
| 1205 for (int i = 0; i < static_cast<int>(resources_list.size()); ++i) { | 1244 for (int i = 0; i < static_cast<int>(resources_list.size()); ++i) { |
| 1206 const GURL& u = resources_list[i]; | 1245 const GURL& u = resources_list[i]; |
| 1207 if (!u.is_valid()) | 1246 if (!u.is_valid()) |
| 1208 continue; | 1247 continue; |
| 1209 if (unique_urls_to_save_.count(u)) | |
| 1210 continue; | |
| 1211 unique_urls_to_save_.insert(u); | |
| 1212 | 1248 |
| 1213 SaveFileCreateInfo::SaveFileSource save_source = | 1249 SaveItem* save_item = url_to_save_item_[u]; |
| 1214 u.SchemeIsFile() ? SaveFileCreateInfo::SAVE_FILE_FROM_FILE | 1250 if (save_item == nullptr) { |
| 1215 : SaveFileCreateInfo::SAVE_FILE_FROM_NET; | 1251 SaveFileCreateInfo::SaveFileSource save_source = |
| 1216 SaveItem* save_item = new SaveItem(u, referrers_list[i], this, save_source); | 1252 u.SchemeIsFile() ? SaveFileCreateInfo::SAVE_FILE_FROM_FILE |
| 1217 waiting_item_queue_.push(save_item); | 1253 : SaveFileCreateInfo::SAVE_FILE_FROM_NET; |
| 1254 url_to_save_item_[u] = save_item = new SaveItem(u, this, save_source); | |
| 1255 waiting_item_queue_.push_back(save_item); | |
| 1256 } | |
| 1257 save_item->set_referrer(referrers_list[i]); | |
| 1218 } | 1258 } |
| 1219 | 1259 |
| 1220 // Store savable frame_url for later processing. | 1260 // Add the frame to wait list. |
| 1221 if (frame_url.is_valid()) | 1261 // TODO(lukasza): Do not dedupe subframes based on url (see crbug.com/538188). |
| 1222 frame_urls_to_save_.push_back(frame_url); | 1262 if (frame_url.is_valid()) { |
| 1263 SaveItem* save_item = url_to_save_item_[frame_url]; | |
| 1264 if (save_item == nullptr) { | |
| 1265 url_to_save_item_[frame_url] = save_item = | |
| 1266 new SaveItem(frame_url, this, SaveFileCreateInfo::SAVE_FILE_FROM_DOM); | |
| 1267 waiting_item_queue_.push_back(save_item); | |
| 1268 } | |
| 1269 int frame_tree_node_id = sender->frame_tree_node()->frame_tree_node_id(); | |
| 1270 frame_tree_node_id_to_save_item_[frame_tree_node_id] = save_item; | |
| 1271 } | |
| 1223 | 1272 |
| 1224 CompleteSavableResourceLinksResponse(); | 1273 CompleteSavableResourceLinksResponse(); |
| 1225 } | 1274 } |
| 1226 | 1275 |
| 1227 void SavePackage::OnSavableResourceLinksError(RenderFrameHost* sender) { | 1276 void SavePackage::OnSavableResourceLinksError(RenderFrameHostImpl* sender) { |
| 1228 CompleteSavableResourceLinksResponse(); | 1277 CompleteSavableResourceLinksResponse(); |
| 1229 } | 1278 } |
| 1230 | 1279 |
| 1231 void SavePackage::CompleteSavableResourceLinksResponse() { | 1280 void SavePackage::CompleteSavableResourceLinksResponse() { |
| 1232 --number_of_frames_pending_response_; | 1281 --number_of_frames_pending_response_; |
| 1233 DCHECK_LE(0, number_of_frames_pending_response_); | 1282 DCHECK_LE(0, number_of_frames_pending_response_); |
| 1234 if (number_of_frames_pending_response_ != 0) | 1283 if (number_of_frames_pending_response_ != 0) |
| 1235 return; // Need to wait for more responses from RenderFrames. | 1284 return; // Need to wait for more responses from RenderFrames. |
| 1236 | 1285 |
| 1237 // Add frame urls to the waiting_item_queue_. This is done *after* processing | 1286 // Sort |waiting_item_queue_| so that frames go last (frames are identified by |
| 1238 // all savable resource links (i.e. in OnSavableResourceLinksResponse), to | 1287 // SAVE_FILE_FROM_DOM in the comparison function below). |
| 1239 // prefer their referrers in cases where the frame url has already been | 1288 std::stable_sort( |
| 1240 // covered by savable resource links. | 1289 waiting_item_queue_.begin(), waiting_item_queue_.end(), |
| 1241 for (auto& frame_url : frame_urls_to_save_) { | 1290 [](SaveItem* x, SaveItem* y) { |
| 1242 DCHECK(frame_url.is_valid()); | 1291 DCHECK(x); |
| 1243 if (0 == unique_urls_to_save_.count(frame_url)) { | 1292 DCHECK(y); |
| 1244 unique_urls_to_save_.insert(frame_url); | 1293 return (x->save_source() != SaveFileCreateInfo::SAVE_FILE_FROM_DOM) && |
| 1245 SaveItem* save_item = new SaveItem( | 1294 (y->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM); |
| 1246 frame_url, Referrer(), this, SaveFileCreateInfo::SAVE_FILE_FROM_DOM); | 1295 }); |
| 1247 waiting_item_queue_.push(save_item); | |
| 1248 } | |
| 1249 } | |
| 1250 | |
| 1251 all_save_items_count_ = static_cast<int>(waiting_item_queue_.size()); | 1296 all_save_items_count_ = static_cast<int>(waiting_item_queue_.size()); |
| 1252 | 1297 |
| 1253 // We use total bytes as the total number of files we want to save. | 1298 // We use total bytes as the total number of files we want to save. |
| 1254 // Hack to avoid touching download_ after user cancel. | 1299 // Hack to avoid touching download_ after user cancel. |
| 1255 // TODO(rdsmith/benjhayden): Integrate canceling on DownloadItem | 1300 // TODO(rdsmith/benjhayden): Integrate canceling on DownloadItem |
| 1256 // with SavePackage flow. | 1301 // with SavePackage flow. |
| 1257 if (download_ && (download_->GetState() == DownloadItem::IN_PROGRESS)) | 1302 if (download_ && (download_->GetState() == DownloadItem::IN_PROGRESS)) |
| 1258 download_->SetTotalBytes(all_save_items_count_); | 1303 download_->SetTotalBytes(all_save_items_count_); |
| 1259 | 1304 |
| 1260 if (all_save_items_count_) { | 1305 if (all_save_items_count_) { |
| (...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1505 | 1550 |
| 1506 void SavePackage::FinalizeDownloadEntry() { | 1551 void SavePackage::FinalizeDownloadEntry() { |
| 1507 DCHECK(download_); | 1552 DCHECK(download_); |
| 1508 DCHECK(download_manager_); | 1553 DCHECK(download_manager_); |
| 1509 | 1554 |
| 1510 download_manager_->OnSavePackageSuccessfullyFinished(download_); | 1555 download_manager_->OnSavePackageSuccessfullyFinished(download_); |
| 1511 StopObservation(); | 1556 StopObservation(); |
| 1512 } | 1557 } |
| 1513 | 1558 |
| 1514 } // namespace content | 1559 } // namespace content |
| OLD | NEW |