save_package.cc revision 513209b27ff55e2841eac0e4120199c23acce758
1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/download/save_package.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "app/l10n_util.h" 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_path.h" 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_util.h" 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/i18n/file_util_icu.h" 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h" 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/message_loop.h" 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/stl_util-inl.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_piece.h" 153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_split.h" 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h" 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/task.h" 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/thread.h" 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_process.h" 20731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/browser/browser_thread.h" 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/download/download_item.h" 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/download/download_item_model.h" 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/download/download_manager.h" 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/download/download_shelf.h" 253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/download/download_util.h" 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/download/save_file.h" 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/download/save_file_manager.h" 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/download/save_item.h" 293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/net/url_fixer_upper.h" 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/platform_util.h" 313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/prefs/pref_member.h" 323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/prefs/pref_service.h" 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/profile.h" 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/renderer_host/render_process_host.h" 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/renderer_host/render_view_host.h" 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/renderer_host/render_view_host_delegate.h" 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/renderer_host/resource_dispatcher_host.h" 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/tab_contents/tab_contents.h" 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/tab_contents/tab_util.h" 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_paths.h" 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/net/url_request_context_getter.h" 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/notification_service.h" 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/notification_type.h" 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/pref_names.h" 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/url_constants.h" 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h" 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/io_buffer.h" 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/mime_util.h" 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_util.h" 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/url_request/url_request_context.h" 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "third_party/WebKit/WebKit/chromium/public/WebPageSerializerClient.h" 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::Time; 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing WebKit::WebPageSerializerClient; 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// A counter for uniquely identifying each save package. 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint g_save_package_id = 0; 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Default name which will be used when we can not get proper name from 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// resource URL. 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst FilePath::CharType kDefaultSaveName[] = 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FILE_PATH_LITERAL("saved_resource"); 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst FilePath::CharType kDefaultHtmlExtension[] = 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN) 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FILE_PATH_LITERAL("htm"); 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FILE_PATH_LITERAL("html"); 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Maximum number of file ordinal number. I think it's big enough for resolving 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// name-conflict files which has same base file name. 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int32 kMaxFileOrdinalNumber = 9999; 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Maximum length for file path. Since Windows have MAX_PATH limitation for 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// file path, we need to make sure length of file path of every saved file 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// is less than MAX_PATH 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN) 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst uint32 kMaxFilePathLength = MAX_PATH - 1; 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(OS_POSIX) 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst uint32 kMaxFilePathLength = PATH_MAX - 1; 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Maximum length for file ordinal number part. Since we only support the 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// maximum 9999 for ordinal number, which means maximum file ordinal number part 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// should be "(9998)", so the value is 6. 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst uint32 kMaxFileOrdinalNumberPartLength = 6; 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// If false, we don't prompt the user as to where to save the file. This 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// exists only for testing. 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool g_should_prompt_for_filename = true; 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Strip current ordinal number, if any. Should only be used on pure 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// file names, i.e. those stripped of their extensions. 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TODO(estade): improve this to not choke on alternate encodings. 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochFilePath::StringType StripOrdinalNumber( 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const FilePath::StringType& pure_file_name) { 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType::size_type r_paren_index = 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch pure_file_name.rfind(FILE_PATH_LITERAL(')')); 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType::size_type l_paren_index = 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch pure_file_name.rfind(FILE_PATH_LITERAL('(')); 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (l_paren_index >= r_paren_index) 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return pure_file_name; 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (FilePath::StringType::size_type i = l_paren_index + 1; 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i != r_paren_index; ++i) { 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!IsAsciiDigit(pure_file_name[i])) 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return pure_file_name; 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return pure_file_name.substr(0, l_paren_index); 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Check whether we can save page as complete-HTML for the contents which 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// have specified a MIME type. Now only contents which have the MIME type 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// "text/html" can be saved as complete-HTML. 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool CanSaveAsComplete(const std::string& contents_mime_type) { 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return contents_mime_type == "text/html" || 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch contents_mime_type == "application/xhtml+xml"; 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// File name is considered being consist of pure file name, dot and file 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// extension name. File name might has no dot and file extension, or has 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// multiple dot inside file name. The dot, which separates the pure file 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// name and file extension name, is last dot in the whole file name. 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This function is for making sure the length of specified file path is not 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// great than the specified maximum length of file path and getting safe pure 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// file name part if the input pure file name is too long. 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The parameter |dir_path| specifies directory part of the specified 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// file path. The parameter |file_name_ext| specifies file extension 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// name part of the specified file path (including start dot). The parameter 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// |max_file_path_len| specifies maximum length of the specified file path. 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The parameter |pure_file_name| input pure file name part of the specified 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// file path. If the length of specified file path is great than 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// |max_file_path_len|, the |pure_file_name| will output new pure file name 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// part for making sure the length of specified file path is less than 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// specified maximum length of file path. Return false if the function can 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// not get a safe pure file name, otherwise it returns true. 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool GetSafePureFileName(const FilePath& dir_path, 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const FilePath::StringType& file_name_ext, 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch uint32 max_file_path_len, 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType* pure_file_name) { 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!pure_file_name->empty()); 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int available_length = static_cast<int>( 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch max_file_path_len - dir_path.value().length() - file_name_ext.length()); 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Need an extra space for the separator. 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!file_util::EndsWithSeparator(dir_path)) 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch --available_length; 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Plenty of room. 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (static_cast<int>(pure_file_name->length()) <= available_length) 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Limited room. Truncate |pure_file_name| to fit. 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (available_length > 0) { 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *pure_file_name = 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch pure_file_name->substr(0, available_length); 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Not enough room to even use a shortened |pure_file_name|. 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch pure_file_name->clear(); 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1703345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickSavePackage::SavePackage(TabContents* tab_contents, 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SavePackageType save_type, 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const FilePath& file_full_path, 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const FilePath& directory_full_path) 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : file_manager_(NULL), 1753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick tab_contents_(tab_contents), 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch download_(NULL), 1773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick page_url_(GetUrlToBeSaved()), 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_main_file_path_(file_full_path), 179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_main_directory_path_(directory_full_path), 1803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick title_(tab_contents->GetTitle()), 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch finished_(false), 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch user_canceled_(false), 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch disk_error_occurred_(false), 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_type_(save_type), 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch all_save_items_count_(0), 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch wait_state_(INITIALIZE), 1873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick tab_id_(tab_contents->GetRenderProcessHost()->id()), 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch unique_id_(g_save_package_id++), 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { 1903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(page_url_.is_valid()); 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(save_type_ == SAVE_AS_ONLY_HTML || 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_type_ == SAVE_AS_COMPLETE_HTML); 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!saved_main_file_path_.empty() && 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_main_file_path_.value().length() <= kMaxFilePathLength); 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!saved_main_directory_path_.empty() && 196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_main_directory_path_.value().length() < kMaxFilePathLength); 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch InternalInit(); 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSavePackage::SavePackage(TabContents* tab_contents) 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : file_manager_(NULL), 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_contents_(tab_contents), 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch download_(NULL), 2043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick page_url_(GetUrlToBeSaved()), 2053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick title_(tab_contents->GetTitle()), 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch finished_(false), 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch user_canceled_(false), 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch disk_error_occurred_(false), 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_type_(SAVE_TYPE_UNKNOWN), 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch all_save_items_count_(0), 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch wait_state_(INITIALIZE), 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_id_(tab_contents->GetRenderProcessHost()->id()), 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch unique_id_(g_save_package_id++), 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { 2153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(page_url_.is_valid()); 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch InternalInit(); 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This is for testing use. Set |finished_| as true because we don't want 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// method Cancel to be be called in destructor in test mode. 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// We also don't call InternalInit(). 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSavePackage::SavePackage(TabContents* tab_contents, 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const FilePath& file_full_path, 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const FilePath& directory_full_path) 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : file_manager_(NULL), 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_contents_(tab_contents), 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch download_(NULL), 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_main_file_path_(file_full_path), 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_main_directory_path_(directory_full_path), 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch finished_(true), 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch user_canceled_(false), 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch disk_error_occurred_(false), 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_type_(SAVE_TYPE_UNKNOWN), 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch all_save_items_count_(0), 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch wait_state_(INITIALIZE), 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_id_(0), 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch unique_id_(g_save_package_id++), 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSavePackage::~SavePackage() { 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Stop receiving saving job's updates 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!finished_ && !canceled()) { 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Unexpected quit. 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Cancel(true); 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(all_save_items_count_ == (waiting_item_queue_.size() + 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch completed_count() + 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch in_process_count())); 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Free all SaveItems. 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (!waiting_item_queue_.empty()) { 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We still have some items which are waiting for start to save. 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = waiting_item_queue_.front(); 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch waiting_item_queue_.pop(); 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete save_item; 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch STLDeleteValues(&saved_success_items_); 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch STLDeleteValues(&in_progress_items_); 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch STLDeleteValues(&saved_failed_items_); 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 2633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // The DownloadItem is owned by DownloadManager. 2643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick download_ = NULL; 2653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_manager_ = NULL; 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If there's an outstanding save dialog, make sure it doesn't call us back 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // now that we're gone. 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (select_file_dialog_.get()) 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch select_file_dialog_->ListenerDestroyed(); 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Retrieves the URL to be saved from tab_contents_ variable. 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochGURL SavePackage::GetUrlToBeSaved() { 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Instead of using tab_contents_.GetURL here, we use url() 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // (which is the "real" url of the page) 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // from the NavigationEntry because it reflects its' origin 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // rather than the displayed one (returned by GetURL) which may be 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // different (like having "view-source:" on the front). 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NavigationEntry* active_entry = 2823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick tab_contents_->controller().GetActiveEntry(); 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return active_entry->url(); 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Cancel all in progress request, might be called by user or internal error. 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::Cancel(bool user_action) { 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!canceled()) { 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (user_action) 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch user_canceled_ = true; 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch disk_error_occurred_ = true; 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Stop(); 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Init() can be called directly, or indirectly via GetSaveInfo(). In both 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// cases, we need file_manager_ to be initialized, so we do this first. 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::InternalInit() { 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ResourceDispatcherHost* rdh = g_browser_process->resource_dispatcher_host(); 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!rdh) { 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_manager_ = rdh->save_file_manager(); 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!file_manager_) { 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Initialize the SavePackage. 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SavePackage::Init() { 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Set proper running state. 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (wait_state_ != INITIALIZE) 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch wait_state_ = START_PROCESS; 320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Initialize the request context and resource dispatcher. 322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Profile* profile = tab_contents_->profile(); 323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!profile) { 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch request_context_getter_ = profile->GetRequestContext(); 329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Create the fake DownloadItem and display the view. 3313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DownloadManager* download_manager = 3323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick tab_contents_->profile()->GetDownloadManager(); 3333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick download_ = new DownloadItem(download_manager, 3343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick saved_main_file_path_, 3353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick page_url_, 3363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick profile->IsOffTheRecord()); 3373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 3383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Transfer the ownership to the download manager. We need the DownloadItem 3393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // to be alive as long as the Profile is alive. 3403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick download_manager->SavePageAsDownloadStarted(download_); 3413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_contents_->OnStartDownload(download_); 343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Check save type and process the save page job. 345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (save_type_ == SAVE_AS_COMPLETE_HTML) { 346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Get directory 347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!saved_main_directory_path_.empty()); 348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetAllSavableResourceLinksForCurrentPage(); 349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch wait_state_ = NET_FILES; 3513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SaveFileCreateInfo::SaveFileSource save_source = page_url_.SchemeIsFile() ? 352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveFileCreateInfo::SAVE_FILE_FROM_FILE : 353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveFileCreateInfo::SAVE_FILE_FROM_NET; 354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = new SaveItem(page_url_, 355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL(), 356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this, 357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_source); 358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Add this item to waiting list. 359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch waiting_item_queue_.push(save_item); 360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch all_save_items_count_ = 1; 361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch download_->set_total_bytes(1); 362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DoSavingProcess(); 364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Generate name for saving resource. 370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SavePackage::GenerateFileName(const std::string& disposition, 371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const GURL& url, 372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool need_html_ext, 373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType* generated_name) { 374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(jungshik): Figure out the referrer charset when having one 375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // makes sense and pass it to GetSuggestedFilename. 376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath file_path = net::GetSuggestedFilename(url, disposition, "", 377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath(kDefaultSaveName)); 378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!file_path.empty()); 380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType pure_file_name = 381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_path.RemoveExtension().BaseName().value(); 382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType file_name_ext = file_path.Extension(); 383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If it is HTML resource, use ".htm{l,}" as its extension. 385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (need_html_ext) { 386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_name_ext = FILE_PATH_LITERAL("."); 387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_name_ext.append(kDefaultHtmlExtension); 388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Get safe pure file name. 391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!GetSafePureFileName(saved_main_directory_path_, file_name_ext, 392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kMaxFilePathLength, &pure_file_name)) 393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType file_name = pure_file_name + file_name_ext; 396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Check whether we already have same name. 398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (file_name_set_.find(file_name) == file_name_set_.end()) { 399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_name_set_.insert(file_name); 400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Found same name, increase the ordinal number for the file name. 402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType base_file_name = StripOrdinalNumber(pure_file_name); 403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We need to make sure the length of base file name plus maximum ordinal 405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // number path will be less than or equal to kMaxFilePathLength. 406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!GetSafePureFileName(saved_main_directory_path_, file_name_ext, 407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kMaxFilePathLength - kMaxFileOrdinalNumberPartLength, &base_file_name)) 408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Prepare the new ordinal number. 411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch uint32 ordinal_number; 412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FileNameCountMap::iterator it = file_name_count_map_.find(base_file_name); 413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (it == file_name_count_map_.end()) { 414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // First base-name-conflict resolving, use 1 as initial ordinal number. 415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_name_count_map_[base_file_name] = 1; 416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ordinal_number = 1; 417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We have met same base-name conflict, use latest ordinal number. 419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ordinal_number = it->second; 420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (ordinal_number > (kMaxFileOrdinalNumber - 1)) { 423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Use a random file from temporary file. 424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath temp_file; 425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_util::CreateTemporaryFile(&temp_file); 426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_name = temp_file.RemoveExtension().BaseName().value(); 427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Get safe pure file name. 428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!GetSafePureFileName(saved_main_directory_path_, 429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType(), 430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kMaxFilePathLength, &file_name)) 431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = ordinal_number; i < kMaxFileOrdinalNumber; ++i) { 434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType new_name = base_file_name + 435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StringPrintf(FILE_PATH_LITERAL("(%d)"), i) + file_name_ext; 436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (file_name_set_.find(new_name) == file_name_set_.end()) { 437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Resolved name conflict. 438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_name = new_name; 439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_name_count_map_[base_file_name] = ++i; 440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_name_set_.insert(file_name); 446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!file_name.empty()); 449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch generated_name->assign(file_name); 450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// We have received a message from SaveFileManager about a new saving job. We 455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// create a SaveItem and store it in our in_progress list. 456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::StartSave(const SaveFileCreateInfo* info) { 457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(info && !info->url.is_empty()); 458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveUrlItemMap::iterator it = in_progress_items_.find(info->url.spec()); 460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (it == in_progress_items_.end()) { 461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If not found, we must have cancel action. 462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(canceled()); 463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = it->second; 466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!saved_main_file_path_.empty()); 468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->SetSaveId(info->save_id); 470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->SetTotalBytes(info->total_bytes); 471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Determine the proper path for a saving job, by choosing either the default 473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // save directory, or prompting the user. 474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!save_item->has_final_name()); 475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (info->url != page_url_) { 476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType generated_name; 477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // For HTML resource file, make sure it will have .htm as extension name, 478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // otherwise, when you open the saved page in Chrome again, download 479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // file manager will treat it as downloadable resource, and download it 480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // instead of opening it as HTML. 481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool need_html_ext = 482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_DOM; 483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!GenerateFileName(info->content_disposition, 484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL(info->url), 485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch need_html_ext, 486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &generated_name)) { 487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We can not generate file name for this SaveItem, so we cancel the 488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // saving page job if the save source is from serialized DOM data. 489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Otherwise, it means this SaveItem is sub-resource type, we treat it 490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // as an error happened on saving. We can ignore this type error for 491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // sub-resource links which will be resolved as absolute links instead 492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // of local links in final saved contents. 493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_DOM) 494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Cancel(true); 495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveFinished(save_item->save_id(), 0, false); 497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // When saving page as only-HTML, we only have a SaveItem whose url 501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // must be page_url_. 502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(save_type_ == SAVE_AS_COMPLETE_HTML); 503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!saved_main_directory_path_.empty()); 504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Now we get final name retrieved from GenerateFileName, we will use it 506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // rename the SaveItem. 507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath final_name = saved_main_directory_path_.Append(generated_name); 508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->Rename(final_name); 509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // It is the main HTML file, use the name chosen by the user. 511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->Rename(saved_main_file_path_); 512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the save source is from file system, inform SaveFileManager to copy 515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // corresponding file to the file path which this SaveItem specifies. 516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_FILE) { 517731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 518731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(file_manager_, 520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &SaveFileManager::SaveLocalFile, 521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->url(), 522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->save_id(), 523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_id())); 524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Check whether we begin to require serialized HTML data. 528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (save_type_ == SAVE_AS_COMPLETE_HTML && wait_state_ == HTML_DATA) { 529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Inform backend to serialize the all frames' DOM and send serialized 530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // HTML data back. 531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetSerializedHtmlDataForCurrentPageWithLocalLinks(); 532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Look up SaveItem by save id from in progress map. 536c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSaveItem* SavePackage::LookupItemInProcessBySaveId(int32 save_id) { 537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (in_process_count()) { 538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (SaveUrlItemMap::iterator it = in_progress_items_.begin(); 539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch it != in_progress_items_.end(); ++it) { 540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = it->second; 541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(save_item->state() == SaveItem::IN_PROGRESS); 542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (save_item->save_id() == save_id) 543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return save_item; 544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return NULL; 547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Remove SaveItem from in progress map and put it to saved map. 550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::PutInProgressItemToSavedMap(SaveItem* save_item) { 551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveUrlItemMap::iterator it = in_progress_items_.find( 552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->url().spec()); 553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(it != in_progress_items_.end()); 554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(save_item == it->second); 555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch in_progress_items_.erase(it); 556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (save_item->success()) { 558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Add it to saved_success_items_. 559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(saved_success_items_.find(save_item->save_id()) == 560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_success_items_.end()); 561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_success_items_[save_item->save_id()] = save_item; 562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Add it to saved_failed_items_. 564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(saved_failed_items_.find(save_item->url().spec()) == 565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_failed_items_.end()); 566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_failed_items_[save_item->url().spec()] = save_item; 567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Called for updating saving state. 571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SavePackage::UpdateSaveProgress(int32 save_id, 572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int64 size, 573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool write_success) { 574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Because we might have canceled this saving job before, 575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // so we might not find corresponding SaveItem. 576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = LookupItemInProcessBySaveId(save_id); 577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!save_item) 578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->Update(size); 581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If we got disk error, cancel whole save page job. 583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!write_success) { 584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Cancel job with reason of disk error. 585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Cancel(false); 586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Stop all page saving jobs that are in progress and instruct the file thread 591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// to delete all saved files. 592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::Stop() { 593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If we haven't moved out of the initial state, there's nothing to cancel and 594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // there won't be valid pointers for file_manager_ or download_. 595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (wait_state_ == INITIALIZE) 596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // When stopping, if it still has some items in in_progress, cancel them. 599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(canceled()); 600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (in_process_count()) { 601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveUrlItemMap::iterator it = in_progress_items_.begin(); 602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (; it != in_progress_items_.end(); ++it) { 603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = it->second; 604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(save_item->state() == SaveItem::IN_PROGRESS); 605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->Cancel(); 606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Remove all in progress item to saved map. For failed items, they will 608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // be put into saved_failed_items_, for successful item, they will be put 609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // into saved_success_items_. 610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (in_process_count()) 611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PutInProgressItemToSavedMap(in_progress_items_.begin()->second); 612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This vector contains the save ids of the save files which SaveFileManager 615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // needs to remove from its save_file_map_. 616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveIDList save_ids; 617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (SavedItemMap::iterator it = saved_success_items_.begin(); 618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch it != saved_success_items_.end(); ++it) 619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_ids.push_back(it->first); 620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (SaveUrlItemMap::iterator it = saved_failed_items_.begin(); 621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch it != saved_failed_items_.end(); ++it) 622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_ids.push_back(it->second->save_id()); 623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 624731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 625731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(file_manager_, 627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &SaveFileManager::RemoveSavedFileFromFileMap, 628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_ids)); 629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch finished_ = true; 631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch wait_state_ = FAILED; 632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Inform the DownloadItem we have canceled whole save page job. 634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch download_->Cancel(false); 635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 636c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::CheckFinish() { 638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (in_process_count() || finished_) 639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath dir = (save_type_ == SAVE_AS_COMPLETE_HTML && 642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_success_items_.size() > 1) ? 643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_main_directory_path_ : FilePath(); 644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This vector contains the final names of all the successfully saved files 646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // along with their save ids. It will be passed to SaveFileManager to do the 647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // renaming job. 648c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FinalNameList final_names; 649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (SavedItemMap::iterator it = saved_success_items_.begin(); 650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch it != saved_success_items_.end(); ++it) 651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch final_names.push_back(std::make_pair(it->first, 652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch it->second->full_path())); 653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 654731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 655731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(file_manager_, 657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &SaveFileManager::RenameAllFiles, 658c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch final_names, 659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch dir, 660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_contents_->GetRenderProcessHost()->id(), 661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_contents_->render_view_host()->routing_id(), 662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch id())); 663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 664c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Successfully finished all items of this SavePackage. 666c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::Finish() { 667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // User may cancel the job when we're moving files to the final directory. 668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (canceled()) 669c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 671c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch wait_state_ = SUCCESSFUL; 672c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch finished_ = true; 673c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 674c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This vector contains the save ids of the save files which SaveFileManager 675c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // needs to remove from its save_file_map_. 676c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveIDList save_ids; 677c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (SaveUrlItemMap::iterator it = saved_failed_items_.begin(); 678c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch it != saved_failed_items_.end(); ++it) 679c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_ids.push_back(it->second->save_id()); 680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 681731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 682731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(file_manager_, 684c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &SaveFileManager::RemoveSavedFileFromFileMap, 685c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_ids)); 686c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 6873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick download_->OnAllDataSaved(all_save_items_count_); 6883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Notify download observers that we are complete (the call 6893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // to OnAllDataSaved() set the state to complete but did not notify). 690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch download_->UpdateObservers(); 691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationService::current()->Notify( 693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationType::SAVE_PACKAGE_SUCCESSFULLY_FINISHED, 694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Source<SavePackage>(this), 695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Details<GURL>(&page_url_)); 696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 697c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Called for updating end state. 699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::SaveFinished(int32 save_id, int64 size, bool is_success) { 700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Because we might have canceled this saving job before, 701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // so we might not find corresponding SaveItem. Just ignore it. 702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = LookupItemInProcessBySaveId(save_id); 703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!save_item) 704c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Let SaveItem set end state. 707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->Finish(size, is_success); 708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Remove the associated save id and SavePackage. 709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_manager_->RemoveSaveFile(save_id, save_item->url(), this); 710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PutInProgressItemToSavedMap(save_item); 712c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 713c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Inform the DownloadItem to update UI. 714c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We use the received bytes as number of saved files. 715c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch download_->Update(completed_count()); 716c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 717c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM && 718c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->url() == page_url_ && !save_item->received_bytes()) { 719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If size of main HTML page is 0, treat it as disk error. 720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Cancel(false); 721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 722c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (canceled()) { 725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(finished_); 726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Continue processing the save page job. 730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DoSavingProcess(); 731c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 732c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Check whether we can successfully finish whole job. 733c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CheckFinish(); 734c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 735c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Sometimes, the net io will only call SaveFileManager::SaveFinished with 737c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// save id -1 when it encounters error. Since in this case, save id will be 738c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// -1, so we can only use URL to find which SaveItem is associated with 739c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// this error. 740c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Saving an item failed. If it's a sub-resource, ignore it. If the error comes 741c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// from serializing HTML data, then cancel saving page. 742c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::SaveFailed(const GURL& save_url) { 743c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveUrlItemMap::iterator it = in_progress_items_.find(save_url.spec()); 744c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (it == in_progress_items_.end()) { 745c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); // Should not exist! 746c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 747c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = it->second; 749c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 750c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->Finish(0, false); 751c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 752c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PutInProgressItemToSavedMap(save_item); 753c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 754c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Inform the DownloadItem to update UI. 755c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We use the received bytes as number of saved files. 756c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch download_->Update(completed_count()); 757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 758c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (save_type_ == SAVE_AS_ONLY_HTML || 759c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM) { 760c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We got error when saving page. Treat it as disk error. 761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Cancel(true); 762c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 763c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 764c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (canceled()) { 765c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(finished_); 766c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 767c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 768c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 769c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Continue processing the save page job. 770c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DoSavingProcess(); 771c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CheckFinish(); 773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::SaveCanceled(SaveItem* save_item) { 776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Call the RemoveSaveFile in UI thread. 777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_manager_->RemoveSaveFile(save_item->save_id(), 778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->url(), 779c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this); 780c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (save_item->save_id() != -1) 781731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 782731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(file_manager_, 784c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &SaveFileManager::CancelSave, 785c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->save_id())); 786c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 787c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 788c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Initiate a saving job of a specific URL. We send the request to 789c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// SaveFileManager, which will dispatch it to different approach according to 790c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// the save source. Parameter process_all_remaining_items indicates whether 791c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// we need to save all remaining items. 792c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::SaveNextFile(bool process_all_remaining_items) { 793c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(tab_contents_); 794c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(waiting_item_queue_.size()); 795c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 796c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch do { 797c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Pop SaveItem from waiting list. 798c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = waiting_item_queue_.front(); 799c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch waiting_item_queue_.pop(); 800c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 801c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Add the item to in_progress_items_. 802c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveUrlItemMap::iterator it = in_progress_items_.find( 803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->url().spec()); 804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(it == in_progress_items_.end()); 805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch in_progress_items_[save_item->url().spec()] = save_item; 806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->Start(); 807c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_manager_->SaveURL(save_item->url(), 808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->referrer(), 809c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_contents_->GetRenderProcessHost()->id(), 810c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_contents_->render_view_host()->routing_id(), 811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->save_source(), 812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->full_path(), 813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch request_context_getter_.get(), 814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this); 815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } while (process_all_remaining_items && waiting_item_queue_.size()); 816c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 818c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Open download page in windows explorer on file thread, to avoid blocking the 820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// user interface. 821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::ShowDownloadInShell() { 822c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(file_manager_); 823c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(finished_ && !canceled() && !saved_main_file_path_.empty()); 824731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 825c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_MACOSX) 826c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Mac OS X requires opening downloads on the UI thread. 827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch platform_util::ShowItemInFolder(saved_main_file_path_); 828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else 829731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 830731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 831c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(file_manager_, 832c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &SaveFileManager::OnShowSavedFileInShell, 833c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_main_file_path_)); 834c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 835c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 836c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 837c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Calculate the percentage of whole save page job. 838c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint SavePackage::PercentComplete() { 839c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!all_save_items_count_) 840c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 0; 841c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else if (!in_process_count()) 842c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 100; 843c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 844c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return completed_count() / all_save_items_count_; 845c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 846c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 847c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Continue processing the save page job after one SaveItem has been 848c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// finished. 849c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::DoSavingProcess() { 850c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (save_type_ == SAVE_AS_COMPLETE_HTML) { 851c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We guarantee that images and JavaScripts must be downloaded first. 852c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // So when finishing all those sub-resources, we will know which 853c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // sub-resource's link can be replaced with local file path, which 854c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // sub-resource's link need to be replaced with absolute URL which 855c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // point to its internet address because it got error when saving its data. 856c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = NULL; 857c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Start a new SaveItem job if we still have job in waiting queue. 858c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (waiting_item_queue_.size()) { 859c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(wait_state_ == NET_FILES); 860c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item = waiting_item_queue_.front(); 861c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (save_item->save_source() != SaveFileCreateInfo::SAVE_FILE_FROM_DOM) { 862c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveNextFile(false); 863c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (!in_process_count()) { 864c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If there is no in-process SaveItem, it means all sub-resources 865c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // have been processed. Now we need to start serializing HTML DOM 866c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // for the current page to get the generated HTML data. 867c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch wait_state_ = HTML_DATA; 868c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // All non-HTML resources have been finished, start all remaining 869c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // HTML files. 870c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveNextFile(true); 871c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 872c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (in_process_count()) { 873c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Continue asking for HTML data. 874c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(wait_state_ == HTML_DATA); 875c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 876c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 877c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Save as HTML only. 878c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(wait_state_ == NET_FILES); 879c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(save_type_ == SAVE_AS_ONLY_HTML); 880c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (waiting_item_queue_.size()) { 881c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(all_save_items_count_ == waiting_item_queue_.size()); 882c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveNextFile(false); 883c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 884c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 885c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 886c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 887c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// After finishing all SaveItems which need to get data from net. 888c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// We collect all URLs which have local storage and send the 889c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// map:(originalURL:currentLocalPath) to render process (backend). 890c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Then render process will serialize DOM and send data to us. 891c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::GetSerializedHtmlDataForCurrentPageWithLocalLinks() { 892c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (wait_state_ != HTML_DATA) 893c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 894c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<GURL> saved_links; 895c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<FilePath> saved_file_paths; 896c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int successful_started_items_count = 0; 897c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 898c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Collect all saved items which have local storage. 899c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // First collect the status of all the resource files and check whether they 900c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // have created local files although they have not been completely saved. 901c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If yes, the file can be saved. Otherwise, there is a disk error, so we 902c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // need to cancel the page saving job. 903c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (SaveUrlItemMap::iterator it = in_progress_items_.begin(); 904c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch it != in_progress_items_.end(); ++it) { 905c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(it->second->save_source() == 906c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveFileCreateInfo::SAVE_FILE_FROM_DOM); 907c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (it->second->has_final_name()) 908c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch successful_started_items_count++; 909c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_links.push_back(it->second->url()); 910c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_file_paths.push_back(it->second->file_name()); 911c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 912c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 913c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If not all file of HTML resource have been started, then wait. 914c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (successful_started_items_count != in_process_count()) 915c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 916c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 917c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Collect all saved success items. 918c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (SavedItemMap::iterator it = saved_success_items_.begin(); 919c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch it != saved_success_items_.end(); ++it) { 920c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(it->second->has_final_name()); 921c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_links.push_back(it->second->url()); 922c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_file_paths.push_back(it->second->file_name()); 923c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 924c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 925c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Get the relative directory name. 926c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath relative_dir_name = saved_main_directory_path_.BaseName(); 927c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 928c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_contents_->render_view_host()-> 929c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetSerializedHtmlDataForCurrentPageWithLocalLinks( 930c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_links, saved_file_paths, relative_dir_name); 931c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 932c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 933c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Process the serialized HTML content data of a specified web page 934c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// retrieved from render process. 935c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::OnReceivedSerializedHtmlData(const GURL& frame_url, 936c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string& data, 937c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int32 status) { 938c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WebPageSerializerClient::PageSerializationStatus flag = 939c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<WebPageSerializerClient::PageSerializationStatus>(status); 940c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Check current state. 941c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (wait_state_ != HTML_DATA) 942c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 943c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 944c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int id = tab_id(); 945c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the all frames are finished saving, we need to close the 946c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // remaining SaveItems. 947c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (flag == WebPageSerializerClient::AllFramesAreFinished) { 948c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (SaveUrlItemMap::iterator it = in_progress_items_.begin(); 949c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch it != in_progress_items_.end(); ++it) { 950731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 951731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 952c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(file_manager_, 953c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &SaveFileManager::SaveFinished, 954c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch it->second->save_id(), 955c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch it->second->url(), 956c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch id, 957c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch true)); 958c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 959c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 960c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 961c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 962c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveUrlItemMap::iterator it = in_progress_items_.find(frame_url.spec()); 963c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (it == in_progress_items_.end()) 964c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 965c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = it->second; 966c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM); 967c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 968c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!data.empty()) { 969c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Prepare buffer for saving HTML data. 970513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch scoped_refptr<net::IOBuffer> new_data(new net::IOBuffer(data.size())); 971c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch memcpy(new_data->data(), data.data(), data.size()); 972c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 973c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Call write file functionality in file thread. 974731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 975731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 976c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(file_manager_, 977c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &SaveFileManager::UpdateSaveProgress, 978c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->save_id(), 979c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_data, 980c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<int>(data.size()))); 981c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 982c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 983c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Current frame is completed saving, call finish in file thread. 984c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (flag == WebPageSerializerClient::CurrentFrameIsFinished) { 985731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 986731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 987c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(file_manager_, 988c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &SaveFileManager::SaveFinished, 989c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->save_id(), 990c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->url(), 991c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch id, 992c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch true)); 993c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 994c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 995c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 996c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Ask for all savable resource links from backend, include main frame and 997c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// sub-frame. 998c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::GetAllSavableResourceLinksForCurrentPage() { 999c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (wait_state_ != START_PROCESS) 1000c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 1001c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1002c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch wait_state_ = RESOURCES_LIST; 1003c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_contents_->render_view_host()-> 10043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick GetAllSavableResourceLinksForCurrentPage(page_url_); 1005c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1006c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1007c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Give backend the lists which contain all resource links that have local 1008c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// storage, after which, render process will serialize DOM for generating 1009c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// HTML data. 1010c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::OnReceivedSavableResourceLinksForCurrentPage( 1011c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::vector<GURL>& resources_list, 1012c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::vector<GURL>& referrers_list, 1013c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::vector<GURL>& frames_list) { 1014c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (wait_state_ != RESOURCES_LIST) 1015c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 1016c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1017c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(resources_list.size() == referrers_list.size()); 1018c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch all_save_items_count_ = static_cast<int>(resources_list.size()) + 1019c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<int>(frames_list.size()); 1020c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1021c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We use total bytes as the total number of files we want to save. 1022c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch download_->set_total_bytes(all_save_items_count_); 1023c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1024c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (all_save_items_count_) { 1025c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Put all sub-resources to wait list. 1026c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = 0; i < static_cast<int>(resources_list.size()); ++i) { 1027c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const GURL& u = resources_list[i]; 1028c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(u.is_valid()); 1029c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveFileCreateInfo::SaveFileSource save_source = u.SchemeIsFile() ? 1030c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveFileCreateInfo::SAVE_FILE_FROM_FILE : 1031c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveFileCreateInfo::SAVE_FILE_FROM_NET; 1032c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = new SaveItem(u, referrers_list[i], 1033c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this, save_source); 1034c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch waiting_item_queue_.push(save_item); 1035c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1036c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Put all HTML resources to wait list. 1037c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = 0; i < static_cast<int>(frames_list.size()); ++i) { 1038c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const GURL& u = frames_list[i]; 1039c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(u.is_valid()); 1040c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = new SaveItem(u, GURL(), 1041c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this, SaveFileCreateInfo::SAVE_FILE_FROM_DOM); 1042c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch waiting_item_queue_.push(save_item); 1043c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1044c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch wait_state_ = NET_FILES; 1045c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DoSavingProcess(); 1046c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 1047c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // No resource files need to be saved, treat it as user cancel. 1048c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Cancel(true); 1049c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1050c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1051c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1052c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::SetShouldPromptUser(bool should_prompt) { 1053c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch g_should_prompt_for_filename = should_prompt; 1054c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1055c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 10563345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickFilePath SavePackage::GetSuggestedNameForSaveAs( 1057c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool can_save_as_complete, 1058513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch const std::string& contents_mime_type) { 10593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick FilePath name_with_proper_ext = 10603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick FilePath::FromWStringHack(UTF16ToWideHack(title_)); 10613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 10623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // If the page's title matches its URL, use the URL. Try to use the last path 10633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // component or if there is none, the domain as the file name. 10643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Normally we want to base the filename on the page title, or if it doesn't 10653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // exist, on the URL. It's not easy to tell if the page has no title, because 10663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // if the page has no title, TabContents::GetTitle() will return the page's 10673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // URL (adjusted for display purposes). Therefore, we convert the "title" 10683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // back to a URL, and if it matches the original page URL, we know the page 10693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // had no title (or had a title equal to its URL, which is fine to treat 10703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // similarly). 10713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick GURL fixed_up_title_url = 10723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick URLFixerUpper::FixupURL(UTF16ToUTF8(title_), std::string()); 10733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 10743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (page_url_ == fixed_up_title_url) { 1075c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string url_path; 1076c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<std::string> url_parts; 1077731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick base::SplitString(page_url_.path(), '/', &url_parts); 1078c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!url_parts.empty()) { 1079c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = static_cast<int>(url_parts.size()) - 1; i >= 0; --i) { 1080c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url_path = url_parts[i]; 1081c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!url_path.empty()) 1082c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 1083c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1084c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1085c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (url_path.empty()) 10863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick url_path = page_url_.host(); 1087c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch name_with_proper_ext = FilePath::FromWStringHack(UTF8ToWide(url_path)); 1088c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1089c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1090c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Ask user for getting final saving name. 1091c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch name_with_proper_ext = EnsureMimeExtension(name_with_proper_ext, 1092c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch contents_mime_type); 1093c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Adjust extension for complete types. 1094c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (can_save_as_complete) 1095c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch name_with_proper_ext = EnsureHtmlExtension(name_with_proper_ext); 1096c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1097c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType file_name = name_with_proper_ext.value(); 1098c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_util::ReplaceIllegalCharactersInPath(&file_name, ' '); 1099c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return FilePath(file_name); 1100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1102c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochFilePath SavePackage::EnsureHtmlExtension(const FilePath& name) { 1103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the file name doesn't have an extension suitable for HTML files, 1104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // append one. 1105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType ext = name.Extension(); 1106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!ext.empty()) 1107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ext.erase(ext.begin()); // Erase preceding '.'. 1108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string mime_type; 1109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!net::GetMimeTypeFromExtension(ext, &mime_type) || 1110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch !CanSaveAsComplete(mime_type)) { 1111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return FilePath(name.value() + FILE_PATH_LITERAL(".") + 1112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kDefaultHtmlExtension); 1113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return name; 1115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1117c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochFilePath SavePackage::EnsureMimeExtension(const FilePath& name, 1118513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch const std::string& contents_mime_type) { 1119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Start extension at 1 to skip over period if non-empty. 1120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType ext = name.Extension().length() ? 1121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch name.Extension().substr(1) : name.Extension(); 1122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType suggested_extension = 1123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ExtensionForMimeType(contents_mime_type); 1124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string mime_type; 1125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!suggested_extension.empty() && 1126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (!net::GetMimeTypeFromExtension(ext, &mime_type) || 1127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch !IsSavableContents(mime_type))) { 1128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Extension is absent or needs to be updated. 1129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return FilePath(name.value() + FILE_PATH_LITERAL(".") + 1130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch suggested_extension); 1131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return name; 1133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1135513209b27ff55e2841eac0e4120199c23acce758Ben Murdochconst FilePath::CharType* SavePackage::ExtensionForMimeType( 1136513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch const std::string& contents_mime_type) { 1137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static const struct { 1138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const FilePath::CharType *mime_type; 1139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const FilePath::CharType *suggested_extension; 1140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } extensions[] = { 1141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch { FILE_PATH_LITERAL("text/html"), kDefaultHtmlExtension }, 1142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch { FILE_PATH_LITERAL("text/xml"), FILE_PATH_LITERAL("xml") }, 1143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch { FILE_PATH_LITERAL("application/xhtml+xml"), FILE_PATH_LITERAL("xhtml") }, 1144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch { FILE_PATH_LITERAL("text/plain"), FILE_PATH_LITERAL("txt") }, 1145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch { FILE_PATH_LITERAL("text/css"), FILE_PATH_LITERAL("css") }, 1146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }; 1147513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#if defined(OS_POSIX) 1148513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch FilePath::StringType mime_type(contents_mime_type); 1149513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#elif defined(OS_WIN) 1150513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch FilePath::StringType mime_type(UTF8ToWide(contents_mime_type)); 1151513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#endif // OS_WIN 1152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (uint32 i = 0; i < ARRAYSIZE_UNSAFE(extensions); ++i) { 1153513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (mime_type == extensions[i].mime_type) 1154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return extensions[i].suggested_extension; 1155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return FILE_PATH_LITERAL(""); 1157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static. 1162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Check whether the preference has the preferred directory for saving file. If 1163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// not, initialize it with default directory. 1164c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochFilePath SavePackage::GetSaveDirPreference(PrefService* prefs) { 1165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(prefs); 1166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!prefs->FindPreference(prefs::kSaveFileDefaultDirectory)) { 1168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(prefs->FindPreference(prefs::kDownloadDefaultDirectory)); 1169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath default_save_path = prefs->GetFilePath( 1170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs::kDownloadDefaultDirectory); 1171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs->RegisterFilePathPref(prefs::kSaveFileDefaultDirectory, 1172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default_save_path); 1173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Get the directory from preference. 1176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath save_file_path = prefs->GetFilePath( 1177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs::kSaveFileDefaultDirectory); 1178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!save_file_path.empty()); 1179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return save_file_path; 1181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::GetSaveInfo() { 1184513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // Can't use tab_contents_ in the file thread, so get the data that we need 1185513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // before calling to it. 1186731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick PrefService* prefs = tab_contents_->profile()->GetPrefs(); 1187731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick FilePath website_save_dir = GetSaveDirPreference(prefs); 1188731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick FilePath download_save_dir = prefs->GetFilePath( 1189731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick prefs::kDownloadDefaultDirectory); 1190513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch std::string mime_type = tab_contents_->contents_mime_type(); 1191731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 1192731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 1193731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 1194513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch NewRunnableMethod(this, &SavePackage::CreateDirectoryOnFileThread, 1195513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch website_save_dir, download_save_dir, mime_type)); 1196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1198513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid SavePackage::CreateDirectoryOnFileThread( 1199513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch const FilePath& website_save_dir, 1200513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch const FilePath& download_save_dir, 1201513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch const std::string& mime_type) { 1202513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch FilePath save_dir; 1203513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // If the default html/websites save folder doesn't exist... 1204513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (!file_util::DirectoryExists(website_save_dir)) { 1205513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // If the default download dir doesn't exist, create it. 1206513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (!file_util::DirectoryExists(download_save_dir)) 1207513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch file_util::CreateDirectory(download_save_dir); 1208513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch save_dir = download_save_dir; 1209513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch } else { 1210513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // If it does exist, use the default save dir param. 1211513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch save_dir = website_save_dir; 1212513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch } 1213513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 1214513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch bool can_save_as_complete = CanSaveAsComplete(mime_type); 1215513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch FilePath suggested_path = save_dir.Append( 1216513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch GetSuggestedNameForSaveAs(can_save_as_complete, mime_type)); 1217513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch BrowserThread::PostTask( 1218513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch BrowserThread::UI, FROM_HERE, 1219513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch NewRunnableMethod(this, &SavePackage::ContinueGetSaveInfo, 1220513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch suggested_path, can_save_as_complete)); 1221513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} 1222513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 1223513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid SavePackage::ContinueGetSaveInfo(const FilePath& suggested_path, 1224513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch bool can_save_as_complete) { 1225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Use "Web Page, Complete" option as default choice of saving page. 1226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int file_type_index = 2; 1227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SelectFileDialog::FileTypeInfo file_type_info; 1228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType default_extension; 1229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the contents can not be saved as complete-HTML, do not show the 1231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // file filters. 1232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (can_save_as_complete) { 1233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool add_extra_extension = false; 1234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType extra_extension; 1235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!suggested_path.Extension().empty() && 1236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch suggested_path.Extension().compare(FILE_PATH_LITERAL("htm")) && 1237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch suggested_path.Extension().compare(FILE_PATH_LITERAL("html"))) { 1238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch add_extra_extension = true; 1239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extra_extension = suggested_path.Extension().substr(1); 1240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_type_info.extensions.resize(2); 1242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("htm")); 1243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("html")); 1244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (add_extra_extension) 1245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_type_info.extensions[0].push_back(extra_extension); 1246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_type_info.extension_description_overrides.push_back( 12473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick l10n_util::GetStringUTF16(IDS_SAVE_PAGE_DESC_HTML_ONLY)); 1248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_type_info.extensions[1].push_back(FILE_PATH_LITERAL("htm")); 1249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_type_info.extensions[1].push_back(FILE_PATH_LITERAL("html")); 1250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (add_extra_extension) 1251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_type_info.extensions[1].push_back(extra_extension); 1252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_type_info.extension_description_overrides.push_back( 12533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick l10n_util::GetStringUTF16(IDS_SAVE_PAGE_DESC_COMPLETE)); 1254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_type_info.include_all_files = false; 1255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default_extension = kDefaultHtmlExtension; 1256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 1257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_type_info.extensions.resize(1); 1258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_type_info.extensions[0].push_back(suggested_path.Extension()); 1259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!file_type_info.extensions[0][0].empty()) 1260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_type_info.extensions[0][0].erase(0, 1); // drop the . 1261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_type_info.include_all_files = true; 1262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_type_index = 1; 1263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (g_should_prompt_for_filename) { 1266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!select_file_dialog_.get()) 1267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch select_file_dialog_ = SelectFileDialog::Create(this); 1268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch select_file_dialog_->SelectFile(SelectFileDialog::SELECT_SAVEAS_FILE, 1269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch string16(), 1270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch suggested_path, 1271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &file_type_info, 1272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_type_index, 1273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default_extension, 1274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch platform_util::GetTopLevel( 1275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_contents_->GetNativeView()), 1276513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch NULL); 1277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 1278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Just use 'suggested_path' instead of opening the dialog prompt. 1279513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch ContinueSave(suggested_path, file_type_index); 1280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Called after the save file dialog box returns. 1284513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid SavePackage::ContinueSave(const FilePath& final_name, 1285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index) { 1286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Ensure the filename is safe. 1287513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch saved_main_file_path_ = final_name; 1288513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch download_util::GenerateSafeFileName(tab_contents_->contents_mime_type(), 1289513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch &saved_main_file_path_); 1290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The option index is not zero-based. 1292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(index > 0 && index < 3); 1293513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch saved_main_directory_path_ = saved_main_file_path_.DirName(); 1294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PrefService* prefs = tab_contents_->profile()->GetPrefs(); 1296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StringPrefMember save_file_path; 1297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_file_path.Init(prefs::kSaveFileDefaultDirectory, prefs, NULL); 1298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_POSIX) 1299513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch std::string path_string = saved_main_directory_path_.value(); 1300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(OS_WIN) 1301513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch std::string path_string = WideToUTF8(saved_main_directory_path_.value()); 1302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 1303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If user change the default saving directory, we will remember it just 1304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // like IE and FireFox. 1305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!tab_contents_->profile()->IsOffTheRecord() && 1306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_file_path.GetValue() != path_string) { 1307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_file_path.SetValue(path_string); 1308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1310513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch save_type_ = (index == 1) ? SavePackage::SAVE_AS_ONLY_HTML : 1311513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch SavePackage::SAVE_AS_COMPLETE_HTML; 1312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1313513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (save_type_ == SavePackage::SAVE_AS_COMPLETE_HTML) { 1314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make new directory for saving complete file. 1315513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch saved_main_directory_path_ = saved_main_directory_path_.Append( 1316513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch saved_main_file_path_.RemoveExtension().BaseName().value() + 1317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FILE_PATH_LITERAL("_files")); 1318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Init(); 1321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Static 1324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SavePackage::IsSavableURL(const GURL& url) { 1325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = 0; chrome::kSavableSchemes[i] != NULL; ++i) { 1326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (url.SchemeIs(chrome::kSavableSchemes[i])) { 1327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 1328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 1331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Static 1334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SavePackage::IsSavableContents(const std::string& contents_mime_type) { 1335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // WebKit creates Document object when MIME type is application/xhtml+xml, 1336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // so we also support this MIME type. 1337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return contents_mime_type == "text/html" || 1338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch contents_mime_type == "text/xml" || 1339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch contents_mime_type == "application/xhtml+xml" || 1340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch contents_mime_type == "text/plain" || 1341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch contents_mime_type == "text/css" || 1342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch net::IsSupportedJavascriptMimeType(contents_mime_type.c_str()); 1343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// SelectFileDialog::Listener interface. 1346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::FileSelected(const FilePath& path, 1347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index, void* params) { 1348513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch ContinueSave(path, index); 1349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::FileSelectionCanceled(void* params) { 1352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1353