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

Side by Side Diff: components/password_manager/core/browser/affiliation_backend.cc

Issue 868253005: AffiliationBackend: Implement the better part of on-demand fetching. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Tidy up NULL time related issues. Created 5 years, 10 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
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 #include "components/password_manager/core/browser/affiliation_backend.h" 5 #include "components/password_manager/core/browser/affiliation_backend.h"
6 6
7 #include <stdint.h>
8
9 #include "base/bind.h"
10 #include "base/location.h"
7 #include "base/task_runner.h" 11 #include "base/task_runner.h"
12 #include "base/threading/thread_checker.h"
13 #include "base/time/clock.h"
14 #include "base/time/time.h"
15 #include "components/password_manager/core/browser/affiliation_database.h"
16 #include "components/password_manager/core/browser/affiliation_fetcher.h"
17 #include "net/url_request/url_request_context_getter.h"
8 18
9 namespace password_manager { 19 namespace password_manager {
10 20 namespace {
11 AffiliationBackend::AffiliationBackend() { 21
22 // The duration after which cached affiliation data is considered stale and will
23 // not be used to serve requests any longer.
24 const int kCacheLifetimeInHours = 24;
25
26 // RequestInfo ----------------------------------------------------------------
27
28 // Encapsulates the details of a pending GetAffiliations() request.
29 struct RequestInfo {
30 AffiliationService::ResultCallback callback;
31 scoped_refptr<base::TaskRunner> callback_task_runner;
32 };
33
34 } // namespace
35
36 // AffiliationBackend::FacetManager -------------------------------------------
37
38 // Manages and performs ongoing tasks concerning a single facet.
39 class AffiliationBackend::FacetManager {
40 public:
41 // The |backend| must outlive this object.
42 FacetManager(AffiliationBackend* backend, const FacetURI& facet_uri);
43 ~FacetManager();
44
45 // Called when |affiliation| information regarding this facet has just been
46 // fetched from the Affiliation API.
47 void OnFetchSucceeded(const AffiliatedFacetsWithUpdateTime& affiliation);
48
49 // Returns whether this instance has becomes redundant, that is, it has no
50 // more meaningful state than a newly created instance would have.
51 bool CanBeDiscarded() const;
52
53 // Returns whether or not affiliation information relating to this facet needs
54 // to be fetched right now.
55 bool DoesRequireFetch() const;
56
57 // Facet-specific implementations for methods in AffiliationService of the
58 // same name. See documentation in affiliation_service.h for details:
59 void GetAffiliations(bool cached_only, const RequestInfo& request_info);
60
61 private:
62 // Returns the time when cached data for this facet will expire. The data is
63 // already considered expired at the returned microsecond.
64 base::Time GetCacheExpirationTime() const;
65
66 // Returns whether or not the cache has fresh data for this facet.
67 bool IsCachedDataFresh() const;
68
69 // Posts the callback of the request described by |request_info| with success.
70 static void ServeRequestWithSuccess(const RequestInfo& request_info,
71 const AffiliatedFacets& affiliation);
72
73 // Posts the callback of the request described by |request_info| with failure.
74 static void ServeRequestWithFailure(const RequestInfo& request_info);
75
76 AffiliationBackend* backend_;
77 FacetURI facet_uri_;
78
79 // The last time affiliation information was fetched for this facet, i.e. the
80 // freshness of the data in the cache. If there is no corresponding data in
81 // the database, this will contain the NULL time. Otherwise, the update time
82 // in the database should match this value; it is stored to reduce disk I/O.
83 base::Time last_update_time_;
84
85 // Contains information about the GetAffiliations() requests that are waiting
86 // for the result of looking up this facet.
87 std::vector<RequestInfo> pending_requests_;
88
89 DISALLOW_COPY_AND_ASSIGN(FacetManager);
90 };
91
92 AffiliationBackend::FacetManager::FacetManager(AffiliationBackend* backend,
93 const FacetURI& facet_uri)
94 : backend_(backend),
95 facet_uri_(facet_uri),
96 last_update_time_(backend_->ReadLastUpdateTimeFromDatabase(facet_uri)) {
97 }
98
99 AffiliationBackend::FacetManager::~FacetManager() {
100 // The manager will only be destroyed while there are pending requests if the
101 // entire backend is going. Call failure on pending requests in this case.
102 for (const auto& request_info : pending_requests_)
103 ServeRequestWithFailure(request_info);
104 }
105
106 void AffiliationBackend::FacetManager::GetAffiliations(
107 bool cached_only,
108 const RequestInfo& request_info) {
109 if (IsCachedDataFresh()) {
110 AffiliatedFacetsWithUpdateTime affiliation;
111 if (!backend_->ReadAffiliationsFromDatabase(facet_uri_, &affiliation)) {
112 // TODO(engedy): Implement this. crbug.com/437865.
113 NOTIMPLEMENTED();
114 }
115 DCHECK_EQ(affiliation.last_update_time, last_update_time_) << facet_uri_;
116 ServeRequestWithSuccess(request_info, affiliation.facets);
117 } else if (cached_only) {
118 ServeRequestWithFailure(request_info);
119 } else {
120 pending_requests_.push_back(request_info);
121 backend_->SignalNeedNetworkRequest();
122 }
123 }
124
125 void AffiliationBackend::FacetManager::OnFetchSucceeded(
126 const AffiliatedFacetsWithUpdateTime& affiliation) {
127 last_update_time_ = affiliation.last_update_time;
128 DCHECK(IsCachedDataFresh()) << facet_uri_;
129 for (const auto& request_info : pending_requests_)
130 ServeRequestWithSuccess(request_info, affiliation.facets);
131 pending_requests_.clear();
132 }
133
134 bool AffiliationBackend::FacetManager::CanBeDiscarded() const {
135 return pending_requests_.empty();
136 }
137
138 bool AffiliationBackend::FacetManager::DoesRequireFetch() const {
139 return !pending_requests_.empty() && !IsCachedDataFresh();
140 }
141
142 base::Time AffiliationBackend::FacetManager::GetCacheExpirationTime() const {
143 if (last_update_time_.is_null())
144 return base::Time();
145 return last_update_time_ + base::TimeDelta::FromHours(kCacheLifetimeInHours);
146 }
147
148 bool AffiliationBackend::FacetManager::IsCachedDataFresh() const {
149 return backend_->GetCurrentTime() < GetCacheExpirationTime();
150 }
151
152 // static
153 void AffiliationBackend::FacetManager::ServeRequestWithSuccess(
154 const RequestInfo& request_info,
155 const AffiliatedFacets& affiliation) {
156 request_info.callback_task_runner->PostTask(
157 FROM_HERE, base::Bind(request_info.callback, affiliation, true));
158 }
159
160 // static
161 void AffiliationBackend::FacetManager::ServeRequestWithFailure(
162 const RequestInfo& request_info) {
163 request_info.callback_task_runner->PostTask(
164 FROM_HERE, base::Bind(request_info.callback, AffiliatedFacets(), false));
165 }
166
167 // AffiliationBackend ---------------------------------------------------------
168
169 AffiliationBackend::AffiliationBackend(
170 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
171 scoped_ptr<base::Clock> time_source)
172 : request_context_getter_(request_context_getter),
173 clock_(time_source.Pass()),
174 weak_ptr_factory_(this) {
175 DCHECK_LT(base::Time(), clock_->Now());
12 } 176 }
13 177
14 AffiliationBackend::~AffiliationBackend() { 178 AffiliationBackend::~AffiliationBackend() {
15 } 179 }
16 180
17 void AffiliationBackend::Initialize() { 181 void AffiliationBackend::Initialize(const base::FilePath& db_path) {
18 NOTIMPLEMENTED(); 182 thread_checker_.reset(new base::ThreadChecker);
183 cache_.reset(new AffiliationDatabase());
184 if (!cache_->Init(db_path)) {
185 // TODO(engedy): Implement this. crbug.com/437865.
186 NOTIMPLEMENTED();
187 }
19 } 188 }
20 189
21 void AffiliationBackend::GetAffiliations( 190 void AffiliationBackend::GetAffiliations(
22 const FacetURI& facet_uri, 191 const FacetURI& facet_uri,
23 bool cached_only, 192 bool cached_only,
24 const AffiliationService::ResultCallback& callback, 193 const AffiliationService::ResultCallback& callback,
25 scoped_refptr<base::TaskRunner> callback_task_runner) { 194 const scoped_refptr<base::TaskRunner>& callback_task_runner) {
26 NOTIMPLEMENTED(); 195 DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
196 if (!facet_managers_.contains(facet_uri)) {
197 scoped_ptr<FacetManager> new_manager(new FacetManager(this, facet_uri));
198 facet_managers_.add(facet_uri, new_manager.Pass());
199 }
200
201 FacetManager* facet_manager = facet_managers_.get(facet_uri);
202 DCHECK(facet_manager);
203 RequestInfo request_info;
204 request_info.callback = callback;
205 request_info.callback_task_runner = callback_task_runner;
206 facet_manager->GetAffiliations(cached_only, request_info);
207
208 if (facet_manager->CanBeDiscarded())
209 facet_managers_.erase(facet_uri);
27 } 210 }
28 211
29 void AffiliationBackend::Prefetch(const FacetURI& facet_uri, 212 void AffiliationBackend::Prefetch(const FacetURI& facet_uri,
30 const base::Time& keep_fresh_until) { 213 const base::Time& keep_fresh_until) {
214 DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
215
216 // TODO(engedy): Implement this. crbug.com/437865.
31 NOTIMPLEMENTED(); 217 NOTIMPLEMENTED();
32 } 218 }
33 219
34 void AffiliationBackend::CancelPrefetch(const FacetURI& facet_uri, 220 void AffiliationBackend::CancelPrefetch(const FacetURI& facet_uri,
35 const base::Time& keep_fresh_until) { 221 const base::Time& keep_fresh_until) {
222 DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
223
224 // TODO(engedy): Implement this. crbug.com/437865.
36 NOTIMPLEMENTED(); 225 NOTIMPLEMENTED();
37 } 226 }
38 227
39 void AffiliationBackend::TrimCache() { 228 void AffiliationBackend::TrimCache() {
40 NOTIMPLEMENTED(); 229 DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
41 } 230
42 231 // TODO(engedy): Implement this. crbug.com/437865.
232 NOTIMPLEMENTED();
233 }
234
235 void AffiliationBackend::SendNetworkRequest() {
236 DCHECK(!fetcher_);
237
238 std::vector<FacetURI> requested_facet_uris;
239 for (const auto& facet_manager_pair : facet_managers_) {
240 if (facet_manager_pair.second->DoesRequireFetch())
241 requested_facet_uris.push_back(facet_manager_pair.first);
242 }
243 DCHECK(!requested_facet_uris.empty());
244 fetcher_.reset(AffiliationFetcher::Create(request_context_getter_.get(),
245 requested_facet_uris, this));
246 fetcher_->StartRequest();
247 }
248
249 base::Time AffiliationBackend::GetCurrentTime() {
250 return clock_->Now();
251 }
252
253 base::Time AffiliationBackend::ReadLastUpdateTimeFromDatabase(
254 const FacetURI& facet_uri) {
255 AffiliatedFacetsWithUpdateTime affiliation;
256 return ReadAffiliationsFromDatabase(facet_uri, &affiliation)
257 ? affiliation.last_update_time
258 : base::Time();
259 }
260
261 bool AffiliationBackend::ReadAffiliationsFromDatabase(
262 const FacetURI& facet_uri,
263 AffiliatedFacetsWithUpdateTime* affiliations) {
264 return cache_->GetAffiliationsForFacet(facet_uri, affiliations);
265 }
266
267 void AffiliationBackend::SignalNeedNetworkRequest() {
268 // TODO(engedy): Add more sophisticated throttling logic. crbug.com/437865.
269 if (fetcher_)
270 return;
271 SendNetworkRequest();
272 }
273
274 void AffiliationBackend::OnFetchSucceeded(
275 scoped_ptr<AffiliationFetcherDelegate::Result> result) {
276 DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
277 fetcher_.reset();
278
279 for (const AffiliatedFacets& affiliated_facets : *result) {
280 AffiliatedFacetsWithUpdateTime affiliation;
281 affiliation.facets = affiliated_facets;
282 affiliation.last_update_time = clock_->Now();
283
284 std::vector<AffiliatedFacetsWithUpdateTime> obsoleted_affiliations;
285 cache_->StoreAndRemoveConflicting(affiliation, &obsoleted_affiliations);
286
287 // Cached data in contradiction with newly stored data automatically gets
288 // removed from the DB, and will be stored into |obsoleted_affiliations|.
289 // Let facet managers know if data is removed from under them.
290 // TODO(engedy): Implement this. crbug.com/437865.
291 if (!obsoleted_affiliations.empty())
292 NOTIMPLEMENTED();
293
294 for (const auto& facet_uri : affiliated_facets) {
295 if (!facet_managers_.contains(facet_uri))
296 continue;
297 FacetManager* facet_manager = facet_managers_.get(facet_uri);
298 facet_manager->OnFetchSucceeded(affiliation);
299 if (facet_manager->CanBeDiscarded())
300 facet_managers_.erase(facet_uri);
301 }
302 }
303
304 // A subsequent fetch may be needed if any additional GetAffiliations()
305 // requests came in while the current fetch was in flight.
306 for (const auto& facet_manager_pair : facet_managers_) {
307 if (facet_manager_pair.second->DoesRequireFetch()) {
308 SendNetworkRequest();
309 return;
310 }
311 }
312 }
313
314 void AffiliationBackend::OnFetchFailed() {
315 DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
316
317 // TODO(engedy): Implement this. crbug.com/437865.
318 NOTIMPLEMENTED();
319 }
320
321 void AffiliationBackend::OnMalformedResponse() {
322 DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
323
324 // TODO(engedy): Implement this. crbug.com/437865.
325 NOTIMPLEMENTED();
326 }
327
43 } // namespace password_manager 328 } // namespace password_manager
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698