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 "components/network_session_configurator/switches.h" | |
13 #include "content/public/browser/content_browser_client.h" | |
14 #include "content/public/browser/web_contents.h" | |
15 #include "content/public/common/content_switches.h" | |
16 #include "content/public/test/content_browser_test.h" | |
17 #include "content/public/test/content_browser_test_utils.h" | |
18 #include "content/public/test/test_navigation_observer.h" | |
19 #include "content/shell/browser/shell.h" | |
20 #include "net/base/escape.h" | |
21 #include "net/base/url_util.h" | |
22 #include "net/dns/mock_host_resolver.h" | |
23 #include "net/test/embedded_test_server/http_request.h" | |
24 #include "net/test/embedded_test_server/http_response.h" | |
25 #include "testing/gmock/include/gmock/gmock.h" | |
26 #include "url/origin.h" | |
27 #include "url/url_constants.h" | |
28 | |
29 using testing::_; | |
30 | |
31 namespace content { | |
32 | |
33 namespace { | |
34 | |
35 class TestContentBrowserClient : public ContentBrowserClient { | |
36 public: | |
37 MOCK_METHOD5(ClearSiteData, void( | |
38 content::BrowserContext* browser_context, const url::Origin& origin, | |
39 bool remove_cookies, bool remove_storage, bool remove_cache)); | |
40 }; | |
41 | |
42 // Adds a key=value pair to the url's query. | |
43 void AddQuery( | |
44 GURL* url, const std::string& key, const std::string& value) { | |
45 *url = GURL( | |
46 url->spec() + | |
47 (url->has_query() ? "&" : "?") + | |
48 key + | |
49 "=" + | |
50 net::EscapeQueryParamValue(value, false)); | |
51 } | |
52 | |
53 // A value of the Clear-Site-Data header that requests cookie deletion. Reused | |
54 // 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")
| |
55 static const char* kClearCookiesHeader = "{ \"types\": [ \"cookies\" ] }"; | |
56 | |
57 } // namespace | |
58 | |
59 | |
60 class ClearSiteDataThrottleBrowsertest : public ContentBrowserTest { | |
61 public: | |
62 void SetUpCommandLine(base::CommandLine* command_line) override { | |
63 ContentBrowserTest::SetUpCommandLine(command_line); | |
64 command_line->AppendSwitch( | |
65 switches::kEnableExperimentalWebPlatformFeatures); | |
66 | |
67 // We're redirecting all hosts to localhost even on HTTPS, so we'll get | |
68 // certificate errors. | |
69 command_line->AppendSwitch(switches::kIgnoreCertificateErrors); | |
70 } | |
71 | |
72 void SetUpOnMainThread() override { | |
73 ContentBrowserTest::SetUpOnMainThread(); | |
74 | |
75 SetBrowserClientForTesting(&test_client_); | |
76 | |
77 // Set up HTTP and HTTPS test servers that handle all hosts. | |
78 host_resolver()->AddRule("*", "127.0.0.1"); | |
79 | |
80 embedded_test_server()->RegisterRequestHandler( | |
81 base::Bind(&ClearSiteDataThrottleBrowsertest::HandleRequest, | |
82 base::Unretained(this))); | |
83 ASSERT_TRUE(embedded_test_server()->Start()); | |
84 | |
85 https_server_.reset(new net::EmbeddedTestServer( | |
86 net::test_server::EmbeddedTestServer::TYPE_HTTPS)); | |
87 https_server_->SetSSLConfig(net::EmbeddedTestServer::CERT_OK); | |
88 https_server_->RegisterRequestHandler( | |
89 base::Bind(&ClearSiteDataThrottleBrowsertest::HandleRequest, | |
90 base::Unretained(this))); | |
91 ASSERT_TRUE(https_server_->Start()); | |
92 } | |
93 | |
94 TestContentBrowserClient* GetContentBrowserClient() { | |
95 return &test_client_; | |
96 } | |
97 | |
98 net::EmbeddedTestServer* https_server() { | |
99 return https_server_.get(); | |
100 } | |
101 | |
102 private: | |
103 // Handles all requests. If the request url query contains a "header" key, | |
104 // responds with the "Clear-Site-Data" header of the corresponding value. | |
105 // If the query contains a "redirect" key, responds with a redirect to a url | |
106 // given by the corresponding value. | |
107 // | |
108 // Example: "https://localhost/?header={}&redirect=example.com" will respond | |
109 // with headers | |
110 // Clear-Site-Data: {} | |
111 // Location: example.com | |
112 std::unique_ptr<net::test_server::HttpResponse> HandleRequest( | |
113 const net::test_server::HttpRequest& request) { | |
114 std::unique_ptr<net::test_server::BasicHttpResponse> response( | |
115 new net::test_server::BasicHttpResponse()); | |
116 | |
117 std::string value; | |
118 if (net::GetValueForKeyInQuery(request.GetURL(), "header", &value)) | |
119 response->AddCustomHeader("Clear-Site-Data", value); | |
120 | |
121 if (net::GetValueForKeyInQuery(request.GetURL(), "redirect", &value)) { | |
122 response->set_code(net::HTTP_FOUND); | |
123 response->AddCustomHeader("Location", value); | |
124 } else { | |
125 response->set_code(net::HTTP_OK); | |
126 } | |
127 | |
128 return std::move(response); | |
129 } | |
130 | |
131 TestContentBrowserClient test_client_; | |
132 std::unique_ptr<net::EmbeddedTestServer> https_server_; | |
133 std::map<GURL, std::string> headers_; | |
134 std::map<GURL, GURL> redirects_; | |
135 }; | |
136 | |
137 // Tests that the header is recognized on the beginning, in the middle, and on | |
138 // the end of a redirect chain. Each of the three parts of the chain may or | |
139 // may not send the header, so there are 8 configurations to test. | |
140 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowsertest, Redirect) { | |
141 GURL base_urls[3] = { | |
142 https_server()->GetURL("origin1.com", "/"), | |
143 https_server()->GetURL("origin2.com", "/foo/bar"), | |
144 https_server()->GetURL("origin3.com", "/index.html"), | |
145 }; | |
146 | |
147 // Iterate through the configurations. URLs whose index is matched by the mask | |
148 // will send the header, the others won't. | |
149 for (int mask = 0; mask < (1 << 3); ++mask) { | |
150 GURL urls[3]; | |
151 | |
152 // Set up the expectations. | |
153 for (int i = 0; i < 3; ++i) { | |
154 urls[i] = base_urls[i]; | |
155 if (mask & (1 << i)) | |
156 AddQuery(&urls[i], "header", kClearCookiesHeader); | |
157 | |
158 EXPECT_CALL( | |
159 *GetContentBrowserClient(), | |
160 ClearSiteData( | |
161 shell()->web_contents()->GetBrowserContext(), | |
162 url::Origin(urls[i]), | |
163 _, _, _)).Times((mask & (1 << i)) ? 1 : 0); | |
164 } | |
165 | |
166 // Set up redirects between urls 0 --> 1 --> 2. | |
167 AddQuery(&urls[1], "redirect", urls[2].spec()); | |
168 AddQuery(&urls[0], "redirect", urls[1].spec()); | |
169 | |
170 // Navigate to the first url of the redirect chain. | |
171 NavigateToURL(shell(), urls[0]); | |
172 | |
173 // We reached the end of the redirect chain. | |
174 EXPECT_EQ(urls[2], shell()->web_contents()->GetURL()); | |
175 | |
176 testing::Mock::VerifyAndClearExpectations(GetContentBrowserClient()); | |
177 } | |
178 } | |
179 | |
180 // Tests that the Clear-Site-Data header is ignored for insecure origins. | |
181 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowsertest, Insecure) { | |
182 // ClearSiteData() should not be called on HTTP. | |
183 GURL url = embedded_test_server()->GetURL("example.com", "/"); | |
184 AddQuery(&url, "header", kClearCookiesHeader); | |
185 ASSERT_FALSE(url.SchemeIsCryptographic()); | |
186 | |
187 EXPECT_CALL( | |
188 *GetContentBrowserClient(), ClearSiteData(_, _, _, _, _)).Times(0); | |
189 | |
190 NavigateToURL(shell(), url); | |
191 } | |
192 | |
193 // Tests that ClearSiteData() is called for the correct datatypes. | |
194 IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowsertest, Types) { | |
195 GURL base_url = https_server()->GetURL("example.com", "/"); | |
196 | |
197 struct TestCase { | |
198 const char* value; | |
199 bool remove_cookies; | |
200 bool remove_storage; | |
201 bool remove_cache; | |
202 } test_cases[] = { | |
203 { "{ \"types\": [ \"cookies\" ] }", true, false, false}, | |
204 { "{ \"types\": [ \"storage\" ] }", false, true, false}, | |
205 { "{ \"types\": [ \"cache\" ] }", false, false, true}, | |
206 { "{ \"types\": [ \"cookies\", \"storage\" ] }", true, true, false}, | |
207 { "{ \"types\": [ \"cookies\", \"cache\" ] }", true, false, true}, | |
208 { "{ \"types\": [ \"storage\", \"cache\" ] }", false, true, true}, | |
209 { "{ \"types\": [ \"cookies\", \"storage\", \"cache\" ] }", | |
210 true, true, true}, | |
211 }; | |
212 | |
213 for (const TestCase& test_case : test_cases) { | |
214 GURL url = base_url; | |
215 AddQuery(&url, "header", test_case.value); | |
216 | |
217 EXPECT_CALL( | |
218 *GetContentBrowserClient(), | |
219 ClearSiteData( | |
220 shell()->web_contents()->GetBrowserContext(), | |
221 url::Origin(url), | |
222 test_case.remove_cookies, | |
223 test_case.remove_storage, | |
224 test_case.remove_cache)); | |
225 | |
226 NavigateToURL(shell(), url); | |
227 | |
228 testing::Mock::VerifyAndClearExpectations(GetContentBrowserClient()); | |
229 } | |
230 } | |
231 | |
232 } // namespace content | |
OLD | NEW |