172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 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 "base/file_path.h" 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_util.h" 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/i18n/file_util_icu.h" 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h" 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/message_loop.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/stl_util-inl.h" 15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_piece.h" 163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_split.h" 1772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/sys_string_conversions.h" 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/task.h" 193f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread.h" 20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/utf_string_conversions.h" 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_process.h" 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/download/download_item.h" 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/download/download_item_model.h" 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/download/download_manager.h" 2572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/download/download_prefs.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" 3521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h" 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/tab_contents/tab_util.h" 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_paths.h" 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/pref_names.h" 3972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/common/render_messages.h" 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/url_constants.h" 41dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h" 42dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_process_host.h" 43dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_view_host.h" 44dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_view_host_delegate.h" 45dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/resource_dispatcher_host.h" 46dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents.h" 47ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_service.h" 48ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_type.h" 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h" 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/io_buffer.h" 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/mime_util.h" 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_util.h" 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/url_request/url_request_context.h" 5472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "third_party/WebKit/Source/WebKit/chromium/public/WebPageSerializerClient.h" 5572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h" 56ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "net/url_request/url_request_context_getter.h" 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::Time; 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing WebKit::WebPageSerializerClient; 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// A counter for uniquely identifying each save package. 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint g_save_package_id = 0; 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Default name which will be used when we can not get proper name from 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// resource URL. 6872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenconst char kDefaultSaveName[] = "saved_resource"; 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst FilePath::CharType kDefaultHtmlExtension[] = 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN) 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FILE_PATH_LITERAL("htm"); 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FILE_PATH_LITERAL("html"); 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Maximum number of file ordinal number. I think it's big enough for resolving 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// name-conflict files which has same base file name. 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int32 kMaxFileOrdinalNumber = 9999; 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Maximum length for file path. Since Windows have MAX_PATH limitation for 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// file path, we need to make sure length of file path of every saved file 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// is less than MAX_PATH 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN) 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst uint32 kMaxFilePathLength = MAX_PATH - 1; 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(OS_POSIX) 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst uint32 kMaxFilePathLength = PATH_MAX - 1; 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Maximum length for file ordinal number part. Since we only support the 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// maximum 9999 for ordinal number, which means maximum file ordinal number part 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// should be "(9998)", so the value is 6. 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst uint32 kMaxFileOrdinalNumberPartLength = 6; 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// If false, we don't prompt the user as to where to save the file. This 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// exists only for testing. 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool g_should_prompt_for_filename = true; 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 9972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Indexes used for specifying which element in the extensions dropdown 10072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// the user chooses when picking a save type. 10172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenconst int kSelectFileHtmlOnlyIndex = 1; 10272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenconst int kSelectFileCompleteIndex = 2; 10372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 10472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Used for mapping between SavePackageType constants and the indexes above. 10572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenconst SavePackage::SavePackageType kIndexToSaveType[] = { 10672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen SavePackage::SAVE_TYPE_UNKNOWN, 10772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen SavePackage::SAVE_AS_ONLY_HTML, 10872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen SavePackage::SAVE_AS_COMPLETE_HTML, 10972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}; 11072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 11172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Used for mapping between the IDS_ string identifiers and the indexes above. 11272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenconst int kIndexToIDS[] = { 11372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 0, IDS_SAVE_PAGE_DESC_HTML_ONLY, IDS_SAVE_PAGE_DESC_COMPLETE, 11472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}; 11572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 11672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenint SavePackageTypeToIndex(SavePackage::SavePackageType type) { 11772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen for (size_t i = 0; i < arraysize(kIndexToSaveType); ++i) { 11872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (kIndexToSaveType[i] == type) 11972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return i; 12072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 12172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen NOTREACHED(); 12272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return -1; 12372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 12472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Strip current ordinal number, if any. Should only be used on pure 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// file names, i.e. those stripped of their extensions. 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TODO(estade): improve this to not choke on alternate encodings. 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochFilePath::StringType StripOrdinalNumber( 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const FilePath::StringType& pure_file_name) { 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType::size_type r_paren_index = 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch pure_file_name.rfind(FILE_PATH_LITERAL(')')); 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType::size_type l_paren_index = 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch pure_file_name.rfind(FILE_PATH_LITERAL('(')); 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (l_paren_index >= r_paren_index) 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return pure_file_name; 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (FilePath::StringType::size_type i = l_paren_index + 1; 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i != r_paren_index; ++i) { 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!IsAsciiDigit(pure_file_name[i])) 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return pure_file_name; 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return pure_file_name.substr(0, l_paren_index); 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Check whether we can save page as complete-HTML for the contents which 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// have specified a MIME type. Now only contents which have the MIME type 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// "text/html" can be saved as complete-HTML. 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool CanSaveAsComplete(const std::string& contents_mime_type) { 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return contents_mime_type == "text/html" || 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch contents_mime_type == "application/xhtml+xml"; 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1563345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickSavePackage::SavePackage(TabContents* tab_contents, 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SavePackageType save_type, 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const FilePath& file_full_path, 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const FilePath& directory_full_path) 160dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen : TabContentsObserver(tab_contents), 161dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen file_manager_(NULL), 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch download_(NULL), 1633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick page_url_(GetUrlToBeSaved()), 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_main_file_path_(file_full_path), 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_main_directory_path_(directory_full_path), 1663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick title_(tab_contents->GetTitle()), 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch finished_(false), 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch user_canceled_(false), 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch disk_error_occurred_(false), 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_type_(save_type), 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch all_save_items_count_(0), 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch wait_state_(INITIALIZE), 1733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick tab_id_(tab_contents->GetRenderProcessHost()->id()), 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch unique_id_(g_save_package_id++), 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { 1763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(page_url_.is_valid()); 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(save_type_ == SAVE_AS_ONLY_HTML || 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_type_ == SAVE_AS_COMPLETE_HTML); 179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!saved_main_file_path_.empty() && 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_main_file_path_.value().length() <= kMaxFilePathLength); 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!saved_main_directory_path_.empty() && 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_main_directory_path_.value().length() < kMaxFilePathLength); 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch InternalInit(); 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSavePackage::SavePackage(TabContents* tab_contents) 187dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen : TabContentsObserver(tab_contents), 188dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen file_manager_(NULL), 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch download_(NULL), 1903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick page_url_(GetUrlToBeSaved()), 1913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick title_(tab_contents->GetTitle()), 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch finished_(false), 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch user_canceled_(false), 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch disk_error_occurred_(false), 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_type_(SAVE_TYPE_UNKNOWN), 196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch all_save_items_count_(0), 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch wait_state_(INITIALIZE), 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_id_(tab_contents->GetRenderProcessHost()->id()), 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch unique_id_(g_save_package_id++), 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { 2013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(page_url_.is_valid()); 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch InternalInit(); 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This is for testing use. Set |finished_| as true because we don't want 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// method Cancel to be be called in destructor in test mode. 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// We also don't call InternalInit(). 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSavePackage::SavePackage(TabContents* tab_contents, 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const FilePath& file_full_path, 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const FilePath& directory_full_path) 211dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen : TabContentsObserver(tab_contents), 212dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen file_manager_(NULL), 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch download_(NULL), 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_main_file_path_(file_full_path), 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_main_directory_path_(directory_full_path), 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch finished_(true), 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch user_canceled_(false), 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch disk_error_occurred_(false), 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_type_(SAVE_TYPE_UNKNOWN), 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch all_save_items_count_(0), 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch wait_state_(INITIALIZE), 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_id_(0), 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch unique_id_(g_save_package_id++), 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSavePackage::~SavePackage() { 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Stop receiving saving job's updates 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!finished_ && !canceled()) { 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Unexpected quit. 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Cancel(true); 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(all_save_items_count_ == (waiting_item_queue_.size() + 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch completed_count() + 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch in_process_count())); 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Free all SaveItems. 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (!waiting_item_queue_.empty()) { 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We still have some items which are waiting for start to save. 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = waiting_item_queue_.front(); 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch waiting_item_queue_.pop(); 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete save_item; 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch STLDeleteValues(&saved_success_items_); 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch STLDeleteValues(&in_progress_items_); 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch STLDeleteValues(&saved_failed_items_); 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 2493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // The DownloadItem is owned by DownloadManager. 2503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick download_ = NULL; 2513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_manager_ = NULL; 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If there's an outstanding save dialog, make sure it doesn't call us back 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // now that we're gone. 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (select_file_dialog_.get()) 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch select_file_dialog_->ListenerDestroyed(); 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Retrieves the URL to be saved from tab_contents_ variable. 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochGURL SavePackage::GetUrlToBeSaved() { 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Instead of using tab_contents_.GetURL here, we use url() 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // (which is the "real" url of the page) 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // from the NavigationEntry because it reflects its' origin 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // rather than the displayed one (returned by GetURL) which may be 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // different (like having "view-source:" on the front). 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NavigationEntry* active_entry = 268dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen tab_contents()->controller().GetActiveEntry(); 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return active_entry->url(); 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Cancel all in progress request, might be called by user or internal error. 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::Cancel(bool user_action) { 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!canceled()) { 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (user_action) 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch user_canceled_ = true; 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch disk_error_occurred_ = true; 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Stop(); 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Init() can be called directly, or indirectly via GetSaveInfo(). In both 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// cases, we need file_manager_ to be initialized, so we do this first. 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::InternalInit() { 286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ResourceDispatcherHost* rdh = g_browser_process->resource_dispatcher_host(); 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!rdh) { 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_manager_ = rdh->save_file_manager(); 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!file_manager_) { 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Initialize the SavePackage. 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SavePackage::Init() { 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Set proper running state. 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (wait_state_ != INITIALIZE) 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch wait_state_ = START_PROCESS; 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Initialize the request context and resource dispatcher. 308dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen Profile* profile = tab_contents()->profile(); 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!profile) { 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch request_context_getter_ = profile->GetRequestContext(); 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 316ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Create the fake DownloadItem and display the view. 317ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DownloadManager* download_manager = 318ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen tab_contents()->profile()->GetDownloadManager(); 319ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen download_ = new DownloadItem(download_manager, 320ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen saved_main_file_path_, 321ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen page_url_, 322ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen profile->IsOffTheRecord()); 323ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 324ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Transfer the ownership to the download manager. We need the DownloadItem 325ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // to be alive as long as the Profile is alive. 326ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen download_manager->SavePageAsDownloadStarted(download_); 3273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 328dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen tab_contents()->OnStartDownload(download_); 329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Check save type and process the save page job. 331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (save_type_ == SAVE_AS_COMPLETE_HTML) { 332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Get directory 333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!saved_main_directory_path_.empty()); 334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetAllSavableResourceLinksForCurrentPage(); 335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch wait_state_ = NET_FILES; 3373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SaveFileCreateInfo::SaveFileSource save_source = page_url_.SchemeIsFile() ? 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveFileCreateInfo::SAVE_FILE_FROM_FILE : 339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveFileCreateInfo::SAVE_FILE_FROM_NET; 340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = new SaveItem(page_url_, 341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL(), 342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this, 343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_source); 344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Add this item to waiting list. 345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch waiting_item_queue_.push(save_item); 346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch all_save_items_count_ = 1; 347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch download_->set_total_bytes(1); 348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DoSavingProcess(); 350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 35572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// On POSIX, the length of |pure_file_name| + |file_name_ext| is further 35672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// restricted by NAME_MAX. The maximum allowed path looks like: 35772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// '/path/to/save_dir' + '/' + NAME_MAX. 35872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenuint32 SavePackage::GetMaxPathLengthForDirectory(const FilePath& base_dir) { 35972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#if defined(OS_POSIX) 36072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return std::min(kMaxFilePathLength, 36172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen static_cast<uint32>(base_dir.value().length()) + 36272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen NAME_MAX + 1); 36372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#else 36472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return kMaxFilePathLength; 36572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#endif 36672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 36772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 36872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// File name is considered being consist of pure file name, dot and file 36972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// extension name. File name might has no dot and file extension, or has 37072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// multiple dot inside file name. The dot, which separates the pure file 37172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// name and file extension name, is last dot in the whole file name. 37272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// This function is for making sure the length of specified file path is not 37372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// great than the specified maximum length of file path and getting safe pure 37472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// file name part if the input pure file name is too long. 37572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// The parameter |dir_path| specifies directory part of the specified 37672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// file path. The parameter |file_name_ext| specifies file extension 37772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// name part of the specified file path (including start dot). The parameter 37872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// |max_file_path_len| specifies maximum length of the specified file path. 37972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// The parameter |pure_file_name| input pure file name part of the specified 38072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// file path. If the length of specified file path is great than 38172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// |max_file_path_len|, the |pure_file_name| will output new pure file name 38272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// part for making sure the length of specified file path is less than 38372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// specified maximum length of file path. Return false if the function can 38472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// not get a safe pure file name, otherwise it returns true. 38572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool SavePackage::GetSafePureFileName(const FilePath& dir_path, 38672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const FilePath::StringType& file_name_ext, 38772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen uint32 max_file_path_len, 38872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen FilePath::StringType* pure_file_name) { 38972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen DCHECK(!pure_file_name->empty()); 39072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen int available_length = static_cast<int>(max_file_path_len - 39172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen dir_path.value().length() - 39272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen file_name_ext.length()); 39372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Need an extra space for the separator. 39472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!file_util::EndsWithSeparator(dir_path)) 39572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen --available_length; 39672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 39772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Plenty of room. 39872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (static_cast<int>(pure_file_name->length()) <= available_length) 39972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return true; 40072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 40172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Limited room. Truncate |pure_file_name| to fit. 40272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (available_length > 0) { 40372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen *pure_file_name = pure_file_name->substr(0, available_length); 40472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return true; 40572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 40672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 40772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Not enough room to even use a shortened |pure_file_name|. 40872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen pure_file_name->clear(); 40972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return false; 41072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 41172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Generate name for saving resource. 413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SavePackage::GenerateFileName(const std::string& disposition, 414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const GURL& url, 415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool need_html_ext, 416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType* generated_name) { 417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(jungshik): Figure out the referrer charset when having one 418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // makes sense and pass it to GetSuggestedFilename. 41972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen string16 suggested_name = 42072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen net::GetSuggestedFilename(url, disposition, "", 42172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ASCIIToUTF16(kDefaultSaveName)); 42272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 42372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // TODO(evan): this code is totally wrong -- we should just generate 42472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Unicode filenames and do all this encoding switching at the end. 42572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // However, I'm just shuffling wrong code around, at least not adding 42672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // to it. 42772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#if defined(OS_WIN) 42872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen FilePath file_path = FilePath(suggested_name); 42972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#else 43072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen FilePath file_path = FilePath( 43172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::SysWideToNativeMB(UTF16ToWide(suggested_name))); 43272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#endif 433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!file_path.empty()); 435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType pure_file_name = 436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_path.RemoveExtension().BaseName().value(); 437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType file_name_ext = file_path.Extension(); 438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If it is HTML resource, use ".htm{l,}" as its extension. 440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (need_html_ext) { 441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_name_ext = FILE_PATH_LITERAL("."); 442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_name_ext.append(kDefaultHtmlExtension); 443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 44572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Need to make sure the suggested file name is not too long. 44672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen uint32 max_path = GetMaxPathLengthForDirectory(saved_main_directory_path_); 44772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Get safe pure file name. 449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!GetSafePureFileName(saved_main_directory_path_, file_name_ext, 45072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen max_path, &pure_file_name)) 451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType file_name = pure_file_name + file_name_ext; 454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Check whether we already have same name. 456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (file_name_set_.find(file_name) == file_name_set_.end()) { 457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_name_set_.insert(file_name); 458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Found same name, increase the ordinal number for the file name. 460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType base_file_name = StripOrdinalNumber(pure_file_name); 461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We need to make sure the length of base file name plus maximum ordinal 463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // number path will be less than or equal to kMaxFilePathLength. 464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!GetSafePureFileName(saved_main_directory_path_, file_name_ext, 46572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen max_path - kMaxFileOrdinalNumberPartLength, &base_file_name)) 466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Prepare the new ordinal number. 469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch uint32 ordinal_number; 470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FileNameCountMap::iterator it = file_name_count_map_.find(base_file_name); 471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (it == file_name_count_map_.end()) { 472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // First base-name-conflict resolving, use 1 as initial ordinal number. 473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_name_count_map_[base_file_name] = 1; 474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ordinal_number = 1; 475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We have met same base-name conflict, use latest ordinal number. 477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ordinal_number = it->second; 478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (ordinal_number > (kMaxFileOrdinalNumber - 1)) { 481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Use a random file from temporary file. 482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath temp_file; 483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_util::CreateTemporaryFile(&temp_file); 484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_name = temp_file.RemoveExtension().BaseName().value(); 485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Get safe pure file name. 486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!GetSafePureFileName(saved_main_directory_path_, 487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType(), 48872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen max_path, &file_name)) 489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = ordinal_number; i < kMaxFileOrdinalNumber; ++i) { 492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType new_name = base_file_name + 493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StringPrintf(FILE_PATH_LITERAL("(%d)"), i) + file_name_ext; 494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (file_name_set_.find(new_name) == file_name_set_.end()) { 495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Resolved name conflict. 496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_name = new_name; 497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_name_count_map_[base_file_name] = ++i; 498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_name_set_.insert(file_name); 504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!file_name.empty()); 507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch generated_name->assign(file_name); 508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// We have received a message from SaveFileManager about a new saving job. We 513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// create a SaveItem and store it in our in_progress list. 514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::StartSave(const SaveFileCreateInfo* info) { 515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(info && !info->url.is_empty()); 516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveUrlItemMap::iterator it = in_progress_items_.find(info->url.spec()); 518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (it == in_progress_items_.end()) { 519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If not found, we must have cancel action. 520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(canceled()); 521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = it->second; 524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!saved_main_file_path_.empty()); 526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->SetSaveId(info->save_id); 528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->SetTotalBytes(info->total_bytes); 529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Determine the proper path for a saving job, by choosing either the default 531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // save directory, or prompting the user. 532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!save_item->has_final_name()); 533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (info->url != page_url_) { 534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType generated_name; 535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // For HTML resource file, make sure it will have .htm as extension name, 536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // otherwise, when you open the saved page in Chrome again, download 537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // file manager will treat it as downloadable resource, and download it 538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // instead of opening it as HTML. 539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool need_html_ext = 540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_DOM; 541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!GenerateFileName(info->content_disposition, 542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL(info->url), 543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch need_html_ext, 544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &generated_name)) { 545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We can not generate file name for this SaveItem, so we cancel the 546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // saving page job if the save source is from serialized DOM data. 547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Otherwise, it means this SaveItem is sub-resource type, we treat it 548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // as an error happened on saving. We can ignore this type error for 549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // sub-resource links which will be resolved as absolute links instead 550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // of local links in final saved contents. 551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_DOM) 552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Cancel(true); 553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveFinished(save_item->save_id(), 0, false); 555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // When saving page as only-HTML, we only have a SaveItem whose url 559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // must be page_url_. 560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(save_type_ == SAVE_AS_COMPLETE_HTML); 561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!saved_main_directory_path_.empty()); 562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Now we get final name retrieved from GenerateFileName, we will use it 564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // rename the SaveItem. 565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath final_name = saved_main_directory_path_.Append(generated_name); 566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->Rename(final_name); 567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // It is the main HTML file, use the name chosen by the user. 569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->Rename(saved_main_file_path_); 570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the save source is from file system, inform SaveFileManager to copy 573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // corresponding file to the file path which this SaveItem specifies. 574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_FILE) { 575731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 576731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(file_manager_, 578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &SaveFileManager::SaveLocalFile, 579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->url(), 580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->save_id(), 581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_id())); 582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Check whether we begin to require serialized HTML data. 586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (save_type_ == SAVE_AS_COMPLETE_HTML && wait_state_ == HTML_DATA) { 587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Inform backend to serialize the all frames' DOM and send serialized 588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // HTML data back. 589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetSerializedHtmlDataForCurrentPageWithLocalLinks(); 590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Look up SaveItem by save id from in progress map. 594c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSaveItem* SavePackage::LookupItemInProcessBySaveId(int32 save_id) { 595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (in_process_count()) { 596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (SaveUrlItemMap::iterator it = in_progress_items_.begin(); 597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch it != in_progress_items_.end(); ++it) { 598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = it->second; 599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(save_item->state() == SaveItem::IN_PROGRESS); 600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (save_item->save_id() == save_id) 601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return save_item; 602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return NULL; 605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Remove SaveItem from in progress map and put it to saved map. 608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::PutInProgressItemToSavedMap(SaveItem* save_item) { 609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveUrlItemMap::iterator it = in_progress_items_.find( 610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->url().spec()); 611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(it != in_progress_items_.end()); 612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(save_item == it->second); 613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch in_progress_items_.erase(it); 614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (save_item->success()) { 616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Add it to saved_success_items_. 617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(saved_success_items_.find(save_item->save_id()) == 618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_success_items_.end()); 619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_success_items_[save_item->save_id()] = save_item; 620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Add it to saved_failed_items_. 622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(saved_failed_items_.find(save_item->url().spec()) == 623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_failed_items_.end()); 624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_failed_items_[save_item->url().spec()] = save_item; 625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Called for updating saving state. 629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SavePackage::UpdateSaveProgress(int32 save_id, 630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int64 size, 631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool write_success) { 632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Because we might have canceled this saving job before, 633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // so we might not find corresponding SaveItem. 634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = LookupItemInProcessBySaveId(save_id); 635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!save_item) 636c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->Update(size); 639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If we got disk error, cancel whole save page job. 641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!write_success) { 642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Cancel job with reason of disk error. 643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Cancel(false); 644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 648c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Stop all page saving jobs that are in progress and instruct the file thread 649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// to delete all saved files. 650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::Stop() { 651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If we haven't moved out of the initial state, there's nothing to cancel and 652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // there won't be valid pointers for file_manager_ or download_. 653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (wait_state_ == INITIALIZE) 654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // When stopping, if it still has some items in in_progress, cancel them. 657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(canceled()); 658c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (in_process_count()) { 659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveUrlItemMap::iterator it = in_progress_items_.begin(); 660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (; it != in_progress_items_.end(); ++it) { 661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = it->second; 662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(save_item->state() == SaveItem::IN_PROGRESS); 663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->Cancel(); 664c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Remove all in progress item to saved map. For failed items, they will 666c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // be put into saved_failed_items_, for successful item, they will be put 667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // into saved_success_items_. 668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (in_process_count()) 669c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PutInProgressItemToSavedMap(in_progress_items_.begin()->second); 670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 671c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 672c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This vector contains the save ids of the save files which SaveFileManager 673c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // needs to remove from its save_file_map_. 674c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveIDList save_ids; 675c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (SavedItemMap::iterator it = saved_success_items_.begin(); 676c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch it != saved_success_items_.end(); ++it) 677c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_ids.push_back(it->first); 678c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (SaveUrlItemMap::iterator it = saved_failed_items_.begin(); 679c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch it != saved_failed_items_.end(); ++it) 680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_ids.push_back(it->second->save_id()); 681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 682731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 683731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 684c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(file_manager_, 685c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &SaveFileManager::RemoveSavedFileFromFileMap, 686c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_ids)); 687c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 688c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch finished_ = true; 689c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch wait_state_ = FAILED; 690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Inform the DownloadItem we have canceled whole save page job. 692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch download_->Cancel(false); 693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::CheckFinish() { 696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (in_process_count() || finished_) 697c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath dir = (save_type_ == SAVE_AS_COMPLETE_HTML && 700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_success_items_.size() > 1) ? 701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_main_directory_path_ : FilePath(); 702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This vector contains the final names of all the successfully saved files 704c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // along with their save ids. It will be passed to SaveFileManager to do the 705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // renaming job. 706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FinalNameList final_names; 707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (SavedItemMap::iterator it = saved_success_items_.begin(); 708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch it != saved_success_items_.end(); ++it) 709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch final_names.push_back(std::make_pair(it->first, 710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch it->second->full_path())); 711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 712731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 713731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 714c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(file_manager_, 715c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &SaveFileManager::RenameAllFiles, 716c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch final_names, 717c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch dir, 718dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen tab_contents()->GetRenderProcessHost()->id(), 719dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen tab_contents()->render_view_host()->routing_id(), 720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch id())); 721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 722c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Successfully finished all items of this SavePackage. 724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::Finish() { 725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // User may cancel the job when we're moving files to the final directory. 726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (canceled()) 727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch wait_state_ = SUCCESSFUL; 730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch finished_ = true; 731c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 732c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This vector contains the save ids of the save files which SaveFileManager 733c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // needs to remove from its save_file_map_. 734c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveIDList save_ids; 735c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (SaveUrlItemMap::iterator it = saved_failed_items_.begin(); 736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch it != saved_failed_items_.end(); ++it) 737c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_ids.push_back(it->second->save_id()); 738c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 739731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 740731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 741c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(file_manager_, 742c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &SaveFileManager::RemoveSavedFileFromFileMap, 743c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_ids)); 744c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick download_->OnAllDataSaved(all_save_items_count_); 74672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen download_->MarkAsComplete(); 747dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationService::current()->Notify( 749c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationType::SAVE_PACKAGE_SUCCESSFULLY_FINISHED, 750c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Source<SavePackage>(this), 751c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Details<GURL>(&page_url_)); 752c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 753c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 754c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Called for updating end state. 755c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::SaveFinished(int32 save_id, int64 size, bool is_success) { 756c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Because we might have canceled this saving job before, 757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // so we might not find corresponding SaveItem. Just ignore it. 758c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = LookupItemInProcessBySaveId(save_id); 759c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!save_item) 760c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 762c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Let SaveItem set end state. 763c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->Finish(size, is_success); 764c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Remove the associated save id and SavePackage. 765c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_manager_->RemoveSaveFile(save_id, save_item->url(), this); 766c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 767c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PutInProgressItemToSavedMap(save_item); 768c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 769c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Inform the DownloadItem to update UI. 770c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We use the received bytes as number of saved files. 771c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch download_->Update(completed_count()); 772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM && 774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->url() == page_url_ && !save_item->received_bytes()) { 775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If size of main HTML page is 0, treat it as disk error. 776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Cancel(false); 777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 779c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 780c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (canceled()) { 781c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(finished_); 782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 784c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 785c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Continue processing the save page job. 786c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DoSavingProcess(); 787c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 788c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Check whether we can successfully finish whole job. 789c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CheckFinish(); 790c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 791c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 792c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Sometimes, the net io will only call SaveFileManager::SaveFinished with 793c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// save id -1 when it encounters error. Since in this case, save id will be 794c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// -1, so we can only use URL to find which SaveItem is associated with 795c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// this error. 796c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Saving an item failed. If it's a sub-resource, ignore it. If the error comes 797c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// from serializing HTML data, then cancel saving page. 798c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::SaveFailed(const GURL& save_url) { 799c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveUrlItemMap::iterator it = in_progress_items_.find(save_url.spec()); 800c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (it == in_progress_items_.end()) { 801c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); // Should not exist! 802c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = it->second; 805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->Finish(0, false); 807c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PutInProgressItemToSavedMap(save_item); 809c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 810c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Inform the DownloadItem to update UI. 811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We use the received bytes as number of saved files. 812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch download_->Update(completed_count()); 813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (save_type_ == SAVE_AS_ONLY_HTML || 815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM) { 816c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We got error when saving page. Treat it as disk error. 817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Cancel(true); 818c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (canceled()) { 821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(finished_); 822c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 823c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 824c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 825c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Continue processing the save page job. 826c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DoSavingProcess(); 827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CheckFinish(); 829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 830c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 831c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::SaveCanceled(SaveItem* save_item) { 832c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Call the RemoveSaveFile in UI thread. 833c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_manager_->RemoveSaveFile(save_item->save_id(), 834c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->url(), 835c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this); 836c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (save_item->save_id() != -1) 837731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 838731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 839c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(file_manager_, 840c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &SaveFileManager::CancelSave, 841c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->save_id())); 842c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 843c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 844c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Initiate a saving job of a specific URL. We send the request to 845c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// SaveFileManager, which will dispatch it to different approach according to 846c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// the save source. Parameter process_all_remaining_items indicates whether 847c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// we need to save all remaining items. 848c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::SaveNextFile(bool process_all_remaining_items) { 849dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen DCHECK(tab_contents()); 850c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(waiting_item_queue_.size()); 851c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 852c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch do { 853c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Pop SaveItem from waiting list. 854c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = waiting_item_queue_.front(); 855c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch waiting_item_queue_.pop(); 856c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 857c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Add the item to in_progress_items_. 858c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveUrlItemMap::iterator it = in_progress_items_.find( 859c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->url().spec()); 860c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(it == in_progress_items_.end()); 861c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch in_progress_items_[save_item->url().spec()] = save_item; 862c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->Start(); 863c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_manager_->SaveURL(save_item->url(), 864c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->referrer(), 865dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen tab_contents()->GetRenderProcessHost()->id(), 866dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen routing_id(), 867c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->save_source(), 868c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->full_path(), 869c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch request_context_getter_.get(), 870c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this); 871c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } while (process_all_remaining_items && waiting_item_queue_.size()); 872c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 873c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 874c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 875c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Open download page in windows explorer on file thread, to avoid blocking the 876c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// user interface. 877c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::ShowDownloadInShell() { 878c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(file_manager_); 879c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(finished_ && !canceled() && !saved_main_file_path_.empty()); 880731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 881c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_MACOSX) 882c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Mac OS X requires opening downloads on the UI thread. 883c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch platform_util::ShowItemInFolder(saved_main_file_path_); 884c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else 885731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 886731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 887c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(file_manager_, 888c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &SaveFileManager::OnShowSavedFileInShell, 889c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_main_file_path_)); 890c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 891c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 892c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 893c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Calculate the percentage of whole save page job. 894c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint SavePackage::PercentComplete() { 895c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!all_save_items_count_) 896c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 0; 897c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else if (!in_process_count()) 898c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 100; 899c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 900c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return completed_count() / all_save_items_count_; 901c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 902c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 903c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Continue processing the save page job after one SaveItem has been 904c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// finished. 905c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::DoSavingProcess() { 906c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (save_type_ == SAVE_AS_COMPLETE_HTML) { 907c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We guarantee that images and JavaScripts must be downloaded first. 908c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // So when finishing all those sub-resources, we will know which 909c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // sub-resource's link can be replaced with local file path, which 910c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // sub-resource's link need to be replaced with absolute URL which 911c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // point to its internet address because it got error when saving its data. 912c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = NULL; 913c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Start a new SaveItem job if we still have job in waiting queue. 914c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (waiting_item_queue_.size()) { 915c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(wait_state_ == NET_FILES); 916c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item = waiting_item_queue_.front(); 917c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (save_item->save_source() != SaveFileCreateInfo::SAVE_FILE_FROM_DOM) { 918c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveNextFile(false); 919c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (!in_process_count()) { 920c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If there is no in-process SaveItem, it means all sub-resources 921c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // have been processed. Now we need to start serializing HTML DOM 922c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // for the current page to get the generated HTML data. 923c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch wait_state_ = HTML_DATA; 924c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // All non-HTML resources have been finished, start all remaining 925c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // HTML files. 926c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveNextFile(true); 927c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 928c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (in_process_count()) { 929c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Continue asking for HTML data. 930c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(wait_state_ == HTML_DATA); 931c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 932c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 933c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Save as HTML only. 934c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(wait_state_ == NET_FILES); 935c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(save_type_ == SAVE_AS_ONLY_HTML); 936c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (waiting_item_queue_.size()) { 937c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(all_save_items_count_ == waiting_item_queue_.size()); 938c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveNextFile(false); 939c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 940c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 941c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 942c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 94372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool SavePackage::OnMessageReceived(const IPC::Message& message) { 94472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen bool handled = true; 94572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen IPC_BEGIN_MESSAGE_MAP(SavePackage, message) 94672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen IPC_MESSAGE_HANDLER(ViewHostMsg_SendCurrentPageAllSavableResourceLinks, 94772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen OnReceivedSavableResourceLinksForCurrentPage) 94872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen IPC_MESSAGE_HANDLER(ViewHostMsg_SendSerializedHtmlData, 94972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen OnReceivedSerializedHtmlData) 95072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen IPC_MESSAGE_UNHANDLED(handled = false) 95172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen IPC_END_MESSAGE_MAP() 95272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return handled; 95372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 95472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 955c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// After finishing all SaveItems which need to get data from net. 956c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// We collect all URLs which have local storage and send the 957c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// map:(originalURL:currentLocalPath) to render process (backend). 958c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Then render process will serialize DOM and send data to us. 959c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::GetSerializedHtmlDataForCurrentPageWithLocalLinks() { 960c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (wait_state_ != HTML_DATA) 961c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 962c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<GURL> saved_links; 963c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<FilePath> saved_file_paths; 964c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int successful_started_items_count = 0; 965c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 966c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Collect all saved items which have local storage. 967c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // First collect the status of all the resource files and check whether they 968c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // have created local files although they have not been completely saved. 969c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If yes, the file can be saved. Otherwise, there is a disk error, so we 970c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // need to cancel the page saving job. 971c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (SaveUrlItemMap::iterator it = in_progress_items_.begin(); 972c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch it != in_progress_items_.end(); ++it) { 973c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(it->second->save_source() == 974c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveFileCreateInfo::SAVE_FILE_FROM_DOM); 975c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (it->second->has_final_name()) 976c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch successful_started_items_count++; 977c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_links.push_back(it->second->url()); 978c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_file_paths.push_back(it->second->file_name()); 979c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 980c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 981c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If not all file of HTML resource have been started, then wait. 982c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (successful_started_items_count != in_process_count()) 983c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 984c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 985c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Collect all saved success items. 986c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (SavedItemMap::iterator it = saved_success_items_.begin(); 987c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch it != saved_success_items_.end(); ++it) { 988c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(it->second->has_final_name()); 989c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_links.push_back(it->second->url()); 990c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_file_paths.push_back(it->second->file_name()); 991c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 992c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 993c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Get the relative directory name. 994c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath relative_dir_name = saved_main_directory_path_.BaseName(); 995c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 996dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen tab_contents()->render_view_host()-> 997c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetSerializedHtmlDataForCurrentPageWithLocalLinks( 998c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch saved_links, saved_file_paths, relative_dir_name); 999c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1000c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1001c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Process the serialized HTML content data of a specified web page 1002c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// retrieved from render process. 1003c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::OnReceivedSerializedHtmlData(const GURL& frame_url, 1004c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string& data, 1005c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int32 status) { 1006c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WebPageSerializerClient::PageSerializationStatus flag = 1007c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<WebPageSerializerClient::PageSerializationStatus>(status); 1008c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Check current state. 1009c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (wait_state_ != HTML_DATA) 1010c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 1011c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1012c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int id = tab_id(); 1013c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the all frames are finished saving, we need to close the 1014c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // remaining SaveItems. 1015c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (flag == WebPageSerializerClient::AllFramesAreFinished) { 1016c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (SaveUrlItemMap::iterator it = in_progress_items_.begin(); 1017c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch it != in_progress_items_.end(); ++it) { 1018ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen VLOG(20) << " " << __FUNCTION__ << "()" 1019ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen << " save_id = " << it->second->save_id() 1020ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen << " url = \"" << it->second->url().spec() << "\""; 1021731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 1022731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 1023c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(file_manager_, 1024c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &SaveFileManager::SaveFinished, 1025c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch it->second->save_id(), 1026c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch it->second->url(), 1027c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch id, 1028c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch true)); 1029c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1030c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 1031c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1032c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1033c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveUrlItemMap::iterator it = in_progress_items_.find(frame_url.spec()); 1034c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (it == in_progress_items_.end()) 1035c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 1036c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = it->second; 1037c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM); 1038c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1039c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!data.empty()) { 1040c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Prepare buffer for saving HTML data. 1041513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch scoped_refptr<net::IOBuffer> new_data(new net::IOBuffer(data.size())); 1042c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch memcpy(new_data->data(), data.data(), data.size()); 1043c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1044c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Call write file functionality in file thread. 1045731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 1046731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 1047c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(file_manager_, 1048c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &SaveFileManager::UpdateSaveProgress, 1049c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->save_id(), 1050c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_data, 1051c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<int>(data.size()))); 1052c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1053c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1054c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Current frame is completed saving, call finish in file thread. 1055c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (flag == WebPageSerializerClient::CurrentFrameIsFinished) { 1056ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen VLOG(20) << " " << __FUNCTION__ << "()" 1057ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen << " save_id = " << save_item->save_id() 1058ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen << " url = \"" << save_item->url().spec() << "\""; 1059731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 1060731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 1061c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(file_manager_, 1062c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &SaveFileManager::SaveFinished, 1063c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->save_id(), 1064c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_item->url(), 1065c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch id, 1066c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch true)); 1067c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1068c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1069c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1070c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Ask for all savable resource links from backend, include main frame and 1071c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// sub-frame. 1072c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::GetAllSavableResourceLinksForCurrentPage() { 1073c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (wait_state_ != START_PROCESS) 1074c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 1075c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1076c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch wait_state_ = RESOURCES_LIST; 1077dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen tab_contents()->render_view_host()-> 10783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick GetAllSavableResourceLinksForCurrentPage(page_url_); 1079c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1080c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1081c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Give backend the lists which contain all resource links that have local 1082c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// storage, after which, render process will serialize DOM for generating 1083c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// HTML data. 1084c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::OnReceivedSavableResourceLinksForCurrentPage( 1085c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::vector<GURL>& resources_list, 1086c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::vector<GURL>& referrers_list, 1087c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::vector<GURL>& frames_list) { 1088c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (wait_state_ != RESOURCES_LIST) 1089c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 1090c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1091c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(resources_list.size() == referrers_list.size()); 1092c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch all_save_items_count_ = static_cast<int>(resources_list.size()) + 1093c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<int>(frames_list.size()); 1094c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1095c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We use total bytes as the total number of files we want to save. 1096c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch download_->set_total_bytes(all_save_items_count_); 1097c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1098c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (all_save_items_count_) { 1099c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Put all sub-resources to wait list. 1100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = 0; i < static_cast<int>(resources_list.size()); ++i) { 1101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const GURL& u = resources_list[i]; 1102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(u.is_valid()); 1103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveFileCreateInfo::SaveFileSource save_source = u.SchemeIsFile() ? 1104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveFileCreateInfo::SAVE_FILE_FROM_FILE : 1105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveFileCreateInfo::SAVE_FILE_FROM_NET; 1106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = new SaveItem(u, referrers_list[i], 1107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this, save_source); 1108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch waiting_item_queue_.push(save_item); 1109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Put all HTML resources to wait list. 1111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = 0; i < static_cast<int>(frames_list.size()); ++i) { 1112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const GURL& u = frames_list[i]; 1113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(u.is_valid()); 1114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SaveItem* save_item = new SaveItem(u, GURL(), 1115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this, SaveFileCreateInfo::SAVE_FILE_FROM_DOM); 1116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch waiting_item_queue_.push(save_item); 1117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch wait_state_ = NET_FILES; 1119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DoSavingProcess(); 1120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 1121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // No resource files need to be saved, treat it as user cancel. 1122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Cancel(true); 1123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::SetShouldPromptUser(bool should_prompt) { 1127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch g_should_prompt_for_filename = should_prompt; 1128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 11303345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickFilePath SavePackage::GetSuggestedNameForSaveAs( 1131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool can_save_as_complete, 1132513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch const std::string& contents_mime_type) { 11333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick FilePath name_with_proper_ext = 11343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick FilePath::FromWStringHack(UTF16ToWideHack(title_)); 11353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 11363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // If the page's title matches its URL, use the URL. Try to use the last path 11373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // component or if there is none, the domain as the file name. 11383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Normally we want to base the filename on the page title, or if it doesn't 11393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // exist, on the URL. It's not easy to tell if the page has no title, because 11403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // if the page has no title, TabContents::GetTitle() will return the page's 11413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // URL (adjusted for display purposes). Therefore, we convert the "title" 11423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // back to a URL, and if it matches the original page URL, we know the page 11433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // had no title (or had a title equal to its URL, which is fine to treat 11443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // similarly). 11453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick GURL fixed_up_title_url = 11463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick URLFixerUpper::FixupURL(UTF16ToUTF8(title_), std::string()); 11473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 11483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (page_url_ == fixed_up_title_url) { 1149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string url_path; 1150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<std::string> url_parts; 1151731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick base::SplitString(page_url_.path(), '/', &url_parts); 1152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!url_parts.empty()) { 1153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = static_cast<int>(url_parts.size()) - 1; i >= 0; --i) { 1154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url_path = url_parts[i]; 1155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!url_path.empty()) 1156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 1157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (url_path.empty()) 11603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick url_path = page_url_.host(); 1161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch name_with_proper_ext = FilePath::FromWStringHack(UTF8ToWide(url_path)); 1162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Ask user for getting final saving name. 1165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch name_with_proper_ext = EnsureMimeExtension(name_with_proper_ext, 1166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch contents_mime_type); 1167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Adjust extension for complete types. 1168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (can_save_as_complete) 1169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch name_with_proper_ext = EnsureHtmlExtension(name_with_proper_ext); 1170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType file_name = name_with_proper_ext.value(); 1172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_util::ReplaceIllegalCharactersInPath(&file_name, ' '); 1173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return FilePath(file_name); 1174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1176c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochFilePath SavePackage::EnsureHtmlExtension(const FilePath& name) { 1177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the file name doesn't have an extension suitable for HTML files, 1178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // append one. 1179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType ext = name.Extension(); 1180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!ext.empty()) 1181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ext.erase(ext.begin()); // Erase preceding '.'. 1182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string mime_type; 1183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!net::GetMimeTypeFromExtension(ext, &mime_type) || 1184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch !CanSaveAsComplete(mime_type)) { 1185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return FilePath(name.value() + FILE_PATH_LITERAL(".") + 1186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kDefaultHtmlExtension); 1187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return name; 1189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1191c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochFilePath SavePackage::EnsureMimeExtension(const FilePath& name, 1192513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch const std::string& contents_mime_type) { 1193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Start extension at 1 to skip over period if non-empty. 1194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType ext = name.Extension().length() ? 1195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch name.Extension().substr(1) : name.Extension(); 1196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType suggested_extension = 1197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ExtensionForMimeType(contents_mime_type); 1198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string mime_type; 1199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!suggested_extension.empty() && 1200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (!net::GetMimeTypeFromExtension(ext, &mime_type) || 1201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch !IsSavableContents(mime_type))) { 1202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Extension is absent or needs to be updated. 1203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return FilePath(name.value() + FILE_PATH_LITERAL(".") + 1204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch suggested_extension); 1205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return name; 1207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1209513209b27ff55e2841eac0e4120199c23acce758Ben Murdochconst FilePath::CharType* SavePackage::ExtensionForMimeType( 1210513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch const std::string& contents_mime_type) { 1211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static const struct { 1212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const FilePath::CharType *mime_type; 1213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const FilePath::CharType *suggested_extension; 1214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } extensions[] = { 1215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch { FILE_PATH_LITERAL("text/html"), kDefaultHtmlExtension }, 1216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch { FILE_PATH_LITERAL("text/xml"), FILE_PATH_LITERAL("xml") }, 1217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch { FILE_PATH_LITERAL("application/xhtml+xml"), FILE_PATH_LITERAL("xhtml") }, 1218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch { FILE_PATH_LITERAL("text/plain"), FILE_PATH_LITERAL("txt") }, 1219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch { FILE_PATH_LITERAL("text/css"), FILE_PATH_LITERAL("css") }, 1220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }; 1221513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#if defined(OS_POSIX) 1222513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch FilePath::StringType mime_type(contents_mime_type); 1223513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#elif defined(OS_WIN) 1224513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch FilePath::StringType mime_type(UTF8ToWide(contents_mime_type)); 1225513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#endif // OS_WIN 1226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (uint32 i = 0; i < ARRAYSIZE_UNSAFE(extensions); ++i) { 1227513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (mime_type == extensions[i].mime_type) 1228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return extensions[i].suggested_extension; 1229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return FILE_PATH_LITERAL(""); 1231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static. 1236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Check whether the preference has the preferred directory for saving file. If 1237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// not, initialize it with default directory. 1238c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochFilePath SavePackage::GetSaveDirPreference(PrefService* prefs) { 1239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(prefs); 1240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!prefs->FindPreference(prefs::kSaveFileDefaultDirectory)) { 1242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(prefs->FindPreference(prefs::kDownloadDefaultDirectory)); 1243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath default_save_path = prefs->GetFilePath( 1244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs::kDownloadDefaultDirectory); 1245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs->RegisterFilePathPref(prefs::kSaveFileDefaultDirectory, 1246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default_save_path); 1247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Get the directory from preference. 1250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath save_file_path = prefs->GetFilePath( 1251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs::kSaveFileDefaultDirectory); 1252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!save_file_path.empty()); 1253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return save_file_path; 1255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::GetSaveInfo() { 1258513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // Can't use tab_contents_ in the file thread, so get the data that we need 1259513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // before calling to it. 1260dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen PrefService* prefs = tab_contents()->profile()->GetPrefs(); 1261731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick FilePath website_save_dir = GetSaveDirPreference(prefs); 1262731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick FilePath download_save_dir = prefs->GetFilePath( 1263731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick prefs::kDownloadDefaultDirectory); 1264dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen std::string mime_type = tab_contents()->contents_mime_type(); 1265731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 1266731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 1267731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 1268513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch NewRunnableMethod(this, &SavePackage::CreateDirectoryOnFileThread, 1269513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch website_save_dir, download_save_dir, mime_type)); 1270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1272513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid SavePackage::CreateDirectoryOnFileThread( 1273513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch const FilePath& website_save_dir, 1274513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch const FilePath& download_save_dir, 1275513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch const std::string& mime_type) { 1276513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch FilePath save_dir; 1277513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // If the default html/websites save folder doesn't exist... 1278513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (!file_util::DirectoryExists(website_save_dir)) { 1279513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // If the default download dir doesn't exist, create it. 1280513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (!file_util::DirectoryExists(download_save_dir)) 1281513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch file_util::CreateDirectory(download_save_dir); 1282513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch save_dir = download_save_dir; 1283513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch } else { 1284513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // If it does exist, use the default save dir param. 1285513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch save_dir = website_save_dir; 1286513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch } 1287513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 1288513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch bool can_save_as_complete = CanSaveAsComplete(mime_type); 1289201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch FilePath suggested_filename = GetSuggestedNameForSaveAs(can_save_as_complete, 1290201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch mime_type); 1291201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch FilePath::StringType pure_file_name = 1292201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch suggested_filename.RemoveExtension().BaseName().value(); 1293201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch FilePath::StringType file_name_ext = suggested_filename.Extension(); 1294201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch 1295201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch // Need to make sure the suggested file name is not too long. 129672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen uint32 max_path = GetMaxPathLengthForDirectory(save_dir); 129772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 1298201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch if (GetSafePureFileName(save_dir, file_name_ext, max_path, &pure_file_name)) { 1299201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch save_dir = save_dir.Append(pure_file_name + file_name_ext); 1300201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch } else { 1301201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch // Cannot create a shorter filename. This will cause the save as operation 1302201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch // to fail unless the user pick a shorter name. Continuing even though it 1303201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch // will fail because returning means no save as popup for the user, which 1304201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch // is even more confusing. This case should be rare though. 1305201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch save_dir = save_dir.Append(suggested_filename); 1306201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch } 1307201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch 1308513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch BrowserThread::PostTask( 1309513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch BrowserThread::UI, FROM_HERE, 1310201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch NewRunnableMethod(this, &SavePackage::ContinueGetSaveInfo, save_dir, 1311201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch can_save_as_complete)); 1312513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} 1313513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 1314513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid SavePackage::ContinueGetSaveInfo(const FilePath& suggested_path, 1315513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch bool can_save_as_complete) { 1316ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // The TabContents which owns this SavePackage may have disappeared during 1317ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // the UI->FILE->UI thread hop of 1318ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // GetSaveInfo->CreateDirectoryOnFileThread->ContinueGetSaveInfo. 1319ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!tab_contents()) 1320ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return; 132172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen DownloadPrefs* download_prefs = 1322dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen tab_contents()->profile()->GetDownloadManager()->download_prefs(); 132372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen int file_type_index = 132472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen SavePackageTypeToIndex( 132572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen static_cast<SavePackageType>(download_prefs->save_file_type())); 132672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 1327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SelectFileDialog::FileTypeInfo file_type_info; 1328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType default_extension; 1329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the contents can not be saved as complete-HTML, do not show the 1331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // file filters. 1332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (can_save_as_complete) { 1333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool add_extra_extension = false; 1334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath::StringType extra_extension; 1335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!suggested_path.Extension().empty() && 1336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch suggested_path.Extension().compare(FILE_PATH_LITERAL("htm")) && 1337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch suggested_path.Extension().compare(FILE_PATH_LITERAL("html"))) { 1338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch add_extra_extension = true; 1339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extra_extension = suggested_path.Extension().substr(1); 1340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 134172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 1342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_type_info.extensions.resize(2); 134372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen file_type_info.extensions[kSelectFileHtmlOnlyIndex - 1].push_back( 134472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen FILE_PATH_LITERAL("htm")); 134572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen file_type_info.extensions[kSelectFileHtmlOnlyIndex - 1].push_back( 134672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen FILE_PATH_LITERAL("html")); 134772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 134872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (add_extra_extension) { 134972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen file_type_info.extensions[kSelectFileHtmlOnlyIndex - 1].push_back( 135072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen extra_extension); 135172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 135272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 1353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_type_info.extension_description_overrides.push_back( 135472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen l10n_util::GetStringUTF16(kIndexToIDS[kSelectFileCompleteIndex - 1])); 135572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen file_type_info.extensions[kSelectFileCompleteIndex - 1].push_back( 135672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen FILE_PATH_LITERAL("htm")); 135772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen file_type_info.extensions[kSelectFileCompleteIndex - 1].push_back( 135872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen FILE_PATH_LITERAL("html")); 135972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 136072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (add_extra_extension) { 136172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen file_type_info.extensions[kSelectFileCompleteIndex - 1].push_back( 136272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen extra_extension); 136372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 136472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 1365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_type_info.extension_description_overrides.push_back( 136672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen l10n_util::GetStringUTF16(kIndexToIDS[kSelectFileCompleteIndex])); 1367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_type_info.include_all_files = false; 1368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default_extension = kDefaultHtmlExtension; 1369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 1370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_type_info.extensions.resize(1); 137172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen file_type_info.extensions[kSelectFileHtmlOnlyIndex - 1].push_back( 137272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen suggested_path.Extension()); 137372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 137472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!file_type_info.extensions[kSelectFileHtmlOnlyIndex - 1][0].empty()) { 137572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Drop the . 137672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen file_type_info.extensions[kSelectFileHtmlOnlyIndex - 1][0].erase(0, 1); 137772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 137872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 1379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_type_info.include_all_files = true; 1380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_type_index = 1; 1381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (g_should_prompt_for_filename) { 1384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!select_file_dialog_.get()) 1385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch select_file_dialog_ = SelectFileDialog::Create(this); 1386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch select_file_dialog_->SelectFile(SelectFileDialog::SELECT_SAVEAS_FILE, 1387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch string16(), 1388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch suggested_path, 1389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &file_type_info, 1390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_type_index, 1391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default_extension, 1392ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen tab_contents(), 1393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch platform_util::GetTopLevel( 1394dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen tab_contents()->GetNativeView()), 1395513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch NULL); 1396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 1397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Just use 'suggested_path' instead of opening the dialog prompt. 1398513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch ContinueSave(suggested_path, file_type_index); 1399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Called after the save file dialog box returns. 1403513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid SavePackage::ContinueSave(const FilePath& final_name, 1404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index) { 1405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Ensure the filename is safe. 1406513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch saved_main_file_path_ = final_name; 1407dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen download_util::GenerateSafeFileName(tab_contents()->contents_mime_type(), 1408513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch &saved_main_file_path_); 1409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The option index is not zero-based. 141172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen DCHECK(index >= kSelectFileHtmlOnlyIndex && 141272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen index <= kSelectFileCompleteIndex); 141372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 1414513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch saved_main_directory_path_ = saved_main_file_path_.DirName(); 1415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1416dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen PrefService* prefs = tab_contents()->profile()->GetPrefs(); 1417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StringPrefMember save_file_path; 1418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_file_path.Init(prefs::kSaveFileDefaultDirectory, prefs, NULL); 1419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_POSIX) 1420513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch std::string path_string = saved_main_directory_path_.value(); 1421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(OS_WIN) 1422513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch std::string path_string = WideToUTF8(saved_main_directory_path_.value()); 1423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 1424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If user change the default saving directory, we will remember it just 1425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // like IE and FireFox. 1426dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (!tab_contents()->profile()->IsOffTheRecord() && 1427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_file_path.GetValue() != path_string) { 1428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_file_path.SetValue(path_string); 1429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 143172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen save_type_ = kIndexToSaveType[index]; 143272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 143372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen prefs->SetInteger(prefs::kSaveFileType, save_type_); 1434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1435513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (save_type_ == SavePackage::SAVE_AS_COMPLETE_HTML) { 1436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make new directory for saving complete file. 1437513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch saved_main_directory_path_ = saved_main_directory_path_.Append( 1438513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch saved_main_file_path_.RemoveExtension().BaseName().value() + 1439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FILE_PATH_LITERAL("_files")); 1440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Init(); 1443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Static 1446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SavePackage::IsSavableURL(const GURL& url) { 1447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = 0; chrome::kSavableSchemes[i] != NULL; ++i) { 1448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (url.SchemeIs(chrome::kSavableSchemes[i])) { 1449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 1450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 1453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Static 1456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SavePackage::IsSavableContents(const std::string& contents_mime_type) { 1457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // WebKit creates Document object when MIME type is application/xhtml+xml, 1458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // so we also support this MIME type. 1459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return contents_mime_type == "text/html" || 1460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch contents_mime_type == "text/xml" || 1461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch contents_mime_type == "application/xhtml+xml" || 1462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch contents_mime_type == "text/plain" || 1463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch contents_mime_type == "text/css" || 1464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch net::IsSupportedJavascriptMimeType(contents_mime_type.c_str()); 1465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// SelectFileDialog::Listener interface. 1468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::FileSelected(const FilePath& path, 1469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index, void* params) { 1470513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch ContinueSave(path, index); 1471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePackage::FileSelectionCanceled(void* params) { 1474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1475