OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
| 5 // DownloadHistory manages persisting DownloadItems to the history service by |
| 6 // observing a single DownloadManager and all its DownloadItems. |
| 7 // DownloadHistory decides whether and when to add items to, remove items from, |
| 8 // and update items in the database. DownloadHistory uses DownloadHistoryData to |
| 9 // store per-DownloadItem data such as its db_handle, whether the item is being |
| 10 // added and waiting for its db_handle, and the last DownloadPersistentStoreInfo |
| 11 // that was passed to the database. When the DownloadManager and its delegate |
| 12 // (ChromeDownloadManagerDelegate) are initialized, DownloadHistory is created |
| 13 // and queries the HistoryService. When the HistoryService calls back from |
| 14 // QueryDownloads() to QueryCallback(), DownloadHistory uses |
| 15 // DownloadManager::CreateDownloadItem() to inform DownloadManager of these |
| 16 // persisted DownloadItems. CreateDownloadItem() internally calls |
| 17 // OnDownloadCreated(), which normally adds items to the database, so |
| 18 // QueryCallback() uses |loading_db_handle_| to disable adding these items to |
| 19 // the database as it matches them up with their db_handles. If a download is |
| 20 // removed via OnDownloadRemoved() while the item is still being added to the |
| 21 // database, DownloadHistory uses |removed_while_adding_| to remember to remove |
| 22 // the item when its ItemAdded() callback is called. All callbacks are bound |
| 23 // with a weak pointer to DownloadHistory to prevent use-after-free bugs. |
| 24 // ChromeDownloadManagerDelegate owns DownloadHistory, and deletes it in |
| 25 // Shutdown(), which is called by DownloadManagerImpl::Shutdown() after all |
| 26 // DownloadItems are destroyed. |
| 27 |
5 #include "chrome/browser/download/download_history.h" | 28 #include "chrome/browser/download/download_history.h" |
6 | 29 |
7 #include "base/logging.h" | 30 #include "base/metrics/histogram.h" |
8 #include "chrome/browser/download/download_crx_util.h" | 31 #include "chrome/browser/download/download_crx_util.h" |
9 #include "chrome/browser/history/history_marshaling.h" | 32 #include "chrome/browser/history/download_database.h" |
10 #include "chrome/browser/history/history_service_factory.h" | 33 #include "chrome/browser/history/download_persistent_store_info.h" |
11 #include "chrome/browser/profiles/profile.h" | 34 #include "content/public/browser/browser_thread.h" |
12 #include "content/public/browser/download_item.h" | 35 #include "content/public/browser/download_item.h" |
13 #include "content/public/browser/download_persistent_store_info.h" | 36 #include "content/public/browser/download_manager.h" |
14 | 37 |
| 38 using content::BrowserThread; |
15 using content::DownloadItem; | 39 using content::DownloadItem; |
16 using content::DownloadPersistentStoreInfo; | 40 using content::DownloadManager; |
17 | 41 |
18 DownloadHistory::DownloadHistory(Profile* profile) | 42 namespace { |
19 : profile_(profile), | 43 |
20 next_fake_db_handle_(DownloadItem::kUninitializedHandle - 1) { | 44 // Per-DownloadItem data. This information does not belong inside DownloadItem, |
21 DCHECK(profile); | 45 // and keeping maps in DownloadHistory from DownloadItem to this information is |
22 } | 46 // error-prone and complicated. Unfortunately, DownloadHistory::removing_ and |
23 | 47 // removed_while_adding_ cannot be moved into this class partly because |
24 DownloadHistory::~DownloadHistory() {} | 48 // DownloadHistoryData is destroyed when DownloadItems are destroyed, and we |
25 | 49 // have no control over when DownloadItems are destroyed. |
26 void DownloadHistory::GetNextId( | 50 class DownloadHistoryData : public base::SupportsUserData::Data { |
27 const HistoryService::DownloadNextIdCallback& callback) { | 51 public: |
28 HistoryService* hs = HistoryServiceFactory::GetForProfile( | 52 static DownloadHistoryData* Get(DownloadItem* item) { |
29 profile_, Profile::EXPLICIT_ACCESS); | 53 base::SupportsUserData::Data* data = item->GetUserData(kKey); |
30 if (!hs) | 54 return (data == NULL) ? NULL : |
31 return; | 55 static_cast<DownloadHistoryData*>(data); |
32 | 56 } |
33 hs->GetNextDownloadId(&history_consumer_, callback); | 57 |
34 } | 58 DownloadHistoryData(DownloadItem* item, int64 handle) |
35 | 59 : is_adding_(false), |
36 void DownloadHistory::Load( | 60 db_handle_(handle), |
37 const HistoryService::DownloadQueryCallback& callback) { | 61 info_(NULL) { |
38 HistoryService* hs = HistoryServiceFactory::GetForProfile( | 62 item->SetUserData(kKey, this); |
39 profile_, Profile::EXPLICIT_ACCESS); | 63 } |
40 if (!hs) | 64 |
41 return; | 65 virtual ~DownloadHistoryData() { |
42 | 66 } |
43 hs->QueryDownloads(&history_consumer_, callback); | 67 |
44 | 68 // Whether this item is currently being added to the database. |
45 // This is the initial load, so do a cleanup of corrupt in-progress entries. | 69 bool is_adding() const { return is_adding_; } |
46 hs->CleanUpInProgressEntries(); | 70 void set_is_adding(bool a) { is_adding_ = a; } |
| 71 |
| 72 // Whether this item is already persisted in the database. |
| 73 bool is_persisted() const { |
| 74 return db_handle_ != history::DownloadDatabase::kUninitializedHandle; |
| 75 } |
| 76 |
| 77 int64 db_handle() const { return db_handle_; } |
| 78 void set_db_handle(int64 h) { db_handle_ = h; } |
| 79 |
| 80 // This allows DownloadHistory::OnDownloadUpdated() to see what changed in a |
| 81 // DownloadItem if anything, in order to prevent writing to the database |
| 82 // unnecessarily. It is nullified when the item is no longer in progress in |
| 83 // order to save memory. |
| 84 DownloadPersistentStoreInfo* info() { return info_.get(); } |
| 85 void set_info(const DownloadPersistentStoreInfo& i) { |
| 86 info_.reset(new DownloadPersistentStoreInfo(i)); |
| 87 } |
| 88 void clear_info() { |
| 89 info_.reset(); |
| 90 } |
| 91 |
| 92 private: |
| 93 static const char kKey[]; |
| 94 |
| 95 bool is_adding_; |
| 96 int64 db_handle_; |
| 97 scoped_ptr<DownloadPersistentStoreInfo> info_; |
| 98 |
| 99 DISALLOW_COPY_AND_ASSIGN(DownloadHistoryData); |
| 100 }; |
| 101 |
| 102 const char DownloadHistoryData::kKey[] = |
| 103 "DownloadItem DownloadHistoryData"; |
| 104 |
| 105 DownloadPersistentStoreInfo GetPersistentStoreInfo(DownloadItem* item) { |
| 106 DownloadHistoryData* dhd = DownloadHistoryData::Get(item); |
| 107 return DownloadPersistentStoreInfo( |
| 108 item->GetFullPath(), |
| 109 item->GetURL(), |
| 110 item->GetReferrerUrl(), |
| 111 item->GetStartTime(), |
| 112 item->GetEndTime(), |
| 113 item->GetReceivedBytes(), |
| 114 item->GetTotalBytes(), |
| 115 item->GetState(), |
| 116 ((dhd != NULL) ? dhd->db_handle() |
| 117 : history::DownloadDatabase::kUninitializedHandle), |
| 118 item->GetOpened()); |
| 119 } |
| 120 |
| 121 typedef std::vector<DownloadPersistentStoreInfo> InfoVector; |
| 122 |
| 123 // The HistoryService would normally use CancelableRequestConsumer to ensure |
| 124 // that callbacks from the HistoryService are run on the same thread that issued |
| 125 // the request, but DownloadHistory has opted for less magic by relying on |
| 126 // WeakPtrs instead, so it uses Ensure*OnUI to explicitly bounce to the UI |
| 127 // thread. |
| 128 void EnsureQueryOnUI( |
| 129 const base::Callback<void(scoped_ptr<InfoVector>)>& callback, |
| 130 scoped_ptr<InfoVector> infos) { |
| 131 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| 132 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( |
| 133 callback, base::Passed(infos.Pass()))); |
| 134 return; |
| 135 } |
| 136 callback.Run(infos.Pass()); |
| 137 } |
| 138 |
| 139 void EnsureItemAddedOnUI(const base::Callback<void(int64)>& callback, |
| 140 int64 handle) { |
| 141 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| 142 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( |
| 143 callback, handle)); |
| 144 return; |
| 145 } |
| 146 callback.Run(handle); |
| 147 } |
| 148 |
| 149 void EnsureVisitedOnUI( |
| 150 const base::Callback<void(bool, int, base::Time)>& callback, |
| 151 bool success, int count, base::Time first_visit) { |
| 152 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| 153 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( |
| 154 callback, success, count, first_visit)); |
| 155 return; |
| 156 } |
| 157 callback.Run(success, count, first_visit); |
| 158 } |
| 159 |
| 160 } // anonymous namespace |
| 161 |
| 162 DownloadHistory::DownloadHistory( |
| 163 DownloadManager* manager, |
| 164 HistoryService* history) |
| 165 : manager_(manager), |
| 166 history_(history), |
| 167 loading_db_handle_(history::DownloadDatabase::kUninitializedHandle), |
| 168 history_size_(0), |
| 169 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { |
| 170 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 171 DCHECK(manager_); |
| 172 manager_->AddObserver(this); |
| 173 DownloadManager::DownloadVector items; |
| 174 manager_->GetAllDownloads(&items); |
| 175 for (DownloadManager::DownloadVector::const_iterator it = items.begin(); |
| 176 it != items.end(); ++it) { |
| 177 OnDownloadCreated(manager_, *it); |
| 178 } |
| 179 history_->QueryDownloads(base::Bind(&EnsureQueryOnUI, base::Bind( |
| 180 &DownloadHistory::QueryCallback, weak_ptr_factory_.GetWeakPtr()))); |
| 181 } |
| 182 |
| 183 DownloadHistory::~DownloadHistory() { |
| 184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 185 for (ItemSet::const_iterator iter = observing_items_.begin(); |
| 186 iter != observing_items_.end(); ++iter) { |
| 187 (*iter)->RemoveObserver(this); |
| 188 } |
| 189 observing_items_.clear(); |
| 190 if (manager_) |
| 191 manager_->RemoveObserver(this); |
| 192 } |
| 193 |
| 194 void DownloadHistory::QueryCallback(scoped_ptr<InfoVector> infos) { |
| 195 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 196 // ManagerGoingDown() may have happened before the history loaded. |
| 197 if (!manager_) |
| 198 return; |
| 199 for (InfoVector::const_iterator it = infos->begin(); |
| 200 it != infos->end(); ++it) { |
| 201 // OnDownloadCreated() is called inside DM::CreateDownloadItem(), so set |
| 202 // loading_db_handle_ to match up the created item with its db_handle. All |
| 203 // methods run on the UI thread and CreateDownloadItem() is synchronous. |
| 204 loading_db_handle_ = it->db_handle; |
| 205 DownloadItem* download_item = manager_->CreateDownloadItem( |
| 206 it->path, |
| 207 it->url, |
| 208 it->referrer_url, |
| 209 it->start_time, |
| 210 it->end_time, |
| 211 it->received_bytes, |
| 212 it->total_bytes, |
| 213 it->state, |
| 214 it->opened); |
| 215 DownloadHistoryData* dhd = DownloadHistoryData::Get(download_item); |
| 216 |
| 217 // If this DCHECK fails, then you probably added an Observer that |
| 218 // synchronously creates a DownloadItem in response to |
| 219 // DownloadManager::OnDownloadCreated(), and your observer runs before |
| 220 // DownloadHistory, and DownloadManager creates items synchronously. Just |
| 221 // bounce your DownloadItem creation off the message loop to flush |
| 222 // DownloadHistory::OnDownloadCreated. |
| 223 DCHECK_EQ(it->db_handle, dhd->db_handle()); |
| 224 ++history_size_; |
| 225 } |
| 226 manager_->CheckForHistoryFilesRemoval(); |
| 227 } |
| 228 |
| 229 void DownloadHistory::OnDownloadCreated( |
| 230 DownloadManager* manager, DownloadItem* item) { |
| 231 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 232 |
| 233 // Observe even temporary downloads in case they are marked not temporary. |
| 234 item->AddObserver(this); |
| 235 observing_items_.insert(item); |
| 236 // All downloads should pass through OnDownloadCreated exactly once. |
| 237 CHECK(!DownloadHistoryData::Get(item)); |
| 238 DownloadHistoryData* dhd = new DownloadHistoryData(item, loading_db_handle_); |
| 239 loading_db_handle_ = history::DownloadDatabase::kUninitializedHandle; |
| 240 if (item->GetState() == DownloadItem::IN_PROGRESS) { |
| 241 dhd->set_info(GetPersistentStoreInfo(item)); |
| 242 } |
| 243 MaybeAddToHistory(item); |
| 244 } |
| 245 |
| 246 void DownloadHistory::MaybeAddToHistory(DownloadItem* item) { |
| 247 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 248 int32 download_id = item->GetId(); |
| 249 DownloadHistoryData* dhd = DownloadHistoryData::Get(item); |
| 250 bool removing = (removing_.find(dhd->db_handle()) != removing_.end()); |
| 251 // TODO(benjhayden): Remove IsTemporary(). |
| 252 if (download_crx_util::IsExtensionDownload(*item) || |
| 253 dhd->is_persisted() || |
| 254 item->IsTemporary() || |
| 255 removing || |
| 256 dhd->is_adding()) |
| 257 return; |
| 258 dhd->set_is_adding(true); |
| 259 if (dhd->info() == NULL) { |
| 260 // Keep the info here regardless of whether the item is in progress so |
| 261 // that, when ItemAdded() calls OnDownloadUpdated(), it can choose more |
| 262 // intelligently whether to Update the db and/or discard the info. |
| 263 dhd->set_info(GetPersistentStoreInfo(item)); |
| 264 } |
| 265 history_->CreateDownload(*dhd->info(), base::Bind( |
| 266 &EnsureItemAddedOnUI, base::Bind( |
| 267 &DownloadHistory::ItemAdded, weak_ptr_factory_.GetWeakPtr(), |
| 268 download_id))); |
| 269 } |
| 270 |
| 271 void DownloadHistory::ItemAdded(int32 download_id, int64 db_handle) { |
| 272 if (removed_while_adding_.find(download_id) != |
| 273 removed_while_adding_.end()) { |
| 274 removed_while_adding_.erase(download_id); |
| 275 if (removing_.empty()) { |
| 276 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 277 base::Bind(&DownloadHistory::RemoveDownloadsBatch, |
| 278 weak_ptr_factory_.GetWeakPtr())); |
| 279 } |
| 280 removing_.insert(db_handle); |
| 281 return; |
| 282 } |
| 283 |
| 284 if (!manager_) |
| 285 return; |
| 286 |
| 287 DownloadItem* item = manager_->GetDownload(download_id); |
| 288 if (!item) { |
| 289 // This item will have called OnDownloadDestroyed(). If the item should |
| 290 // have been removed from history, then it would have also called |
| 291 // OnDownloadRemoved(), which would have put |download_id| in |
| 292 // removed_while_adding_, handled above. |
| 293 return; |
| 294 } |
| 295 |
| 296 UMA_HISTOGRAM_CUSTOM_COUNTS("Download.HistorySize2", |
| 297 history_size_, |
| 298 0/*min*/, |
| 299 (1 << 23)/*max*/, |
| 300 (1 << 7)/*num_buckets*/); |
| 301 ++history_size_; |
| 302 |
| 303 DownloadHistoryData* dhd = DownloadHistoryData::Get(item); |
| 304 dhd->set_is_adding(false); |
| 305 DCHECK_NE(db_handle, history::DownloadDatabase::kUninitializedHandle); |
| 306 dhd->set_db_handle(db_handle); |
| 307 |
| 308 // In case the item changed or became temporary while it was being added. |
| 309 // Don't just update all of the item's observers because we're the only |
| 310 // observer that can also see db_handle, which is the only thing that |
| 311 // ItemAdded changed. |
| 312 OnDownloadUpdated(item); |
| 313 } |
| 314 |
| 315 void DownloadHistory::OnDownloadUpdated(DownloadItem* item) { |
| 316 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 317 |
| 318 DownloadHistoryData* dhd = DownloadHistoryData::Get(item); |
| 319 if (!dhd->is_persisted()) { |
| 320 MaybeAddToHistory(item); |
| 321 return; |
| 322 } |
| 323 if (item->IsTemporary()) { |
| 324 OnDownloadRemoved(item); |
| 325 return; |
| 326 } |
| 327 |
| 328 // TODO(asanka): Persist GetTargetFilePath() as well. |
| 329 DownloadPersistentStoreInfo current_info(GetPersistentStoreInfo(item)); |
| 330 DownloadPersistentStoreInfo* previous_info = dhd->info(); |
| 331 bool do_update = ( |
| 332 (previous_info == NULL) || |
| 333 (previous_info->path != current_info.path) || |
| 334 (previous_info->end_time != current_info.end_time) || |
| 335 (previous_info->received_bytes != current_info.received_bytes) || |
| 336 (previous_info->total_bytes != current_info.total_bytes) || |
| 337 (previous_info->state != current_info.state) || |
| 338 (previous_info->opened != current_info.opened)); |
| 339 UMA_HISTOGRAM_ENUMERATION("Download.HistoryPropagatedUpdate", do_update, 2); |
| 340 if (do_update) |
| 341 history_->UpdateDownload(current_info); |
| 342 if (item->GetState() == DownloadItem::IN_PROGRESS) { |
| 343 dhd->set_info(current_info); |
| 344 } else { |
| 345 dhd->clear_info(); |
| 346 } |
| 347 } |
| 348 |
| 349 // Downloads may be opened after they are completed. |
| 350 void DownloadHistory::OnDownloadOpened(DownloadItem* item) { |
| 351 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 352 DownloadHistoryData* dhd = DownloadHistoryData::Get(item); |
| 353 if (!dhd->is_persisted()) { |
| 354 MaybeAddToHistory(item); |
| 355 return; |
| 356 } |
| 357 if (item->IsTemporary()) { |
| 358 OnDownloadRemoved(item); |
| 359 return; |
| 360 } |
| 361 |
| 362 DownloadPersistentStoreInfo current_info(GetPersistentStoreInfo(item)); |
| 363 history_->UpdateDownload(current_info); |
| 364 if (item->GetState() == DownloadItem::IN_PROGRESS) { |
| 365 dhd->set_info(current_info); |
| 366 } |
| 367 } |
| 368 |
| 369 void DownloadHistory::OnDownloadRemoved(DownloadItem* item) { |
| 370 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 371 |
| 372 DownloadHistoryData* dhd = DownloadHistoryData::Get(item); |
| 373 if (!dhd->is_persisted()) { |
| 374 if (dhd->is_adding()) { |
| 375 removed_while_adding_.insert(item->GetId()); |
| 376 } |
| 377 return; |
| 378 } |
| 379 |
| 380 // For database efficiency, batch removals together if they happen all at |
| 381 // once. |
| 382 if (removing_.empty()) { |
| 383 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 384 base::Bind(&DownloadHistory::RemoveDownloadsBatch, |
| 385 weak_ptr_factory_.GetWeakPtr())); |
| 386 } |
| 387 removing_.insert(dhd->db_handle()); |
| 388 dhd->set_db_handle(history::DownloadDatabase::kUninitializedHandle); |
| 389 --history_size_; |
| 390 } |
| 391 |
| 392 void DownloadHistory::RemoveDownloadsBatch() { |
| 393 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 394 HandleSet remove_handles; |
| 395 removing_.swap(remove_handles); |
| 396 history_->RemoveDownloads(remove_handles); |
| 397 } |
| 398 |
| 399 void DownloadHistory::ManagerGoingDown(DownloadManager* manager) { |
| 400 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 401 DCHECK_EQ(manager_, manager); |
| 402 manager_->RemoveObserver(this); |
| 403 manager_ = NULL; |
| 404 } |
| 405 |
| 406 void DownloadHistory::OnDownloadDestroyed(DownloadItem* item) { |
| 407 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 408 item->RemoveObserver(this); |
| 409 observing_items_.erase(item); |
47 } | 410 } |
48 | 411 |
49 void DownloadHistory::CheckVisitedReferrerBefore( | 412 void DownloadHistory::CheckVisitedReferrerBefore( |
50 int32 download_id, | 413 int32 download_id, |
51 const GURL& referrer_url, | 414 const GURL& referrer_url, |
52 const VisitedBeforeDoneCallback& callback) { | 415 const VisitedBeforeDoneCallback& callback) { |
53 if (referrer_url.is_valid()) { | 416 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
54 HistoryService* hs = HistoryServiceFactory::GetForProfileIfExists( | 417 if (!referrer_url.is_valid()) { |
55 profile_, Profile::EXPLICIT_ACCESS); | 418 callback.Run(false); |
56 if (hs) { | 419 return; |
57 HistoryService::Handle handle = | 420 } |
58 hs->GetVisibleVisitCountToHost(referrer_url, &history_consumer_, | 421 history_->GetVisibleVisitCountToHostSimple( |
59 base::Bind(&DownloadHistory::OnGotVisitCountToHost, | 422 referrer_url, |
60 base::Unretained(this))); | 423 base::Bind(&EnsureVisitedOnUI, base::Bind( |
61 visited_before_requests_[handle] = callback; | 424 &DownloadHistory::OnGotVisitCountToHost, |
62 return; | 425 weak_ptr_factory_.GetWeakPtr(), callback))); |
63 } | 426 } |
64 } | 427 |
65 callback.Run(false); | 428 void DownloadHistory::OnGotVisitCountToHost( |
66 } | 429 const VisitedBeforeDoneCallback& callback, |
67 | 430 bool found_visits, |
68 void DownloadHistory::AddEntry( | 431 int count, |
69 DownloadItem* download_item, | 432 base::Time first_visit) { |
70 const HistoryService::DownloadCreateCallback& callback) { | |
71 DCHECK(download_item); | |
72 // Do not store the download in the history database for a few special cases: | |
73 // - incognito mode (that is the point of this mode) | |
74 // - extensions (users don't think of extension installation as 'downloading') | |
75 // - temporary download, like in drag-and-drop | |
76 // - history service is not available (e.g. in tests) | |
77 // We have to make sure that these handles don't collide with normal db | |
78 // handles, so we use a negative value. Eventually, they could overlap, but | |
79 // you'd have to do enough downloading that your ISP would likely stab you in | |
80 // the neck first. YMMV. | |
81 HistoryService* hs = HistoryServiceFactory::GetForProfileIfExists( | |
82 profile_, Profile::EXPLICIT_ACCESS); | |
83 if (download_crx_util::IsExtensionDownload(*download_item) || | |
84 download_item->IsTemporary() || !hs) { | |
85 callback.Run(download_item->GetId(), GetNextFakeDbHandle()); | |
86 return; | |
87 } | |
88 | |
89 int32 id = download_item->GetId(); | |
90 DownloadPersistentStoreInfo history_info = | |
91 download_item->GetPersistentStoreInfo(); | |
92 hs->CreateDownload(id, history_info, &history_consumer_, callback); | |
93 } | |
94 | |
95 void DownloadHistory::UpdateEntry(DownloadItem* download_item) { | |
96 // Don't store info in the database if the download was initiated while in | |
97 // incognito mode or if it hasn't been initialized in our database table. | |
98 if (download_item->GetDbHandle() <= DownloadItem::kUninitializedHandle) | |
99 return; | |
100 | |
101 HistoryService* hs = HistoryServiceFactory::GetForProfileIfExists( | |
102 profile_, Profile::EXPLICIT_ACCESS); | |
103 if (!hs) | |
104 return; | |
105 hs->UpdateDownload(download_item->GetPersistentStoreInfo()); | |
106 } | |
107 | |
108 void DownloadHistory::UpdateDownloadPath(DownloadItem* download_item, | |
109 const FilePath& new_path) { | |
110 // No update necessary if the download was initiated while in incognito mode. | |
111 if (download_item->GetDbHandle() <= DownloadItem::kUninitializedHandle) | |
112 return; | |
113 | |
114 HistoryService* hs = HistoryServiceFactory::GetForProfileIfExists( | |
115 profile_, Profile::EXPLICIT_ACCESS); | |
116 if (hs) | |
117 hs->UpdateDownloadPath(new_path, download_item->GetDbHandle()); | |
118 } | |
119 | |
120 void DownloadHistory::RemoveEntry(DownloadItem* download_item) { | |
121 // No update necessary if the download was initiated while in incognito mode. | |
122 if (download_item->GetDbHandle() <= DownloadItem::kUninitializedHandle) | |
123 return; | |
124 | |
125 HistoryService* hs = HistoryServiceFactory::GetForProfileIfExists( | |
126 profile_, Profile::EXPLICIT_ACCESS); | |
127 if (hs) | |
128 hs->RemoveDownload(download_item->GetDbHandle()); | |
129 } | |
130 | |
131 void DownloadHistory::RemoveEntriesBetween(const base::Time remove_begin, | |
132 const base::Time remove_end) { | |
133 HistoryService* hs = HistoryServiceFactory::GetForProfileIfExists( | |
134 profile_, Profile::EXPLICIT_ACCESS); | |
135 if (hs) | |
136 hs->RemoveDownloadsBetween(remove_begin, remove_end); | |
137 } | |
138 | |
139 int64 DownloadHistory::GetNextFakeDbHandle() { | |
140 return next_fake_db_handle_--; | |
141 } | |
142 | |
143 void DownloadHistory::OnGotVisitCountToHost(HistoryService::Handle handle, | |
144 bool found_visits, | |
145 int count, | |
146 base::Time first_visit) { | |
147 VisitedBeforeRequestsMap::iterator request = | |
148 visited_before_requests_.find(handle); | |
149 DCHECK(request != visited_before_requests_.end()); | |
150 VisitedBeforeDoneCallback callback = request->second; | |
151 visited_before_requests_.erase(request); | |
152 callback.Run(found_visits && count && | 433 callback.Run(found_visits && count && |
153 (first_visit.LocalMidnight() < base::Time::Now().LocalMidnight())); | 434 (first_visit.LocalMidnight() < base::Time::Now().LocalMidnight())); |
154 } | 435 } |
OLD | NEW |