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

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

Powered by Google App Engine
This is Rietveld 408576698