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

Side by Side Diff: content/browser/browsing_data/clear_site_data_throttle_browsertest.cc

Issue 2368923003: Support the Clear-Site-Data header on resource requests (Closed)
Patch Set: Addressed comments. Created 3 years, 6 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 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);
501
502 // We do not expect any calls to have been made.
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();
204 } 721 }
205 722
206 // Tests that ClearSiteData() is called for the correct datatypes. 723 // Tests that ClearSiteData() is called for the correct datatypes.
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");
mmenke 2017/06/06 16:16:09 Why does requesting /resource delete the service w
msramek 2017/06/06 18:20:57 This test conveniently reuses the infrastructure f
mmenke 2017/06/06 18:30:57 Oops, completely missed the header part on the nex
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 datatypes, 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
866 shell()->CloseAllWindows();
msramek 2017/06/06 18:20:57 I changed this to Close(), as this test was failin
867 }
868
242 } // namespace content 869 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698