1 // Copyright 2018 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 "services/network/conditional_cache_deletion_helper.h"
6
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/location.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/threading/thread_task_runner_handle.h"
12 #include "net/http/http_cache.h"
13 #include "net/http/http_util.h"
14
15 namespace {
16
EntryPredicateFromURLsAndTime(const base::RepeatingCallback<bool (const GURL &)> & url_matcher,const base::Time & begin_time,const base::Time & end_time,const disk_cache::Entry * entry)17 bool EntryPredicateFromURLsAndTime(
18 const base::RepeatingCallback<bool(const GURL&)>& url_matcher,
19 const base::Time& begin_time,
20 const base::Time& end_time,
21 const disk_cache::Entry* entry) {
22 std::string entry_key(entry->GetKey());
23 std::string url_string(
24 net::HttpCache::GetResourceURLFromHttpCacheKey(entry_key));
25 return (entry->GetLastUsed() >= begin_time &&
26 entry->GetLastUsed() < end_time && url_matcher.Run(GURL(url_string)));
27 }
28
29 } // namespace
30
31 namespace network {
32
33 // static
34 std::unique_ptr<ConditionalCacheDeletionHelper>
CreateAndStart(disk_cache::Backend * cache,const base::RepeatingCallback<bool (const GURL &)> & url_matcher,const base::Time & begin_time,const base::Time & end_time,base::OnceClosure completion_callback)35 ConditionalCacheDeletionHelper::CreateAndStart(
36 disk_cache::Backend* cache,
37 const base::RepeatingCallback<bool(const GURL&)>& url_matcher,
38 const base::Time& begin_time,
39 const base::Time& end_time,
40 base::OnceClosure completion_callback) {
41 std::unique_ptr<ConditionalCacheDeletionHelper> deletion_helper(
42 new ConditionalCacheDeletionHelper(
43 base::BindRepeating(
44 &EntryPredicateFromURLsAndTime, url_matcher,
45 begin_time.is_null() ? base::Time() : begin_time,
46 end_time.is_null() ? base::Time::Max() : end_time),
47 std::move(completion_callback), cache->CreateIterator()));
48
49 // Any status other than OK (since no entry), IO_PENDING, or FAILED would
50 // work here.
51 deletion_helper->IterateOverEntries(
52 disk_cache::EntryResult::MakeError(net::ERR_CACHE_OPEN_FAILURE));
53 return deletion_helper;
54 }
55
ConditionalCacheDeletionHelper(const base::RepeatingCallback<bool (const disk_cache::Entry *)> & condition,base::OnceClosure completion_callback,std::unique_ptr<disk_cache::Backend::Iterator> iterator)56 ConditionalCacheDeletionHelper::ConditionalCacheDeletionHelper(
57 const base::RepeatingCallback<bool(const disk_cache::Entry*)>& condition,
58 base::OnceClosure completion_callback,
59 std::unique_ptr<disk_cache::Backend::Iterator> iterator)
60 : condition_(condition),
61 completion_callback_(std::move(completion_callback)),
62 iterator_(std::move(iterator)) {}
63
64 ConditionalCacheDeletionHelper::~ConditionalCacheDeletionHelper() = default;
65
IterateOverEntries(disk_cache::EntryResult result)66 void ConditionalCacheDeletionHelper::IterateOverEntries(
67 disk_cache::EntryResult result) {
68 while (result.net_error() != net::ERR_IO_PENDING) {
69 // If the entry obtained in the previous iteration matches the condition,
70 // mark it for deletion. The iterator is already one step forward, so it
71 // won't be invalidated. Always close the previous entry so it does not
72 // leak.
73 if (previous_entry_) {
74 if (condition_.Run(previous_entry_)) {
75 previous_entry_->Doom();
76 }
77 previous_entry_->Close();
78 }
79
80 if (result.net_error() == net::ERR_FAILED) {
81 // The iteration finished successfully or we can no longer iterate
82 // (e.g. the cache was destroyed). We cannot distinguish between the two,
83 // but we know that there is nothing more that we can do.
84 base::ThreadTaskRunnerHandle::Get()->PostTask(
85 FROM_HERE,
86 base::BindOnce(&ConditionalCacheDeletionHelper::NotifyCompletion,
87 weak_factory_.GetWeakPtr()));
88 return;
89 }
90
91 previous_entry_ = result.ReleaseEntry();
92 result = iterator_->OpenNextEntry(
93 base::BindRepeating(&ConditionalCacheDeletionHelper::IterateOverEntries,
94 weak_factory_.GetWeakPtr()));
95 }
96 }
97
NotifyCompletion()98 void ConditionalCacheDeletionHelper::NotifyCompletion() {
99 std::move(completion_callback_).Run();
100 }
101
102 } // namespace network
103