blob: 426a4345ff1717053737253bfb607ed3f27efaca [file] [log] [blame]
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/download/download_history.h"
#include "base/logging.h"
#include "chrome/browser/download/chrome_download_manager_delegate.h"
#include "chrome/browser/history/history_marshaling.h"
#include "chrome/browser/profiles/profile.h"
#include "content/browser/download/download_item.h"
#include "content/browser/download/download_persistent_store_info.h"
DownloadHistory::DownloadHistory(Profile* profile)
: profile_(profile),
next_fake_db_handle_(DownloadItem::kUninitializedHandle - 1) {
DCHECK(profile);
}
DownloadHistory::~DownloadHistory() {
// For any outstanding requests to
// HistoryService::GetVisibleVisitCountToHost(), since they'll be cancelled
// and thus not call back to OnGotVisitCountToHost(), we need to delete the
// associated VisitedBeforeDoneCallbacks.
for (VisitedBeforeRequestsMap::iterator i(visited_before_requests_.begin());
i != visited_before_requests_.end(); ++i)
delete i->second.second;
}
void DownloadHistory::GetNextId(
HistoryService::DownloadNextIdCallback* callback) {
DCHECK(callback);
HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
if (!hs) {
delete callback;
return;
}
hs->GetNextDownloadId(&history_consumer_, callback);
}
void DownloadHistory::Load(HistoryService::DownloadQueryCallback* callback) {
DCHECK(callback);
HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
if (!hs) {
delete callback;
return;
}
hs->QueryDownloads(&history_consumer_, callback);
// This is the initial load, so do a cleanup of corrupt in-progress entries.
hs->CleanUpInProgressEntries();
}
void DownloadHistory::CheckVisitedReferrerBefore(
int32 download_id,
const GURL& referrer_url,
VisitedBeforeDoneCallback* callback) {
DCHECK(callback);
if (referrer_url.is_valid()) {
HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
if (hs) {
HistoryService::Handle handle =
hs->GetVisibleVisitCountToHost(referrer_url, &history_consumer_,
NewCallback(this, &DownloadHistory::OnGotVisitCountToHost));
visited_before_requests_[handle] = std::make_pair(download_id, callback);
return;
}
}
callback->Run(download_id, false);
delete callback;
}
void DownloadHistory::AddEntry(
DownloadItem* download_item,
HistoryService::DownloadCreateCallback* callback) {
DCHECK(download_item);
// Do not store the download in the history database for a few special cases:
// - incognito mode (that is the point of this mode)
// - extensions (users don't think of extension installation as 'downloading')
// - temporary download, like in drag-and-drop
// - history service is not available (e.g. in tests)
// We have to make sure that these handles don't collide with normal db
// handles, so we use a negative value. Eventually, they could overlap, but
// you'd have to do enough downloading that your ISP would likely stab you in
// the neck first. YMMV.
HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
if (download_item->is_otr() ||
ChromeDownloadManagerDelegate::IsExtensionDownload(download_item) ||
download_item->is_temporary() || !hs) {
callback->RunWithParams(
history::DownloadCreateRequest::TupleType(download_item->id(),
GetNextFakeDbHandle()));
delete callback;
return;
}
int32 id = download_item->id();
DownloadPersistentStoreInfo history_info =
download_item->GetPersistentStoreInfo();
hs->CreateDownload(id, history_info, &history_consumer_, callback);
}
void DownloadHistory::UpdateEntry(DownloadItem* download_item) {
// Don't store info in the database if the download was initiated while in
// incognito mode or if it hasn't been initialized in our database table.
if (download_item->db_handle() <= DownloadItem::kUninitializedHandle)
return;
HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
if (!hs)
return;
hs->UpdateDownload(download_item->received_bytes(),
download_item->state(),
download_item->db_handle());
}
void DownloadHistory::UpdateDownloadPath(DownloadItem* download_item,
const FilePath& new_path) {
// No update necessary if the download was initiated while in incognito mode.
if (download_item->db_handle() <= DownloadItem::kUninitializedHandle)
return;
HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
if (hs)
hs->UpdateDownloadPath(new_path, download_item->db_handle());
}
void DownloadHistory::RemoveEntry(DownloadItem* download_item) {
// No update necessary if the download was initiated while in incognito mode.
if (download_item->db_handle() <= DownloadItem::kUninitializedHandle)
return;
HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
if (hs)
hs->RemoveDownload(download_item->db_handle());
}
void DownloadHistory::RemoveEntriesBetween(const base::Time remove_begin,
const base::Time remove_end) {
HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
if (hs)
hs->RemoveDownloadsBetween(remove_begin, remove_end);
}
int64 DownloadHistory::GetNextFakeDbHandle() {
return next_fake_db_handle_--;
}
void DownloadHistory::OnGotVisitCountToHost(HistoryService::Handle handle,
bool found_visits,
int count,
base::Time first_visit) {
VisitedBeforeRequestsMap::iterator request =
visited_before_requests_.find(handle);
DCHECK(request != visited_before_requests_.end());
int32 download_id = request->second.first;
VisitedBeforeDoneCallback* callback = request->second.second;
visited_before_requests_.erase(request);
callback->Run(download_id, found_visits && count &&
(first_visit.LocalMidnight() < base::Time::Now().LocalMidnight()));
delete callback;
}