Index: content/browser/browsing_data/clear_site_data_throttle_browsertest.cc |
diff --git a/content/browser/browsing_data/clear_site_data_throttle_browsertest.cc b/content/browser/browsing_data/clear_site_data_throttle_browsertest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..79902e8de410fb84ff301e611710fadc9d834dc2 |
--- /dev/null |
+++ b/content/browser/browsing_data/clear_site_data_throttle_browsertest.cc |
@@ -0,0 +1,232 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "content/browser/browsing_data/clear_site_data_throttle.h" |
+ |
+#include <memory> |
+ |
+#include "base/bind.h" |
+#include "base/callback.h" |
+#include "base/command_line.h" |
+#include "components/network_session_configurator/switches.h" |
+#include "content/public/browser/content_browser_client.h" |
+#include "content/public/browser/web_contents.h" |
+#include "content/public/common/content_switches.h" |
+#include "content/public/test/content_browser_test.h" |
+#include "content/public/test/content_browser_test_utils.h" |
+#include "content/public/test/test_navigation_observer.h" |
+#include "content/shell/browser/shell.h" |
+#include "net/base/escape.h" |
+#include "net/base/url_util.h" |
+#include "net/dns/mock_host_resolver.h" |
+#include "net/test/embedded_test_server/http_request.h" |
+#include "net/test/embedded_test_server/http_response.h" |
+#include "testing/gmock/include/gmock/gmock.h" |
+#include "url/origin.h" |
+#include "url/url_constants.h" |
+ |
+using testing::_; |
+ |
+namespace content { |
+ |
+namespace { |
+ |
+class TestContentBrowserClient : public ContentBrowserClient { |
+ public: |
+ MOCK_METHOD5(ClearSiteData, void( |
+ content::BrowserContext* browser_context, const url::Origin& origin, |
+ bool remove_cookies, bool remove_storage, bool remove_cache)); |
+}; |
+ |
+// Adds a key=value pair to the url's query. |
+void AddQuery( |
+ GURL* url, const std::string& key, const std::string& value) { |
+ *url = GURL( |
+ url->spec() + |
+ (url->has_query() ? "&" : "?") + |
+ key + |
+ "=" + |
+ net::EscapeQueryParamValue(value, false)); |
+} |
+ |
+// A value of the Clear-Site-Data header that requests cookie deletion. Reused |
+// in tests that need a valid header but do not depend about its value. |
Mike West
2016/07/18 08:48:18
Nit: s/depend about/depend on/
msramek
2016/07/18 10:02:04
Done. (I originally wrote "care about")
|
+static const char* kClearCookiesHeader = "{ \"types\": [ \"cookies\" ] }"; |
+ |
+} // namespace |
+ |
+ |
+class ClearSiteDataThrottleBrowsertest : public ContentBrowserTest { |
+ public: |
+ void SetUpCommandLine(base::CommandLine* command_line) override { |
+ ContentBrowserTest::SetUpCommandLine(command_line); |
+ command_line->AppendSwitch( |
+ switches::kEnableExperimentalWebPlatformFeatures); |
+ |
+ // We're redirecting all hosts to localhost even on HTTPS, so we'll get |
+ // certificate errors. |
+ command_line->AppendSwitch(switches::kIgnoreCertificateErrors); |
+ } |
+ |
+ void SetUpOnMainThread() override { |
+ ContentBrowserTest::SetUpOnMainThread(); |
+ |
+ SetBrowserClientForTesting(&test_client_); |
+ |
+ // Set up HTTP and HTTPS test servers that handle all hosts. |
+ host_resolver()->AddRule("*", "127.0.0.1"); |
+ |
+ embedded_test_server()->RegisterRequestHandler( |
+ base::Bind(&ClearSiteDataThrottleBrowsertest::HandleRequest, |
+ base::Unretained(this))); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ https_server_.reset(new net::EmbeddedTestServer( |
+ net::test_server::EmbeddedTestServer::TYPE_HTTPS)); |
+ https_server_->SetSSLConfig(net::EmbeddedTestServer::CERT_OK); |
+ https_server_->RegisterRequestHandler( |
+ base::Bind(&ClearSiteDataThrottleBrowsertest::HandleRequest, |
+ base::Unretained(this))); |
+ ASSERT_TRUE(https_server_->Start()); |
+ } |
+ |
+ TestContentBrowserClient* GetContentBrowserClient() { |
+ return &test_client_; |
+ } |
+ |
+ net::EmbeddedTestServer* https_server() { |
+ return https_server_.get(); |
+ } |
+ |
+ private: |
+ // Handles all requests. If the request url query contains a "header" key, |
+ // responds with the "Clear-Site-Data" header of the corresponding value. |
+ // If the query contains a "redirect" key, responds with a redirect to a url |
+ // given by the corresponding value. |
+ // |
+ // Example: "https://localhost/?header={}&redirect=example.com" will respond |
+ // with headers |
+ // Clear-Site-Data: {} |
+ // Location: example.com |
+ std::unique_ptr<net::test_server::HttpResponse> HandleRequest( |
+ const net::test_server::HttpRequest& request) { |
+ std::unique_ptr<net::test_server::BasicHttpResponse> response( |
+ new net::test_server::BasicHttpResponse()); |
+ |
+ std::string value; |
+ if (net::GetValueForKeyInQuery(request.GetURL(), "header", &value)) |
+ response->AddCustomHeader("Clear-Site-Data", value); |
+ |
+ if (net::GetValueForKeyInQuery(request.GetURL(), "redirect", &value)) { |
+ response->set_code(net::HTTP_FOUND); |
+ response->AddCustomHeader("Location", value); |
+ } else { |
+ response->set_code(net::HTTP_OK); |
+ } |
+ |
+ return std::move(response); |
+ } |
+ |
+ TestContentBrowserClient test_client_; |
+ std::unique_ptr<net::EmbeddedTestServer> https_server_; |
+ std::map<GURL, std::string> headers_; |
+ std::map<GURL, GURL> redirects_; |
+}; |
+ |
+// Tests that the header is recognized on the beginning, in the middle, and on |
+// the end of a redirect chain. Each of the three parts of the chain may or |
+// may not send the header, so there are 8 configurations to test. |
+IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowsertest, Redirect) { |
+ GURL base_urls[3] = { |
+ https_server()->GetURL("origin1.com", "/"), |
+ https_server()->GetURL("origin2.com", "/foo/bar"), |
+ https_server()->GetURL("origin3.com", "/index.html"), |
+ }; |
+ |
+ // Iterate through the configurations. URLs whose index is matched by the mask |
+ // will send the header, the others won't. |
+ for (int mask = 0; mask < (1 << 3); ++mask) { |
+ GURL urls[3]; |
+ |
+ // Set up the expectations. |
+ for (int i = 0; i < 3; ++i) { |
+ urls[i] = base_urls[i]; |
+ if (mask & (1 << i)) |
+ AddQuery(&urls[i], "header", kClearCookiesHeader); |
+ |
+ EXPECT_CALL( |
+ *GetContentBrowserClient(), |
+ ClearSiteData( |
+ shell()->web_contents()->GetBrowserContext(), |
+ url::Origin(urls[i]), |
+ _, _, _)).Times((mask & (1 << i)) ? 1 : 0); |
+ } |
+ |
+ // Set up redirects between urls 0 --> 1 --> 2. |
+ AddQuery(&urls[1], "redirect", urls[2].spec()); |
+ AddQuery(&urls[0], "redirect", urls[1].spec()); |
+ |
+ // Navigate to the first url of the redirect chain. |
+ NavigateToURL(shell(), urls[0]); |
+ |
+ // We reached the end of the redirect chain. |
+ EXPECT_EQ(urls[2], shell()->web_contents()->GetURL()); |
+ |
+ testing::Mock::VerifyAndClearExpectations(GetContentBrowserClient()); |
+ } |
+} |
+ |
+// Tests that the Clear-Site-Data header is ignored for insecure origins. |
+IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowsertest, Insecure) { |
+ // ClearSiteData() should not be called on HTTP. |
+ GURL url = embedded_test_server()->GetURL("example.com", "/"); |
+ AddQuery(&url, "header", kClearCookiesHeader); |
+ ASSERT_FALSE(url.SchemeIsCryptographic()); |
+ |
+ EXPECT_CALL( |
+ *GetContentBrowserClient(), ClearSiteData(_, _, _, _, _)).Times(0); |
+ |
+ NavigateToURL(shell(), url); |
+} |
+ |
+// Tests that ClearSiteData() is called for the correct datatypes. |
+IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowsertest, Types) { |
+ GURL base_url = https_server()->GetURL("example.com", "/"); |
+ |
+ struct TestCase { |
+ const char* value; |
+ bool remove_cookies; |
+ bool remove_storage; |
+ bool remove_cache; |
+ } test_cases[] = { |
+ { "{ \"types\": [ \"cookies\" ] }", true, false, false}, |
+ { "{ \"types\": [ \"storage\" ] }", false, true, false}, |
+ { "{ \"types\": [ \"cache\" ] }", false, false, true}, |
+ { "{ \"types\": [ \"cookies\", \"storage\" ] }", true, true, false}, |
+ { "{ \"types\": [ \"cookies\", \"cache\" ] }", true, false, true}, |
+ { "{ \"types\": [ \"storage\", \"cache\" ] }", false, true, true}, |
+ { "{ \"types\": [ \"cookies\", \"storage\", \"cache\" ] }", |
+ true, true, true}, |
+ }; |
+ |
+ for (const TestCase& test_case : test_cases) { |
+ GURL url = base_url; |
+ AddQuery(&url, "header", test_case.value); |
+ |
+ EXPECT_CALL( |
+ *GetContentBrowserClient(), |
+ ClearSiteData( |
+ shell()->web_contents()->GetBrowserContext(), |
+ url::Origin(url), |
+ test_case.remove_cookies, |
+ test_case.remove_storage, |
+ test_case.remove_cache)); |
+ |
+ NavigateToURL(shell(), url); |
+ |
+ testing::Mock::VerifyAndClearExpectations(GetContentBrowserClient()); |
+ } |
+} |
+ |
+} // namespace content |