1 // Copyright (c) 2015 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 <algorithm>
6 #include <memory>
7 #include <set>
8 #include <string>
9 #include <vector>
10
11 #include "base/bind.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/task/post_task.h"
15 #include "base/test/test_timeouts.h"
16 #include "base/threading/platform_thread.h"
17 #include "build/build_config.h"
18 #include "content/browser/browsing_data/conditional_cache_deletion_helper.h"
19 #include "content/public/browser/browser_context.h"
20 #include "content/public/browser/browser_task_traits.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/storage_partition.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/test/browser_test_utils.h"
25 #include "content/public/test/content_browser_test.h"
26 #include "content/shell/browser/shell.h"
27 #include "net/disk_cache/disk_cache.h"
28 #include "net/dns/mock_host_resolver.h"
29 #include "net/http/http_cache.h"
30 #include "net/url_request/url_request_context.h"
31 #include "net/url_request/url_request_context_getter.h"
32
33 namespace content {
34
35 class ConditionalCacheDeletionHelperBrowserTest : public ContentBrowserTest {
36 public:
SetUpOnMainThread()37 void SetUpOnMainThread() override {
38 host_resolver()->AddRule("*", "127.0.0.1");
39 ASSERT_TRUE(embedded_test_server()->Start());
40 }
41
TearDownOnMainThread()42 void TearDownOnMainThread() override {}
43
TestCacheEntry(const GURL & url)44 bool TestCacheEntry(const GURL& url) {
45 return LoadBasicRequest(storage_partition()->GetNetworkContext(), url,
46 0 /* process_id */, 0 /* render_frame_id */,
47 net::LOAD_ONLY_FROM_CACHE |
48 net::LOAD_SKIP_CACHE_VALIDATION) == net::OK;
49 }
50
CreateCacheEntries(const std::set<GURL> & urls)51 void CreateCacheEntries(const std::set<GURL>& urls) {
52 for (auto& url : urls) {
53 ASSERT_EQ(net::OK, LoadBasicRequest(
54 storage_partition()->GetNetworkContext(), url));
55 }
56
57 // Wait for the entries to be written. There is no callback for this action
58 // being completed, only scheduled. Therefore, we need to continuously poll
59 // every |tiny_timeout|. However, wait at most |action_timeout| for this
60 // action to be performed.
61 base::Time start = base::Time::Now();
62 bool all_entries_written = false;
63
64 while (base::Time::Now() - start < TestTimeouts::action_timeout()) {
65 all_entries_written = true;
66 for (auto& url : urls) {
67 if (!TestCacheEntry(url)) {
68 all_entries_written = false;
69 break;
70 }
71 }
72
73 if (all_entries_written)
74 break;
75
76 base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
77 }
78
79 ASSERT_TRUE(all_entries_written)
80 << "Unable to write cache entries. The deletion test can't proceed.";
81 }
82
CompareRemainingKeys(const std::set<GURL> & expected_urls,const std::set<GURL> & erase_urls)83 void CompareRemainingKeys(const std::set<GURL>& expected_urls,
84 const std::set<GURL>& erase_urls) {
85 for (auto& url : expected_urls)
86 EXPECT_TRUE(TestCacheEntry(url));
87 for (auto& url : erase_urls)
88 EXPECT_FALSE(TestCacheEntry(url));
89 }
90
DoneCallback(int value)91 void DoneCallback(int value) {
92 DCHECK_GE(value, 0); // Negative values represent an error.
93 DCHECK_CURRENTLY_ON(BrowserThread::IO);
94 waitable_event_->Signal();
95 }
96
WaitForTasksOnIOThread()97 void WaitForTasksOnIOThread() {
98 DCHECK_CURRENTLY_ON(BrowserThread::UI);
99 waitable_event_->Wait();
100 }
101
storage_partition()102 StoragePartition* storage_partition() {
103 return BrowserContext::GetDefaultStoragePartition(browser_context());
104 }
105
106 private:
browser_context()107 BrowserContext* browser_context() {
108 return shell()->web_contents()->GetBrowserContext();
109 }
110
111 base::OnceCallback<void(int)> done_callback_;
112 std::unique_ptr<base::WaitableEvent> waitable_event_;
113 };
114
115 // Tests that ConditionalCacheDeletionHelper only deletes those cache entries
116 // that match the condition.
IN_PROC_BROWSER_TEST_F(ConditionalCacheDeletionHelperBrowserTest,Condition)117 IN_PROC_BROWSER_TEST_F(ConditionalCacheDeletionHelperBrowserTest, Condition) {
118 std::set<GURL> urls = {
119 embedded_test_server()->GetURL("foo.com", "/title1.html"),
120 embedded_test_server()->GetURL("bar.com", "/title1.html"),
121 embedded_test_server()->GetURL("baz.com", "/title1.html"),
122 embedded_test_server()->GetURL("qux.com", "/title1.html")};
123
124 CreateCacheEntries(urls);
125
126 std::set<GURL> erase_urls = {
127 embedded_test_server()->GetURL("bar.com", "/title1.html"),
128 embedded_test_server()->GetURL("baz.com", "/title1.html"),
129 };
130
131 for (auto& url : erase_urls)
132 urls.erase(url);
133
134 network::mojom::ClearDataFilterPtr filter =
135 network::mojom::ClearDataFilter::New();
136 filter->type = network::mojom::ClearDataFilter::Type::DELETE_MATCHES;
137 for (auto& url : erase_urls)
138 filter->origins.push_back(url::Origin::Create(url));
139
140 base::RunLoop run_loop;
141 storage_partition()->GetNetworkContext()->ClearHttpCache(
142 base::Time(), base::Time::Max(), std::move(filter),
143 run_loop.QuitClosure());
144 run_loop.Run();
145
146 CompareRemainingKeys(urls, erase_urls);
147 }
148
149 // Tests that ConditionalCacheDeletionHelper correctly constructs a condition
150 // for time and URL.
151 // crbug.com/1010102: fails on win.
152 #if defined(OS_WIN)
153 #define MAYBE_TimeAndURL DISABLED_TimeAndURL
154 #else
155 #define MAYBE_TimeAndURL TimeAndURL
156 #endif
IN_PROC_BROWSER_TEST_F(ConditionalCacheDeletionHelperBrowserTest,MAYBE_TimeAndURL)157 IN_PROC_BROWSER_TEST_F(ConditionalCacheDeletionHelperBrowserTest,
158 MAYBE_TimeAndURL) {
159 // Create some entries.
160 std::set<GURL> urls = {
161 embedded_test_server()->GetURL("foo.com", "/title1.html"),
162 embedded_test_server()->GetURL("example.com", "/title1.html"),
163 embedded_test_server()->GetURL("bar.com", "/title1.html")};
164 CreateCacheEntries(urls);
165
166 // Wait a short time after writing the entries.
167 // This assures that future entries will have timestamps strictly greater than
168 // the ones we just added.
169 base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
170 base::Time now = base::Time::Now();
171
172 // Create a few more entries with a later timestamp.
173 std::set<GURL> newer_urls = {
174 embedded_test_server()->GetURL("foo.com", "/simple_page.html"),
175 embedded_test_server()->GetURL("example.com", "/title2.html"),
176 embedded_test_server()->GetURL("example.com", "/title3.html"),
177 embedded_test_server()->GetURL("example2.com", "/simple_page.html")};
178 CreateCacheEntries(newer_urls);
179
180 // Create a condition for entries with the "http://example.com" origin
181 // created after waiting.
182 network::mojom::ClearDataFilterPtr filter =
183 network::mojom::ClearDataFilter::New();
184 filter->type = network::mojom::ClearDataFilter::Type::DELETE_MATCHES;
185 filter->origins.push_back(
186 url::Origin::Create(embedded_test_server()->GetURL("example.com", "/")));
187
188 base::RunLoop run_loop;
189 storage_partition()->GetNetworkContext()->ClearHttpCache(
190 now, base::Time::Max(), std::move(filter), run_loop.QuitClosure());
191 run_loop.Run();
192
193 // Expect that only "title2.html" and "title3.html" were deleted.
194 std::set<GURL> erase_urls = {
195 embedded_test_server()->GetURL("example.com", "/title2.html"),
196 embedded_test_server()->GetURL("example.com", "/title3.html"),
197 };
198
199 for (auto& url : newer_urls)
200 urls.insert(url);
201
202 for (auto& url : erase_urls)
203 urls.erase(url);
204
205 CompareRemainingKeys(urls, erase_urls);
206 }
207
208 } // namespace content
209