 Chromium Code Reviews
 Chromium Code Reviews Issue 2368923003:
  Support the Clear-Site-Data header on resource requests  (Closed)
    
  
    Issue 2368923003:
  Support the Clear-Site-Data header on resource requests  (Closed) 
  | OLD | NEW | 
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "content/browser/browsing_data/clear_site_data_throttle.h" | 5 #include "content/browser/browsing_data/clear_site_data_throttle.h" | 
| 6 | 6 | 
| 7 #include <memory> | 7 #include <memory> | 
| 8 | 8 | 
| 9 #include "base/bind.h" | 9 #include "base/bind.h" | 
| 10 #include "base/callback.h" | 10 #include "base/callback.h" | 
| 11 #include "base/command_line.h" | 11 #include "base/command_line.h" | 
| 12 #include "base/scoped_observer.h" | |
| 13 #include "base/strings/stringprintf.h" | |
| 14 #include "base/strings/utf_string_conversions.h" | |
| 15 #include "content/browser/browsing_data/browsing_data_filter_builder_impl.h" | |
| 16 #include "content/browser/service_worker/service_worker_context_observer.h" | |
| 17 #include "content/browser/service_worker/service_worker_context_wrapper.h" | |
| 18 #include "content/public/browser/browser_context.h" | |
| 19 #include "content/public/browser/browsing_data_remover.h" | |
| 12 #include "content/public/browser/content_browser_client.h" | 20 #include "content/public/browser/content_browser_client.h" | 
| 21 #include "content/public/browser/storage_partition.h" | |
| 13 #include "content/public/browser/web_contents.h" | 22 #include "content/public/browser/web_contents.h" | 
| 14 #include "content/public/common/content_switches.h" | 23 #include "content/public/common/content_switches.h" | 
| 24 #include "content/public/test/browser_test_utils.h" | |
| 25 #include "content/public/test/cache_test_util.h" | |
| 15 #include "content/public/test/content_browser_test.h" | 26 #include "content/public/test/content_browser_test.h" | 
| 16 #include "content/public/test/content_browser_test_utils.h" | 27 #include "content/public/test/content_browser_test_utils.h" | 
| 28 #include "content/public/test/mock_browsing_data_remover_delegate.h" | |
| 17 #include "content/public/test/test_navigation_observer.h" | 29 #include "content/public/test/test_navigation_observer.h" | 
| 18 #include "content/shell/browser/shell.h" | 30 #include "content/shell/browser/shell.h" | 
| 19 #include "net/base/escape.h" | 31 #include "net/base/escape.h" | 
| 20 #include "net/base/url_util.h" | 32 #include "net/base/url_util.h" | 
| 33 #include "net/cookies/cookie_store.h" | |
| 21 #include "net/dns/mock_host_resolver.h" | 34 #include "net/dns/mock_host_resolver.h" | 
| 22 #include "net/test/embedded_test_server/http_request.h" | 35 #include "net/test/embedded_test_server/http_request.h" | 
| 23 #include "net/test/embedded_test_server/http_response.h" | 36 #include "net/test/embedded_test_server/http_response.h" | 
| 37 #include "net/url_request/url_request_context.h" | |
| 38 #include "net/url_request/url_request_context_getter.h" | |
| 24 #include "storage/browser/quota/quota_settings.h" | 39 #include "storage/browser/quota/quota_settings.h" | 
| 25 #include "testing/gmock/include/gmock/gmock.h" | 40 #include "testing/gmock/include/gmock/gmock.h" | 
| 26 #include "url/origin.h" | 41 #include "url/origin.h" | 
| 27 #include "url/url_constants.h" | 42 #include "url/url_constants.h" | 
| 28 | 43 | 
| 29 using testing::_; | 44 using testing::_; | 
| 30 | 45 | 
| 31 namespace content { | 46 namespace content { | 
| 32 | 47 | 
| 33 namespace { | 48 namespace { | 
| 34 | 49 | 
| 35 class MockContentBrowserClient : public ContentBrowserClient { | |
| 36 public: | |
| 37 MOCK_METHOD6(ClearSiteData, | |
| 38 void(content::BrowserContext* browser_context, | |
| 39 const url::Origin& origin, | |
| 40 bool remove_cookies, | |
| 41 bool remove_storage, | |
| 42 bool remove_cache, | |
| 43 const base::Closure& callback)); | |
| 44 | |
| 45 void GetQuotaSettings( | |
| 46 content::BrowserContext* context, | |
| 47 content::StoragePartition* partition, | |
| 48 const storage::OptionalQuotaSettingsCallback& callback) override { | |
| 49 callback.Run(storage::GetHardCodedSettings(100 * 1024 * 1024)); | |
| 50 } | |
| 51 }; | |
| 52 | |
| 53 class TestContentBrowserClient : public MockContentBrowserClient { | |
| 54 public: | |
| 55 void ClearSiteData(content::BrowserContext* browser_context, | |
| 56 const url::Origin& origin, | |
| 57 bool remove_cookies, | |
| 58 bool remove_storage, | |
| 59 bool remove_cache, | |
| 60 const base::Closure& callback) override { | |
| 61 // Record the method call and run the |callback|. | |
| 62 MockContentBrowserClient::ClearSiteData(browser_context, origin, | |
| 63 remove_cookies, remove_storage, | |
| 64 remove_cache, callback); | |
| 65 callback.Run(); | |
| 66 } | |
| 67 }; | |
| 68 | |
| 69 // Adds a key=value pair to the url's query. | 50 // Adds a key=value pair to the url's query. | 
| 70 void AddQuery(GURL* url, const std::string& key, const std::string& value) { | 51 void AddQuery(GURL* url, const std::string& key, const std::string& value) { | 
| 71 *url = GURL(url->spec() + (url->has_query() ? "&" : "?") + key + "=" + | 52 *url = GURL(url->spec() + (url->has_query() ? "&" : "?") + key + "=" + | 
| 72 net::EscapeQueryParamValue(value, false)); | 53 net::EscapeQueryParamValue(value, false)); | 
| 73 } | 54 } | 
| 74 | 55 | 
| 56 // A helper function to synchronize with JS side of the tests. JS can append | |
| 57 // information to the loaded website's title and C++ will wait until that | |
| 58 // happens. | |
| 59 void WaitForTitle(const Shell* shell, const char* expected_title) { | |
| 60 base::string16 expected_title_16 = base::ASCIIToUTF16(expected_title); | |
| 61 TitleWatcher title_watcher(shell->web_contents(), expected_title_16); | |
| 62 ASSERT_EQ(expected_title_16, title_watcher.WaitAndGetTitle()); | |
| 63 } | |
| 64 | |
| 75 // A value of the Clear-Site-Data header that requests cookie deletion. Reused | 65 // A value of the Clear-Site-Data header that requests cookie deletion. Reused | 
| 76 // in tests that need a valid header but do not depend on its value. | 66 // in tests that need a valid header but do not depend on its value. | 
| 77 static const char* kClearCookiesHeader = "{ \"types\": [ \"cookies\" ] }"; | 67 static const char* kClearCookiesHeader = "{ \"types\": [ \"cookies\" ] }"; | 
| 78 | 68 | 
| 69 // 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 | 
| OLD | NEW |