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

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

Powered by Google App Engine
This is Rietveld 408576698