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