Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(451)

Side by Side Diff: chrome/browser/download/download_history.cc

Issue 10915180: Make DownloadHistory observe manager, items (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698