OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/browsing_data/browsing_data_remover_impl.h" | |
6 | |
7 #include <map> | |
8 #include <set> | |
9 #include <string> | |
10 #include <utility> | |
11 | |
12 #include "base/bind.h" | |
13 #include "base/bind_helpers.h" | |
14 #include "base/callback.h" | |
15 #include "base/logging.h" | |
16 #include "base/memory/ptr_util.h" | |
17 #include "base/metrics/histogram_macros.h" | |
18 #include "base/metrics/user_metrics.h" | |
19 #include "chrome/browser/browsing_data/browsing_data_remover_delegate.h" | |
20 #include "chrome/browser/profiles/profile.h" | |
21 #include "chrome/common/pref_names.h" | |
22 #include "components/prefs/pref_service.h" | |
23 #include "content/public/browser/browser_context.h" | |
24 #include "content/public/browser/browser_thread.h" | |
25 #include "content/public/browser/browsing_data_filter_builder.h" | |
26 #include "content/public/browser/content_browser_client.h" | |
27 #include "content/public/browser/download_manager.h" | |
28 #include "content/public/browser/notification_service.h" | |
29 #include "content/public/browser/storage_partition.h" | |
30 #include "net/base/net_errors.h" | |
31 #include "net/cookies/cookie_store.h" | |
32 #include "net/http/http_network_session.h" | |
33 #include "net/http/http_transaction_factory.h" | |
34 #include "net/http/transport_security_state.h" | |
35 #include "net/ssl/channel_id_service.h" | |
36 #include "net/ssl/channel_id_store.h" | |
37 #include "net/url_request/url_request_context.h" | |
38 #include "net/url_request/url_request_context_getter.h" | |
39 #include "ppapi/features/features.h" | |
40 #include "storage/browser/quota/special_storage_policy.h" | |
41 #include "url/origin.h" | |
42 | |
43 using base::UserMetricsAction; | |
44 using content::BrowserContext; | |
45 using content::BrowserThread; | |
46 using content::BrowsingDataFilterBuilder; | |
47 using content::DOMStorageContext; | |
48 | |
49 namespace { | |
50 | |
51 // Returns whether |origin| matches |origin_type_mask| given the special | |
52 // storage |policy|; and if |predicate| is not null, then also whether | |
53 // it matches |predicate|. If |origin_type_mask| contains embedder-specific | |
54 // datatypes, |embedder_matcher| must not be null; the decision for those | |
55 // datatypes will be delegated to it. | |
56 bool DoesOriginMatchMaskAndURLs( | |
57 int origin_type_mask, | |
58 const base::Callback<bool(const GURL&)>& predicate, | |
59 const BrowsingDataRemoverDelegate::EmbedderOriginTypeMatcher& | |
60 embedder_matcher, | |
61 const GURL& origin, | |
62 storage::SpecialStoragePolicy* policy) { | |
63 if (!predicate.is_null() && !predicate.Run(origin)) | |
64 return false; | |
65 | |
66 const std::vector<std::string>& schemes = url::GetWebStorageSchemes(); | |
67 bool is_web_scheme = | |
68 (std::find(schemes.begin(), schemes.end(), origin.GetOrigin().scheme()) != | |
69 schemes.end()); | |
70 | |
71 // If a websafe origin is unprotected, it matches iff UNPROTECTED_WEB. | |
72 if ((!policy || !policy->IsStorageProtected(origin.GetOrigin())) && | |
73 is_web_scheme && | |
74 (origin_type_mask & BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB)) { | |
75 return true; | |
76 } | |
77 origin_type_mask &= ~BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB; | |
78 | |
79 // Hosted applications (protected and websafe origins) iff PROTECTED_WEB. | |
80 if (policy && policy->IsStorageProtected(origin.GetOrigin()) && | |
81 is_web_scheme && | |
82 (origin_type_mask & BrowsingDataRemover::ORIGIN_TYPE_PROTECTED_WEB)) { | |
83 return true; | |
84 } | |
85 origin_type_mask &= ~BrowsingDataRemover::ORIGIN_TYPE_PROTECTED_WEB; | |
86 | |
87 DCHECK(embedder_matcher || !origin_type_mask) | |
88 << "The mask contains embedder-defined origin types, but there is no " | |
89 << "embedder delegate matcher to process them."; | |
90 | |
91 if (!embedder_matcher.is_null()) | |
92 return embedder_matcher.Run(origin_type_mask, origin, policy); | |
93 | |
94 return false; | |
95 } | |
96 | |
97 void ClearHttpAuthCacheOnIOThread( | |
98 scoped_refptr<net::URLRequestContextGetter> context_getter, | |
99 base::Time delete_begin) { | |
100 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
101 | |
102 net::HttpNetworkSession* http_session = context_getter->GetURLRequestContext() | |
103 ->http_transaction_factory() | |
104 ->GetSession(); | |
105 DCHECK(http_session); | |
106 http_session->http_auth_cache()->ClearEntriesAddedWithin(base::Time::Now() - | |
107 delete_begin); | |
108 http_session->CloseAllConnections(); | |
109 } | |
110 | |
111 void OnClearedChannelIDsOnIOThread(net::URLRequestContextGetter* rq_context, | |
112 const base::Closure& callback) { | |
113 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
114 | |
115 // Need to close open SSL connections which may be using the channel ids we | |
116 // are deleting. | |
117 // TODO(mattm): http://crbug.com/166069 Make the server bound cert | |
118 // service/store have observers that can notify relevant things directly. | |
119 rq_context->GetURLRequestContext() | |
120 ->ssl_config_service() | |
121 ->NotifySSLConfigChange(); | |
122 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); | |
123 } | |
124 | |
125 void ClearChannelIDsOnIOThread( | |
126 const base::Callback<bool(const std::string&)>& domain_predicate, | |
127 base::Time delete_begin, | |
128 base::Time delete_end, | |
129 scoped_refptr<net::URLRequestContextGetter> rq_context, | |
130 const base::Closure& callback) { | |
131 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
132 net::ChannelIDService* channel_id_service = | |
133 rq_context->GetURLRequestContext()->channel_id_service(); | |
134 channel_id_service->GetChannelIDStore()->DeleteForDomainsCreatedBetween( | |
135 domain_predicate, delete_begin, delete_end, | |
136 base::Bind(&OnClearedChannelIDsOnIOThread, | |
137 base::RetainedRef(std::move(rq_context)), callback)); | |
138 } | |
139 | |
140 } // namespace | |
141 | |
142 BrowsingDataRemoverImpl::SubTask::SubTask(const base::Closure& forward_callback) | |
143 : is_pending_(false), | |
144 forward_callback_(forward_callback), | |
145 weak_ptr_factory_(this) { | |
146 DCHECK(!forward_callback_.is_null()); | |
147 } | |
148 | |
149 BrowsingDataRemoverImpl::SubTask::~SubTask() {} | |
150 | |
151 void BrowsingDataRemoverImpl::SubTask::Start() { | |
152 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
153 DCHECK(!is_pending_); | |
154 is_pending_ = true; | |
155 } | |
156 | |
157 base::Closure BrowsingDataRemoverImpl::SubTask::GetCompletionCallback() { | |
158 return base::Bind(&BrowsingDataRemoverImpl::SubTask::CompletionCallback, | |
159 weak_ptr_factory_.GetWeakPtr()); | |
160 } | |
161 | |
162 void BrowsingDataRemoverImpl::SubTask::CompletionCallback() { | |
163 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
164 DCHECK(is_pending_); | |
165 is_pending_ = false; | |
166 forward_callback_.Run(); | |
167 } | |
168 | |
169 BrowsingDataRemoverImpl::BrowsingDataRemoverImpl( | |
170 content::BrowserContext* browser_context) | |
171 : browser_context_(browser_context), | |
172 remove_mask_(-1), | |
173 origin_type_mask_(-1), | |
174 is_removing_(false), | |
175 sub_task_forward_callback_( | |
176 base::Bind(&BrowsingDataRemoverImpl::NotifyIfDone, | |
177 base::Unretained(this))), | |
178 synchronous_clear_operations_(sub_task_forward_callback_), | |
179 clear_embedder_data_(sub_task_forward_callback_), | |
180 clear_cache_(sub_task_forward_callback_), | |
181 clear_channel_ids_(sub_task_forward_callback_), | |
182 clear_http_auth_cache_(sub_task_forward_callback_), | |
183 clear_storage_partition_data_(sub_task_forward_callback_), | |
184 storage_partition_for_testing_(nullptr), | |
185 weak_ptr_factory_(this) { | |
186 DCHECK(browser_context_); | |
187 } | |
188 | |
189 BrowsingDataRemoverImpl::~BrowsingDataRemoverImpl() { | |
190 if (!task_queue_.empty()) { | |
191 VLOG(1) << "BrowsingDataRemoverImpl shuts down with " << task_queue_.size() | |
192 << " pending tasks"; | |
193 } | |
194 | |
195 // If we are still removing data, notify observers that their task has been | |
196 // (albeit unsucessfuly) processed, so they can unregister themselves. | |
197 // TODO(bauerb): If it becomes a problem that browsing data might not actually | |
198 // be fully cleared when an observer is notified, add a success flag. | |
199 while (!task_queue_.empty()) { | |
200 if (observer_list_.HasObserver(task_queue_.front().observer)) | |
201 task_queue_.front().observer->OnBrowsingDataRemoverDone(); | |
202 task_queue_.pop(); | |
203 } | |
204 } | |
205 | |
206 void BrowsingDataRemoverImpl::Shutdown() { | |
207 embedder_delegate_.reset(); | |
208 } | |
209 | |
210 void BrowsingDataRemoverImpl::SetRemoving(bool is_removing) { | |
211 DCHECK_NE(is_removing_, is_removing); | |
212 is_removing_ = is_removing; | |
213 } | |
214 | |
215 void BrowsingDataRemoverImpl::SetEmbedderDelegate( | |
216 std::unique_ptr<BrowsingDataRemoverDelegate> embedder_delegate) { | |
217 embedder_delegate_ = std::move(embedder_delegate); | |
218 } | |
219 | |
220 BrowsingDataRemoverDelegate* | |
221 BrowsingDataRemoverImpl::GetEmbedderDelegate() const { | |
222 return embedder_delegate_.get(); | |
223 } | |
224 | |
225 bool BrowsingDataRemoverImpl::DoesOriginMatchMask( | |
226 int origin_type_mask, | |
227 const GURL& origin, | |
228 storage::SpecialStoragePolicy* policy) const { | |
229 BrowsingDataRemoverDelegate::EmbedderOriginTypeMatcher embedder_matcher; | |
230 if (embedder_delegate_) | |
231 embedder_matcher = embedder_delegate_->GetOriginTypeMatcher(); | |
232 | |
233 return DoesOriginMatchMaskAndURLs(origin_type_mask, | |
234 base::Callback<bool(const GURL&)>(), | |
235 embedder_matcher, origin, policy); | |
236 } | |
237 | |
238 void BrowsingDataRemoverImpl::Remove(const base::Time& delete_begin, | |
239 const base::Time& delete_end, | |
240 int remove_mask, | |
241 int origin_type_mask) { | |
242 RemoveInternal(delete_begin, delete_end, remove_mask, origin_type_mask, | |
243 std::unique_ptr<BrowsingDataFilterBuilder>(), nullptr); | |
244 } | |
245 | |
246 void BrowsingDataRemoverImpl::RemoveAndReply( | |
247 const base::Time& delete_begin, | |
248 const base::Time& delete_end, | |
249 int remove_mask, | |
250 int origin_type_mask, | |
251 Observer* observer) { | |
252 DCHECK(observer); | |
253 RemoveInternal(delete_begin, delete_end, remove_mask, origin_type_mask, | |
254 std::unique_ptr<BrowsingDataFilterBuilder>(), observer); | |
255 } | |
256 | |
257 void BrowsingDataRemoverImpl::RemoveWithFilter( | |
258 const base::Time& delete_begin, | |
259 const base::Time& delete_end, | |
260 int remove_mask, | |
261 int origin_type_mask, | |
262 std::unique_ptr<BrowsingDataFilterBuilder> filter_builder) { | |
263 DCHECK(filter_builder); | |
264 RemoveInternal(delete_begin, delete_end, remove_mask, origin_type_mask, | |
265 std::move(filter_builder), nullptr); | |
266 } | |
267 | |
268 void BrowsingDataRemoverImpl::RemoveWithFilterAndReply( | |
269 const base::Time& delete_begin, | |
270 const base::Time& delete_end, | |
271 int remove_mask, | |
272 int origin_type_mask, | |
273 std::unique_ptr<BrowsingDataFilterBuilder> filter_builder, | |
274 Observer* observer) { | |
275 DCHECK(filter_builder); | |
276 DCHECK(observer); | |
277 RemoveInternal(delete_begin, delete_end, remove_mask, origin_type_mask, | |
278 std::move(filter_builder), observer); | |
279 } | |
280 | |
281 void BrowsingDataRemoverImpl::RemoveInternal( | |
282 const base::Time& delete_begin, | |
283 const base::Time& delete_end, | |
284 int remove_mask, | |
285 int origin_type_mask, | |
286 std::unique_ptr<BrowsingDataFilterBuilder> filter_builder, | |
287 Observer* observer) { | |
288 DCHECK(!observer || observer_list_.HasObserver(observer)) | |
289 << "Every observer must register itself (by calling AddObserver()) " | |
290 << "before observing a removal task."; | |
291 | |
292 // Remove() and RemoveAndReply() pass a null pointer to indicate no filter. | |
293 // No filter is equivalent to one that |IsEmptyBlacklist()|. | |
294 if (!filter_builder) { | |
295 filter_builder = BrowsingDataFilterBuilder::Create( | |
296 BrowsingDataFilterBuilder::BLACKLIST); | |
297 DCHECK(filter_builder->IsEmptyBlacklist()); | |
298 } | |
299 | |
300 task_queue_.emplace( | |
301 delete_begin, | |
302 delete_end, | |
303 remove_mask, | |
304 origin_type_mask, | |
305 std::move(filter_builder), | |
306 observer); | |
307 | |
308 // If this is the only scheduled task, execute it immediately. Otherwise, | |
309 // it will be automatically executed when all tasks scheduled before it | |
310 // finish. | |
311 if (task_queue_.size() == 1) { | |
312 SetRemoving(true); | |
313 RunNextTask(); | |
314 } | |
315 } | |
316 | |
317 void BrowsingDataRemoverImpl::RunNextTask() { | |
318 DCHECK(!task_queue_.empty()); | |
319 const RemovalTask& removal_task = task_queue_.front(); | |
320 | |
321 RemoveImpl(removal_task.delete_begin, | |
322 removal_task.delete_end, | |
323 removal_task.remove_mask, | |
324 *removal_task.filter_builder, | |
325 removal_task.origin_type_mask); | |
326 } | |
327 | |
328 void BrowsingDataRemoverImpl::RemoveImpl( | |
329 const base::Time& delete_begin, | |
330 const base::Time& delete_end, | |
331 int remove_mask, | |
332 const BrowsingDataFilterBuilder& filter_builder, | |
333 int origin_type_mask) { | |
334 // =============== README before adding more storage backends =============== | |
335 // | |
336 // If you're adding a data storage backend that is included among | |
337 // RemoveDataMask::FILTERABLE_DATATYPES, you must do one of the following: | |
338 // 1. Support one of the filters generated by |filter_builder|. | |
339 // 2. Add a comment explaining why is it acceptable in your case to delete all | |
340 // data without filtering URLs / origins / domains. | |
341 // 3. Do not support partial deletion, i.e. only delete your data if | |
342 // |filter_builder.IsEmptyBlacklist()|. Add a comment explaining why this | |
343 // is acceptable. | |
344 synchronous_clear_operations_.Start(); | |
345 | |
346 // crbug.com/140910: Many places were calling this with base::Time() as | |
347 // delete_end, even though they should've used base::Time::Max(). | |
348 DCHECK_NE(base::Time(), delete_end); | |
349 | |
350 delete_begin_ = delete_begin; | |
351 delete_end_ = delete_end; | |
352 remove_mask_ = remove_mask; | |
353 origin_type_mask_ = origin_type_mask; | |
354 | |
355 // Record the combined deletion of cookies and cache. | |
356 CookieOrCacheDeletionChoice choice = NEITHER_COOKIES_NOR_CACHE; | |
357 if (remove_mask & DATA_TYPE_COOKIES && | |
358 origin_type_mask_ & ORIGIN_TYPE_UNPROTECTED_WEB) { | |
359 choice = | |
360 remove_mask & DATA_TYPE_CACHE ? BOTH_COOKIES_AND_CACHE : ONLY_COOKIES; | |
361 } else if (remove_mask & DATA_TYPE_CACHE) { | |
362 choice = ONLY_CACHE; | |
363 } | |
364 | |
365 UMA_HISTOGRAM_ENUMERATION( | |
366 "History.ClearBrowsingData.UserDeletedCookieOrCache", | |
367 choice, MAX_CHOICE_VALUE); | |
368 | |
369 // Managed devices and supervised users can have restrictions on history | |
370 // deletion. | |
371 // TODO(crbug.com/668114): This should be provided via ContentBrowserClient | |
372 // once BrowsingDataRemoverImpl moves to content. | |
373 PrefService* prefs = | |
374 Profile::FromBrowserContext(browser_context_)->GetPrefs(); | |
375 bool may_delete_history = | |
376 prefs->GetBoolean(prefs::kAllowDeletingBrowserHistory); | |
377 | |
378 ////////////////////////////////////////////////////////////////////////////// | |
379 // INITIALIZATION | |
380 base::Callback<bool(const GURL& url)> filter = | |
381 filter_builder.BuildGeneralFilter(); | |
382 | |
383 ////////////////////////////////////////////////////////////////////////////// | |
384 // DATA_TYPE_DOWNLOADS | |
385 if ((remove_mask & DATA_TYPE_DOWNLOADS) && may_delete_history) { | |
386 base::RecordAction(UserMetricsAction("ClearBrowsingData_Downloads")); | |
387 content::DownloadManager* download_manager = | |
388 BrowserContext::GetDownloadManager(browser_context_); | |
389 download_manager->RemoveDownloadsByURLAndTime(filter, | |
390 delete_begin_, delete_end_); | |
391 } | |
392 | |
393 ////////////////////////////////////////////////////////////////////////////// | |
394 // DATA_TYPE_CHANNEL_IDS | |
395 // Channel IDs are not separated for protected and unprotected web | |
396 // origins. We check the origin_type_mask_ to prevent unintended deletion. | |
397 if (remove_mask & DATA_TYPE_CHANNEL_IDS && | |
398 origin_type_mask_ & ORIGIN_TYPE_UNPROTECTED_WEB) { | |
399 base::RecordAction(UserMetricsAction("ClearBrowsingData_ChannelIDs")); | |
400 // Since we are running on the UI thread don't call GetURLRequestContext(). | |
401 scoped_refptr<net::URLRequestContextGetter> rq_context = | |
402 content::BrowserContext::GetDefaultStoragePartition(browser_context_)-> | |
403 GetURLRequestContext(); | |
404 clear_channel_ids_.Start(); | |
405 BrowserThread::PostTask( | |
406 BrowserThread::IO, FROM_HERE, | |
407 base::BindOnce(&ClearChannelIDsOnIOThread, | |
408 filter_builder.BuildChannelIDFilter(), delete_begin_, | |
409 delete_end_, std::move(rq_context), | |
410 clear_channel_ids_.GetCompletionCallback())); | |
411 } | |
412 | |
413 ////////////////////////////////////////////////////////////////////////////// | |
414 // STORAGE PARTITION DATA | |
415 uint32_t storage_partition_remove_mask = 0; | |
416 | |
417 // We ignore the DATA_TYPE_COOKIES request if UNPROTECTED_WEB is not set, | |
418 // so that callers who request DATA_TYPE_SITE_DATA with another origin type | |
419 // don't accidentally remove the cookies that are associated with the | |
420 // UNPROTECTED_WEB origin. This is necessary because cookies are not separated | |
421 // between UNPROTECTED_WEB and other origin types. | |
422 if (remove_mask & DATA_TYPE_COOKIES && | |
423 origin_type_mask_ & ORIGIN_TYPE_UNPROTECTED_WEB) { | |
424 storage_partition_remove_mask |= | |
425 content::StoragePartition::REMOVE_DATA_MASK_COOKIES; | |
426 } | |
427 if (remove_mask & DATA_TYPE_LOCAL_STORAGE) { | |
428 storage_partition_remove_mask |= | |
429 content::StoragePartition::REMOVE_DATA_MASK_LOCAL_STORAGE; | |
430 } | |
431 if (remove_mask & DATA_TYPE_INDEXED_DB) { | |
432 storage_partition_remove_mask |= | |
433 content::StoragePartition::REMOVE_DATA_MASK_INDEXEDDB; | |
434 } | |
435 if (remove_mask & DATA_TYPE_WEB_SQL) { | |
436 storage_partition_remove_mask |= | |
437 content::StoragePartition::REMOVE_DATA_MASK_WEBSQL; | |
438 } | |
439 if (remove_mask & DATA_TYPE_APP_CACHE) { | |
440 storage_partition_remove_mask |= | |
441 content::StoragePartition::REMOVE_DATA_MASK_APPCACHE; | |
442 } | |
443 if (remove_mask & DATA_TYPE_SERVICE_WORKERS) { | |
444 storage_partition_remove_mask |= | |
445 content::StoragePartition::REMOVE_DATA_MASK_SERVICE_WORKERS; | |
446 } | |
447 if (remove_mask & DATA_TYPE_CACHE_STORAGE) { | |
448 storage_partition_remove_mask |= | |
449 content::StoragePartition::REMOVE_DATA_MASK_CACHE_STORAGE; | |
450 } | |
451 if (remove_mask & DATA_TYPE_FILE_SYSTEMS) { | |
452 storage_partition_remove_mask |= | |
453 content::StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS; | |
454 } | |
455 | |
456 // Content Decryption Modules used by Encrypted Media store licenses in a | |
457 // private filesystem. These are different than content licenses used by | |
458 // Flash (which are deleted father down in this method). | |
459 if (remove_mask & DATA_TYPE_MEDIA_LICENSES) { | |
460 storage_partition_remove_mask |= | |
461 content::StoragePartition::REMOVE_DATA_MASK_PLUGIN_PRIVATE_DATA; | |
462 } | |
463 | |
464 content::StoragePartition* storage_partition; | |
465 if (storage_partition_for_testing_) { | |
466 storage_partition = storage_partition_for_testing_; | |
467 } else { | |
468 storage_partition = | |
469 BrowserContext::GetDefaultStoragePartition(browser_context_); | |
470 } | |
471 | |
472 if (storage_partition_remove_mask) { | |
473 clear_storage_partition_data_.Start(); | |
474 | |
475 uint32_t quota_storage_remove_mask = | |
476 ~content::StoragePartition::QUOTA_MANAGED_STORAGE_MASK_PERSISTENT; | |
477 | |
478 if (delete_begin_ == base::Time() || | |
479 ((origin_type_mask_ & ~ORIGIN_TYPE_UNPROTECTED_WEB) != 0)) { | |
480 // If we're deleting since the beginning of time, or we're removing | |
481 // protected origins, then remove persistent quota data. | |
482 quota_storage_remove_mask |= | |
483 content::StoragePartition::QUOTA_MANAGED_STORAGE_MASK_PERSISTENT; | |
484 } | |
485 | |
486 // If cookies are supposed to be conditionally deleted from the storage | |
487 // partition, create a cookie matcher function. | |
488 content::StoragePartition::CookieMatcherFunction cookie_matcher; | |
489 if (!filter_builder.IsEmptyBlacklist() && | |
490 (storage_partition_remove_mask & | |
491 content::StoragePartition::REMOVE_DATA_MASK_COOKIES)) { | |
492 cookie_matcher = filter_builder.BuildCookieFilter(); | |
493 } | |
494 | |
495 BrowsingDataRemoverDelegate::EmbedderOriginTypeMatcher embedder_matcher; | |
496 if (embedder_delegate_) | |
497 embedder_matcher = embedder_delegate_->GetOriginTypeMatcher(); | |
498 | |
499 storage_partition->ClearData( | |
500 storage_partition_remove_mask, quota_storage_remove_mask, | |
501 base::Bind(&DoesOriginMatchMaskAndURLs, origin_type_mask_, filter, | |
502 embedder_matcher), | |
503 cookie_matcher, delete_begin_, delete_end_, | |
504 clear_storage_partition_data_.GetCompletionCallback()); | |
505 } | |
506 | |
507 ////////////////////////////////////////////////////////////////////////////// | |
508 // CACHE | |
509 if (remove_mask & DATA_TYPE_CACHE) { | |
510 base::RecordAction(UserMetricsAction("ClearBrowsingData_Cache")); | |
511 | |
512 // TODO(msramek): Clear the cache of all renderers. | |
513 | |
514 clear_cache_.Start(); | |
515 storage_partition->ClearHttpAndMediaCaches( | |
516 delete_begin, delete_end, | |
517 filter_builder.IsEmptyBlacklist() ? base::Callback<bool(const GURL&)>() | |
518 : filter, | |
519 clear_cache_.GetCompletionCallback()); | |
520 | |
521 // Tell the shader disk cache to clear. | |
522 base::RecordAction(UserMetricsAction("ClearBrowsingData_ShaderCache")); | |
523 storage_partition_remove_mask |= | |
524 content::StoragePartition::REMOVE_DATA_MASK_SHADER_CACHE; | |
525 } | |
526 | |
527 ////////////////////////////////////////////////////////////////////////////// | |
528 // Auth cache. | |
529 if (remove_mask & DATA_TYPE_COOKIES) { | |
530 scoped_refptr<net::URLRequestContextGetter> request_context = | |
531 BrowserContext::GetDefaultStoragePartition(browser_context_) | |
532 ->GetURLRequestContext(); | |
533 clear_http_auth_cache_.Start(); | |
534 BrowserThread::PostTaskAndReply( | |
535 BrowserThread::IO, FROM_HERE, | |
536 base::BindOnce(&ClearHttpAuthCacheOnIOThread, | |
537 std::move(request_context), delete_begin_), | |
538 clear_http_auth_cache_.GetCompletionCallback()); | |
539 } | |
540 | |
541 ////////////////////////////////////////////////////////////////////////////// | |
542 // Embedder data. | |
543 if (embedder_delegate_) { | |
544 clear_embedder_data_.Start(); | |
545 embedder_delegate_->RemoveEmbedderData( | |
546 delete_begin_, | |
547 delete_end_, | |
548 remove_mask, | |
549 filter_builder, | |
550 origin_type_mask, | |
551 clear_embedder_data_.GetCompletionCallback()); | |
552 } | |
553 | |
554 // Notify in case all actions taken were synchronous. | |
555 synchronous_clear_operations_.GetCompletionCallback().Run(); | |
556 } | |
557 | |
558 void BrowsingDataRemoverImpl::AddObserver(Observer* observer) { | |
559 observer_list_.AddObserver(observer); | |
560 } | |
561 | |
562 void BrowsingDataRemoverImpl::RemoveObserver(Observer* observer) { | |
563 observer_list_.RemoveObserver(observer); | |
564 } | |
565 | |
566 void BrowsingDataRemoverImpl::SetWouldCompleteCallbackForTesting( | |
567 const base::Callback<void(const base::Closure& continue_to_completion)>& | |
568 callback) { | |
569 would_complete_callback_ = callback; | |
570 } | |
571 | |
572 void BrowsingDataRemoverImpl::OverrideStoragePartitionForTesting( | |
573 content::StoragePartition* storage_partition) { | |
574 storage_partition_for_testing_ = storage_partition; | |
575 } | |
576 | |
577 const base::Time& BrowsingDataRemoverImpl::GetLastUsedBeginTime() { | |
578 return delete_begin_; | |
579 } | |
580 | |
581 const base::Time& BrowsingDataRemoverImpl::GetLastUsedEndTime() { | |
582 return delete_end_; | |
583 } | |
584 | |
585 int BrowsingDataRemoverImpl::GetLastUsedRemovalMask() { | |
586 return remove_mask_; | |
587 } | |
588 | |
589 int BrowsingDataRemoverImpl::GetLastUsedOriginTypeMask() { | |
590 return origin_type_mask_; | |
591 } | |
592 | |
593 BrowsingDataRemoverImpl::RemovalTask::RemovalTask( | |
594 const base::Time& delete_begin, | |
595 const base::Time& delete_end, | |
596 int remove_mask, | |
597 int origin_type_mask, | |
598 std::unique_ptr<BrowsingDataFilterBuilder> filter_builder, | |
599 Observer* observer) | |
600 : delete_begin(delete_begin), | |
601 delete_end(delete_end), | |
602 remove_mask(remove_mask), | |
603 origin_type_mask(origin_type_mask), | |
604 filter_builder(std::move(filter_builder)), | |
605 observer(observer) {} | |
606 | |
607 BrowsingDataRemoverImpl::RemovalTask::~RemovalTask() {} | |
608 | |
609 bool BrowsingDataRemoverImpl::AllDone() { | |
610 return !synchronous_clear_operations_.is_pending() && | |
611 !clear_embedder_data_.is_pending() && | |
612 !clear_cache_.is_pending() && | |
613 !clear_channel_ids_.is_pending() && | |
614 !clear_http_auth_cache_.is_pending() && | |
615 !clear_storage_partition_data_.is_pending(); | |
616 } | |
617 | |
618 void BrowsingDataRemoverImpl::Notify() { | |
619 // Some tests call |RemoveImpl| directly, without using the task scheduler. | |
620 // TODO(msramek): Improve those tests so we don't have to do this. Tests | |
621 // relying on |RemoveImpl| do so because they need to pass in | |
622 // BrowsingDataFilterBuilder while still keeping ownership of it. Making | |
623 // BrowsingDataFilterBuilder copyable would solve this. | |
624 if (!is_removing_) { | |
625 DCHECK(task_queue_.empty()); | |
626 return; | |
627 } | |
628 | |
629 // Inform the observer of the current task unless it has unregistered | |
630 // itself in the meantime. | |
631 DCHECK(!task_queue_.empty()); | |
632 | |
633 if (task_queue_.front().observer != nullptr && | |
634 observer_list_.HasObserver(task_queue_.front().observer)) { | |
635 task_queue_.front().observer->OnBrowsingDataRemoverDone(); | |
636 } | |
637 | |
638 task_queue_.pop(); | |
639 | |
640 if (task_queue_.empty()) { | |
641 // All removal tasks have finished. Inform the observers that we're idle. | |
642 SetRemoving(false); | |
643 return; | |
644 } | |
645 | |
646 // Yield to the UI thread before executing the next removal task. | |
647 // TODO(msramek): Consider also adding a backoff if too many tasks | |
648 // are scheduled. | |
649 BrowserThread::PostTask( | |
650 BrowserThread::UI, FROM_HERE, | |
651 base::BindOnce(&BrowsingDataRemoverImpl::RunNextTask, GetWeakPtr())); | |
652 } | |
653 | |
654 void BrowsingDataRemoverImpl::NotifyIfDone() { | |
655 // TODO(brettw) http://crbug.com/305259: This should also observe session | |
656 // clearing (what about other things such as passwords, etc.?) and wait for | |
657 // them to complete before continuing. | |
658 | |
659 if (!AllDone()) | |
660 return; | |
661 | |
662 if (!would_complete_callback_.is_null()) { | |
663 would_complete_callback_.Run( | |
664 base::Bind(&BrowsingDataRemoverImpl::Notify, GetWeakPtr())); | |
665 return; | |
666 } | |
667 | |
668 Notify(); | |
669 } | |
670 | |
671 base::WeakPtr<BrowsingDataRemoverImpl> BrowsingDataRemoverImpl::GetWeakPtr() { | |
672 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
673 base::WeakPtr<BrowsingDataRemoverImpl> weak_ptr = | |
674 weak_ptr_factory_.GetWeakPtr(); | |
675 | |
676 // Immediately bind the weak pointer to the UI thread. This makes it easier | |
677 // to discover potential misuse on the IO thread. | |
678 weak_ptr.get(); | |
679 | |
680 return weak_ptr; | |
681 } | |
OLD | NEW |