OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "content/browser/browsing_data/clear_site_data_throttle.h" |
| 6 |
| 7 #include <memory> |
| 8 |
| 9 #include "base/bind.h" |
| 10 #include "base/callback.h" |
| 11 #include "base/command_line.h" |
| 12 #include "content/public/browser/content_browser_client.h" |
| 13 #include "content/public/browser/web_contents.h" |
| 14 #include "content/public/common/content_switches.h" |
| 15 #include "content/public/test/content_browser_test.h" |
| 16 #include "content/public/test/content_browser_test_utils.h" |
| 17 #include "content/public/test/test_navigation_observer.h" |
| 18 #include "content/shell/browser/shell.h" |
| 19 #include "net/dns/mock_host_resolver.h" |
| 20 #include "net/test/embedded_test_server/http_request.h" |
| 21 #include "net/test/embedded_test_server/http_response.h" |
| 22 #include "testing/gmock/include/gmock/gmock.h" |
| 23 #include "url/origin.h" |
| 24 #include "url/url_constants.h" |
| 25 |
| 26 using testing::_; |
| 27 |
| 28 namespace content { |
| 29 |
| 30 namespace { |
| 31 |
| 32 class TestContentBrowserClient : public ContentBrowserClient { |
| 33 public: |
| 34 MOCK_METHOD5(ClearSiteData, void( |
| 35 content::BrowserContext* browser_context, const url::Origin& origin, |
| 36 bool remove_cookies, bool remove_storage, bool remove_cache)); |
| 37 }; |
| 38 |
| 39 } // namespace |
| 40 |
| 41 |
| 42 class ClearSiteDataThrottleBrowsertest : public ContentBrowserTest { |
| 43 public: |
| 44 void SetUpCommandLine(base::CommandLine* command_line) override { |
| 45 command_line->AppendSwitch( |
| 46 switches::kEnableExperimentalWebPlatformFeatures); |
| 47 } |
| 48 |
| 49 void SetUpOnMainThread() override { |
| 50 SetBrowserClientForTesting(&test_client_); |
| 51 |
| 52 // Header to be served by default. |
| 53 SetHeaderValue("{ \"types\": [ \"cookies\" ] }"); |
| 54 |
| 55 // Run three HTTPS servers, each serving 127.0.0.1 on a different port. |
| 56 origin1_server_.reset(new net::EmbeddedTestServer( |
| 57 net::test_server::EmbeddedTestServer::TYPE_HTTPS)); |
| 58 origin1_server_->RegisterRequestHandler( |
| 59 base::Bind(&ClearSiteDataThrottleBrowsertest::HandleRequestForOrigin1, |
| 60 base::Unretained(this))); |
| 61 |
| 62 origin2_server_.reset(new net::EmbeddedTestServer( |
| 63 net::test_server::EmbeddedTestServer::TYPE_HTTPS)); |
| 64 origin2_server_->RegisterRequestHandler( |
| 65 base::Bind(&ClearSiteDataThrottleBrowsertest::HandleRequestForOrigin2, |
| 66 base::Unretained(this))); |
| 67 |
| 68 origin3_server_.reset(new net::EmbeddedTestServer( |
| 69 net::test_server::EmbeddedTestServer::TYPE_HTTPS)); |
| 70 origin3_server_->RegisterRequestHandler( |
| 71 base::Bind(&ClearSiteDataThrottleBrowsertest::HandleRequestForOrigin3, |
| 72 base::Unretained(this))); |
| 73 |
| 74 ASSERT_TRUE(origin1_server_->Start()); |
| 75 ASSERT_TRUE(origin2_server_->Start()); |
| 76 ASSERT_TRUE(origin3_server_->Start()); |
| 77 } |
| 78 |
| 79 // Getters for the testing server origins, i.e. http(s)://127.0.0.1:<port>. |
| 80 GURL origin1() { return origin1_server_->base_url(); } |
| 81 GURL origin2() { return origin2_server_->base_url(); } |
| 82 GURL origin3() { return origin3_server_->base_url(); } |
| 83 |
| 84 // Defines which of the three origins should send the Clear-Site-Data header. |
| 85 // This is used for testing of the redirect chain where either the start, |
| 86 // middle, or end of the chain sends the header. |
| 87 void SetOriginThatShouldSendClearSiteData(const GURL& origin) { |
| 88 origin_that_should_send_clear_site_data_ = origin; |
| 89 } |
| 90 |
| 91 // Finds out which of the three server origins should send Clear-Site-Data. |
| 92 GURL OriginThatShouldSendClearSiteData() { |
| 93 return origin_that_should_send_clear_site_data_; |
| 94 } |
| 95 |
| 96 // Sets the desired Clear-Site-Data header value to be sent by the servers. |
| 97 void SetHeaderValue(const std::string& value) { |
| 98 header_value_ = value; |
| 99 } |
| 100 |
| 101 TestContentBrowserClient* GetContentBrowserClient() { |
| 102 return &test_client_; |
| 103 } |
| 104 |
| 105 // Navigates over the redirect chain origin1()->origin2()->origin3(), sending |
| 106 // the Clear-Site-Data header on |origin_to_test|. |
| 107 void TestRedirectChainWithHeaderOn(const GURL& origin_to_test) { |
| 108 SCOPED_TRACE( |
| 109 "ClearSiteData() should have been called for " + origin_to_test.spec()); |
| 110 SetOriginThatShouldSendClearSiteData(origin_to_test); |
| 111 |
| 112 // The |tested_origin| is expected to call ClearSiteData(). The other two |
| 113 // origins are not expected to call it. |
| 114 const GURL origins[] = {origin1(), origin2(), origin3()}; |
| 115 for (const GURL& origin : origins) { |
| 116 EXPECT_CALL( |
| 117 *GetContentBrowserClient(), |
| 118 ClearSiteData( |
| 119 shell()->web_contents()->GetBrowserContext(), |
| 120 url::Origin(origin), |
| 121 _, _, _)).Times(origin == origin_to_test ? 1 : 0); |
| 122 } |
| 123 |
| 124 // Navigate to the first origin of the redirect chain. |
| 125 TestNavigationObserver observer(shell()->web_contents()); |
| 126 NavigateToURL(shell(), origin1()); |
| 127 observer.Wait(); |
| 128 |
| 129 // We reached the end of the redirect chain. |
| 130 EXPECT_EQ(origin3(), shell()->web_contents()->GetURL()); |
| 131 } |
| 132 |
| 133 private: |
| 134 // Requests to origin1() always redirect to origin2(). |
| 135 std::unique_ptr<net::test_server::HttpResponse> HandleRequestForOrigin1( |
| 136 const net::test_server::HttpRequest& request) { |
| 137 std::unique_ptr<net::test_server::BasicHttpResponse> response( |
| 138 new net::test_server::BasicHttpResponse()); |
| 139 response->set_code(net::HTTP_FOUND); |
| 140 response->AddCustomHeader( |
| 141 "Location", origin2_server_->base_url().spec()); |
| 142 |
| 143 if (origin1() == OriginThatShouldSendClearSiteData()) { |
| 144 response->AddCustomHeader("Clear-Site-Data", header_value_); |
| 145 } |
| 146 |
| 147 return std::move(response); |
| 148 } |
| 149 |
| 150 // Requests to origin2() always redirect to origin3(). |
| 151 std::unique_ptr<net::test_server::HttpResponse> HandleRequestForOrigin2( |
| 152 const net::test_server::HttpRequest& request) { |
| 153 std::unique_ptr<net::test_server::BasicHttpResponse> response( |
| 154 new net::test_server::BasicHttpResponse()); |
| 155 response->set_code(net::HTTP_FOUND); |
| 156 response->AddCustomHeader( |
| 157 "Location", origin3_server_->base_url().spec()); |
| 158 |
| 159 if (origin2() == OriginThatShouldSendClearSiteData()) |
| 160 response->AddCustomHeader("Clear-Site-Data", header_value_); |
| 161 |
| 162 return std::move(response); |
| 163 } |
| 164 |
| 165 // Requests to origin3() always successfully return an empty content. |
| 166 std::unique_ptr<net::test_server::HttpResponse> HandleRequestForOrigin3( |
| 167 const net::test_server::HttpRequest& request) { |
| 168 std::unique_ptr<net::test_server::BasicHttpResponse> response( |
| 169 new net::test_server::BasicHttpResponse()); |
| 170 response->set_code(net::HTTP_OK); |
| 171 |
| 172 if (origin3() == OriginThatShouldSendClearSiteData()) |
| 173 response->AddCustomHeader("Clear-Site-Data", header_value_); |
| 174 |
| 175 return std::move(response); |
| 176 } |
| 177 |
| 178 TestContentBrowserClient test_client_; |
| 179 std::unique_ptr<net::EmbeddedTestServer> origin1_server_; |
| 180 std::unique_ptr<net::EmbeddedTestServer> origin2_server_; |
| 181 std::unique_ptr<net::EmbeddedTestServer> origin3_server_; |
| 182 GURL origin_that_should_send_clear_site_data_; |
| 183 std::string header_value_; |
| 184 }; |
| 185 |
| 186 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowsertest, RedirectStart) { |
| 187 TestRedirectChainWithHeaderOn(origin1()); |
| 188 } |
| 189 |
| 190 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowsertest, RedirectMiddle) { |
| 191 TestRedirectChainWithHeaderOn(origin2()); |
| 192 } |
| 193 |
| 194 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowsertest, RedirectEnd) { |
| 195 TestRedirectChainWithHeaderOn(origin3()); |
| 196 } |
| 197 |
| 198 // Tests that the Clear-Site-Data header is ignored for insecure origins. |
| 199 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowsertest, Insecure) { |
| 200 // ClearSiteData() should not be called for origin3() ... |
| 201 SetOriginThatShouldSendClearSiteData(origin3()); |
| 202 EXPECT_CALL( |
| 203 *GetContentBrowserClient(), ClearSiteData(_, _, _, _, _)).Times(0); |
| 204 |
| 205 // ... when we navigate to it on HTTP instead of HTTPS. |
| 206 GURL::Replacements replace_scheme; |
| 207 std::string new_scheme = url::kHttpScheme; |
| 208 replace_scheme.SetSchemeStr(new_scheme); |
| 209 GURL origin3_on_http = origin3().ReplaceComponents(replace_scheme); |
| 210 ASSERT_TRUE(origin3_on_http.is_valid()); |
| 211 ASSERT_TRUE(!origin3_on_http.SchemeIsCryptographic()); |
| 212 |
| 213 TestNavigationObserver observer(shell()->web_contents()); |
| 214 NavigateToURL(shell(), origin3_on_http); |
| 215 observer.Wait(); |
| 216 } |
| 217 |
| 218 // Tests that ClearSiteData() is called for the correct datatypes. |
| 219 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowsertest, Types) { |
| 220 SetOriginThatShouldSendClearSiteData(origin3()); |
| 221 |
| 222 struct TestCase { |
| 223 const char* value; |
| 224 bool remove_cookies; |
| 225 bool remove_storage; |
| 226 bool remove_cache; |
| 227 } test_cases[] = { |
| 228 { "{ \"types\": [ \"cookies\" ] }", true, false, false}, |
| 229 { "{ \"types\": [ \"storage\" ] }", false, true, false}, |
| 230 { "{ \"types\": [ \"cache\" ] }", false, false, true}, |
| 231 { "{ \"types\": [ \"cookies\", \"storage\" ] }", true, true, false}, |
| 232 { "{ \"types\": [ \"cookies\", \"cache\" ] }", true, false, true}, |
| 233 { "{ \"types\": [ \"storage\", \"cache\" ] }", false, true, true}, |
| 234 { "{ \"types\": [ \"cookies\", \"storage\", \"cache\" ] }", |
| 235 true, true, true}, |
| 236 }; |
| 237 |
| 238 for (const TestCase& test_case : test_cases) { |
| 239 SetHeaderValue(test_case.value); |
| 240 |
| 241 EXPECT_CALL( |
| 242 *GetContentBrowserClient(), |
| 243 ClearSiteData( |
| 244 shell()->web_contents()->GetBrowserContext(), |
| 245 url::Origin(origin3()), |
| 246 test_case.remove_cookies, |
| 247 test_case.remove_storage, |
| 248 test_case.remove_cache)); |
| 249 |
| 250 TestNavigationObserver observer(shell()->web_contents()); |
| 251 NavigateToURL(shell(), origin3()); |
| 252 observer.Wait(); |
| 253 } |
| 254 } |
| 255 |
| 256 } // namespace content |
OLD | NEW |