Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(125)

Side by Side Diff: content/browser/download/save_package.cc

Issue 1373573002: ABANDONED: OOPIFs: Moving stitching of local paths from renderer to browser process. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@page-serialization-recursive-begone
Patch Set: Rebasing... Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « content/browser/download/save_package.h ('k') | content/common/frame_messages.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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 (&quot; + &amp;).
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
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
OLDNEW
« no previous file with comments | « content/browser/download/save_package.h ('k') | content/common/frame_messages.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698