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