save_package.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/save_package.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_util.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/file_util_icu.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
149ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/string_piece.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_split.h"
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/sys_string_conversions.h"
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/download_item_impl.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/download_manager_impl.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/download_stats.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/save_file.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/save_file_manager.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/save_item.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/loader/resource_dispatcher_host_impl.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/render_process_host_impl.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/render_view_host_delegate.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/render_view_host_impl.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/common/view_messages.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_context.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/content_browser_client.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/download_manager_delegate.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/navigation_entry.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_types.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/resource_context.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/url_constants.h"
42c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "net/base/filename_util.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/io_buffer.h"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/mime_util.h"
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_context.h"
467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebPageSerializerClient.h"
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Time;
49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebPageSerializerClient;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A counter for uniquely identifying each save package.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int g_save_package_id = 0;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Default name which will be used when we can not get proper name from
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// resource URL.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kDefaultSaveName[] = "saved_resource";
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Maximum number of file ordinal number. I think it's big enough for resolving
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// name-conflict files which has same base file name.
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int32 kMaxFileOrdinalNumber = 9999;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Maximum length for file path. Since Windows have MAX_PATH limitation for
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// file path, we need to make sure length of file path of every saved file
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is less than MAX_PATH
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const uint32 kMaxFilePathLength = MAX_PATH - 1;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_POSIX)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const uint32 kMaxFilePathLength = PATH_MAX - 1;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Maximum length for file ordinal number part. Since we only support the
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// maximum 9999 for ordinal number, which means maximum file ordinal number part
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// should be "(9998)", so the value is 6.
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const uint32 kMaxFileOrdinalNumberPartLength = 6;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Strip current ordinal number, if any. Should only be used on pure
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// file names, i.e. those stripped of their extensions.
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(estade): improve this to not choke on alternate encodings.
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath::StringType StripOrdinalNumber(
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath::StringType& pure_file_name) {
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath::StringType::size_type r_paren_index =
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pure_file_name.rfind(FILE_PATH_LITERAL(')'));
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath::StringType::size_type l_paren_index =
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pure_file_name.rfind(FILE_PATH_LITERAL('('));
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (l_paren_index >= r_paren_index)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return pure_file_name;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (base::FilePath::StringType::size_type i = l_paren_index + 1;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != r_paren_index; ++i) {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!IsAsciiDigit(pure_file_name[i]))
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return pure_file_name;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pure_file_name.substr(0, l_paren_index);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Check whether we can save page as complete-HTML for the contents which
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// have specified a MIME type. Now only contents which have the MIME type
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "text/html" can be saved as complete-HTML.
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CanSaveAsComplete(const std::string& contents_mime_type) {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return contents_mime_type == "text/html" ||
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         contents_mime_type == "application/xhtml+xml";
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Request handle for SavePackage downloads. Currently doesn't support
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// pause/resume/cancel, but returns a WebContents.
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class SavePackageRequestHandle : public DownloadRequestHandleInterface {
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SavePackageRequestHandle(base::WeakPtr<SavePackage> save_package)
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : save_package_(save_package) {}
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // DownloadRequestHandleInterface
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual WebContents* GetWebContents() const OVERRIDE {
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return save_package_.get() ? save_package_->web_contents() : NULL;
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual DownloadManager* GetDownloadManager() const OVERRIDE {
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return NULL;
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void PauseRequest() const OVERRIDE {}
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void ResumeRequest() const OVERRIDE {}
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void CancelRequest() const OVERRIDE {}
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual std::string DebugString() const OVERRIDE {
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return "SavePackage DownloadRequestHandle";
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::WeakPtr<SavePackage> save_package_;
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const base::FilePath::CharType SavePackage::kDefaultHtmlExtension[] =
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FILE_PATH_LITERAL("htm");
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FILE_PATH_LITERAL("html");
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SavePackage::SavePackage(WebContents* web_contents,
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         SavePageType save_type,
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         const base::FilePath& file_full_path,
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         const base::FilePath& directory_full_path)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : WebContentsObserver(web_contents),
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_manager_(NULL),
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      download_manager_(NULL),
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      download_(NULL),
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      page_url_(GetUrlToBeSaved()),
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      saved_main_file_path_(file_full_path),
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      saved_main_directory_path_(directory_full_path),
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      title_(web_contents->GetTitle()),
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      start_tick_(base::TimeTicks::Now()),
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      finished_(false),
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mhtml_finishing_(false),
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      user_canceled_(false),
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      disk_error_occurred_(false),
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      save_type_(save_type),
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      all_save_items_count_(0),
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      file_name_set_(&base::FilePath::CompareLessIgnoreCase),
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wait_state_(INITIALIZE),
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      contents_id_(web_contents->GetRenderProcessHost()->GetID()),
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unique_id_(g_save_package_id++),
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wrote_to_completed_file_(false),
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wrote_to_failed_file_(false) {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(page_url_.is_valid());
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK((save_type_ == SAVE_PAGE_TYPE_AS_ONLY_HTML) ||
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         (save_type_ == SAVE_PAGE_TYPE_AS_MHTML) ||
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML));
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!saved_main_file_path_.empty() &&
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         saved_main_file_path_.value().length() <= kMaxFilePathLength);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!saved_main_directory_path_.empty() &&
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         saved_main_directory_path_.value().length() < kMaxFilePathLength);
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InternalInit();
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SavePackage::SavePackage(WebContents* web_contents)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : WebContentsObserver(web_contents),
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_manager_(NULL),
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      download_manager_(NULL),
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      download_(NULL),
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      page_url_(GetUrlToBeSaved()),
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      title_(web_contents->GetTitle()),
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      start_tick_(base::TimeTicks::Now()),
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      finished_(false),
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mhtml_finishing_(false),
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      user_canceled_(false),
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      disk_error_occurred_(false),
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      save_type_(SAVE_PAGE_TYPE_UNKNOWN),
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      all_save_items_count_(0),
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      file_name_set_(&base::FilePath::CompareLessIgnoreCase),
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wait_state_(INITIALIZE),
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      contents_id_(web_contents->GetRenderProcessHost()->GetID()),
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unique_id_(g_save_package_id++),
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wrote_to_completed_file_(false),
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wrote_to_failed_file_(false) {
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(page_url_.is_valid());
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InternalInit();
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is for testing use. Set |finished_| as true because we don't want
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// method Cancel to be be called in destructor in test mode.
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We also don't call InternalInit().
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SavePackage::SavePackage(WebContents* web_contents,
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         const base::FilePath& file_full_path,
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         const base::FilePath& directory_full_path)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : WebContentsObserver(web_contents),
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_manager_(NULL),
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      download_manager_(NULL),
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      download_(NULL),
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      saved_main_file_path_(file_full_path),
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      saved_main_directory_path_(directory_full_path),
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      start_tick_(base::TimeTicks::Now()),
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      finished_(true),
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mhtml_finishing_(false),
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      user_canceled_(false),
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      disk_error_occurred_(false),
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      save_type_(SAVE_PAGE_TYPE_UNKNOWN),
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      all_save_items_count_(0),
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      file_name_set_(&base::FilePath::CompareLessIgnoreCase),
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wait_state_(INITIALIZE),
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      contents_id_(0),
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unique_id_(g_save_package_id++),
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wrote_to_completed_file_(false),
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wrote_to_failed_file_(false) {
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SavePackage::~SavePackage() {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Stop receiving saving job's updates
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!finished_ && !canceled()) {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Unexpected quit.
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Cancel(true);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We should no longer be observing the DownloadItem at this point.
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!download_);
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(all_save_items_count_ == (waiting_item_queue_.size() +
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   completed_count() +
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   in_process_count()));
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Free all SaveItems.
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!waiting_item_queue_.empty()) {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We still have some items which are waiting for start to save.
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SaveItem* save_item = waiting_item_queue_.front();
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    waiting_item_queue_.pop();
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete save_item;
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteValues(&saved_success_items_);
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteValues(&in_progress_items_);
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteValues(&saved_failed_items_);
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_manager_ = NULL;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GURL SavePackage::GetUrlToBeSaved() {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Instead of using web_contents_.GetURL here, we use url() (which is the
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // "real" url of the page) from the NavigationEntry because it reflects its
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // origin rather than the displayed one (returned by GetURL) which may be
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // different (like having "view-source:" on the front).
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NavigationEntry* active_entry =
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      web_contents()->GetController().GetActiveEntry();
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return active_entry->GetURL();
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::Cancel(bool user_action) {
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!canceled()) {
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (user_action)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      user_canceled_ = true;
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      disk_error_occurred_ = true;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Stop();
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordSavePackageEvent(SAVE_PACKAGE_CANCELLED);
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Init() can be called directly, or indirectly via GetSaveInfo(). In both
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// cases, we need file_manager_ to be initialized, so we do this first.
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::InternalInit() {
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!rdh) {
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_manager_ = rdh->save_file_manager();
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(file_manager_);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  download_manager_ = static_cast<DownloadManagerImpl*>(
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserContext::GetDownloadManager(
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          web_contents()->GetBrowserContext()));
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(download_manager_);
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordSavePackageEvent(SAVE_PACKAGE_STARTED);
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SavePackage::Init(
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SavePackageDownloadCreatedCallback& download_created_callback) {
3007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set proper running state.
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (wait_state_ != INITIALIZE)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wait_state_ = START_PROCESS;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Initialize the request context and resource dispatcher.
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserContext* browser_context = web_contents()->GetBrowserContext();
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!browser_context) {
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<DownloadRequestHandleInterface> request_handle(
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new SavePackageRequestHandle(AsWeakPtr()));
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The download manager keeps ownership but adds us as an observer.
3177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  download_manager_->CreateSavePackageDownloadItem(
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      saved_main_file_path_,
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      page_url_,
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ((save_type_ == SAVE_PAGE_TYPE_AS_MHTML) ?
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       "multipart/related" : "text/html"),
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      request_handle.Pass(),
3237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      base::Bind(&SavePackage::InitWithDownloadItem, AsWeakPtr(),
3247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                 download_created_callback));
3257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return true;
3267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
3277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid SavePackage::InitWithDownloadItem(
3297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const SavePackageDownloadCreatedCallback& download_created_callback,
3307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    DownloadItemImpl* item) {
3317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(item);
3337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  download_ = item;
3347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  download_->AddObserver(this);
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Confirm above didn't delete the tab out from under us.
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!download_created_callback.is_null())
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    download_created_callback.Run(download_);
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check save type and process the save page job.
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML) {
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Get directory
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!saved_main_directory_path_.empty());
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetAllSavableResourceLinksForCurrentPage();
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (save_type_ == SAVE_PAGE_TYPE_AS_MHTML) {
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    web_contents()->GenerateMHTML(saved_main_file_path_, base::Bind(
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        &SavePackage::OnMHTMLGenerated, this));
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_EQ(SAVE_PAGE_TYPE_AS_ONLY_HTML, save_type_) << save_type_;
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    wait_state_ = NET_FILES;
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SaveFileCreateInfo::SaveFileSource save_source = page_url_.SchemeIsFile() ?
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SaveFileCreateInfo::SAVE_FILE_FROM_FILE :
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SaveFileCreateInfo::SAVE_FILE_FROM_NET;
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SaveItem* save_item = new SaveItem(page_url_,
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       Referrer(),
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       this,
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       save_source);
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Add this item to waiting list.
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    waiting_item_queue_.push(save_item);
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    all_save_items_count_ = 1;
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    download_->SetTotalBytes(1);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DoSavingProcess();
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
366424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void SavePackage::OnMHTMLGenerated(int64 size) {
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (size <= 0) {
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Cancel(false);
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wrote_to_completed_file_ = true;
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Hack to avoid touching download_ after user cancel.
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(rdsmith/benjhayden): Integrate canceling on DownloadItem
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // with SavePackage flow.
3767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (download_->GetState() == DownloadItem::IN_PROGRESS) {
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    download_->SetTotalBytes(size);
37890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    download_->DestinationUpdate(size, 0, std::string());
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Must call OnAllDataSaved here in order for
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // GDataDownloadObserver::ShouldUpload() to return true.
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // ShouldCompleteDownload() may depend on the gdata uploader to finish.
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    download_->OnAllDataSaved(DownloadItem::kEmptyFileHash);
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!download_manager_->GetDelegate()) {
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Finish();
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (download_manager_->GetDelegate()->ShouldCompleteDownload(
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          download_, base::Bind(&SavePackage::Finish, this))) {
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Finish();
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On POSIX, the length of |pure_file_name| + |file_name_ext| is further
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// restricted by NAME_MAX. The maximum allowed path looks like:
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// '/path/to/save_dir' + '/' + NAME_MAX.
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)uint32 SavePackage::GetMaxPathLengthForDirectory(
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& base_dir) {
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_POSIX)
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::min(kMaxFilePathLength,
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  static_cast<uint32>(base_dir.value().length()) +
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  NAME_MAX + 1);
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return kMaxFilePathLength;
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// File name is considered being consist of pure file name, dot and file
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// extension name. File name might has no dot and file extension, or has
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// multiple dot inside file name. The dot, which separates the pure file
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// name and file extension name, is last dot in the whole file name.
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This function is for making sure the length of specified file path is not
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// great than the specified maximum length of file path and getting safe pure
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// file name part if the input pure file name is too long.
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The parameter |dir_path| specifies directory part of the specified
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// file path. The parameter |file_name_ext| specifies file extension
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// name part of the specified file path (including start dot). The parameter
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |max_file_path_len| specifies maximum length of the specified file path.
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The parameter |pure_file_name| input pure file name part of the specified
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// file path. If the length of specified file path is great than
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |max_file_path_len|, the |pure_file_name| will output new pure file name
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// part for making sure the length of specified file path is less than
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// specified maximum length of file path. Return false if the function can
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// not get a safe pure file name, otherwise it returns true.
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SavePackage::GetSafePureFileName(
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& dir_path,
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath::StringType& file_name_ext,
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    uint32 max_file_path_len,
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath::StringType* pure_file_name) {
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!pure_file_name->empty());
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int available_length = static_cast<int>(max_file_path_len -
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          dir_path.value().length() -
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          file_name_ext.length());
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Need an extra space for the separator.
437c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!dir_path.EndsWithSeparator())
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    --available_length;
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Plenty of room.
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (static_cast<int>(pure_file_name->length()) <= available_length)
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Limited room. Truncate |pure_file_name| to fit.
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (available_length > 0) {
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *pure_file_name = pure_file_name->substr(0, available_length);
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Not enough room to even use a shortened |pure_file_name|.
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pure_file_name->clear();
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Generate name for saving resource.
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SavePackage::GenerateFileName(const std::string& disposition,
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const GURL& url,
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   bool need_html_ext,
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   base::FilePath::StringType* generated_name) {
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(jungshik): Figure out the referrer charset when having one
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // makes sense and pass it to GenerateFileName.
462c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath file_path = net::GenerateFileName(url,
463c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                   disposition,
464c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                   std::string(),
465c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                   std::string(),
466c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                   std::string(),
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                   kDefaultSaveName);
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!file_path.empty());
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath::StringType pure_file_name =
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_path.RemoveExtension().BaseName().value();
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath::StringType file_name_ext = file_path.Extension();
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If it is HTML resource, use ".htm{l,}" as its extension.
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (need_html_ext) {
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file_name_ext = FILE_PATH_LITERAL(".");
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file_name_ext.append(kDefaultHtmlExtension);
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Need to make sure the suggested file name is not too long.
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32 max_path = GetMaxPathLengthForDirectory(saved_main_directory_path_);
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get safe pure file name.
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetSafePureFileName(saved_main_directory_path_, file_name_ext,
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           max_path, &pure_file_name))
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath::StringType file_name = pure_file_name + file_name_ext;
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Check whether we already have same name in a case insensitive manner.
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FileNameSet::const_iterator iter = file_name_set_.find(file_name);
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (iter == file_name_set_.end()) {
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file_name_set_.insert(file_name);
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Found same name, increase the ordinal number for the file name.
4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    pure_file_name =
4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::FilePath(*iter).RemoveExtension().BaseName().value();
4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath::StringType base_file_name =
4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        StripOrdinalNumber(pure_file_name);
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We need to make sure the length of base file name plus maximum ordinal
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // number path will be less than or equal to kMaxFilePathLength.
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!GetSafePureFileName(saved_main_directory_path_, file_name_ext,
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        max_path - kMaxFileOrdinalNumberPartLength, &base_file_name))
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Prepare the new ordinal number.
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32 ordinal_number;
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FileNameCountMap::iterator it = file_name_count_map_.find(base_file_name);
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (it == file_name_count_map_.end()) {
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // First base-name-conflict resolving, use 1 as initial ordinal number.
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_name_count_map_[base_file_name] = 1;
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ordinal_number = 1;
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We have met same base-name conflict, use latest ordinal number.
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ordinal_number = it->second;
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ordinal_number > (kMaxFileOrdinalNumber - 1)) {
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Use a random file from temporary file.
5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::FilePath temp_file;
522a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base::CreateTemporaryFile(&temp_file);
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_name = temp_file.RemoveExtension().BaseName().value();
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Get safe pure file name.
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!GetSafePureFileName(saved_main_directory_path_,
5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               base::FilePath::StringType(),
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               max_path, &file_name))
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (int i = ordinal_number; i < kMaxFileOrdinalNumber; ++i) {
5312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::FilePath::StringType new_name = base_file_name +
5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            base::StringPrintf(FILE_PATH_LITERAL("(%d)"), i) + file_name_ext;
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (file_name_set_.find(new_name) == file_name_set_.end()) {
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Resolved name conflict.
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          file_name = new_name;
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          file_name_count_map_[base_file_name] = ++i;
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file_name_set_.insert(file_name);
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!file_name.empty());
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  generated_name->assign(file_name);
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We have received a message from SaveFileManager about a new saving job. We
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// create a SaveItem and store it in our in_progress list.
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::StartSave(const SaveFileCreateInfo* info) {
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(info && !info->url.is_empty());
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveUrlItemMap::iterator it = in_progress_items_.find(info->url.spec());
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it == in_progress_items_.end()) {
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If not found, we must have cancel action.
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(canceled());
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveItem* save_item = it->second;
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!saved_main_file_path_.empty());
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  save_item->SetSaveId(info->save_id);
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  save_item->SetTotalBytes(info->total_bytes);
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Determine the proper path for a saving job, by choosing either the default
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // save directory, or prompting the user.
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!save_item->has_final_name());
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (info->url != page_url_) {
5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath::StringType generated_name;
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // For HTML resource file, make sure it will have .htm as extension name,
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // otherwise, when you open the saved page in Chrome again, download
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // file manager will treat it as downloadable resource, and download it
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // instead of opening it as HTML.
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool need_html_ext =
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_DOM;
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!GenerateFileName(info->content_disposition,
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          GURL(info->url),
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          need_html_ext,
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          &generated_name)) {
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We can not generate file name for this SaveItem, so we cancel the
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // saving page job if the save source is from serialized DOM data.
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Otherwise, it means this SaveItem is sub-resource type, we treat it
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // as an error happened on saving. We can ignore this type error for
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // sub-resource links which will be resolved as absolute links instead
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // of local links in final saved contents.
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_DOM)
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Cancel(true);
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SaveFinished(save_item->save_id(), 0, false);
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // When saving page as only-HTML, we only have a SaveItem whose url
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // must be page_url_.
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML);
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!saved_main_directory_path_.empty());
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Now we get final name retrieved from GenerateFileName, we will use it
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // rename the SaveItem.
6042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath final_name =
6052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        saved_main_directory_path_.Append(generated_name);
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    save_item->Rename(final_name);
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // It is the main HTML file, use the name chosen by the user.
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    save_item->Rename(saved_main_file_path_);
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the save source is from file system, inform SaveFileManager to copy
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // corresponding file to the file path which this SaveItem specifies.
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_FILE) {
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::FILE, FROM_HERE,
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&SaveFileManager::SaveLocalFile,
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   file_manager_,
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   save_item->url(),
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   save_item->save_id(),
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   contents_id()));
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check whether we begin to require serialized HTML data.
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML &&
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wait_state_ == HTML_DATA) {
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Inform backend to serialize the all frames' DOM and send serialized
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // HTML data back.
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetSerializedHtmlDataForCurrentPageWithLocalLinks();
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SaveItem* SavePackage::LookupItemInProcessBySaveId(int32 save_id) {
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (in_process_count()) {
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (SaveUrlItemMap::iterator it = in_progress_items_.begin();
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        it != in_progress_items_.end(); ++it) {
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SaveItem* save_item = it->second;
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(save_item->state() == SaveItem::IN_PROGRESS);
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (save_item->save_id() == save_id)
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return save_item;
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::PutInProgressItemToSavedMap(SaveItem* save_item) {
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveUrlItemMap::iterator it = in_progress_items_.find(
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      save_item->url().spec());
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(it != in_progress_items_.end());
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(save_item == it->second);
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  in_progress_items_.erase(it);
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (save_item->success()) {
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Add it to saved_success_items_.
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(saved_success_items_.find(save_item->save_id()) ==
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           saved_success_items_.end());
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    saved_success_items_[save_item->save_id()] = save_item;
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Add it to saved_failed_items_.
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(saved_failed_items_.find(save_item->url().spec()) ==
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           saved_failed_items_.end());
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    saved_failed_items_[save_item->url().spec()] = save_item;
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Called for updating saving state.
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SavePackage::UpdateSaveProgress(int32 save_id,
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     int64 size,
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     bool write_success) {
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Because we might have canceled this saving job before,
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // so we might not find corresponding SaveItem.
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveItem* save_item = LookupItemInProcessBySaveId(save_id);
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!save_item)
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  save_item->Update(size);
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we got disk error, cancel whole save page job.
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!write_success) {
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Cancel job with reason of disk error.
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Cancel(false);
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Stop all page saving jobs that are in progress and instruct the file thread
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to delete all saved  files.
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::Stop() {
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we haven't moved out of the initial state, there's nothing to cancel and
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // there won't be valid pointers for file_manager_ or download_.
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (wait_state_ == INITIALIZE)
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // When stopping, if it still has some items in in_progress, cancel them.
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(canceled());
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (in_process_count()) {
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SaveUrlItemMap::iterator it = in_progress_items_.begin();
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (; it != in_progress_items_.end(); ++it) {
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SaveItem* save_item = it->second;
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(save_item->state() == SaveItem::IN_PROGRESS);
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      save_item->Cancel();
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Remove all in progress item to saved map. For failed items, they will
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // be put into saved_failed_items_, for successful item, they will be put
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // into saved_success_items_.
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (in_process_count())
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PutInProgressItemToSavedMap(in_progress_items_.begin()->second);
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This vector contains the save ids of the save files which SaveFileManager
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // needs to remove from its save_file_map_.
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveIDList save_ids;
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (SavedItemMap::iterator it = saved_success_items_.begin();
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      it != saved_success_items_.end(); ++it)
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    save_ids.push_back(it->first);
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (SaveUrlItemMap::iterator it = saved_failed_items_.begin();
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      it != saved_failed_items_.end(); ++it)
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    save_ids.push_back(it->second->save_id());
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::FILE, FROM_HERE,
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&SaveFileManager::RemoveSavedFileFromFileMap,
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 file_manager_,
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 save_ids));
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  finished_ = true;
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wait_state_ = FAILED;
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Inform the DownloadItem we have canceled whole save page job.
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (download_) {
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    download_->Cancel(false);
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FinalizeDownloadEntry();
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::CheckFinish() {
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (in_process_count() || finished_)
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath dir = (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML &&
7422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        saved_success_items_.size() > 1) ?
7432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        saved_main_directory_path_ : base::FilePath();
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This vector contains the final names of all the successfully saved files
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // along with their save ids. It will be passed to SaveFileManager to do the
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // renaming job.
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FinalNameList final_names;
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (SavedItemMap::iterator it = saved_success_items_.begin();
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      it != saved_success_items_.end(); ++it)
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    final_names.push_back(std::make_pair(it->first,
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         it->second->full_path()));
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::FILE, FROM_HERE,
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&SaveFileManager::RenameAllFiles,
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 file_manager_,
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 final_names,
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 dir,
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 web_contents()->GetRenderProcessHost()->GetID(),
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 web_contents()->GetRenderViewHost()->GetRoutingID(),
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 id()));
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Successfully finished all items of this SavePackage.
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::Finish() {
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // User may cancel the job when we're moving files to the final directory.
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (canceled())
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wait_state_ = SUCCESSFUL;
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  finished_ = true;
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Record finish.
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordSavePackageEvent(SAVE_PACKAGE_FINISHED);
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Record any errors that occurred.
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (wrote_to_completed_file_) {
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordSavePackageEvent(SAVE_PACKAGE_WRITE_TO_COMPLETED);
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (wrote_to_failed_file_) {
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordSavePackageEvent(SAVE_PACKAGE_WRITE_TO_FAILED);
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This vector contains the save ids of the save files which SaveFileManager
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // needs to remove from its save_file_map_.
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveIDList save_ids;
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (SaveUrlItemMap::iterator it = saved_failed_items_.begin();
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != saved_failed_items_.end(); ++it)
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    save_ids.push_back(it->second->save_id());
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::FILE, FROM_HERE,
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&SaveFileManager::RemoveSavedFileFromFileMap,
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 file_manager_,
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 save_ids));
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (download_) {
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Hack to avoid touching download_ after user cancel.
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(rdsmith/benjhayden): Integrate canceling on DownloadItem
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // with SavePackage flow.
8037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (download_->GetState() == DownloadItem::IN_PROGRESS) {
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (save_type_ != SAVE_PAGE_TYPE_AS_MHTML) {
80590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        download_->DestinationUpdate(
806c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            all_save_items_count_, CurrentSpeed(), std::string());
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        download_->OnAllDataSaved(DownloadItem::kEmptyFileHash);
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      download_->MarkAsComplete();
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FinalizeDownloadEntry();
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Called for updating end state.
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::SaveFinished(int32 save_id, int64 size, bool is_success) {
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Because we might have canceled this saving job before,
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // so we might not find corresponding SaveItem. Just ignore it.
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveItem* save_item = LookupItemInProcessBySaveId(save_id);
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!save_item)
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Let SaveItem set end state.
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  save_item->Finish(size, is_success);
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove the associated save id and SavePackage.
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_manager_->RemoveSaveFile(save_id, save_item->url(), this);
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PutInProgressItemToSavedMap(save_item);
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Inform the DownloadItem to update UI.
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We use the received bytes as number of saved files.
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Hack to avoid touching download_ after user cancel.
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(rdsmith/benjhayden): Integrate canceling on DownloadItem
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // with SavePackage flow.
8357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (download_ && (download_->GetState() == DownloadItem::IN_PROGRESS)) {
83690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    download_->DestinationUpdate(
83790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        completed_count(), CurrentSpeed(), std::string());
83890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM &&
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      save_item->url() == page_url_ && !save_item->received_bytes()) {
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If size of main HTML page is 0, treat it as disk error.
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Cancel(false);
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (canceled()) {
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(finished_);
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Continue processing the save page job.
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DoSavingProcess();
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check whether we can successfully finish whole job.
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckFinish();
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Sometimes, the net io will only call SaveFileManager::SaveFinished with
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// save id -1 when it encounters error. Since in this case, save id will be
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// -1, so we can only use URL to find which SaveItem is associated with
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this error.
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Saving an item failed. If it's a sub-resource, ignore it. If the error comes
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// from serializing HTML data, then cancel saving page.
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::SaveFailed(const GURL& save_url) {
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveUrlItemMap::iterator it = in_progress_items_.find(save_url.spec());
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it == in_progress_items_.end()) {
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();  // Should not exist!
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveItem* save_item = it->second;
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  save_item->Finish(0, false);
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PutInProgressItemToSavedMap(save_item);
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Inform the DownloadItem to update UI.
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We use the received bytes as number of saved files.
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Hack to avoid touching download_ after user cancel.
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(rdsmith/benjhayden): Integrate canceling on DownloadItem
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // with SavePackage flow.
8827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (download_ && (download_->GetState() == DownloadItem::IN_PROGRESS)) {
88390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    download_->DestinationUpdate(
88490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        completed_count(), CurrentSpeed(), std::string());
88590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((save_type_ == SAVE_PAGE_TYPE_AS_ONLY_HTML) ||
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (save_type_ == SAVE_PAGE_TYPE_AS_MHTML) ||
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM)) {
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We got error when saving page. Treat it as disk error.
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Cancel(true);
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (canceled()) {
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(finished_);
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Continue processing the save page job.
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DoSavingProcess();
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckFinish();
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::SaveCanceled(SaveItem* save_item) {
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Call the RemoveSaveFile in UI thread.
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_manager_->RemoveSaveFile(save_item->save_id(),
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                save_item->url(),
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                this);
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (save_item->save_id() != -1)
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::FILE, FROM_HERE,
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&SaveFileManager::CancelSave,
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   file_manager_,
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   save_item->save_id()));
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Initiate a saving job of a specific URL. We send the request to
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SaveFileManager, which will dispatch it to different approach according to
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the save source. Parameter process_all_remaining_items indicates whether
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we need to save all remaining items.
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::SaveNextFile(bool process_all_remaining_items) {
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(web_contents());
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(waiting_item_queue_.size());
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  do {
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Pop SaveItem from waiting list.
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SaveItem* save_item = waiting_item_queue_.front();
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    waiting_item_queue_.pop();
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Add the item to in_progress_items_.
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SaveUrlItemMap::iterator it = in_progress_items_.find(
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        save_item->url().spec());
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(it == in_progress_items_.end());
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    in_progress_items_[save_item->url().spec()] = save_item;
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    save_item->Start();
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file_manager_->SaveURL(save_item->url(),
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           save_item->referrer(),
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           web_contents()->GetRenderProcessHost()->GetID(),
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           routing_id(),
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           save_item->save_source(),
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           save_item->full_path(),
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           web_contents()->
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               GetBrowserContext()->GetResourceContext(),
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           this);
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } while (process_all_remaining_items && waiting_item_queue_.size());
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Calculate the percentage of whole save page job.
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SavePackage::PercentComplete() {
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!all_save_items_count_)
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else if (!in_process_count())
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 100;
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return completed_count() / all_save_items_count_;
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int64 SavePackage::CurrentSpeed() const {
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta diff = base::TimeTicks::Now() - start_tick_;
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 diff_ms = diff.InMilliseconds();
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return diff_ms == 0 ? 0 : completed_count() * 1000 / diff_ms;
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Continue processing the save page job after one SaveItem has been
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// finished.
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::DoSavingProcess() {
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML) {
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We guarantee that images and JavaScripts must be downloaded first.
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // So when finishing all those sub-resources, we will know which
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // sub-resource's link can be replaced with local file path, which
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // sub-resource's link need to be replaced with absolute URL which
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // point to its internet address because it got error when saving its data.
9743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Start a new SaveItem job if we still have job in waiting queue.
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (waiting_item_queue_.size()) {
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(wait_state_ == NET_FILES);
9783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      SaveItem* save_item = waiting_item_queue_.front();
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (save_item->save_source() != SaveFileCreateInfo::SAVE_FILE_FROM_DOM) {
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SaveNextFile(false);
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (!in_process_count()) {
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If there is no in-process SaveItem, it means all sub-resources
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // have been processed. Now we need to start serializing HTML DOM
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // for the current page to get the generated HTML data.
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        wait_state_ = HTML_DATA;
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // All non-HTML resources have been finished, start all remaining
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // HTML files.
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SaveNextFile(true);
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (in_process_count()) {
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Continue asking for HTML data.
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(wait_state_ == HTML_DATA);
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Save as HTML only or MHTML.
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(wait_state_ == NET_FILES);
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK((save_type_ == SAVE_PAGE_TYPE_AS_ONLY_HTML) ||
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           (save_type_ == SAVE_PAGE_TYPE_AS_MHTML));
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (waiting_item_queue_.size()) {
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(all_save_items_count_ == waiting_item_queue_.size());
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SaveNextFile(false);
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SavePackage::OnMessageReceived(const IPC::Message& message) {
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool handled = true;
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IPC_BEGIN_MESSAGE_MAP(SavePackage, message)
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPC_MESSAGE_HANDLER(ViewHostMsg_SendCurrentPageAllSavableResourceLinks,
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        OnReceivedSavableResourceLinksForCurrentPage)
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPC_MESSAGE_HANDLER(ViewHostMsg_SendSerializedHtmlData,
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        OnReceivedSerializedHtmlData)
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPC_MESSAGE_UNHANDLED(handled = false)
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IPC_END_MESSAGE_MAP()
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return handled;
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// After finishing all SaveItems which need to get data from net.
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We collect all URLs which have local storage and send the
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// map:(originalURL:currentLocalPath) to render process (backend).
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Then render process will serialize DOM and send data to us.
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::GetSerializedHtmlDataForCurrentPageWithLocalLinks() {
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (wait_state_ != HTML_DATA)
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<GURL> saved_links;
10262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<base::FilePath> saved_file_paths;
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int successful_started_items_count = 0;
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Collect all saved items which have local storage.
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First collect the status of all the resource files and check whether they
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // have created local files although they have not been completely saved.
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If yes, the file can be saved. Otherwise, there is a disk error, so we
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // need to cancel the page saving job.
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (SaveUrlItemMap::iterator it = in_progress_items_.begin();
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != in_progress_items_.end(); ++it) {
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(it->second->save_source() ==
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           SaveFileCreateInfo::SAVE_FILE_FROM_DOM);
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (it->second->has_final_name())
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      successful_started_items_count++;
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    saved_links.push_back(it->second->url());
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    saved_file_paths.push_back(it->second->file_name());
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If not all file of HTML resource have been started, then wait.
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (successful_started_items_count != in_process_count())
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Collect all saved success items.
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (SavedItemMap::iterator it = saved_success_items_.begin();
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != saved_success_items_.end(); ++it) {
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(it->second->has_final_name());
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    saved_links.push_back(it->second->url());
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    saved_file_paths.push_back(it->second->file_name());
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the relative directory name.
10572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath relative_dir_name = saved_main_directory_path_.BaseName();
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Send(new ViewMsg_GetSerializedHtmlDataForCurrentPageWithLocalLinks(
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      routing_id(), saved_links, saved_file_paths, relative_dir_name));
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Process the serialized HTML content data of a specified web page
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// retrieved from render process.
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::OnReceivedSerializedHtmlData(const GURL& frame_url,
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               const std::string& data,
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               int32 status) {
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebPageSerializerClient::PageSerializationStatus flag =
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<WebPageSerializerClient::PageSerializationStatus>(status);
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check current state.
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (wait_state_ != HTML_DATA)
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int id = contents_id();
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the all frames are finished saving, we need to close the
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // remaining SaveItems.
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (flag == WebPageSerializerClient::AllFramesAreFinished) {
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (SaveUrlItemMap::iterator it = in_progress_items_.begin();
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         it != in_progress_items_.end(); ++it) {
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VLOG(20) << " " << __FUNCTION__ << "()"
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << " save_id = " << it->second->save_id()
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << " url = \"" << it->second->url().spec() << "\"";
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::PostTask(
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          BrowserThread::FILE, FROM_HERE,
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&SaveFileManager::SaveFinished,
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     file_manager_,
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     it->second->save_id(),
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     it->second->url(),
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     id,
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     true));
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveUrlItemMap::iterator it = in_progress_items_.find(frame_url.spec());
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it == in_progress_items_.end()) {
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (SavedItemMap::iterator saved_it = saved_success_items_.begin();
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      saved_it != saved_success_items_.end(); ++saved_it) {
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (saved_it->second->url() == frame_url) {
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        wrote_to_completed_file_ = true;
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    it = saved_failed_items_.find(frame_url.spec());
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (it != saved_failed_items_.end())
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wrote_to_failed_file_ = true;
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveItem* save_item = it->second;
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM);
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!data.empty()) {
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Prepare buffer for saving HTML data.
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<net::IOBuffer> new_data(new net::IOBuffer(data.size()));
11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memcpy(new_data->data(), data.data(), data.size());
11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Call write file functionality in file thread.
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::FILE, FROM_HERE,
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&SaveFileManager::UpdateSaveProgress,
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   file_manager_,
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   save_item->save_id(),
11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   new_data,
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   static_cast<int>(data.size())));
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Current frame is completed saving, call finish in file thread.
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (flag == WebPageSerializerClient::CurrentFrameIsFinished) {
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(20) << " " << __FUNCTION__ << "()"
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             << " save_id = " << save_item->save_id()
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             << " url = \"" << save_item->url().spec() << "\"";
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::FILE, FROM_HERE,
11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&SaveFileManager::SaveFinished,
11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   file_manager_,
11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   save_item->save_id(),
11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   save_item->url(),
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   id,
11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   true));
11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Ask for all savable resource links from backend, include main frame and
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// sub-frame.
11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::GetAllSavableResourceLinksForCurrentPage() {
11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (wait_state_ != START_PROCESS)
11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wait_state_ = RESOURCES_LIST;
11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Send(new ViewMsg_GetAllSavableResourceLinksForCurrentPage(routing_id(),
11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                            page_url_));
11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Give backend the lists which contain all resource links that have local
11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// storage, after which, render process will serialize DOM for generating
11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// HTML data.
11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::OnReceivedSavableResourceLinksForCurrentPage(
11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<GURL>& resources_list,
11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<Referrer>& referrers_list,
11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<GURL>& frames_list) {
11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (wait_state_ != RESOURCES_LIST)
11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (resources_list.size() != referrers_list.size())
11682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
11692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  all_save_items_count_ = static_cast<int>(resources_list.size()) +
11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           static_cast<int>(frames_list.size());
11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We use total bytes as the total number of files we want to save.
11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Hack to avoid touching download_ after user cancel.
11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(rdsmith/benjhayden): Integrate canceling on DownloadItem
11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // with SavePackage flow.
11777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (download_ && (download_->GetState() == DownloadItem::IN_PROGRESS))
11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    download_->SetTotalBytes(all_save_items_count_);
11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (all_save_items_count_) {
11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Put all sub-resources to wait list.
11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < static_cast<int>(resources_list.size()); ++i) {
11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const GURL& u = resources_list[i];
11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(u.is_valid());
11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SaveFileCreateInfo::SaveFileSource save_source = u.SchemeIsFile() ?
11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          SaveFileCreateInfo::SAVE_FILE_FROM_FILE :
11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          SaveFileCreateInfo::SAVE_FILE_FROM_NET;
11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SaveItem* save_item = new SaveItem(u, referrers_list[i],
11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         this, save_source);
11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      waiting_item_queue_.push(save_item);
11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Put all HTML resources to wait list.
11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < static_cast<int>(frames_list.size()); ++i) {
11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const GURL& u = frames_list[i];
11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(u.is_valid());
11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SaveItem* save_item = new SaveItem(
11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u, Referrer(), this, SaveFileCreateInfo::SAVE_FILE_FROM_DOM);
11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      waiting_item_queue_.push(save_item);
11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    wait_state_ = NET_FILES;
12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DoSavingProcess();
12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No resource files need to be saved, treat it as user cancel.
12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Cancel(true);
12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath SavePackage::GetSuggestedNameForSaveAs(
12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool can_save_as_complete,
12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& contents_mime_type,
12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& accept_langs) {
1212424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  base::FilePath name_with_proper_ext = base::FilePath::FromUTF16Unsafe(title_);
12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the page's title matches its URL, use the URL. Try to use the last path
12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // component or if there is none, the domain as the file name.
12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Normally we want to base the filename on the page title, or if it doesn't
12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // exist, on the URL. It's not easy to tell if the page has no title, because
12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // if the page has no title, WebContents::GetTitle() will return the page's
12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // URL (adjusted for display purposes). Therefore, we convert the "title"
12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // back to a URL, and if it matches the original page URL, we know the page
12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // had no title (or had a title equal to its URL, which is fine to treat
12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // similarly).
12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (title_ == net::FormatUrl(page_url_, accept_langs)) {
12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string url_path;
12255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!page_url_.SchemeIs(kDataScheme)) {
12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::vector<std::string> url_parts;
12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::SplitString(page_url_.path(), '/', &url_parts);
12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!url_parts.empty()) {
12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (int i = static_cast<int>(url_parts.size()) - 1; i >= 0; --i) {
12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url_path = url_parts[i];
12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (!url_path.empty())
12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            break;
12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (url_path.empty())
12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        url_path = page_url_.host();
12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_path = "dataurl";
12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1240424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    name_with_proper_ext = base::FilePath::FromUTF8Unsafe(url_path);
12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ask user for getting final saving name.
12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  name_with_proper_ext = EnsureMimeExtension(name_with_proper_ext,
12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             contents_mime_type);
12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Adjust extension for complete types.
12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (can_save_as_complete)
12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    name_with_proper_ext = EnsureHtmlExtension(name_with_proper_ext);
12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath::StringType file_name = name_with_proper_ext.value();
12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_util::ReplaceIllegalCharactersInPath(&file_name, ' ');
12522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base::FilePath(file_name);
12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath SavePackage::EnsureHtmlExtension(const base::FilePath& name) {
12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the file name doesn't have an extension suitable for HTML files,
12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // append one.
12582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath::StringType ext = name.Extension();
12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ext.empty())
12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ext.erase(ext.begin());  // Erase preceding '.'.
12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string mime_type;
12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!net::GetMimeTypeFromExtension(ext, &mime_type) ||
12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !CanSaveAsComplete(mime_type)) {
12642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return base::FilePath(name.value() + FILE_PATH_LITERAL(".") +
12652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          kDefaultHtmlExtension);
12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return name;
12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath SavePackage::EnsureMimeExtension(const base::FilePath& name,
12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& contents_mime_type) {
12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start extension at 1 to skip over period if non-empty.
12732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath::StringType ext = name.Extension().length() ?
12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      name.Extension().substr(1) : name.Extension();
12752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath::StringType suggested_extension =
12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ExtensionForMimeType(contents_mime_type);
12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string mime_type;
12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!suggested_extension.empty() &&
12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !net::GetMimeTypeFromExtension(ext, &mime_type)) {
12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Extension is absent or needs to be updated.
12812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return base::FilePath(name.value() + FILE_PATH_LITERAL(".") +
12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    suggested_extension);
12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return name;
12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const base::FilePath::CharType* SavePackage::ExtensionForMimeType(
12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& contents_mime_type) {
12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const struct {
12902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath::CharType *mime_type;
12912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath::CharType *suggested_extension;
12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } extensions[] = {
12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { FILE_PATH_LITERAL("text/html"), kDefaultHtmlExtension },
12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { FILE_PATH_LITERAL("text/xml"), FILE_PATH_LITERAL("xml") },
12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { FILE_PATH_LITERAL("application/xhtml+xml"), FILE_PATH_LITERAL("xhtml") },
12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { FILE_PATH_LITERAL("text/plain"), FILE_PATH_LITERAL("txt") },
12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { FILE_PATH_LITERAL("text/css"), FILE_PATH_LITERAL("css") },
12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_POSIX)
13002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath::StringType mime_type(contents_mime_type);
13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_WIN)
13025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::FilePath::StringType mime_type(base::UTF8ToWide(contents_mime_type));
13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // OS_WIN
13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (uint32 i = 0; i < ARRAYSIZE_UNSAFE(extensions); ++i) {
13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (mime_type == extensions[i].mime_type)
13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return extensions[i].suggested_extension;
13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return FILE_PATH_LITERAL("");
13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebContents* SavePackage::web_contents() const {
13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return WebContentsObserver::web_contents();
13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::GetSaveInfo() {
13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Can't use web_contents_ in the file thread, so get the data that we need
13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // before calling to it.
13182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath website_save_dir, download_save_dir;
1319a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  bool skip_dir_check = false;
13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(download_manager_);
13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (download_manager_->GetDelegate()) {
13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    download_manager_->GetDelegate()->GetSaveDir(
13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        web_contents()->GetBrowserContext(), &website_save_dir,
13245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        &download_save_dir, &skip_dir_check);
13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string mime_type = web_contents()->GetContentsMimeType();
13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string accept_languages =
13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetContentClient()->browser()->GetAcceptLangs(
13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          web_contents()->GetBrowserContext());
13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::FILE, FROM_HERE,
13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&SavePackage::CreateDirectoryOnFileThread, this,
13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          website_save_dir, download_save_dir, skip_dir_check,
13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          mime_type, accept_languages));
13365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::CreateDirectoryOnFileThread(
13392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& website_save_dir,
13402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& download_save_dir,
13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool skip_dir_check,
13425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& mime_type,
13435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& accept_langs) {
13442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath save_dir;
13455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the default html/websites save folder doesn't exist...
13465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We skip the directory check for gdata directories on ChromeOS.
13477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!skip_dir_check && !base::DirectoryExists(website_save_dir)) {
13485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the default download dir doesn't exist, create it.
13497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (!base::DirectoryExists(download_save_dir)) {
1350a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      bool res = base::CreateDirectory(download_save_dir);
13515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(res);
13525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    save_dir = download_save_dir;
13545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
13555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If it does exist, use the default save dir param.
13565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    save_dir = website_save_dir;
13575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool can_save_as_complete = CanSaveAsComplete(mime_type);
13602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath suggested_filename = GetSuggestedNameForSaveAs(
13615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      can_save_as_complete, mime_type, accept_langs);
13622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath::StringType pure_file_name =
13635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      suggested_filename.RemoveExtension().BaseName().value();
13642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath::StringType file_name_ext = suggested_filename.Extension();
13655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Need to make sure the suggested file name is not too long.
13675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32 max_path = GetMaxPathLengthForDirectory(save_dir);
13685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GetSafePureFileName(save_dir, file_name_ext, max_path, &pure_file_name)) {
13705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    save_dir = save_dir.Append(pure_file_name + file_name_ext);
13715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
13725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Cannot create a shorter filename. This will cause the save as operation
13735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to fail unless the user pick a shorter name. Continuing even though it
13745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // will fail because returning means no save as popup for the user, which
13755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // is even more confusing. This case should be rare though.
13765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    save_dir = save_dir.Append(suggested_filename);
13775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
13805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::UI, FROM_HERE,
13815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&SavePackage::ContinueGetSaveInfo, this, save_dir,
13825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 can_save_as_complete));
13835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SavePackage::ContinueGetSaveInfo(const base::FilePath& suggested_path,
13865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      bool can_save_as_complete) {
13875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The WebContents which owns this SavePackage may have disappeared during
13895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the UI->FILE->UI thread hop of
13905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // GetSaveInfo->CreateDirectoryOnFileThread->ContinueGetSaveInfo.
13915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!web_contents() || !download_manager_->GetDelegate())
13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath::StringType default_extension;
13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (can_save_as_complete)
13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default_extension = kDefaultHtmlExtension;
13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  download_manager_->GetDelegate()->ChooseSavePath(
13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      web_contents(),
14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      suggested_path,
14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default_extension,
14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      can_save_as_complete,
14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&SavePackage::OnPathPicked, AsWeakPtr()));
14045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::OnPathPicked(
14072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& final_name,
14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SavePageType type,
14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SavePackageDownloadCreatedCallback& download_created_callback) {
14102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK((type == SAVE_PAGE_TYPE_AS_ONLY_HTML) ||
14112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         (type == SAVE_PAGE_TYPE_AS_MHTML) ||
14122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         (type == SAVE_PAGE_TYPE_AS_COMPLETE_HTML)) << type;
14135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ensure the filename is safe.
14145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  saved_main_file_path_ = final_name;
14155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(asanka): This call may block on IO and shouldn't be made
14165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // from the UI thread.  See http://crbug.com/61827.
14175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::GenerateSafeFileName(web_contents()->GetContentsMimeType(), false,
14185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            &saved_main_file_path_);
14195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  saved_main_directory_path_ = saved_main_file_path_.DirName();
14215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  save_type_ = type;
14225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML) {
14235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Make new directory for saving complete file.
14245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    saved_main_directory_path_ = saved_main_directory_path_.Append(
14255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        saved_main_file_path_.RemoveExtension().BaseName().value() +
14265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FILE_PATH_LITERAL("_files"));
14275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Init(download_created_callback);
14305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::StopObservation() {
14335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(download_);
14345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(download_manager_);
14355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  download_->RemoveObserver(this);
14375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  download_ = NULL;
14385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  download_manager_ = NULL;
14395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::OnDownloadDestroyed(DownloadItem* download) {
14425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StopObservation();
14435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::FinalizeDownloadEntry() {
14465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(download_);
14475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(download_manager_);
14485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  download_manager_->OnSavePackageSuccessfullyFinished(download_);
14505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StopObservation();
14515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace content
1454