save_file_manager.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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 "build/build_config.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/save_file_manager.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_util.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/save_file.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/save_package.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/loader/resource_dispatcher_host_impl.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/render_view_host_impl.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/web_contents/web_contents_impl.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/io_buffer.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_util.h"
237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SaveFileManager::SaveFileManager()
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : next_id_(0) {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SaveFileManager::~SaveFileManager() {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check for clean shutdown.
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(save_file_map_.empty());
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Called during the browser shutdown process to clean up any state (open files,
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// timers) that live on the saving thread (file thread).
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SaveFileManager::Shutdown() {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::FILE, FROM_HERE,
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&SaveFileManager::OnShutdown, this));
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Stop file thread operations.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SaveFileManager::OnShutdown() {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteValues(&save_file_map_);
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SaveFile* SaveFileManager::LookupSaveFile(int save_id) {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveFileMap::iterator it = save_file_map_.find(save_id);
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return it == save_file_map_.end() ? NULL : it->second;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Called on the IO thread when
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a) The ResourceDispatcherHostImpl has decided that a request is savable.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// b) The resource does not come from the network, but we still need a
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// save ID for for managing the status of the saving operation. So we
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// file a request from the file thread to the IO thread to generate a
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// unique save ID.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SaveFileManager::GetNextId() {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return next_id_++;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SaveFileManager::RegisterStartingRequest(const GURL& save_url,
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              SavePackage* save_package) {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure it runs in the UI thread.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int contents_id = save_package->contents_id();
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Register this starting request.
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartingRequestsMap& starting_requests =
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      contents_starting_requests_[contents_id];
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool never_present = starting_requests.insert(
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      StartingRequestsMap::value_type(save_url.spec(), save_package)).second;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(never_present);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SavePackage* SaveFileManager::UnregisterStartingRequest(
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& save_url, int contents_id) {
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure it runs in UI thread.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ContentsToStartingRequestsMap::iterator it =
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      contents_starting_requests_.find(contents_id);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it != contents_starting_requests_.end()) {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    StartingRequestsMap& requests = it->second;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    StartingRequestsMap::iterator sit = requests.find(save_url.spec());
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (sit == requests.end())
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return NULL;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Found, erase it from starting list and return SavePackage.
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SavePackage* save_package = sit->second;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    requests.erase(sit);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If there is no element in requests, remove it
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (requests.empty())
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      contents_starting_requests_.erase(it);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return save_package;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Look up a SavePackage according to a save id.
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SavePackage* SaveFileManager::LookupPackage(int save_id) {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SavePackageMap::iterator it = packages_.find(save_id);
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it != packages_.end())
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return it->second;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Call from SavePackage for starting a saving job
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SaveFileManager::SaveURL(
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Referrer& referrer,
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int render_process_host_id,
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int render_view_id,
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SaveFileCreateInfo::SaveFileSource save_source,
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& file_full_path,
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ResourceContext* context,
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SavePackage* save_package) {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Register a saving job.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegisterStartingRequest(url, save_package);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (save_source == SaveFileCreateInfo::SAVE_FILE_FROM_NET) {
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(url.is_valid());
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::IO, FROM_HERE,
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&SaveFileManager::OnSaveURL, this, url, referrer,
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            render_process_host_id, render_view_id, context));
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We manually start the save job.
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SaveFileCreateInfo* info = new SaveFileCreateInfo(file_full_path,
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         url,
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         save_source,
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         -1);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    info->render_process_id = render_process_host_id;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    info->render_view_id = render_view_id;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Since the data will come from render process, so we need to start
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // this kind of save job by ourself.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::IO, FROM_HERE,
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&SaveFileManager::OnRequireSaveJobFromOtherSource,
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            this, info));
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Utility function for look up table maintenance, called on the UI thread.
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A manager may have multiple save page job (SavePackage) in progress,
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// so we just look up the save id and remove it from the tracking table.
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If the save id is -1, it means we just send a request to save, but the
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// saving action has still not happened, need to call UnregisterStartingRequest
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to remove it from the tracking map.
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SaveFileManager::RemoveSaveFile(int save_id, const GURL& save_url,
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     SavePackage* package) {
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(package);
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // A save page job (SavePackage) can only have one manager,
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // so remove it if it exists.
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (save_id == -1) {
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SavePackage* old_package =
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        UnregisterStartingRequest(save_url, package->contents_id());
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(old_package, package);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SavePackageMap::iterator it = packages_.find(save_id);
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (it != packages_.end())
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      packages_.erase(it);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Static
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SavePackage* SaveFileManager::GetSavePackageFromRenderIds(
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int render_process_id, int render_view_id) {
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RenderViewHostImpl* render_view_host =
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      RenderViewHostImpl::FromID(render_process_id, render_view_id);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!render_view_host)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebContentsImpl* contents = static_cast<WebContentsImpl*>(
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      render_view_host->GetDelegate()->GetAsWebContents());
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!contents)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return contents->save_package();
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SaveFileManager::DeleteDirectoryOrFile(const base::FilePath& full_path,
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            bool is_dir) {
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::FILE, FROM_HERE,
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&SaveFileManager::OnDeleteDirectoryOrFile,
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          this, full_path, is_dir));
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SaveFileManager::SendCancelRequest(int save_id) {
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cancel the request which has specific save id.
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GT(save_id, -1);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::FILE, FROM_HERE,
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&SaveFileManager::CancelSave, this, save_id));
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Notifications sent from the IO thread and run on the file thread:
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The IO thread created |info|, but the file thread (this method) uses it
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to create a SaveFile which will hold and finally destroy |info|. It will
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// then passes |info| to the UI thread for reporting saving status.
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SaveFileManager::StartSave(SaveFileCreateInfo* info) {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(info);
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No need to calculate hash.
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveFile* save_file = new SaveFile(info, false);
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(phajdan.jr): We should check the return value and handle errors here.
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  save_file->Initialize();
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!LookupSaveFile(info->save_id));
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  save_file_map_[info->save_id] = save_file;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info->path = save_file->FullPath();
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::UI, FROM_HERE,
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&SaveFileManager::OnStartSave, this, info));
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We do forward an update to the UI thread here, since we do not use timer to
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// update the UI. If the user has canceled the saving action (in the UI
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// thread). We may receive a few more updates before the IO thread gets the
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// cancel message. We just delete the data since the SaveFile has been deleted.
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SaveFileManager::UpdateSaveProgress(int save_id,
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         net::IOBuffer* data,
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         int data_len) {
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveFile* save_file = LookupSaveFile(save_id);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (save_file) {
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(save_file->InProgress());
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DownloadInterruptReason reason =
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        save_file->AppendDataToFile(data->data(), data_len);
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::UI, FROM_HERE,
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&SaveFileManager::OnUpdateSaveProgress,
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   this,
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   save_file->save_id(),
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   save_file->BytesSoFar(),
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   reason == DOWNLOAD_INTERRUPT_REASON_NONE));
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The IO thread will call this when saving is completed or it got error when
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// fetching data. In the former case, we forward the message to OnSaveFinished
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in UI thread. In the latter case, the save ID will be -1, which means the
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// saving action did not even start, so we need to call OnErrorFinished in UI
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// thread, which will use the save URL to find corresponding request record and
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// delete it.
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SaveFileManager::SaveFinished(int save_id,
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const GURL& save_url,
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   int render_process_id,
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   bool is_success) {
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(20) << " " << __FUNCTION__ << "()"
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           << " save_id = " << save_id
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           << " save_url = \"" << save_url.spec() << "\""
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           << " is_success = " << is_success;
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveFileMap::iterator it = save_file_map_.find(save_id);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it != save_file_map_.end()) {
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SaveFile* save_file = it->second;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This routine may be called twice for the same from from
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // SaveePackage::OnReceivedSerializedHtmlData, once for the file
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // itself, and once when all frames have been serialized.
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // So we can't assert that the file is InProgress() here.
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(rdsmith): Fix this logic and put the DCHECK below back in.
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // DCHECK(save_file->InProgress());
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(20) << " " << __FUNCTION__ << "()"
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             << " save_file = " << save_file->DebugString();
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::UI, FROM_HERE,
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&SaveFileManager::OnSaveFinished, this, save_id,
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            save_file->BytesSoFar(), is_success));
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    save_file->Finish();
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    save_file->Detach();
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (save_id == -1) {
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Before saving started, we got error. We still call finish process.
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!save_url.is_empty());
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::UI, FROM_HERE,
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&SaveFileManager::OnErrorFinished, this, save_url,
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            render_process_id));
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Notifications sent from the file thread and run on the UI thread.
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SaveFileManager::OnStartSave(const SaveFileCreateInfo* info) {
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SavePackage* save_package =
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetSavePackageFromRenderIds(info->render_process_id,
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  info->render_view_id);
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!save_package) {
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Cancel this request.
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendCancelRequest(info->save_id);
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Insert started saving job to tracking list.
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SavePackageMap::iterator sit = packages_.find(info->save_id);
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (sit == packages_.end()) {
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Find the registered request. If we can not find, it means we have
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // canceled the job before.
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SavePackage* old_save_package = UnregisterStartingRequest(info->url,
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        info->render_process_id);
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!old_save_package) {
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Cancel this request.
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SendCancelRequest(info->save_id);
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(old_save_package, save_package);
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    packages_[info->save_id] = save_package;
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Forward this message to SavePackage.
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  save_package->StartSave(info);
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SaveFileManager::OnUpdateSaveProgress(int save_id, int64 bytes_so_far,
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           bool write_success) {
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SavePackage* package = LookupPackage(save_id);
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (package)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    package->UpdateSaveProgress(save_id, bytes_so_far, write_success);
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendCancelRequest(save_id);
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SaveFileManager::OnSaveFinished(int save_id,
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     int64 bytes_so_far,
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     bool is_success) {
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SavePackage* package = LookupPackage(save_id);
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (package)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    package->SaveFinished(save_id, bytes_so_far, is_success);
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SaveFileManager::OnErrorFinished(const GURL& save_url, int contents_id) {
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SavePackage* save_package = UnregisterStartingRequest(save_url, contents_id);
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (save_package)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    save_package->SaveFailed(save_url);
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Notifications sent from the UI thread and run on the IO thread.
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SaveFileManager::OnSaveURL(
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Referrer& referrer,
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int render_process_host_id,
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int render_view_id,
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ResourceContext* context) {
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ResourceDispatcherHostImpl::Get()->BeginSaveFile(url,
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   referrer,
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   render_process_host_id,
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   render_view_id,
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   context);
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SaveFileManager::OnRequireSaveJobFromOtherSource(
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SaveFileCreateInfo* info) {
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(info->save_id, -1);
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Generate a unique save id.
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info->save_id = GetNextId();
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start real saving action.
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::FILE, FROM_HERE,
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&SaveFileManager::StartSave, this, info));
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SaveFileManager::ExecuteCancelSaveRequest(int render_process_id,
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               int request_id) {
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ResourceDispatcherHostImpl::Get()->CancelRequest(
3935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      render_process_id, request_id);
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Notifications sent from the UI thread and run on the file thread.
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This method will be sent via a user action, or shutdown on the UI thread,
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and run on the file thread. We don't post a message back for cancels,
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// but we do forward the cancel to the IO thread. Since this message has been
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// sent from the UI thread, the saving job may have already completed and
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// won't exist in our map.
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SaveFileManager::CancelSave(int save_id) {
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveFileMap::iterator it = save_file_map_.find(save_id);
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it != save_file_map_.end()) {
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SaveFile* save_file = it->second;
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!save_file->InProgress()) {
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We've won a race with the UI thread--we finished the file before
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the UI thread cancelled it on us.  Unfortunately, in this situation
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the cancel wins, so we need to delete the now detached file.
4137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      base::DeleteFile(save_file->FullPath(), false);
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (save_file->save_source() ==
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               SaveFileCreateInfo::SAVE_FILE_FROM_NET) {
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If the data comes from the net IO thread and hasn't completed
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // yet, then forward the cancel message to IO thread & cancel the
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // save locally.  If the data doesn't come from the IO thread,
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // we can ignore the message.
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::PostTask(
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          BrowserThread::IO, FROM_HERE,
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&SaveFileManager::ExecuteCancelSaveRequest, this,
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              save_file->render_process_id(), save_file->request_id()));
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Whatever the save file is complete or not, just delete it.  This
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // will delete the underlying file if InProgress() is true.
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    save_file_map_.erase(it);
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete save_file;
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It is possible that SaveItem which has specified save_id has been canceled
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// before this function runs. So if we can not find corresponding SaveFile by
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// using specified save_id, just return.
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SaveFileManager::SaveLocalFile(const GURL& original_file_url,
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    int save_id,
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    int render_process_id) {
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveFile* save_file = LookupSaveFile(save_id);
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!save_file)
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If it has finished, just return.
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!save_file->InProgress())
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Close the save file before the copy operation.
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  save_file->Finish();
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  save_file->Detach();
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(original_file_url.SchemeIsFile());
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath file_path;
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::FileURLToFilePath(original_file_url, &file_path);
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we can not get valid file path from original URL, treat it as
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // disk error.
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (file_path.empty())
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SaveFinished(save_id, original_file_url, render_process_id, false);
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Copy the local file to the temporary file. It will be renamed to its
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // final name later.
4617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  bool success = base::CopyFile(file_path, save_file->FullPath());
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!success)
4637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    base::DeleteFile(save_file->FullPath(), false);
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveFinished(save_id, original_file_url, render_process_id, success);
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SaveFileManager::OnDeleteDirectoryOrFile(const base::FilePath& full_path,
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              bool is_dir) {
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!full_path.empty());
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::DeleteFile(full_path, is_dir);
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SaveFileManager::RenameAllFiles(
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const FinalNameList& final_names,
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& resource_dir,
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int render_process_id,
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int render_view_id,
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int save_package_id) {
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!resource_dir.empty() && !base::PathExists(resource_dir))
484a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    base::CreateDirectory(resource_dir);
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (FinalNameList::const_iterator i = final_names.begin();
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      i != final_names.end(); ++i) {
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SaveFileMap::iterator it = save_file_map_.find(i->first);
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (it != save_file_map_.end()) {
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SaveFile* save_file = it->second;
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(!save_file->InProgress());
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      save_file->Rename(i->second);
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delete save_file;
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      save_file_map_.erase(it);
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::UI, FROM_HERE,
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&SaveFileManager::OnFinishSavePageJob, this,
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          render_process_id, render_view_id, save_package_id));
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SaveFileManager::OnFinishSavePageJob(int render_process_id,
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          int render_view_id,
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          int save_package_id) {
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SavePackage* save_package =
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetSavePackageFromRenderIds(render_process_id, render_view_id);
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (save_package && save_package->id() == save_package_id)
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    save_package->Finish();
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SaveFileManager::RemoveSavedFileFromFileMap(
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SaveIDList& save_ids) {
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (SaveIDList::const_iterator i = save_ids.begin();
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      i != save_ids.end(); ++i) {
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SaveFileMap::iterator it = save_file_map_.find(*i);
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (it != save_file_map_.end()) {
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SaveFile* save_file = it->second;
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(!save_file->InProgress());
5267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      base::DeleteFile(save_file->FullPath(), false);
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delete save_file;
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      save_file_map_.erase(it);
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace content
534