OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "content/browser/browsing_data/clear_site_data_throttle.h" | 5 #include "content/browser/browsing_data/clear_site_data_throttle.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/callback.h" | 10 #include "base/callback.h" |
11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
| 12 #include "base/scoped_observer.h" |
| 13 #include "base/strings/stringprintf.h" |
| 14 #include "base/strings/utf_string_conversions.h" |
| 15 #include "content/browser/browsing_data/browsing_data_filter_builder_impl.h" |
| 16 #include "content/browser/service_worker/service_worker_context_observer.h" |
| 17 #include "content/browser/service_worker/service_worker_context_wrapper.h" |
| 18 #include "content/public/browser/browser_context.h" |
| 19 #include "content/public/browser/browsing_data_remover.h" |
12 #include "content/public/browser/content_browser_client.h" | 20 #include "content/public/browser/content_browser_client.h" |
| 21 #include "content/public/browser/storage_partition.h" |
13 #include "content/public/browser/web_contents.h" | 22 #include "content/public/browser/web_contents.h" |
14 #include "content/public/common/content_switches.h" | 23 #include "content/public/common/content_switches.h" |
| 24 #include "content/public/test/browser_test_utils.h" |
| 25 #include "content/public/test/cache_test_util.h" |
15 #include "content/public/test/content_browser_test.h" | 26 #include "content/public/test/content_browser_test.h" |
16 #include "content/public/test/content_browser_test_utils.h" | 27 #include "content/public/test/content_browser_test_utils.h" |
| 28 #include "content/public/test/mock_browsing_data_remover_delegate.h" |
17 #include "content/public/test/test_navigation_observer.h" | 29 #include "content/public/test/test_navigation_observer.h" |
18 #include "content/shell/browser/shell.h" | 30 #include "content/shell/browser/shell.h" |
19 #include "net/base/escape.h" | 31 #include "net/base/escape.h" |
20 #include "net/base/url_util.h" | 32 #include "net/base/url_util.h" |
| 33 #include "net/cookies/cookie_store.h" |
21 #include "net/dns/mock_host_resolver.h" | 34 #include "net/dns/mock_host_resolver.h" |
22 #include "net/test/embedded_test_server/http_request.h" | 35 #include "net/test/embedded_test_server/http_request.h" |
23 #include "net/test/embedded_test_server/http_response.h" | 36 #include "net/test/embedded_test_server/http_response.h" |
| 37 #include "net/url_request/url_request_context.h" |
| 38 #include "net/url_request/url_request_context_getter.h" |
24 #include "storage/browser/quota/quota_settings.h" | 39 #include "storage/browser/quota/quota_settings.h" |
25 #include "testing/gmock/include/gmock/gmock.h" | 40 #include "testing/gmock/include/gmock/gmock.h" |
26 #include "url/origin.h" | 41 #include "url/origin.h" |
27 #include "url/url_constants.h" | 42 #include "url/url_constants.h" |
28 | 43 |
29 using testing::_; | 44 using testing::_; |
30 | 45 |
31 namespace content { | 46 namespace content { |
32 | 47 |
33 namespace { | 48 namespace { |
34 | 49 |
35 class MockContentBrowserClient : public ContentBrowserClient { | |
36 public: | |
37 MOCK_METHOD6(ClearSiteData, | |
38 void(content::BrowserContext* browser_context, | |
39 const url::Origin& origin, | |
40 bool remove_cookies, | |
41 bool remove_storage, | |
42 bool remove_cache, | |
43 const base::Closure& callback)); | |
44 | |
45 void GetQuotaSettings( | |
46 content::BrowserContext* context, | |
47 content::StoragePartition* partition, | |
48 const storage::OptionalQuotaSettingsCallback& callback) override { | |
49 callback.Run(storage::GetHardCodedSettings(100 * 1024 * 1024)); | |
50 } | |
51 }; | |
52 | |
53 class TestContentBrowserClient : public MockContentBrowserClient { | |
54 public: | |
55 void ClearSiteData(content::BrowserContext* browser_context, | |
56 const url::Origin& origin, | |
57 bool remove_cookies, | |
58 bool remove_storage, | |
59 bool remove_cache, | |
60 const base::Closure& callback) override { | |
61 // Record the method call and run the |callback|. | |
62 MockContentBrowserClient::ClearSiteData(browser_context, origin, | |
63 remove_cookies, remove_storage, | |
64 remove_cache, callback); | |
65 callback.Run(); | |
66 } | |
67 }; | |
68 | |
69 // Adds a key=value pair to the url's query. | 50 // Adds a key=value pair to the url's query. |
70 void AddQuery(GURL* url, const std::string& key, const std::string& value) { | 51 void AddQuery(GURL* url, const std::string& key, const std::string& value) { |
71 *url = GURL(url->spec() + (url->has_query() ? "&" : "?") + key + "=" + | 52 *url = GURL(url->spec() + (url->has_query() ? "&" : "?") + key + "=" + |
72 net::EscapeQueryParamValue(value, false)); | 53 net::EscapeQueryParamValue(value, false)); |
73 } | 54 } |
74 | 55 |
| 56 // A helper function to synchronize with JS side of the tests. JS can append |
| 57 // information to the loaded website's title and C++ will wait until that |
| 58 // happens. |
| 59 void WaitForTitle(const Shell* shell, const char* expected_title) { |
| 60 base::string16 expected_title_16 = base::ASCIIToUTF16(expected_title); |
| 61 TitleWatcher title_watcher(shell->web_contents(), expected_title_16); |
| 62 ASSERT_EQ(expected_title_16, title_watcher.WaitAndGetTitle()); |
| 63 } |
| 64 |
75 // A value of the Clear-Site-Data header that requests cookie deletion. Reused | 65 // A value of the Clear-Site-Data header that requests cookie deletion. Reused |
76 // in tests that need a valid header but do not depend on its value. | 66 // in tests that need a valid header but do not depend on its value. |
77 static const char* kClearCookiesHeader = "{ \"types\": [ \"cookies\" ] }"; | 67 static const char* kClearCookiesHeader = "{ \"types\": [ \"cookies\" ] }"; |
78 | 68 |
| 69 // A helper class to observe BrowsingDataRemover deletion tasks coming from |
| 70 // ClearSiteData. |
| 71 class TestBrowsingDataRemoverDelegate : public MockBrowsingDataRemoverDelegate { |
| 72 public: |
| 73 // Sets a test expectation that a Clear-Site-Data header call from |origin|, |
| 74 // instructing to delete |cookies|, |storage|, and |cache|, will schedule |
| 75 // the corresponding BrowsingDataRemover deletion tasks. |
| 76 void ExpectClearSiteDataCall(const url::Origin& origin, |
| 77 bool cookies, |
| 78 bool storage, |
| 79 bool cache) { |
| 80 const int kOriginTypeMask = |
| 81 BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB | |
| 82 BrowsingDataRemover::ORIGIN_TYPE_PROTECTED_WEB; |
| 83 |
| 84 if (cookies) { |
| 85 int data_type_mask = BrowsingDataRemover::DATA_TYPE_COOKIES | |
| 86 BrowsingDataRemover::DATA_TYPE_CHANNEL_IDS; |
| 87 |
| 88 BrowsingDataFilterBuilderImpl filter_builder( |
| 89 BrowsingDataFilterBuilder::WHITELIST); |
| 90 filter_builder.AddRegisterableDomain(origin.host()); |
| 91 ExpectCall(base::Time(), base::Time::Max(), data_type_mask, |
| 92 kOriginTypeMask, std::move(filter_builder)); |
| 93 } |
| 94 if (storage || cache) { |
| 95 int data_type_mask = |
| 96 (storage ? BrowsingDataRemover::DATA_TYPE_DOM_STORAGE : 0) | |
| 97 (cache ? BrowsingDataRemover::DATA_TYPE_CACHE : 0); |
| 98 |
| 99 BrowsingDataFilterBuilderImpl filter_builder( |
| 100 BrowsingDataFilterBuilder::WHITELIST); |
| 101 filter_builder.AddOrigin(origin); |
| 102 ExpectCall(base::Time(), base::Time::Max(), data_type_mask, |
| 103 kOriginTypeMask, std::move(filter_builder)); |
| 104 } |
| 105 } |
| 106 |
| 107 // A shortcut for the above method, but with only cookies deleted. This is |
| 108 // useful for most tests that use |kClearCookiesHeader|. |
| 109 void ExpectClearSiteDataCookiesCall(const url::Origin& origin) { |
| 110 ExpectClearSiteDataCall(origin, true, false, false); |
| 111 } |
| 112 }; |
| 113 |
| 114 // TODO(msramek): A class like this already exists in ServiceWorkerBrowserTest. |
| 115 // Consider extracting it to a test utils file. |
| 116 class ServiceWorkerActivationObserver : public ServiceWorkerContextObserver { |
| 117 public: |
| 118 static void SignalActivation(ServiceWorkerContextWrapper* context, |
| 119 const base::Closure& callback) { |
| 120 new ServiceWorkerActivationObserver(context, callback); |
| 121 } |
| 122 |
| 123 private: |
| 124 ServiceWorkerActivationObserver(ServiceWorkerContextWrapper* context, |
| 125 const base::Closure& callback) |
| 126 : context_(context), scoped_observer_(this), callback_(callback) { |
| 127 scoped_observer_.Add(context); |
| 128 } |
| 129 |
| 130 ~ServiceWorkerActivationObserver() override {} |
| 131 |
| 132 // ServiceWorkerContextObserver overrides. |
| 133 void OnVersionStateChanged(int64_t version_id, |
| 134 ServiceWorkerVersion::Status) override { |
| 135 if (context_->GetLiveVersion(version_id)->status() == |
| 136 ServiceWorkerVersion::ACTIVATED) { |
| 137 callback_.Run(); |
| 138 delete this; |
| 139 } |
| 140 } |
| 141 |
| 142 ServiceWorkerContextWrapper* context_; |
| 143 ScopedObserver<ServiceWorkerContextWrapper, ServiceWorkerContextObserver> |
| 144 scoped_observer_; |
| 145 base::Closure callback_; |
| 146 }; |
| 147 |
79 } // namespace | 148 } // namespace |
80 | 149 |
81 class ClearSiteDataThrottleBrowserTest : public ContentBrowserTest { | 150 class ClearSiteDataThrottleBrowserTest : public ContentBrowserTest { |
82 public: | 151 public: |
83 void SetUpCommandLine(base::CommandLine* command_line) override { | 152 void SetUpCommandLine(base::CommandLine* command_line) override { |
84 ContentBrowserTest::SetUpCommandLine(command_line); | 153 ContentBrowserTest::SetUpCommandLine(command_line); |
85 command_line->AppendSwitch( | 154 command_line->AppendSwitch( |
86 switches::kEnableExperimentalWebPlatformFeatures); | 155 switches::kEnableExperimentalWebPlatformFeatures); |
87 | 156 |
88 // We're redirecting all hosts to localhost even on HTTPS, so we'll get | 157 // We're redirecting all hosts to localhost even on HTTPS, so we'll get |
89 // certificate errors. | 158 // certificate errors. |
90 command_line->AppendSwitch(switches::kIgnoreCertificateErrors); | 159 command_line->AppendSwitch(switches::kIgnoreCertificateErrors); |
91 } | 160 } |
92 | 161 |
93 void SetUpOnMainThread() override { | 162 void SetUpOnMainThread() override { |
94 ContentBrowserTest::SetUpOnMainThread(); | 163 ContentBrowserTest::SetUpOnMainThread(); |
95 | 164 |
96 SetBrowserClientForTesting(&test_client_); | 165 BrowserContext::GetBrowsingDataRemover(browser_context()) |
| 166 ->SetEmbedderDelegate(&embedder_delegate_); |
97 | 167 |
98 // Set up HTTP and HTTPS test servers that handle all hosts. | 168 // Set up HTTP and HTTPS test servers that handle all hosts. |
99 host_resolver()->AddRule("*", "127.0.0.1"); | 169 host_resolver()->AddRule("*", "127.0.0.1"); |
100 | 170 |
101 embedded_test_server()->RegisterRequestHandler( | 171 embedded_test_server()->RegisterRequestHandler( |
102 base::Bind(&ClearSiteDataThrottleBrowserTest::HandleRequest, | 172 base::Bind(&ClearSiteDataThrottleBrowserTest::HandleRequest, |
103 base::Unretained(this))); | 173 base::Unretained(this))); |
104 ASSERT_TRUE(embedded_test_server()->Start()); | 174 ASSERT_TRUE(embedded_test_server()->Start()); |
105 | 175 |
106 https_server_.reset(new net::EmbeddedTestServer( | 176 https_server_.reset(new net::EmbeddedTestServer( |
107 net::test_server::EmbeddedTestServer::TYPE_HTTPS)); | 177 net::test_server::EmbeddedTestServer::TYPE_HTTPS)); |
108 https_server_->SetSSLConfig(net::EmbeddedTestServer::CERT_OK); | 178 https_server_->SetSSLConfig(net::EmbeddedTestServer::CERT_OK); |
109 https_server_->RegisterRequestHandler( | 179 https_server_->RegisterRequestHandler( |
110 base::Bind(&ClearSiteDataThrottleBrowserTest::HandleRequest, | 180 base::Bind(&ClearSiteDataThrottleBrowserTest::HandleRequest, |
111 base::Unretained(this))); | 181 base::Unretained(this))); |
112 ASSERT_TRUE(https_server_->Start()); | 182 ASSERT_TRUE(https_server_->Start()); |
| 183 |
| 184 // Initialize the cookie store pointer on the IO thread. |
| 185 base::RunLoop run_loop; |
| 186 BrowserThread::PostTask( |
| 187 BrowserThread::IO, FROM_HERE, |
| 188 base::BindOnce( |
| 189 &ClearSiteDataThrottleBrowserTest::InitializeCookieStore, |
| 190 base::Unretained(this), |
| 191 base::Unretained( |
| 192 BrowserContext::GetDefaultStoragePartition(browser_context()) |
| 193 ->GetURLRequestContext()), |
| 194 run_loop.QuitClosure())); |
| 195 run_loop.Run(); |
113 } | 196 } |
114 | 197 |
115 TestContentBrowserClient* GetContentBrowserClient() { return &test_client_; } | 198 BrowserContext* browser_context() { |
| 199 return shell()->web_contents()->GetBrowserContext(); |
| 200 } |
| 201 |
| 202 void InitializeCookieStore( |
| 203 net::URLRequestContextGetter* request_context_getter, |
| 204 base::Closure callback) { |
| 205 cookie_store_ = |
| 206 request_context_getter->GetURLRequestContext()->cookie_store(); |
| 207 callback.Run(); |
| 208 } |
| 209 |
| 210 // Adds a cookie for the |url|. Used in the cookie integration tests. |
| 211 void AddCookie(const GURL& url) { |
| 212 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 213 base::RunLoop run_loop; |
| 214 BrowserThread::PostTask( |
| 215 BrowserThread::IO, FROM_HERE, |
| 216 base::BindOnce( |
| 217 &net::CookieStore::SetCookieWithOptionsAsync, |
| 218 base::Unretained(cookie_store_), url, "A=1", net::CookieOptions(), |
| 219 base::Bind(&ClearSiteDataThrottleBrowserTest::AddCookieCallback, |
| 220 run_loop.QuitClosure()))); |
| 221 run_loop.Run(); |
| 222 } |
| 223 |
| 224 // Retrieves the list of all cookies. Used in the cookie integration tests. |
| 225 net::CookieList GetCookies() { |
| 226 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 227 base::RunLoop run_loop; |
| 228 net::CookieList cookie_list; |
| 229 BrowserThread::PostTask( |
| 230 BrowserThread::IO, FROM_HERE, |
| 231 base::BindOnce( |
| 232 &net::CookieStore::GetAllCookiesAsync, |
| 233 base::Unretained(cookie_store_), |
| 234 base::Bind(&ClearSiteDataThrottleBrowserTest::GetCookiesCallback, |
| 235 run_loop.QuitClosure(), |
| 236 base::Unretained(&cookie_list)))); |
| 237 run_loop.Run(); |
| 238 return cookie_list; |
| 239 } |
| 240 |
| 241 // Adds a service worker. Used in the storage integration tests. |
| 242 void AddServiceWorker(const std::string& origin) { |
| 243 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 244 ServiceWorkerContextWrapper* service_worker_context = |
| 245 static_cast<ServiceWorkerContextWrapper*>( |
| 246 BrowserContext::GetDefaultStoragePartition(browser_context()) |
| 247 ->GetServiceWorkerContext()); |
| 248 |
| 249 GURL scope_url = https_server()->GetURL(origin, "/"); |
| 250 GURL js_url = https_server()->GetURL(origin, "/?file=worker.js"); |
| 251 |
| 252 // Register the worker. |
| 253 BrowserThread::PostTask( |
| 254 BrowserThread::IO, FROM_HERE, |
| 255 base::BindOnce( |
| 256 &ServiceWorkerContextWrapper::RegisterServiceWorker, |
| 257 base::Unretained(service_worker_context), scope_url, js_url, |
| 258 base::Bind( |
| 259 &ClearSiteDataThrottleBrowserTest::AddServiceWorkerCallback, |
| 260 base::Unretained(this)))); |
| 261 |
| 262 // Wait for its activation. |
| 263 base::RunLoop run_loop; |
| 264 BrowserThread::PostTask( |
| 265 BrowserThread::IO, FROM_HERE, |
| 266 base::Bind(&ServiceWorkerActivationObserver::SignalActivation, |
| 267 base::Unretained(service_worker_context), |
| 268 run_loop.QuitClosure())); |
| 269 run_loop.Run(); |
| 270 } |
| 271 |
| 272 // Retrieves the list of all service workers. Used in the storage integration |
| 273 // tests. |
| 274 std::vector<ServiceWorkerUsageInfo> GetServiceWorkers() { |
| 275 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 276 ServiceWorkerContextWrapper* service_worker_context = |
| 277 static_cast<ServiceWorkerContextWrapper*>( |
| 278 BrowserContext::GetDefaultStoragePartition(browser_context()) |
| 279 ->GetServiceWorkerContext()); |
| 280 |
| 281 std::vector<ServiceWorkerUsageInfo> service_workers; |
| 282 base::RunLoop run_loop; |
| 283 |
| 284 BrowserThread::PostTask( |
| 285 BrowserThread::IO, FROM_HERE, |
| 286 base::BindOnce( |
| 287 &ServiceWorkerContextWrapper::GetAllOriginsInfo, |
| 288 base::Unretained(service_worker_context), |
| 289 base::Bind( |
| 290 &ClearSiteDataThrottleBrowserTest::GetServiceWorkersCallback, |
| 291 base::Unretained(this), run_loop.QuitClosure(), |
| 292 base::Unretained(&service_workers)))); |
| 293 run_loop.Run(); |
| 294 |
| 295 return service_workers; |
| 296 } |
| 297 |
| 298 TestBrowsingDataRemoverDelegate* delegate() { return &embedder_delegate_; } |
116 | 299 |
117 net::EmbeddedTestServer* https_server() { return https_server_.get(); } | 300 net::EmbeddedTestServer* https_server() { return https_server_.get(); } |
118 | 301 |
119 private: | 302 private: |
120 // Handles all requests. If the request url query contains a "header" key, | 303 // Handles all requests. |
121 // responds with the "Clear-Site-Data" header of the corresponding value. | 304 // |
122 // If the query contains a "redirect" key, responds with a redirect to a url | 305 // Supports the following <key>=<value> query parameters in the url: |
123 // given by the corresponding value. | 306 // <key>="header" responds with the header "Clear-Site-Data: <value>" |
| 307 // <key>="redirect" responds with a redirect to the url <value> |
| 308 // <key>="html" responds with a text/html content <value> |
| 309 // <key>="file" responds with the content of file <value> |
124 // | 310 // |
125 // Example: "https://localhost/?header={}&redirect=example.com" will respond | 311 // Example: "https://localhost/?header={}&redirect=example.com" will respond |
126 // with headers | 312 // with headers |
127 // Clear-Site-Data: {} | 313 // Clear-Site-Data: {} |
128 // Location: example.com | 314 // Location: example.com |
| 315 // |
| 316 // Example: "https://localhost/?html=<html><head></head><body></body></html>" |
| 317 // will respond with the header |
| 318 // Content-Type: text/html |
| 319 // and content |
| 320 // <html><head></head><body></body></html> |
| 321 // |
| 322 // Example: "https://localhost/?file=file.html" |
| 323 // will respond with the header |
| 324 // Content-Type: text/html |
| 325 // and content from the file content/test/data/file.html |
129 std::unique_ptr<net::test_server::HttpResponse> HandleRequest( | 326 std::unique_ptr<net::test_server::HttpResponse> HandleRequest( |
130 const net::test_server::HttpRequest& request) { | 327 const net::test_server::HttpRequest& request) { |
131 std::unique_ptr<net::test_server::BasicHttpResponse> response( | 328 std::unique_ptr<net::test_server::BasicHttpResponse> response( |
132 new net::test_server::BasicHttpResponse()); | 329 new net::test_server::BasicHttpResponse()); |
133 | 330 |
134 std::string value; | 331 std::string value; |
135 if (net::GetValueForKeyInQuery(request.GetURL(), "header", &value)) | 332 if (net::GetValueForKeyInQuery(request.GetURL(), "header", &value)) |
136 response->AddCustomHeader("Clear-Site-Data", value); | 333 response->AddCustomHeader("Clear-Site-Data", value); |
137 | 334 |
138 if (net::GetValueForKeyInQuery(request.GetURL(), "redirect", &value)) { | 335 if (net::GetValueForKeyInQuery(request.GetURL(), "redirect", &value)) { |
139 response->set_code(net::HTTP_FOUND); | 336 response->set_code(net::HTTP_FOUND); |
140 response->AddCustomHeader("Location", value); | 337 response->AddCustomHeader("Location", value); |
141 } else { | 338 } else { |
142 response->set_code(net::HTTP_OK); | 339 response->set_code(net::HTTP_OK); |
143 } | 340 } |
144 | 341 |
| 342 if (net::GetValueForKeyInQuery(request.GetURL(), "html", &value)) { |
| 343 response->set_content_type("text/html"); |
| 344 response->set_content(value); |
| 345 |
| 346 // The "html" parameter is telling the server what to serve, and the XSS |
| 347 // auditor will complain if its |value| contains JS code. Disable that |
| 348 // protection. |
| 349 response->AddCustomHeader("X-XSS-Protection", "0"); |
| 350 } |
| 351 |
| 352 if (net::GetValueForKeyInQuery(request.GetURL(), "file", &value)) { |
| 353 base::FilePath path(GetTestFilePath("browsing_data", value.c_str())); |
| 354 base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ); |
| 355 EXPECT_TRUE(file.IsValid()); |
| 356 int64_t length = file.GetLength(); |
| 357 EXPECT_GE(length, 0); |
| 358 std::unique_ptr<char[]> buffer(new char[length + 1]); |
| 359 file.Read(0, buffer.get(), length); |
| 360 buffer[length] = '\0'; |
| 361 |
| 362 if (path.Extension() == FILE_PATH_LITERAL(".js")) |
| 363 response->set_content_type("application/javascript"); |
| 364 else if (path.Extension() == FILE_PATH_LITERAL(".html")) |
| 365 response->set_content_type("text/html"); |
| 366 else |
| 367 NOTREACHED(); |
| 368 |
| 369 response->set_content(buffer.get()); |
| 370 } |
| 371 |
145 return std::move(response); | 372 return std::move(response); |
146 } | 373 } |
147 | 374 |
148 TestContentBrowserClient test_client_; | 375 // Callback handler for AddCookie(). |
| 376 static void AddCookieCallback(const base::Closure& callback, bool success) { |
| 377 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 378 ASSERT_TRUE(success); |
| 379 callback.Run(); |
| 380 } |
| 381 |
| 382 // Callback handler for GetCookies(). |
| 383 static void GetCookiesCallback(const base::Closure& callback, |
| 384 net::CookieList* out_cookie_list, |
| 385 const net::CookieList& cookie_list) { |
| 386 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 387 *out_cookie_list = cookie_list; |
| 388 callback.Run(); |
| 389 } |
| 390 |
| 391 // Callback handler for AddServiceWorker(). |
| 392 void AddServiceWorkerCallback(bool success) { ASSERT_TRUE(success); } |
| 393 |
| 394 // Callback handler for GetServiceWorkers(). |
| 395 void GetServiceWorkersCallback( |
| 396 const base::Closure& callback, |
| 397 std::vector<ServiceWorkerUsageInfo>* out_service_workers, |
| 398 const std::vector<ServiceWorkerUsageInfo>& service_workers) { |
| 399 *out_service_workers = service_workers; |
| 400 callback.Run(); |
| 401 } |
| 402 |
149 std::unique_ptr<net::EmbeddedTestServer> https_server_; | 403 std::unique_ptr<net::EmbeddedTestServer> https_server_; |
| 404 TestBrowsingDataRemoverDelegate embedder_delegate_; |
| 405 |
| 406 net::CookieStore* cookie_store_; |
150 }; | 407 }; |
151 | 408 |
152 // Tests that the header is recognized on the beginning, in the middle, and on | 409 // Tests that the header is recognized on the beginning, in the middle, and on |
153 // the end of a redirect chain. Each of the three parts of the chain may or | 410 // the end of a navigation redirect chain. Each of the three parts of the chain |
154 // may not send the header, so there are 8 configurations to test. | 411 // may or may not send the header, so there are 8 configurations to test. |
155 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, Redirect) { | 412 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, RedirectNavigation) { |
156 GURL base_urls[3] = { | 413 GURL page_urls[3] = { |
157 https_server()->GetURL("origin1.com", "/"), | 414 https_server()->GetURL("origin1.com", "/"), |
158 https_server()->GetURL("origin2.com", "/foo/bar"), | 415 https_server()->GetURL("origin2.com", "/foo/bar"), |
159 https_server()->GetURL("origin3.com", "/index.html"), | 416 https_server()->GetURL("origin3.com", "/index.html"), |
160 }; | 417 }; |
161 | 418 |
162 // Iterate through the configurations. URLs whose index is matched by the mask | 419 // Iterate through the configurations. URLs whose index is matched by the mask |
163 // will send the header, the others won't. | 420 // will send the header, the others won't. |
164 for (int mask = 0; mask < (1 << 3); ++mask) { | 421 for (int mask = 0; mask < (1 << 3); ++mask) { |
165 GURL urls[3]; | 422 GURL urls[3]; |
166 | 423 |
167 // Set up the expectations. | 424 // Set up the expectations. |
168 for (int i = 0; i < 3; ++i) { | 425 for (int i = 0; i < 3; ++i) { |
169 urls[i] = base_urls[i]; | 426 urls[i] = page_urls[i]; |
170 if (mask & (1 << i)) | 427 if (mask & (1 << i)) |
171 AddQuery(&urls[i], "header", kClearCookiesHeader); | 428 AddQuery(&urls[i], "header", kClearCookiesHeader); |
172 | 429 |
173 EXPECT_CALL(*GetContentBrowserClient(), | 430 if (mask & (1 << i)) |
174 ClearSiteData(shell()->web_contents()->GetBrowserContext(), | 431 delegate()->ExpectClearSiteDataCookiesCall(url::Origin(urls[i])); |
175 url::Origin(urls[i]), _, _, _, _)) | |
176 .Times((mask & (1 << i)) ? 1 : 0); | |
177 } | 432 } |
178 | 433 |
179 // Set up redirects between urls 0 --> 1 --> 2. | 434 // Set up redirects between urls 0 --> 1 --> 2. |
180 AddQuery(&urls[1], "redirect", urls[2].spec()); | 435 AddQuery(&urls[1], "redirect", urls[2].spec()); |
181 AddQuery(&urls[0], "redirect", urls[1].spec()); | 436 AddQuery(&urls[0], "redirect", urls[1].spec()); |
182 | 437 |
183 // Navigate to the first url of the redirect chain. | 438 // Navigate to the first url of the redirect chain. |
184 NavigateToURL(shell(), urls[0]); | 439 NavigateToURL(shell(), urls[0]); |
185 | 440 |
186 // We reached the end of the redirect chain. | 441 // We reached the end of the redirect chain. |
187 EXPECT_EQ(urls[2], shell()->web_contents()->GetURL()); | 442 EXPECT_EQ(urls[2], shell()->web_contents()->GetURL()); |
188 | 443 |
189 testing::Mock::VerifyAndClearExpectations(GetContentBrowserClient()); | 444 delegate()->VerifyAndClearExpectations(); |
190 } | 445 } |
191 } | 446 } |
192 | 447 |
| 448 // Tests that the header is recognized on the beginning, in the middle, and on |
| 449 // the end of a resource load redirect chain. Each of the three parts of the |
| 450 // chain may or may not send the header, so there are 8 configurations to test. |
| 451 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, RedirectResourceLoad) { |
| 452 GURL resource_urls[3] = { |
| 453 https_server()->GetURL("origin1.com", "/redirect-start"), |
| 454 https_server()->GetURL("origin2.com", "/redirect-middle"), |
| 455 https_server()->GetURL("origin3.com", "/redirect-end"), |
| 456 }; |
| 457 |
| 458 // Iterate through the configurations. URLs whose index is matched by the mask |
| 459 // will send the header, the others won't. |
| 460 for (int mask = 0; mask < (1 << 3); ++mask) { |
| 461 GURL urls[3]; |
| 462 |
| 463 // Set up the expectations. |
| 464 for (int i = 0; i < 3; ++i) { |
| 465 urls[i] = resource_urls[i]; |
| 466 if (mask & (1 << i)) |
| 467 AddQuery(&urls[i], "header", kClearCookiesHeader); |
| 468 |
| 469 if (mask & (1 << i)) |
| 470 delegate()->ExpectClearSiteDataCookiesCall(url::Origin(urls[i])); |
| 471 } |
| 472 |
| 473 // Set up redirects between urls 0 --> 1 --> 2. |
| 474 AddQuery(&urls[1], "redirect", urls[2].spec()); |
| 475 AddQuery(&urls[0], "redirect", urls[1].spec()); |
| 476 |
| 477 // Navigate to a page that embeds "https://origin1.com/image.png" |
| 478 // and observe the loading of that resource. |
| 479 GURL page_with_image = https_server()->GetURL("origin4.com", "/index.html"); |
| 480 std::string content_with_image = |
| 481 "<html><head></head><body>" |
| 482 "<img src=\"" + |
| 483 urls[0].spec() + |
| 484 "\" />" |
| 485 "</body></html>"; |
| 486 AddQuery(&page_with_image, "html", content_with_image); |
| 487 NavigateToURL(shell(), page_with_image); |
| 488 |
| 489 delegate()->VerifyAndClearExpectations(); |
| 490 } |
| 491 } |
| 492 |
193 // Tests that the Clear-Site-Data header is ignored for insecure origins. | 493 // Tests that the Clear-Site-Data header is ignored for insecure origins. |
194 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, Insecure) { | 494 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, InsecureNavigation) { |
195 // ClearSiteData() should not be called on HTTP. | 495 // ClearSiteData() should not be called on HTTP. |
196 GURL url = embedded_test_server()->GetURL("example.com", "/"); | 496 GURL url = embedded_test_server()->GetURL("example.com", "/"); |
197 AddQuery(&url, "header", kClearCookiesHeader); | 497 AddQuery(&url, "header", kClearCookiesHeader); |
198 ASSERT_FALSE(url.SchemeIsCryptographic()); | 498 ASSERT_FALSE(url.SchemeIsCryptographic()); |
199 | 499 |
200 EXPECT_CALL(*GetContentBrowserClient(), ClearSiteData(_, _, _, _, _, _)) | |
201 .Times(0); | |
202 | |
203 NavigateToURL(shell(), url); | 500 NavigateToURL(shell(), url); |
204 } | 501 |
205 | 502 // We do not expect any calls to have been made. |
206 // Tests that ClearSiteData() is called for the correct datatypes. | 503 delegate()->VerifyAndClearExpectations(); |
| 504 } |
| 505 |
| 506 // Tests that the Clear-Site-Data header is honored for secure resource loads |
| 507 // and ignored for insecure ones. |
| 508 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, |
| 509 SecureAndInsecureResourceLoad) { |
| 510 GURL insecure_image = |
| 511 embedded_test_server()->GetURL("example.com", "/image.png"); |
| 512 GURL secure_image = https_server()->GetURL("example.com", "/image.png"); |
| 513 |
| 514 ASSERT_TRUE(secure_image.SchemeIsCryptographic()); |
| 515 ASSERT_FALSE(insecure_image.SchemeIsCryptographic()); |
| 516 |
| 517 AddQuery(&secure_image, "header", kClearCookiesHeader); |
| 518 AddQuery(&insecure_image, "header", kClearCookiesHeader); |
| 519 |
| 520 std::string content_with_insecure_image = |
| 521 "<html><head></head><body>" |
| 522 "<img src=\"" + |
| 523 insecure_image.spec() + |
| 524 "\" />" |
| 525 "</body></html>"; |
| 526 |
| 527 std::string content_with_secure_image = |
| 528 "<html><head></head><body>" |
| 529 "<img src=\"" + |
| 530 secure_image.spec() + |
| 531 "\" />" |
| 532 "</body></html>"; |
| 533 |
| 534 // Test insecure resources. |
| 535 GURL insecure_page = embedded_test_server()->GetURL("example.com", "/"); |
| 536 GURL secure_page = https_server()->GetURL("example.com", "/"); |
| 537 |
| 538 AddQuery(&insecure_page, "html", content_with_insecure_image); |
| 539 AddQuery(&secure_page, "html", content_with_insecure_image); |
| 540 |
| 541 // Insecure resource on an insecure page does not execute Clear-Site-Data. |
| 542 NavigateToURL(shell(), insecure_page); |
| 543 |
| 544 // Insecure resource on a secure page does not execute Clear-Site-Data. |
| 545 NavigateToURL(shell(), secure_page); |
| 546 |
| 547 // We do not expect any calls to have been made. |
| 548 delegate()->VerifyAndClearExpectations(); |
| 549 |
| 550 // Test secure resources. |
| 551 insecure_page = embedded_test_server()->GetURL("example.com", "/"); |
| 552 secure_page = https_server()->GetURL("example.com", "/"); |
| 553 |
| 554 AddQuery(&insecure_page, "html", content_with_secure_image); |
| 555 AddQuery(&secure_page, "html", content_with_secure_image); |
| 556 |
| 557 // Secure resource on an insecure page does execute Clear-Site-Data. |
| 558 delegate()->ExpectClearSiteDataCookiesCall(url::Origin(secure_image)); |
| 559 |
| 560 NavigateToURL(shell(), secure_page); |
| 561 delegate()->VerifyAndClearExpectations(); |
| 562 |
| 563 // Secure resource on a secure page does execute Clear-Site-Data. |
| 564 delegate()->ExpectClearSiteDataCookiesCall(url::Origin(secure_image)); |
| 565 |
| 566 NavigateToURL(shell(), secure_page); |
| 567 delegate()->VerifyAndClearExpectations(); |
| 568 } |
| 569 |
| 570 // Tests that the Clear-Site-Data header is ignored for service worker resource |
| 571 // loads. |
| 572 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, ServiceWorker) { |
| 573 GURL origin1 = https_server()->GetURL("origin1.com", "/"); |
| 574 GURL origin2 = https_server()->GetURL("origin2.com", "/"); |
| 575 GURL origin3 = https_server()->GetURL("origin3.com", "/"); |
| 576 GURL origin4 = https_server()->GetURL("origin4.com", "/"); |
| 577 |
| 578 // Navigation to worker_setup.html will install a service worker. Since |
| 579 // the installation is asynchronous, the JS side will inform us about it in |
| 580 // the page title. |
| 581 GURL url = origin1; |
| 582 AddQuery(&url, "file", "worker_setup.html"); |
| 583 NavigateToURL(shell(), url); |
| 584 WaitForTitle(shell(), "service worker is ready"); |
| 585 |
| 586 // The service worker will now serve a page containing several images, which |
| 587 // the browser will try to fetch. The service worker will be instructed |
| 588 // to handle some of the fetches itself, while others will be handled by |
| 589 // the testing server. The setup is the following: |
| 590 // |
| 591 // origin1.com/resource (-> server; should respect header) |
| 592 // origin2.com/resource_from_sw (-> service worker; should not respect header) |
| 593 // origin3.com/resource_from_sw (-> service worker; should not respect header) |
| 594 // origin4.com/resource (-> server; should respect header) |
| 595 // origin1.com/resource_from_sw (-> service worker; should not respect header) |
| 596 // origin2.com/resource (-> server; should respect header) |
| 597 // origin3.com/resource_from_sw (-> service worker; should not respect header) |
| 598 // origin4.com/resource (-> server; should respect header) |
| 599 // |
| 600 // |origin1| and |origin2| are used to test that there is no difference |
| 601 // between same-origin and third-party fetches. Clear-Site-Data should be |
| 602 // called once for each of these origins - caused by the "/resource" fetch, |
| 603 // but not by the "/resource_from_sw" fetch. |origin3| and |origin4| prove |
| 604 // that the number of calls is dependent on the number of network responses, |
| 605 // i.e. that it isn't always 1 as in the case of |origin1| and |origin2|. |
| 606 delegate()->ExpectClearSiteDataCookiesCall(url::Origin(origin1)); |
| 607 delegate()->ExpectClearSiteDataCookiesCall(url::Origin(origin4)); |
| 608 delegate()->ExpectClearSiteDataCookiesCall(url::Origin(origin2)); |
| 609 delegate()->ExpectClearSiteDataCookiesCall(url::Origin(origin4)); |
| 610 |
| 611 url = https_server()->GetURL("origin1.com", "/anything-in-workers-scope"); |
| 612 AddQuery(&url, "origin1", origin1.spec()); |
| 613 AddQuery(&url, "origin2", origin2.spec()); |
| 614 AddQuery(&url, "origin3", origin3.spec()); |
| 615 AddQuery(&url, "origin4", origin4.spec()); |
| 616 NavigateToURL(shell(), url); |
| 617 WaitForTitle(shell(), "done"); |
| 618 delegate()->VerifyAndClearExpectations(); |
| 619 } |
| 620 |
| 621 // Tests that Clear-Site-Data is only executed on a resource fetch |
| 622 // if credentials are allowed in that fetch. |
| 623 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, Credentials) { |
| 624 GURL page_template = https_server()->GetURL("origin1.com", "/"); |
| 625 GURL same_origin_resource = |
| 626 https_server()->GetURL("origin1.com", "/resource"); |
| 627 GURL different_origin_resource = |
| 628 https_server()->GetURL("origin2.com", "/resource"); |
| 629 |
| 630 AddQuery(&same_origin_resource, "header", kClearCookiesHeader); |
| 631 AddQuery(&different_origin_resource, "header", kClearCookiesHeader); |
| 632 |
| 633 const struct TestCase { |
| 634 bool same_origin; |
| 635 std::string credentials; |
| 636 bool should_run; |
| 637 } kTestCases[] = { |
| 638 {true, "", false}, |
| 639 {true, "omit", false}, |
| 640 {true, "same-origin", true}, |
| 641 {true, "include", true}, |
| 642 {false, "", false}, |
| 643 {false, "omit", false}, |
| 644 {false, "same-origin", false}, |
| 645 {false, "include", true}, |
| 646 }; |
| 647 |
| 648 for (const TestCase& test_case : kTestCases) { |
| 649 const GURL& resource = test_case.same_origin ? same_origin_resource |
| 650 : different_origin_resource; |
| 651 std::string credentials = |
| 652 test_case.credentials.empty() |
| 653 ? "" |
| 654 : "credentials: '" + test_case.credentials + "'"; |
| 655 |
| 656 // Fetch a resource. Note that the script also handles fetch() error which |
| 657 // might be thrown for third-party fetches because of missing |
| 658 // Access-Control-Allow-Origin. However, that only affects the visibility |
| 659 // of the response; the header will still be processed. |
| 660 std::string content = base::StringPrintf( |
| 661 "<html><head></head><body><script>" |
| 662 "fetch('%s', {%s})" |
| 663 ".then(function() { document.title = 'done'; })" |
| 664 ".catch(function() { document.title = 'done'; })" |
| 665 "</script></body></html>", |
| 666 resource.spec().c_str(), credentials.c_str()); |
| 667 |
| 668 GURL page = page_template; |
| 669 AddQuery(&page, "html", content); |
| 670 |
| 671 if (test_case.should_run) |
| 672 delegate()->ExpectClearSiteDataCookiesCall(url::Origin(resource)); |
| 673 |
| 674 NavigateToURL(shell(), page); |
| 675 WaitForTitle(shell(), "done"); |
| 676 delegate()->VerifyAndClearExpectations(); |
| 677 } |
| 678 } |
| 679 |
| 680 // Tests that the credentials flag is correctly taken into account when it |
| 681 // interpretation changes after redirect. |
| 682 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, |
| 683 CredentialsOnRedirect) { |
| 684 GURL urls[2] = { |
| 685 https_server()->GetURL("origin1.com", "/image.png"), |
| 686 https_server()->GetURL("origin2.com", "/image.png"), |
| 687 }; |
| 688 |
| 689 AddQuery(&urls[0], "header", kClearCookiesHeader); |
| 690 AddQuery(&urls[1], "header", kClearCookiesHeader); |
| 691 |
| 692 AddQuery(&urls[0], "redirect", urls[1].spec()); |
| 693 |
| 694 // Fetch a resource on origin1.com, which will redirect to origin2.com. |
| 695 // Both URLs will respond with Clear-Site-Data. Since the credentials mode is |
| 696 // 'same-origin', the LOAD_DO_NOT_SAVE_COOKIES flag will be set while |
| 697 // processing the response from origin1.com, but not while processing the |
| 698 // response from origin2.com. Therefore, the deletion will only be executed |
| 699 // for origin1.com. |
| 700 // |
| 701 // Note that the script also handles fetch() error which might be thrown for |
| 702 // third-party fetches because of missing Access-Control-Allow-Origin. |
| 703 // However, that only affects the visibility of the response; the header will |
| 704 // still be processed. |
| 705 std::string content = base::StringPrintf( |
| 706 "<html><head></head><body><script>" |
| 707 "fetch('%s', {'credentials': 'same-origin'})" |
| 708 ".then(function() { document.title = 'done'; })" |
| 709 ".catch(function() { document.title = 'done'; })" |
| 710 "</script></body></html>", |
| 711 urls[0].spec().c_str()); |
| 712 |
| 713 delegate()->ExpectClearSiteDataCookiesCall(url::Origin(urls[0])); |
| 714 |
| 715 GURL page = https_server()->GetURL("origin1.com", "/"); |
| 716 AddQuery(&page, "html", content); |
| 717 |
| 718 NavigateToURL(shell(), page); |
| 719 WaitForTitle(shell(), "done"); |
| 720 delegate()->VerifyAndClearExpectations(); |
| 721 } |
| 722 |
| 723 // Tests that ClearSiteData() is called for the correct data types. |
207 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, Types) { | 724 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, Types) { |
208 GURL base_url = https_server()->GetURL("example.com", "/"); | 725 GURL base_url = https_server()->GetURL("example.com", "/"); |
209 | 726 |
210 struct TestCase { | 727 struct TestCase { |
211 const char* value; | 728 const char* value; |
212 bool remove_cookies; | 729 bool remove_cookies; |
213 bool remove_storage; | 730 bool remove_storage; |
214 bool remove_cache; | 731 bool remove_cache; |
215 } test_cases[] = { | 732 } test_cases[] = { |
216 {"{ \"types\": [ \"cookies\" ] }", true, false, false}, | 733 {"{ \"types\": [ \"cookies\" ] }", true, false, false}, |
217 {"{ \"types\": [ \"storage\" ] }", false, true, false}, | 734 {"{ \"types\": [ \"storage\" ] }", false, true, false}, |
218 {"{ \"types\": [ \"cache\" ] }", false, false, true}, | 735 {"{ \"types\": [ \"cache\" ] }", false, false, true}, |
219 {"{ \"types\": [ \"cookies\", \"storage\" ] }", true, true, false}, | 736 {"{ \"types\": [ \"cookies\", \"storage\" ] }", true, true, false}, |
220 {"{ \"types\": [ \"cookies\", \"cache\" ] }", true, false, true}, | 737 {"{ \"types\": [ \"cookies\", \"cache\" ] }", true, false, true}, |
221 {"{ \"types\": [ \"storage\", \"cache\" ] }", false, true, true}, | 738 {"{ \"types\": [ \"storage\", \"cache\" ] }", false, true, true}, |
222 {"{ \"types\": [ \"cookies\", \"storage\", \"cache\" ] }", true, true, | 739 {"{ \"types\": [ \"cookies\", \"storage\", \"cache\" ] }", true, true, |
223 true}, | 740 true}, |
224 }; | 741 }; |
225 | 742 |
226 for (const TestCase& test_case : test_cases) { | 743 for (const TestCase& test_case : test_cases) { |
227 GURL url = base_url; | 744 GURL url = base_url; |
228 AddQuery(&url, "header", test_case.value); | 745 AddQuery(&url, "header", test_case.value); |
229 | 746 |
230 EXPECT_CALL( | 747 delegate()->ExpectClearSiteDataCall( |
231 *GetContentBrowserClient(), | 748 url::Origin(url), test_case.remove_cookies, test_case.remove_storage, |
232 ClearSiteData(shell()->web_contents()->GetBrowserContext(), | 749 test_case.remove_cache); |
233 url::Origin(url), test_case.remove_cookies, | |
234 test_case.remove_storage, test_case.remove_cache, _)); | |
235 | 750 |
236 NavigateToURL(shell(), url); | 751 NavigateToURL(shell(), url); |
237 | 752 |
238 testing::Mock::VerifyAndClearExpectations(GetContentBrowserClient()); | 753 delegate()->VerifyAndClearExpectations(); |
239 } | 754 } |
240 } | 755 } |
241 | 756 |
| 757 // Integration test for the deletion of cookies. |
| 758 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, |
| 759 CookiesIntegrationTest) { |
| 760 AddCookie(https_server()->GetURL("origin1.com", "/abc")); |
| 761 AddCookie(https_server()->GetURL("subdomain.origin1.com", "/")); |
| 762 AddCookie(https_server()->GetURL("origin2.com", "/def")); |
| 763 AddCookie(https_server()->GetURL("subdomain.origin2.com", "/")); |
| 764 |
| 765 // There are four cookies on two eTLD+1s. |
| 766 net::CookieList cookies = GetCookies(); |
| 767 EXPECT_EQ(4u, cookies.size()); |
| 768 |
| 769 // Let Clear-Site-Data delete the "cookies" of "origin1.com". |
| 770 GURL url = https_server()->GetURL("origin1.com", "/clear-site-data"); |
| 771 AddQuery(&url, "header", kClearCookiesHeader); |
| 772 NavigateToURL(shell(), url); |
| 773 |
| 774 // Only the "origin2.com" eTLD now has cookies. |
| 775 cookies = GetCookies(); |
| 776 ASSERT_EQ(2u, cookies.size()); |
| 777 EXPECT_EQ(cookies[0].Domain(), "origin2.com"); |
| 778 EXPECT_EQ(cookies[1].Domain(), "subdomain.origin2.com"); |
| 779 } |
| 780 |
| 781 // Integration test for the unregistering of service workers. |
| 782 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, |
| 783 StorageServiceWorkersIntegrationTest) { |
| 784 AddServiceWorker("origin1.com"); |
| 785 AddServiceWorker("origin2.com"); |
| 786 |
| 787 // There are two service workers installed on two origins. |
| 788 std::vector<ServiceWorkerUsageInfo> service_workers = GetServiceWorkers(); |
| 789 EXPECT_EQ(2u, service_workers.size()); |
| 790 |
| 791 // Navigate to a URL within the scope of "origin1.com" which responds with |
| 792 // a Clear-Site-Data header. Verify that this did NOT remove the service |
| 793 // worker for "origin1.com", as the header would not be respected outside |
| 794 // of the scope. |
| 795 GURL url = https_server()->GetURL("origin1.com", "/anything-in-the-scope"); |
| 796 AddQuery(&url, "header", "{ \"types\": [ \"storage\" ] }"); |
| 797 NavigateToURL(shell(), url); |
| 798 service_workers = GetServiceWorkers(); |
| 799 EXPECT_EQ(2u, service_workers.size()); |
| 800 |
| 801 // This time, we will navigate to a URL on "origin1.com" that is not handled |
| 802 // by the serice worker, but results in a network request. One such resource |
| 803 // not handled by "worker.js" is the path "resource". |
| 804 // The header will be respected and the worker deleted. |
| 805 url = https_server()->GetURL("origin1.com", "/resource"); |
| 806 AddQuery(&url, "header", "{ \"types\": [ \"storage\" ] }"); |
| 807 NavigateToURL(shell(), url); |
| 808 |
| 809 // Only "origin2.com" now has a service worker. |
| 810 service_workers = GetServiceWorkers(); |
| 811 ASSERT_EQ(1u, service_workers.size()); |
| 812 EXPECT_EQ(service_workers[0].origin, |
| 813 https_server()->GetURL("origin2.com", "/")); |
| 814 |
| 815 // TODO(msramek): Test that the service worker update ping also deletes |
| 816 // the service worker. |
| 817 } |
| 818 |
| 819 // TODO(msramek): Add integration tests for other storage data types, such as |
| 820 // local storage, indexed DB, etc. |
| 821 |
| 822 // Integration test for the deletion of cache entries. |
| 823 // NOTE: This test might be flaky. disk_cache::Backend calls back before cache |
| 824 // entries are actually written to the disk. Other tests using CacheTestUtil |
| 825 // show that a timeout of around 1s between cache operations is necessary to |
| 826 // avoid flakiness. |
| 827 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, CacheIntegrationTest) { |
| 828 const int kTimeoutMs = 1000; |
| 829 |
| 830 CacheTestUtil util( |
| 831 BrowserContext::GetDefaultStoragePartition(browser_context())); |
| 832 std::string url1 = https_server()->GetURL("origin1.com", "/foo").spec(); |
| 833 std::string url2 = https_server()->GetURL("origin1.com", "/bar").spec(); |
| 834 std::string url3 = https_server()->GetURL("origin2.com", "/foo").spec(); |
| 835 std::string url4 = https_server()->GetURL("origin2.com", "/bar").spec(); |
| 836 |
| 837 std::set<std::string> entries_to_create = {url1, url2, url3, url4}; |
| 838 util.CreateCacheEntries(entries_to_create); |
| 839 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(kTimeoutMs)); |
| 840 |
| 841 // There are four cache entries on two origins. |
| 842 std::vector<std::string> cache_keys = util.GetEntryKeys(); |
| 843 EXPECT_EQ(4u, cache_keys.size()); |
| 844 |
| 845 // Let Clear-Site-Data delete the "cache" of "origin1.com". |
| 846 GURL url = https_server()->GetURL("origin1.com", "/clear-site-data"); |
| 847 AddQuery(&url, "header", "{ \"types\": [ \"cache\" ] }"); |
| 848 NavigateToURL(shell(), url); |
| 849 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(kTimeoutMs)); |
| 850 |
| 851 // Only "origin2.com" now has cache entries. |
| 852 cache_keys = util.GetEntryKeys(); |
| 853 ASSERT_EQ(2u, cache_keys.size()); |
| 854 std::sort(cache_keys.begin(), cache_keys.end()); |
| 855 EXPECT_EQ(url4, cache_keys[0]); |
| 856 EXPECT_EQ(url3, cache_keys[1]); |
| 857 } |
| 858 |
| 859 // Tests that closing the tab right after executing Clear-Site-Data does |
| 860 // not crash. |
| 861 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, ClosedTab) { |
| 862 GURL url = https_server()->GetURL("example.com", "/"); |
| 863 AddQuery(&url, "header", kClearCookiesHeader); |
| 864 shell()->LoadURL(url); |
| 865 shell()->Close(); |
| 866 } |
| 867 |
242 } // namespace content | 868 } // namespace content |
OLD | NEW |