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

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

Powered by Google App Engine
This is Rietveld 408576698