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