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

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: Missing override. 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/time/clock.h"
13 #include "base/time/time.h"
14 #include "components/password_manager/core/browser/affiliation_database.h"
15 #include "components/password_manager/core/browser/affiliation_fetcher.h"
16 #include "net/url_request/url_request_context_getter.h"
8 17
9 namespace password_manager { 18 namespace password_manager {
10 19 namespace {
11 AffiliationBackend::AffiliationBackend() { 20
21 // The duration after which cached affiliation data is considered stale and will
22 // not be used to serve requests any longer.
23 const int64_t kCacheHardExpiryDurationInSeconds = 24 * 3600;
Mike West 2015/02/02 15:19:44 Nit: "24 * 60 * 60" seems slightly more common in
engedy 2015/02/02 17:00:12 Done. I have replaced this with kCacheHardExpiryDu
24
25 // RequestInfo ----------------------------------------------------------------
26
27 // Encapsulates the details of a pending GetAffiliations() request.
28 struct RequestInfo {
29 RequestInfo();
30 ~RequestInfo();
31
32 AffiliationService::ResultCallback callback;
33 scoped_refptr<base::TaskRunner> callback_task_runner;
34 };
35
36 RequestInfo::RequestInfo() {
37 }
38
39 RequestInfo::~RequestInfo() {
40 }
Mike West 2015/02/02 15:19:44 Nit: Any reason not to inline these? FacetManager
engedy 2015/02/02 15:33:15 Vaclav prefers we do not inline in production code
vabr (Chromium) 2015/02/02 15:37:37 http://dev.chromium.org/developers/coding-style/cp
Garrett Casto 2015/02/03 08:20:37 Further down on that page it talks about how in th
engedy 2015/02/03 10:49:22 Done.
41
42 } // namespace
43
44 // AffiliationBackend::FacetManager -------------------------------------------
45
46 // Manages and performs ongoing tasks concerning a single facet.
47 class AffiliationBackend::FacetManager {
48 public:
49 // The |backend| must outlive this object.
50 FacetManager(AffiliationBackend* backend, const FacetURI& facet_uri);
51 ~FacetManager();
52
53 // Called when |affiliation| information regarding this facet has just been
54 // fetched from the Affiliation API.
55 void OnFetchSucceeded(const AffiliatedFacetsWithUpdateTime& affiliation);
56
57 // Returns whether this instance has becomes redundant, that is, it has no
58 // more meaningful state than a newly created instance would have.
59 bool CanBeDiscarded() const;
60
61 // Returns whether or not affiliation information relating to this facet needs
62 // to be fetched right now.
63 bool DoesRequireFetch() const;
64
65 // Facet-specific implementations for methods in AffiliationService of the
66 // same name. See documentation in affiliation_service.h for details:
67 void GetAffiliations(bool cached_only, const RequestInfo& request_info);
68
69 private:
70 // Returns the time when cached data for this facet will become stale.
71 base::Time GetCacheHardExpiryTime() const;
72
73 // Returns whether or not the cache has fresh data for this facet.
74 bool IsCachedDataFresh() const;
75
76 // Posts the callback of the request described by |request_info| with success.
77 static void ServeRequestWithSuccess(const RequestInfo& request_info,
78 const AffiliatedFacets& affiliation);
79
80 // Posts the callback of the request described by |request_info| with failure.
81 static void ServeRequestWithFailure(const RequestInfo& request_info);
82
83 AffiliationBackend* backend_;
84 FacetURI facet_uri_;
85
86 // The last time affiliation information was fetched for this facet, i.e. the
87 // freshness of the data in the database. If there is no corresponding data in
88 // in the database, this will contain something sufficiently far away in the
89 // past to be considered stale for sure. Otherwise, the last_update_time in
90 // the database should match this value; it is only cached to reduce disk I/O.
91 base::Time last_update_time_;
92
93 // Contains information about the GetAffiliations() requests that are waiting
94 // for the result of looking up this facet.
95 std::vector<RequestInfo> pending_requests_;
96
97 DISALLOW_COPY_AND_ASSIGN(FacetManager);
98 };
99
100 AffiliationBackend::FacetManager::FacetManager(AffiliationBackend* backend,
101 const FacetURI& facet_uri)
102 : backend_(backend),
103 facet_uri_(facet_uri),
104 last_update_time_(backend_->ReadLastUpdateTimeFromDatabase(facet_uri)) {
105 }
106
107 AffiliationBackend::FacetManager::~FacetManager() {
108 // The manager will only be destroyed while there are pending requests if the
109 // entire backend is going. Call failure on pending requests in this case.
110 for (const auto& request_info : pending_requests_)
111 ServeRequestWithFailure(request_info);
112 }
113
114 void AffiliationBackend::FacetManager::GetAffiliations(
115 bool cached_only,
116 const RequestInfo& request_info) {
117 if (IsCachedDataFresh()) {
118 AffiliatedFacetsWithUpdateTime affiliation;
119 if (!backend_->ReadAffiliationsFromDatabase(facet_uri_, &affiliation))
120 NOTIMPLEMENTED();
121 DCHECK_EQ(affiliation.last_update_time, last_update_time_) << facet_uri_;
122 ServeRequestWithSuccess(request_info, affiliation.facets);
123 } else if (cached_only) {
124 ServeRequestWithFailure(request_info);
125 } else {
126 pending_requests_.push_back(request_info);
127 backend_->SignalNeedNetworkRequest();
128 }
129 }
130
131 void AffiliationBackend::FacetManager::OnFetchSucceeded(
132 const AffiliatedFacetsWithUpdateTime& affiliation) {
133 last_update_time_ = affiliation.last_update_time;
134 DCHECK(IsCachedDataFresh()) << facet_uri_;
135 for (const auto& request_info : pending_requests_)
136 ServeRequestWithSuccess(request_info, affiliation.facets);
137 pending_requests_.clear();
138 }
139
140 bool AffiliationBackend::FacetManager::CanBeDiscarded() const {
141 return pending_requests_.empty();
142 }
143
144 bool AffiliationBackend::FacetManager::DoesRequireFetch() const {
145 return !pending_requests_.empty() && !IsCachedDataFresh();
146 }
147
148 base::Time AffiliationBackend::FacetManager::GetCacheHardExpiryTime() const {
149 return last_update_time_ +
150 base::TimeDelta::FromSeconds(kCacheHardExpiryDurationInSeconds);
151 }
152
153 bool AffiliationBackend::FacetManager::IsCachedDataFresh() const {
154 return backend_->GetCurrentTime() < GetCacheHardExpiryTime();
155 }
156
157 // static
158 void AffiliationBackend::FacetManager::ServeRequestWithSuccess(
159 const RequestInfo& request_info,
160 const AffiliatedFacets& affiliation) {
161 request_info.callback_task_runner->PostTask(
162 FROM_HERE, base::Bind(request_info.callback, affiliation, true));
163 }
164
165 // static
166 void AffiliationBackend::FacetManager::ServeRequestWithFailure(
167 const RequestInfo& request_info) {
168 request_info.callback_task_runner->PostTask(
169 FROM_HERE, base::Bind(request_info.callback, AffiliatedFacets(), false));
170 }
171
172 // AffiliationBackend ---------------------------------------------------------
173
174 AffiliationBackend::AffiliationBackend(
175 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
176 scoped_ptr<base::Clock> time_source)
177 : request_context_getter_(request_context_getter),
178 clock_(time_source.Pass()),
179 weak_ptr_factory_(this) {
12 } 180 }
13 181
14 AffiliationBackend::~AffiliationBackend() { 182 AffiliationBackend::~AffiliationBackend() {
15 } 183 }
16 184
17 void AffiliationBackend::Initialize() { 185 void AffiliationBackend::Initialize(const base::FilePath& db_path) {
Mike West 2015/02/02 15:19:44 Should initialize be called on the same thread as
engedy 2015/02/02 17:00:12 As discussed, I have added a thread checker in a s
18 NOTIMPLEMENTED(); 186 cache_.reset(new AffiliationDatabase());
187 if (!cache_->Init(db_path))
188 NOTIMPLEMENTED();
19 } 189 }
20 190
21 void AffiliationBackend::GetAffiliations( 191 void AffiliationBackend::GetAffiliations(
22 const FacetURI& facet_uri, 192 const FacetURI& facet_uri,
23 bool cached_only, 193 bool cached_only,
24 const AffiliationService::ResultCallback& callback, 194 const AffiliationService::ResultCallback& callback,
25 scoped_refptr<base::TaskRunner> callback_task_runner) { 195 const scoped_refptr<base::TaskRunner>& callback_task_runner) {
26 NOTIMPLEMENTED(); 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);
Mike West 2015/02/02 15:19:45 `.add()` can fail, can't it? OOM, etc. Perhaps `DC
engedy 2015/02/02 17:00:12 Do I understand correctly that you prefer this bec
Mike West 2015/02/03 09:59:02 Right. The value of a DCHECK is that you crash pre
202 RequestInfo request_info;
203 request_info.callback = callback;
204 request_info.callback_task_runner = callback_task_runner;
205 facet_manager->GetAffiliations(cached_only, request_info);
206
207 if (facet_manager->CanBeDiscarded())
208 facet_managers_.erase(facet_uri);
27 } 209 }
28 210
29 void AffiliationBackend::Prefetch(const FacetURI& facet_uri, 211 void AffiliationBackend::Prefetch(const FacetURI& facet_uri,
30 const base::Time& keep_fresh_until) { 212 const base::Time& keep_fresh_until) {
31 NOTIMPLEMENTED(); 213 NOTIMPLEMENTED();
32 } 214 }
33 215
34 void AffiliationBackend::CancelPrefetch(const FacetURI& facet_uri, 216 void AffiliationBackend::CancelPrefetch(const FacetURI& facet_uri,
35 const base::Time& keep_fresh_until) { 217 const base::Time& keep_fresh_until) {
36 NOTIMPLEMENTED(); 218 NOTIMPLEMENTED();
37 } 219 }
38 220
39 void AffiliationBackend::TrimCache() { 221 void AffiliationBackend::TrimCache() {
40 NOTIMPLEMENTED(); 222 NOTIMPLEMENTED();
41 } 223 }
42 224
225 void AffiliationBackend::SendNetworkRequest() {
226 DCHECK(!fetcher_);
Mike West 2015/02/02 15:19:44 DCHECK that you have more than 0 managers? I guess
engedy 2015/02/02 17:00:11 Yes, I'd prefer not checking that separately.
227
228 std::vector<FacetURI> requested_facet_uris;
229 for (const auto& facet_manager_pair : facet_managers_) {
230 if (facet_manager_pair.second->DoesRequireFetch())
231 requested_facet_uris.push_back(facet_manager_pair.first);
232 }
233 DCHECK(!requested_facet_uris.empty());
234 fetcher_.reset(AffiliationFetcher::Create(request_context_getter_.get(),
235 requested_facet_uris, this));
236 fetcher_->StartRequest();
237 }
238
239 base::Time AffiliationBackend::GetCurrentTime() {
240 return clock_->Now();
241 }
242
243 base::Time AffiliationBackend::ReadLastUpdateTimeFromDatabase(
244 const FacetURI& facet_uri) {
245 AffiliatedFacetsWithUpdateTime affiliation;
246 if (cache_->GetAffiliationsForFacet(facet_uri, &affiliation))
Mike West 2015/02/02 15:19:44 You could spell this `ReadAffiliationsFromDatabase
engedy 2015/02/02 17:00:11 Done.
247 return affiliation.last_update_time;
248 else
249 return clock_->Now() -
250 base::TimeDelta::FromSeconds(kCacheHardExpiryDurationInSeconds);
Mike West 2015/02/02 15:19:45 Nit: I think a ternary if would be prettier here.
engedy 2015/02/02 17:00:11 Done.
251 }
252
253 bool AffiliationBackend::ReadAffiliationsFromDatabase(
254 const FacetURI& facet_uri,
255 AffiliatedFacetsWithUpdateTime* affiliations) {
256 return cache_->GetAffiliationsForFacet(facet_uri, affiliations);
257 }
258
259 void AffiliationBackend::SignalNeedNetworkRequest() {
260 // TODO(engedy): Integrate more sophisticated throttling logic here.
261 if (fetcher_)
262 return;
263 SendNetworkRequest();
264 }
265
266 void AffiliationBackend::OnFetchSucceeded(
267 scoped_ptr<AffiliationFetcherDelegate::Result> result) {
268 fetcher_.reset();
269
270 for (const AffiliatedFacets& affiliated_facets : *result) {
271 AffiliatedFacetsWithUpdateTime affiliation;
272 affiliation.facets = affiliated_facets;
273 affiliation.last_update_time = clock_->Now();
274
275 std::vector<AffiliatedFacetsWithUpdateTime> obsoleted_affiliations;
276 cache_->StoreAndRemoveConflicting(affiliation, &obsoleted_affiliations);
277
278 if (!obsoleted_affiliations.empty())
279 NOTIMPLEMENTED();
Mike West 2015/02/02 15:19:45 Can you add a comment here? It's not clear to me w
engedy 2015/02/02 17:00:12 Done.
280
281 for (const auto& facet_uri : affiliated_facets) {
282 if (!facet_managers_.contains(facet_uri))
Mike West 2015/02/02 15:19:44 It feels like there can be a race here if requests
engedy 2015/02/02 17:00:11 Well, if the response happens to contain the data
283 continue;
284 FacetManager* facet_manager = facet_managers_.get(facet_uri);
285 facet_manager->OnFetchSucceeded(affiliation);
286 if (facet_manager->CanBeDiscarded())
287 facet_managers_.erase(facet_uri);
288 }
289 }
290
291 // A subsequent fetch is needed if additional GetAffiliations() request came
Mike West 2015/02/02 15:19:45 Nit: s/request came/requests come/ or s/if additio
engedy 2015/02/02 17:00:11 Done.
292 // in while the current fetch was in flight.
293 for (const auto& facet_manager_pair : facet_managers_) {
294 if (facet_manager_pair.second->DoesRequireFetch()) {
295 SendNetworkRequest();
296 return;
297 }
298 }
299 }
300
301 void AffiliationBackend::OnFetchFailed() {
302 NOTIMPLEMENTED();
Mike West 2015/02/02 15:19:44 Please add TODO comments pointing to a bug for thi
engedy 2015/02/02 17:00:11 Done. I have mentioned the very same bug that this
303 }
304
305 void AffiliationBackend::OnMalformedResponse() {
306 NOTIMPLEMENTED();
307 }
308
43 } // namespace password_manager 309 } // namespace password_manager
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698