| // Copyright (c) 2012 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/download_crx_util.h" |
| #include "chrome/browser/history/history_marshaling.h" |
| #include "chrome/browser/history/history_service_factory.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "content/public/browser/download_item.h" |
| #include "content/public/browser/download_persistent_store_info.h" |
| |
| using content::DownloadItem; |
| using content::DownloadPersistentStoreInfo; |
| |
| DownloadHistory::DownloadHistory(Profile* profile) |
| : profile_(profile), |
| next_fake_db_handle_(DownloadItem::kUninitializedHandle - 1) { |
| DCHECK(profile); |
| } |
| |
| DownloadHistory::~DownloadHistory() {} |
| |
| void DownloadHistory::GetNextId( |
| const HistoryService::DownloadNextIdCallback& callback) { |
| HistoryService* hs = HistoryServiceFactory::GetForProfile( |
| profile_, Profile::EXPLICIT_ACCESS); |
| if (!hs) |
| return; |
| |
| hs->GetNextDownloadId(&history_consumer_, callback); |
| } |
| |
| void DownloadHistory::Load( |
| const HistoryService::DownloadQueryCallback& callback) { |
| HistoryService* hs = HistoryServiceFactory::GetForProfile( |
| profile_, Profile::EXPLICIT_ACCESS); |
| if (!hs) |
| 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, |
| const VisitedBeforeDoneCallback& callback) { |
| if (referrer_url.is_valid()) { |
| HistoryService* hs = HistoryServiceFactory::GetForProfileIfExists( |
| profile_, Profile::EXPLICIT_ACCESS); |
| if (hs) { |
| HistoryService::Handle handle = |
| hs->GetVisibleVisitCountToHost(referrer_url, &history_consumer_, |
| base::Bind(&DownloadHistory::OnGotVisitCountToHost, |
| base::Unretained(this))); |
| visited_before_requests_[handle] = callback; |
| return; |
| } |
| } |
| callback.Run(false); |
| } |
| |
| void DownloadHistory::AddEntry( |
| DownloadItem* download_item, |
| const 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 = HistoryServiceFactory::GetForProfileIfExists( |
| profile_, Profile::EXPLICIT_ACCESS); |
| if (download_crx_util::IsExtensionDownload(*download_item) || |
| download_item->IsTemporary() || !hs) { |
| callback.Run(download_item->GetId(), GetNextFakeDbHandle()); |
| return; |
| } |
| |
| int32 id = download_item->GetId(); |
| 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->GetDbHandle() <= DownloadItem::kUninitializedHandle) |
| return; |
| |
| HistoryService* hs = HistoryServiceFactory::GetForProfileIfExists( |
| profile_, Profile::EXPLICIT_ACCESS); |
| if (!hs) |
| return; |
| hs->UpdateDownload(download_item->GetPersistentStoreInfo()); |
| } |
| |
| 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->GetDbHandle() <= DownloadItem::kUninitializedHandle) |
| return; |
| |
| HistoryService* hs = HistoryServiceFactory::GetForProfileIfExists( |
| profile_, Profile::EXPLICIT_ACCESS); |
| if (hs) |
| hs->UpdateDownloadPath(new_path, download_item->GetDbHandle()); |
| } |
| |
| void DownloadHistory::RemoveEntry(DownloadItem* download_item) { |
| // No update necessary if the download was initiated while in incognito mode. |
| if (download_item->GetDbHandle() <= DownloadItem::kUninitializedHandle) |
| return; |
| |
| HistoryService* hs = HistoryServiceFactory::GetForProfileIfExists( |
| profile_, Profile::EXPLICIT_ACCESS); |
| if (hs) |
| hs->RemoveDownload(download_item->GetDbHandle()); |
| } |
| |
| void DownloadHistory::RemoveEntriesBetween(const base::Time remove_begin, |
| const base::Time remove_end) { |
| HistoryService* hs = HistoryServiceFactory::GetForProfileIfExists( |
| profile_, 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()); |
| VisitedBeforeDoneCallback callback = request->second; |
| visited_before_requests_.erase(request); |
| callback.Run(found_visits && count && |
| (first_visit.LocalMidnight() < base::Time::Now().LocalMidnight())); |
| } |