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

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: Rebase. 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/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);
61 ASSERT_EQ(expected_title_16, title_watcher.WaitAndGetTitle());
mmenke 2017/05/25 19:23:09 I don't think we want to depend on the implementat
msramek 2017/05/30 21:58:45 Sorry, I don't understand. TitleWatcher constructo
mmenke 2017/05/30 22:58:35 TitleWatcher starts watching, which is rather impo
msramek 2017/06/01 22:02:27 Acknowledged. That's true, but indeed isn't the ca
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 19:23:09 kOriginTypeMatch
msramek 2017/05/30 21:58:45 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::BindOnce(
156 &ClearSiteDataThrottleBrowserTest::InitializeCookieStore,
157 base::Unretained(this),
158 base::Unretained(
159 BrowserContext::GetDefaultStoragePartition(browser_context())
160 ->GetURLRequestContext()),
161 base::Unretained(&waitable_event)));
162 waitable_event.Wait();
mmenke 2017/05/25 19:23:10 optional: I think RunLoops are a lot more common
msramek 2017/05/30 21:58:45 Done. (Changed to RunLoops)
113 } 163 }
114 164
115 TestContentBrowserClient* GetContentBrowserClient() { return &test_client_; } 165 BrowserContext* browser_context() {
166 return shell()->web_contents()->GetBrowserContext();
167 }
168
169 void InitializeCookieStore(
mmenke 2017/05/25 19:23:10 Why is this needed? Can't AddCookie/GetCookie tak
msramek 2017/05/30 21:58:45 We need to do two things on the IO thread: 1. Call
170 net::URLRequestContextGetter* request_context_getter,
171 base::WaitableEvent* waitable_event) {
172 cookie_store_ =
173 request_context_getter->GetURLRequestContext()->cookie_store();
174 waitable_event->Signal();
175 }
176
177 // Adds a cookie for the |url|. Used in the cookie integration tests.
178 void AddCookie(const GURL& url) {
179 DCHECK_CURRENTLY_ON(BrowserThread::UI);
180 base::WaitableEvent waitable_event(
181 base::WaitableEvent::ResetPolicy::MANUAL,
182 base::WaitableEvent::InitialState::NOT_SIGNALED);
183 BrowserThread::PostTask(
184 BrowserThread::IO, FROM_HERE,
185 base::BindOnce(
186 &net::CookieStore::SetCookieWithOptionsAsync,
187 base::Unretained(cookie_store_), url, "A=1", net::CookieOptions(),
188 base::Bind(&ClearSiteDataThrottleBrowserTest::AddCookieCallback,
189 base::Unretained(this),
190 base::Unretained(&waitable_event))));
191 waitable_event.Wait();
192 }
193
194 // Retrieves the list of all cookies. Used in the cookie integration tests.
195 net::CookieList GetCookies() {
196 DCHECK_CURRENTLY_ON(BrowserThread::UI);
197 base::WaitableEvent waitable_event(
198 base::WaitableEvent::ResetPolicy::MANUAL,
199 base::WaitableEvent::InitialState::NOT_SIGNALED);
200 net::CookieList cookie_list;
201 BrowserThread::PostTask(
202 BrowserThread::IO, FROM_HERE,
203 base::BindOnce(
204 &net::CookieStore::GetAllCookiesAsync,
205 base::Unretained(cookie_store_),
206 base::Bind(&ClearSiteDataThrottleBrowserTest::GetCookiesCallback,
207 base::Unretained(this),
208 base::Unretained(&waitable_event),
209 base::Unretained(&cookie_list))));
210 waitable_event.Wait();
211 return cookie_list;
212 }
213
214 // Adds a service worker. Used in the storage integration tests.
215 void AddServiceWorker(const std::string& origin) {
216 DCHECK_CURRENTLY_ON(BrowserThread::UI);
217 ServiceWorkerContextWrapper* service_worker_context =
218 static_cast<ServiceWorkerContextWrapper*>(
219 BrowserContext::GetDefaultStoragePartition(browser_context())
220 ->GetServiceWorkerContext());
221
222 GURL html_url = https_server()->GetURL(origin, "/worker_setup.html");
223 GURL js_url = https_server()->GetURL(origin, "/?file=worker.js");
224 base::RunLoop run_loop;
225
226 BrowserThread::PostTask(
227 BrowserThread::IO, FROM_HERE,
228 base::BindOnce(
229 &ServiceWorkerContextWrapper::RegisterServiceWorker,
230 base::Unretained(service_worker_context), html_url, js_url,
231 base::Bind(
232 &ClearSiteDataThrottleBrowserTest::AddServiceWorkerCallback,
233 base::Unretained(this), base::Unretained(&run_loop))));
234 run_loop.Run();
235 }
236
237 // Retrieves the list of all service workers. Used in the storage integration
238 // tests.
239 std::vector<ServiceWorkerUsageInfo> GetServiceWorkers() {
240 DCHECK_CURRENTLY_ON(BrowserThread::UI);
241 ServiceWorkerContextWrapper* service_worker_context =
242 static_cast<ServiceWorkerContextWrapper*>(
243 BrowserContext::GetDefaultStoragePartition(browser_context())
244 ->GetServiceWorkerContext());
245
246 std::vector<ServiceWorkerUsageInfo> service_workers;
247 base::WaitableEvent waitable_event(
248 base::WaitableEvent::ResetPolicy::MANUAL,
249 base::WaitableEvent::InitialState::NOT_SIGNALED);
250
251 BrowserThread::PostTask(
252 BrowserThread::IO, FROM_HERE,
253 base::BindOnce(
254 &ServiceWorkerContextWrapper::GetAllOriginsInfo,
255 base::Unretained(service_worker_context),
256 base::Bind(
257 &ClearSiteDataThrottleBrowserTest::GetServiceWorkersCallback,
258 base::Unretained(this), base::Unretained(&waitable_event),
259 base::Unretained(&service_workers))));
260 waitable_event.Wait();
261
262 return service_workers;
263 }
264
265 TestBrowsingDataRemoverDelegate* delegate() { return &embedder_delegate_; }
116 266
117 net::EmbeddedTestServer* https_server() { return https_server_.get(); } 267 net::EmbeddedTestServer* https_server() { return https_server_.get(); }
118 268
119 private: 269 private:
120 // Handles all requests. If the request url query contains a "header" key, 270 // Handles all requests.
121 // responds with the "Clear-Site-Data" header of the corresponding value. 271 //
122 // If the query contains a "redirect" key, responds with a redirect to a url 272 // Supports the following <key>=<value> query parameters in the url:
123 // given by the corresponding value. 273 // <key>="header" responds with the header "Clear-Site-Data: <value>"
274 // <key>="redirect" responds with a redirect to the url <value>
275 // <key>="html" responds with a text/html content <value>
276 // <key>="file" responds with the content of file <value>
124 // 277 //
125 // Example: "https://localhost/?header={}&redirect=example.com" will respond 278 // Example: "https://localhost/?header={}&redirect=example.com" will respond
126 // with headers 279 // with headers
127 // Clear-Site-Data: {} 280 // Clear-Site-Data: {}
128 // Location: example.com 281 // Location: example.com
282 //
283 // Example: "https://localhost/?html=<html><head></head><body></body></html>"
284 // will respond with the header
285 // Content-Type: text/html
286 // and content
287 // <html><head></head><body></body></html>
288 //
289 // Example: "https://localhost/?file=file.html
mmenke 2017/05/25 19:23:10 +"
msramek 2017/05/30 21:58:45 Done.
290 // will respond with the header
291 // Content-Type: text/html
292 // and content from the file content/test/data/file.html
129 std::unique_ptr<net::test_server::HttpResponse> HandleRequest( 293 std::unique_ptr<net::test_server::HttpResponse> HandleRequest(
130 const net::test_server::HttpRequest& request) { 294 const net::test_server::HttpRequest& request) {
131 std::unique_ptr<net::test_server::BasicHttpResponse> response( 295 std::unique_ptr<net::test_server::BasicHttpResponse> response(
132 new net::test_server::BasicHttpResponse()); 296 new net::test_server::BasicHttpResponse());
133 297
134 std::string value; 298 std::string value;
135 if (net::GetValueForKeyInQuery(request.GetURL(), "header", &value)) 299 if (net::GetValueForKeyInQuery(request.GetURL(), "header", &value))
136 response->AddCustomHeader("Clear-Site-Data", value); 300 response->AddCustomHeader("Clear-Site-Data", value);
137 301
138 if (net::GetValueForKeyInQuery(request.GetURL(), "redirect", &value)) { 302 if (net::GetValueForKeyInQuery(request.GetURL(), "redirect", &value)) {
139 response->set_code(net::HTTP_FOUND); 303 response->set_code(net::HTTP_FOUND);
140 response->AddCustomHeader("Location", value); 304 response->AddCustomHeader("Location", value);
141 } else { 305 } else {
142 response->set_code(net::HTTP_OK); 306 response->set_code(net::HTTP_OK);
143 } 307 }
144 308
309 if (net::GetValueForKeyInQuery(request.GetURL(), "html", &value)) {
310 response->set_content_type("text/html");
311 response->set_content(value);
312
313 // The "html" parameter is telling the server what to serve, and the XSS
314 // auditor will complain if its |value| contains JS code. Disable that
315 // protection.
316 response->AddCustomHeader("X-XSS-Protection", "0");
317 }
318
319 if (net::GetValueForKeyInQuery(request.GetURL(), "file", &value)) {
320 base::FilePath path(GetTestFilePath("browsing_data", value.c_str()));
321 base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
322 EXPECT_TRUE(file.IsValid());
323 int64_t length = file.GetLength();
324 EXPECT_GE(length, 0);
325 std::unique_ptr<char[]> buffer(new char[length + 1]);
326 file.Read(0, buffer.get(), length);
327 buffer[length] = '\0';
328
329 if (path.Extension() == FILE_PATH_LITERAL(".js"))
330 response->set_content_type("application/javascript");
331 else if (path.Extension() == FILE_PATH_LITERAL(".html"))
332 response->set_content_type("text/html");
333 else
334 NOTREACHED();
335
336 response->set_content(buffer.get());
337 }
338
145 return std::move(response); 339 return std::move(response);
146 } 340 }
147 341
148 TestContentBrowserClient test_client_; 342 // Callback handler for AddCookie().
343 void AddCookieCallback(base::WaitableEvent* waitable_event, bool success) {
mmenke 2017/05/25 19:23:10 static?
msramek 2017/05/30 21:58:45 Done.
344 DCHECK_CURRENTLY_ON(BrowserThread::IO);
345 ASSERT_TRUE(success);
346 waitable_event->Signal();
347 }
348
349 // Callback handler for GetCookies().
350 void GetCookiesCallback(base::WaitableEvent* waitable_event,
mmenke 2017/05/25 19:23:09 static?
msramek 2017/05/30 21:58:45 Done.
351 net::CookieList* out_cookie_list,
352 const net::CookieList& cookie_list) {
353 DCHECK_CURRENTLY_ON(BrowserThread::IO);
354 *out_cookie_list = cookie_list;
355 waitable_event->Signal();
356 }
357
358 // Callback handler for AddServiceWorker().
359 void AddServiceWorkerCallback(base::RunLoop* run_loop, bool success) {
360 ASSERT_TRUE(success);
361 run_loop->Quit();
362 }
363
364 // Callback handler for GetServiceWorkers().
365 void GetServiceWorkersCallback(
366 base::WaitableEvent* waitable_event,
367 std::vector<ServiceWorkerUsageInfo>* out_service_workers,
368 const std::vector<ServiceWorkerUsageInfo>& service_workers) {
369 *out_service_workers = service_workers;
370 waitable_event->Signal();
371 }
372
149 std::unique_ptr<net::EmbeddedTestServer> https_server_; 373 std::unique_ptr<net::EmbeddedTestServer> https_server_;
374 TestBrowsingDataRemoverDelegate embedder_delegate_;
375
376 net::CookieStore* cookie_store_;
150 }; 377 };
151 378
152 // Tests that the header is recognized on the beginning, in the middle, and on 379 // 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 380 // 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. 381 // may or may not send the header, so there are 8 configurations to test.
155 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, Redirect) { 382 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, RedirectNavigation) {
156 GURL base_urls[3] = { 383 GURL base_urls[3] = {
157 https_server()->GetURL("origin1.com", "/"), 384 https_server()->GetURL("origin1.com", "/"),
158 https_server()->GetURL("origin2.com", "/foo/bar"), 385 https_server()->GetURL("origin2.com", "/foo/bar"),
159 https_server()->GetURL("origin3.com", "/index.html"), 386 https_server()->GetURL("origin3.com", "/index.html"),
160 }; 387 };
161 388
162 // Iterate through the configurations. URLs whose index is matched by the mask 389 // Iterate through the configurations. URLs whose index is matched by the mask
163 // will send the header, the others won't. 390 // will send the header, the others won't.
164 for (int mask = 0; mask < (1 << 3); ++mask) { 391 for (int mask = 0; mask < (1 << 3); ++mask) {
165 GURL urls[3]; 392 GURL urls[3];
166 393
167 // Set up the expectations. 394 // Set up the expectations.
168 for (int i = 0; i < 3; ++i) { 395 for (int i = 0; i < 3; ++i) {
169 urls[i] = base_urls[i]; 396 urls[i] = base_urls[i];
170 if (mask & (1 << i)) 397 if (mask & (1 << i))
171 AddQuery(&urls[i], "header", kClearCookiesHeader); 398 AddQuery(&urls[i], "header", kClearCookiesHeader);
172 399
173 EXPECT_CALL(*GetContentBrowserClient(), 400 if (mask & (1 << i))
174 ClearSiteData(shell()->web_contents()->GetBrowserContext(), 401 delegate()->ExpectClearSiteDataCookiesCall(url::Origin(urls[i]));
175 url::Origin(urls[i]), _, _, _, _))
176 .Times((mask & (1 << i)) ? 1 : 0);
177 } 402 }
178 403
179 // Set up redirects between urls 0 --> 1 --> 2. 404 // Set up redirects between urls 0 --> 1 --> 2.
180 AddQuery(&urls[1], "redirect", urls[2].spec()); 405 AddQuery(&urls[1], "redirect", urls[2].spec());
181 AddQuery(&urls[0], "redirect", urls[1].spec()); 406 AddQuery(&urls[0], "redirect", urls[1].spec());
182 407
183 // Navigate to the first url of the redirect chain. 408 // Navigate to the first url of the redirect chain.
184 NavigateToURL(shell(), urls[0]); 409 NavigateToURL(shell(), urls[0]);
185 410
186 // We reached the end of the redirect chain. 411 // We reached the end of the redirect chain.
187 EXPECT_EQ(urls[2], shell()->web_contents()->GetURL()); 412 EXPECT_EQ(urls[2], shell()->web_contents()->GetURL());
188 413
189 testing::Mock::VerifyAndClearExpectations(GetContentBrowserClient()); 414 delegate()->VerifyAndClearExpectations();
190 } 415 }
191 } 416 }
192 417
418 // Tests that the header is recognized on the beginning, in the middle, and on
419 // the end of a resource load redirect chain. Each of the three parts of the
420 // chain may or may not send the header, so there are 8 configurations to test.
421 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, RedirectResourceLoad) {
422 GURL base_urls[3] = {
mmenke 2017/05/25 19:23:09 These don't mean the same thing as https_server()-
msramek 2017/05/30 21:58:45 I added the paths here partially to document the m
423 https_server()->GetURL("origin1.com", "/image.png"),
424 https_server()->GetURL("origin2.com", "/redirected-image.png"),
425 https_server()->GetURL("origin3.com", "/actual-image.png"),
mmenke 2017/05/25 19:23:09 Worth noting that actual-image actually just ends
msramek 2017/05/30 21:58:45 As mentioned in the above comment, I renamed the p
426 };
427
428 // Iterate through the configurations. URLs whose index is matched by the mask
429 // will send the header, the others won't.
430 for (int mask = 0; mask < (1 << 3); ++mask) {
431 GURL urls[3];
432
433 // Set up the expectations.
434 for (int i = 0; i < 3; ++i) {
435 urls[i] = base_urls[i];
436 if (mask & (1 << i))
437 AddQuery(&urls[i], "header", kClearCookiesHeader);
438
439 if (mask & (1 << i))
440 delegate()->ExpectClearSiteDataCookiesCall(url::Origin(urls[i]));
441 }
442
443 // Set up redirects between urls 0 --> 1 --> 2.
444 AddQuery(&urls[1], "redirect", urls[2].spec());
445 AddQuery(&urls[0], "redirect", urls[1].spec());
446
447 // Navigate to a page that embeds "https://origin1.com/image.png"
448 // and observe the loading of that resource.
449 GURL page_with_image = https_server()->GetURL("origin4.com", "/index.html");
450 std::string content_with_image =
451 "<html><head></head><body>"
452 "<img src=\"" +
453 urls[0].spec() +
454 "\" />"
455 "</body></html>";
456 AddQuery(&page_with_image, "html", content_with_image);
457 NavigateToURL(shell(), page_with_image);
458
459 delegate()->VerifyAndClearExpectations();
460 }
461 }
462
193 // Tests that the Clear-Site-Data header is ignored for insecure origins. 463 // Tests that the Clear-Site-Data header is ignored for insecure origins.
194 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, Insecure) { 464 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, InsecureNavigation) {
195 // ClearSiteData() should not be called on HTTP. 465 // ClearSiteData() should not be called on HTTP.
196 GURL url = embedded_test_server()->GetURL("example.com", "/"); 466 GURL url = embedded_test_server()->GetURL("example.com", "/");
197 AddQuery(&url, "header", kClearCookiesHeader); 467 AddQuery(&url, "header", kClearCookiesHeader);
198 ASSERT_FALSE(url.SchemeIsCryptographic()); 468 ASSERT_FALSE(url.SchemeIsCryptographic());
199 469
200 EXPECT_CALL(*GetContentBrowserClient(), ClearSiteData(_, _, _, _, _, _))
201 .Times(0);
202
203 NavigateToURL(shell(), url); 470 NavigateToURL(shell(), url);
471
472 // We do not expect any calls to have been made.
473 delegate()->VerifyAndClearExpectations();
474 }
475
476 // Tests that the Clear-Site-Data header is honored for secure resource loads
477 // and ignored for insecure ones.
mmenke 2017/05/25 19:23:10 This doesn't check the header is ignored for insec
msramek 2017/05/30 21:58:45 It does? This test tries all four combinations - i
mmenke 2017/05/30 22:58:35 Hrm...not sure what I was thinking. I'll take ano
478 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest,
479 SecureAndInsecureResourceLoad) {
480 GURL insecure_image =
481 embedded_test_server()->GetURL("example.com", "/image.png");
482 GURL secure_image = https_server()->GetURL("example.com", "/image.png");
483
484 ASSERT_TRUE(secure_image.SchemeIsCryptographic());
485 ASSERT_FALSE(insecure_image.SchemeIsCryptographic());
486
487 AddQuery(&secure_image, "header", kClearCookiesHeader);
488 AddQuery(&insecure_image, "header", kClearCookiesHeader);
489
490 std::string content_with_insecure_image =
491 "<html><head></head><body>"
492 "<img src=\"" +
493 insecure_image.spec() +
494 "\" />"
495 "</body></html>";
496
497 std::string content_with_secure_image =
498 "<html><head></head><body>"
499 "<img src=\"" +
500 secure_image.spec() +
501 "\" />"
502 "</body></html>";
503
504 // Test insecure resources.
505 GURL insecure_page = embedded_test_server()->GetURL("example.com", "/");
506 GURL secure_page = https_server()->GetURL("example.com", "/");
507
508 AddQuery(&insecure_page, "html", content_with_insecure_image);
509 AddQuery(&secure_page, "html", content_with_insecure_image);
510
511 // Insecure resource on an insecure page does not execute Clear-Site-Data.
512 NavigateToURL(shell(), insecure_page);
513
514 // Insecure resource on a secure page does not execute Clear-Site-Data.
515 NavigateToURL(shell(), secure_page);
516
517 // We do not expect any calls to have been made.
518 delegate()->VerifyAndClearExpectations();
519
520 // Test secure resources.
521 insecure_page = embedded_test_server()->GetURL("example.com", "/");
522 secure_page = https_server()->GetURL("example.com", "/");
523
524 AddQuery(&insecure_page, "html", content_with_secure_image);
525 AddQuery(&secure_page, "html", content_with_secure_image);
526
527 // Secure resource on an insecure page does execute Clear-Site-Data.
528 delegate()->ExpectClearSiteDataCookiesCall(url::Origin(secure_image));
529
530 NavigateToURL(shell(), secure_page);
531 delegate()->VerifyAndClearExpectations();
532
533 // Secure resource on a secure page does execute Clear-Site-Data.
534 delegate()->ExpectClearSiteDataCookiesCall(url::Origin(secure_image));
535
536 NavigateToURL(shell(), secure_page);
537 delegate()->VerifyAndClearExpectations();
538 }
539
540 // Tests that the Clear-Site-Data header is ignored for service worker resource
541 // loads.
542 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, ServiceWorker) {
543 GURL origin1 = https_server()->GetURL("origin1.com", "/");
544 GURL origin2 = https_server()->GetURL("origin2.com", "/");
545 GURL origin3 = https_server()->GetURL("origin3.com", "/");
546 GURL origin4 = https_server()->GetURL("origin4.com", "/");
547
548 // Navigation to worker_setup.html will install a service worker. Since
549 // the installation is asynchronous, the JS side will inform us about it in
550 // the page title.
551 GURL url = origin1;
552 AddQuery(&url, "file", "worker_setup.html");
553 NavigateToURL(shell(), url);
554 WaitForTitle(shell(), "service worker is ready");
555
556 // The service worker will now serve a page containing several images, which
557 // the browser will try to fetch. The service worker will be instructed
558 // to handle some of the fetches itself, while others will be handled by
559 // the testing server. The setup is the following:
560 //
561 // origin1.com/resource (-> server; should respect header)
562 // origin1.com/resource_from_sw (-> service worker; should not respect header)
563 // origin2.com/resource_from_sw (-> service worker; should not respect header)
564 // origin2.com/resource (-> server; should respect header)
565 // origin3.com/resource_from_sw (-> service worker; should not respect header)
566 // origin3.com/resource_from_sw (-> service worker; should not respect header)
567 // origin4.com/resource (-> server; should respect header)
568 // origin4.com/resource (-> server; should respect header)
mmenke 2017/05/25 19:23:09 Out of paranoia, and since we check ordering, woul
msramek 2017/05/30 21:58:44 Done. That's fine, I like paranoid tests :) Inter
mmenke 2017/05/31 16:25:33 I didn't realize it wasn't fetching sequentially..
569 //
570 // |origin1| and |origin2| are used to test that there is no difference
571 // between same-origin and third-party fetches. Clear-Site-Data should be
572 // called once for each of these origins - caused by the "/resource" fetch,
573 // but not by the "/resource_from_sw" fetch. |origin3| and |origin4| prove
574 // that the number of calls is dependent on the number of network responses,
575 // i.e. that it isn't always 1 as in the case of |origin1| and |origin2|.
576 delegate()->ExpectClearSiteDataCookiesCall(url::Origin(origin1));
577 delegate()->ExpectClearSiteDataCookiesCall(url::Origin(origin2));
578 delegate()->ExpectClearSiteDataCookiesCall(url::Origin(origin4));
579 delegate()->ExpectClearSiteDataCookiesCall(url::Origin(origin4));
580
581 url = https_server()->GetURL("origin1.com", "/anything-in-workers-scope");
582 AddQuery(&url, "origin1", origin1.spec());
583 AddQuery(&url, "origin2", origin2.spec());
584 AddQuery(&url, "origin3", origin3.spec());
585 AddQuery(&url, "origin4", origin4.spec());
586 NavigateToURL(shell(), url);
587 WaitForTitle(shell(), "done");
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());
mmenke 2017/05/25 19:23:10 ASSERT_EQ?
msramek 2017/05/30 21:58:45 Done.
747 EXPECT_EQ(cookies[1].Domain(), "subdomain.origin2.com");
748 EXPECT_EQ(cookies[0].Domain(), "origin2.com");
mmenke 2017/05/25 19:23:10 nit: Why the flipped order?
msramek 2017/05/30 21:58:45 Done. Flipped, no reason :)
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");
mmenke 2017/05/25 19:23:09 Why doesn't origin1's SW intercept this and return
msramek 2017/05/30 21:58:45 That's a great question :) Apparently I confused t
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());
mmenke 2017/05/25 19:23:10 ASSERT_EQ?
msramek 2017/05/30 21:58:45 Done.
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