OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 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 "base/command_line.h" | |
6 #include "base/strings/pattern.h" | |
7 #include "base/strings/utf_string_conversions.h" | |
8 #include "content/public/browser/browser_context.h" | |
9 #include "content/public/browser/navigation_entry.h" | |
10 #include "content/public/browser/plugin_service.h" | |
11 #include "content/public/browser/web_contents.h" | |
12 #include "content/public/common/content_switches.h" | |
13 #include "content/public/common/webplugininfo.h" | |
14 #include "content/public/test/browser_test_utils.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/download_test_observer.h" | |
18 #include "content/public/test/test_navigation_observer.h" | |
19 #include "content/shell/browser/shell.h" | |
20 #include "net/test/embedded_test_server/embedded_test_server.h" | |
21 | |
22 namespace content { | |
23 | |
24 namespace { | |
25 const char kDataUrlBlockedPattern[] = | |
26 "Not allowed to top-level navigate to resource:*"; | |
27 | |
28 const char kHtmlUrl[] = "data:text/html, <html>test</html>"; | |
29 | |
30 // Octet streams are always downloaded. | |
31 const char kOctetStreamUrl[] = "data:application/octet-stream,test"; | |
32 | |
33 // Unknown mime types that aren't handled by plugins are always downloaded. | |
34 const char kUnknownMimeTypeUrl[] = "data:unknown/some-mime,test"; | |
35 | |
36 // A "Hello World" PDF encoded as a data URL. Source of this PDF: | |
37 // ------------------------- | |
38 // %PDF-1.7 | |
39 // 1 0 obj << /Type /Page /Parent 3 0 R /Resources 5 0 R /Contents 2 0 R >> | |
40 // endobj | |
41 // 2 0 obj << /Length 51 >> | |
42 // stream BT | |
43 // /F1 12 Tf | |
44 // 1 0 0 1 100 20 Tm | |
45 // (Hello World)Tj | |
46 // ET | |
47 // endstream | |
48 // endobj | |
49 // 3 0 obj << /Type /Pages /Kids [ 1 0 R ] /Count 1 /MediaBox [ 0 0 300 50] >> | |
50 // endobj | |
51 // 4 0 obj << /Type /Font /Subtype /Type1 /Name /F1 /BaseFont/Arial >> | |
52 // endobj | |
53 // 5 0 obj << /ProcSet[/PDF/Text] /Font <</F1 4 0 R >> >> | |
54 // endobj | |
55 // 6 0 obj << /Type /Catalog /Pages 3 0 R >> | |
56 // endobj | |
57 // trailer << /Root 6 0 R >> | |
58 // ------------------------- | |
59 const char kPdfUrl[] = | |
60 "data:application/pdf;base64,JVBERi0xLjcKMSAwIG9iaiA8PCAvVHlwZSAvUGFnZSAvUG" | |
61 "FyZW50IDMgMCBSIC9SZXNvdXJjZXMgNSAwIFIgL0NvbnRlbnRzIDIgMCBSID4+CmVuZG9iagoy" | |
62 "IDAgb2JqIDw8IC9MZW5ndGggNTEgPj4KIHN0cmVhbSBCVAogL0YxIDEyIFRmCiAxIDAgMCAxID" | |
63 "EwMCAyMCBUbQogKEhlbGxvIFdvcmxkKVRqCiBFVAogZW5kc3RyZWFtCmVuZG9iagozIDAgb2Jq" | |
64 "IDw8IC9UeXBlIC9QYWdlcyAvS2lkcyBbIDEgMCBSIF0gL0NvdW50IDEgL01lZGlhQm94IFsgMC" | |
65 "AwIDMwMCA1MF0gPj4KZW5kb2JqCjQgMCBvYmogPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5" | |
66 "cGUxIC9OYW1lIC9GMSAvQmFzZUZvbnQvQXJpYWwgPj4KZW5kb2JqCjUgMCBvYmogPDwgL1Byb2" | |
67 "NTZXRbL1BERi9UZXh0XSAvRm9udCA8PC9GMSA0IDAgUiA+PiA+PgplbmRvYmoKNiAwIG9iaiA8" | |
68 "PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMyAwIFIgPj4KZW5kb2JqCnRyYWlsZXIgPDwgL1Jvb3" | |
69 "QgNiAwIFIgPj4K"; | |
70 | |
71 // Helper class for testing data URL navigations with and without browser side | |
72 // navigation enabled. | |
73 class DataUrlNavigationTester { | |
74 public: | |
75 DataUrlNavigationTester(Shell* shell) : shell_(shell) {} | |
76 | |
77 // Tests that a direct navigation to a data URL doesn't show a console warning | |
78 // and is not blocked. | |
79 void TestBrowserInitiatedAllowed() { | |
80 ConsoleObserverDelegate console_delegate(shell_->web_contents(), "FINISH"); | |
81 shell_->web_contents()->SetDelegate(&console_delegate); | |
82 | |
83 NavigateToURL( | |
84 shell_, | |
85 GURL("data:text/html,<html><script>console.log('FINISH');</script>")); | |
86 console_delegate.Wait(); | |
87 EXPECT_TRUE(shell_->web_contents()->GetURL().SchemeIs(url::kDataScheme)); | |
88 EXPECT_TRUE(shell_->web_contents() | |
89 ->GetController() | |
90 .GetLastCommittedEntry() | |
91 ->GetURL() | |
92 .SchemeIs(url::kDataScheme)); | |
93 } | |
94 | |
95 // Tests that a direct navigation to a data URL with mime type PDF isn't | |
96 // blocked. | |
97 void TestBrowserInitiatedToPDFAllowed() { | |
98 TestNavigationObserver observer(shell_->web_contents()); | |
99 NavigateToURL(shell_, GURL(kPdfUrl)); | |
100 EXPECT_EQ(GURL(kPdfUrl), observer.last_navigation_url()); | |
101 EXPECT_TRUE(observer.last_navigation_succeeded()); | |
102 EXPECT_TRUE(shell_->web_contents()->GetURL().SchemeIs(url::kDataScheme)); | |
103 EXPECT_TRUE(shell_->web_contents() | |
104 ->GetController() | |
105 .GetLastCommittedEntry() | |
106 ->GetURL() | |
107 .SchemeIs(url::kDataScheme)); | |
108 } | |
109 | |
110 // Test that a window.open on ||original_url| to |data_url| URL is blocked | |
nasko
2017/03/28 19:58:01
nit: Only one |.
meacer
2017/03/30 20:43:55
Done.
| |
111 // and prints a console message. | |
112 void TestWindowOpenBlocked(const GURL& original_url, const GURL& data_url) { | |
113 NavigateToURL(shell_, original_url); | |
114 | |
115 ShellAddedObserver new_shell_observer; | |
116 EXPECT_TRUE(ExecuteScript( | |
117 shell_->web_contents(), | |
118 base::StringPrintf("window.open('%s');", data_url.spec().c_str()))); | |
119 Shell* new_shell = new_shell_observer.GetShell(); | |
120 WaitForLoadStop(new_shell->web_contents()); | |
121 EXPECT_TRUE(new_shell->web_contents()->GetURL().spec().empty()); | |
122 // No navigation should commit. | |
123 EXPECT_FALSE( | |
124 new_shell->web_contents()->GetController().GetLastCommittedEntry()); | |
125 } | |
126 | |
127 // Tests that a redirect from |original_url| to |data_url| is blocked and | |
128 // prints a console message. | |
129 void TestRedirectBlocked(const GURL& original_url, const GURL& data_url) { | |
nasko
2017/03/28 19:58:00
I don't see any redirects in this test method. How
meacer
2017/03/30 20:43:55
As we discussed, my terminology was wrong here. I
| |
130 ASSERT_TRUE(data_url.SchemeIs("data")); | |
131 NavigateToURL(shell_, original_url); | |
132 ConsoleObserverDelegate console_delegate(shell_->web_contents(), | |
133 kDataUrlBlockedPattern); | |
134 shell_->web_contents()->SetDelegate(&console_delegate); | |
135 EXPECT_TRUE(ExecuteScript(shell_->web_contents(), | |
136 base::StringPrintf("window.location.href = '%s';", | |
137 data_url.spec().c_str()))); | |
138 console_delegate.Wait(); | |
139 // Original page shouldn't navigate away. | |
140 EXPECT_EQ(original_url, shell_->web_contents()->GetURL()); | |
141 EXPECT_EQ(original_url, shell_->web_contents() | |
142 ->GetController() | |
143 .GetLastCommittedEntry() | |
144 ->GetURL()); | |
145 } | |
146 | |
147 // Tests that window.open to a data URL is not blocked if the mime type | |
148 // indicates that the URL will be downloaded. | |
149 void TestWindowOpenDownloadAllowed(const GURL& original_url, | |
150 const GURL& data_url) { | |
151 ASSERT_TRUE(data_url.SchemeIs("data")); | |
152 NavigateToURL(shell_, original_url); | |
153 | |
154 ShellAddedObserver new_shell_observer; | |
155 EXPECT_TRUE(ExecuteScript( | |
156 shell_->web_contents(), | |
157 base::StringPrintf("window.open('%s');", data_url.spec().c_str()))); | |
158 Shell* new_shell = new_shell_observer.GetShell(); | |
159 | |
160 DownloadManager* download_manager = BrowserContext::GetDownloadManager( | |
161 new_shell->web_contents()->GetBrowserContext()); | |
162 DownloadTestObserverTerminal download_observer( | |
163 download_manager, 1, DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL); | |
164 | |
165 WaitForLoadStop(new_shell->web_contents()); | |
166 download_observer.WaitForFinished(); | |
nasko
2017/03/28 19:58:01
Would this observer time out if no download occurr
meacer
2017/03/30 20:43:55
Yes, added a comment.
| |
167 | |
168 EXPECT_TRUE(new_shell->web_contents()->GetURL().spec().empty()); | |
169 // No navigation should commit. | |
170 EXPECT_FALSE( | |
171 new_shell->web_contents()->GetController().GetLastCommittedEntry()); | |
172 // Original page shouldn't navigate away. | |
173 EXPECT_EQ(original_url, shell_->web_contents()->GetURL()); | |
174 EXPECT_EQ(original_url, shell_->web_contents() | |
175 ->GetController() | |
176 .GetLastCommittedEntry() | |
177 ->GetURL()); | |
178 } | |
179 | |
180 // Tests that a redirect to a data URL is not blocked if the mime type | |
181 // indicates that the URL will be downloaded. | |
182 void TestRedirectDownloadAllowed(const GURL& original_url, | |
183 const GURL& data_url) { | |
184 ASSERT_TRUE(data_url.SchemeIs("data")); | |
185 NavigateToURL(shell_, original_url); | |
186 | |
187 DownloadManager* download_manager = BrowserContext::GetDownloadManager( | |
188 shell_->web_contents()->GetBrowserContext()); | |
189 DownloadTestObserverTerminal download_observer( | |
190 download_manager, 1, DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL); | |
191 | |
192 EXPECT_TRUE(ExecuteScript(shell_->web_contents(), | |
193 base::StringPrintf("window.location.href = '%s';", | |
194 data_url.spec().c_str()))); | |
195 download_observer.WaitForFinished(); | |
196 | |
197 // Original page shouldn't navigate away. | |
198 EXPECT_EQ(original_url, shell_->web_contents()->GetURL()); | |
199 EXPECT_EQ(original_url, shell_->web_contents() | |
200 ->GetController() | |
201 .GetLastCommittedEntry() | |
202 ->GetURL()); | |
203 } | |
204 | |
205 private: | |
206 Shell* const shell_; | |
207 }; | |
208 | |
209 class ScopedPluginRegister { | |
210 public: | |
211 ScopedPluginRegister(content::PluginService* plugin_service) | |
212 : plugin_service_(plugin_service) { | |
213 const char kPluginName[] = "PDF"; | |
214 const char kPdfMimeType[] = "application/pdf"; | |
215 const char kPdfFileType[] = "pdf"; | |
216 WebPluginInfo plugin_info; | |
217 plugin_info.type = WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS; | |
218 plugin_info.name = base::ASCIIToUTF16(kPluginName); | |
219 plugin_info.mime_types.push_back( | |
220 WebPluginMimeType(kPdfMimeType, kPdfFileType, std::string())); | |
221 plugin_service_->RegisterInternalPlugin(plugin_info, false); | |
222 plugin_service_->RefreshPlugins(); | |
223 } | |
224 | |
225 ~ScopedPluginRegister() { | |
226 std::vector<WebPluginInfo> plugins; | |
227 plugin_service_->GetInternalPlugins(&plugins); | |
228 EXPECT_EQ(1u, plugins.size()); | |
229 plugin_service_->UnregisterInternalPlugin(plugins[0].path); | |
230 plugin_service_->RefreshPlugins(); | |
231 | |
232 plugins.clear(); | |
233 plugin_service_->GetInternalPlugins(&plugins); | |
234 EXPECT_TRUE(plugins.empty()); | |
235 } | |
236 | |
237 private: | |
238 content::PluginService* plugin_service_; | |
239 }; | |
240 | |
241 } // namespace | |
242 | |
243 class DataUrlNavigationBrowserTest : public ContentBrowserTest { | |
244 public: | |
245 DataUrlNavigationBrowserTest() | |
246 : scoped_plugin_register_(PluginService::GetInstance()) {} | |
247 | |
248 protected: | |
249 void SetUpOnMainThread() override { | |
250 ASSERT_TRUE(embedded_test_server()->Start()); | |
251 } | |
252 | |
253 private: | |
254 ScopedPluginRegister scoped_plugin_register_; | |
255 }; | |
256 | |
257 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, BrowserInitiated) { | |
258 DataUrlNavigationTester(shell()).TestBrowserInitiatedAllowed(); | |
259 } | |
260 | |
261 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, RendererInitiated) { | |
262 DataUrlNavigationTester(shell()).TestRedirectBlocked( | |
263 embedded_test_server()->GetURL("/simple_links.html"), GURL(kHtmlUrl)); | |
264 } | |
265 | |
266 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, WindowOpen_Block) { | |
267 DataUrlNavigationTester(shell()).TestWindowOpenBlocked( | |
268 embedded_test_server()->GetURL("/simple_page.html"), GURL(kHtmlUrl)); | |
269 } | |
270 | |
271 // Test that window.open to a data URL is not blocked if the mime type indicates | |
272 // that the URL will be downloaded. | |
273 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, | |
274 WindowOpen_OctetStream_Download) { | |
275 DataUrlNavigationTester(shell()).TestWindowOpenDownloadAllowed( | |
276 embedded_test_server()->GetURL("/simple_page.html"), | |
277 GURL(kOctetStreamUrl)); | |
278 } | |
279 | |
280 // Test that a content initiated navigation to a data URL is not blocked if the | |
281 // mime type indicates that the URL will be downloaded. | |
282 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, | |
283 Redirect_OctetStream_Download) { | |
284 DataUrlNavigationTester(shell()).TestRedirectDownloadAllowed( | |
285 embedded_test_server()->GetURL("/simple_page.html"), | |
286 GURL(kOctetStreamUrl)); | |
287 } | |
288 | |
289 // Test that window.open to a data URL results in an allowed download if the URL | |
290 // has an unknown mime type. | |
291 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, | |
292 WindowOpen_UnknownMimeType_Download) { | |
293 DataUrlNavigationTester(shell()).TestWindowOpenDownloadAllowed( | |
294 embedded_test_server()->GetURL("/simple_page.html"), | |
295 GURL(kUnknownMimeTypeUrl)); | |
296 } | |
297 | |
298 // Test that redirect to a data URL results in an allowed download if the URL | |
299 // has an unknown mime type. | |
300 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, | |
301 Redirect_UnknownMimeType_Download) { | |
302 DataUrlNavigationTester(shell()).TestRedirectDownloadAllowed( | |
303 embedded_test_server()->GetURL("/simple_page.html"), | |
304 GURL(kUnknownMimeTypeUrl)); | |
305 } | |
306 | |
307 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, | |
308 DirectNavigation_PDF_Allow) { | |
309 DataUrlNavigationTester(shell()).TestBrowserInitiatedToPDFAllowed(); | |
310 } | |
311 | |
312 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, WindowOpen_PDF_Block) { | |
313 DataUrlNavigationTester(shell()).TestWindowOpenBlocked( | |
314 embedded_test_server()->GetURL("/simple_page.html"), GURL(kPdfUrl)); | |
315 } | |
316 | |
317 // Test that a content initiated navigation to a data URL should be blocked if | |
318 // the data URL has a mime type that will be handled by a plugin (PDF in this | |
319 // case). | |
320 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, Redirect_PDF_Block) { | |
321 DataUrlNavigationTester(shell()).TestRedirectBlocked( | |
322 embedded_test_server()->GetURL("/simple_page.html"), GURL(kPdfUrl)); | |
323 } | |
324 | |
325 // Same as DataUrlNavigationBrowserTest tests, except these tests have browser | |
326 // side navigation enabled. | |
327 class DataUrlBrowserSideNavigationBrowserTest : public ContentBrowserTest { | |
328 public: | |
329 DataUrlBrowserSideNavigationBrowserTest() | |
330 : scoped_plugin_register_(PluginService::GetInstance()) {} | |
331 | |
332 protected: | |
333 void SetUpCommandLine(base::CommandLine* command_line) override { | |
334 command_line->AppendSwitch(switches::kEnableBrowserSideNavigation); | |
335 } | |
336 | |
337 void SetUpOnMainThread() override { | |
338 ASSERT_TRUE(embedded_test_server()->Start()); | |
339 } | |
340 | |
341 private: | |
342 ScopedPluginRegister scoped_plugin_register_; | |
343 }; | |
344 | |
345 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest, | |
346 BrowserInitiated) { | |
347 DataUrlNavigationTester(shell()).TestBrowserInitiatedAllowed(); | |
348 } | |
349 | |
350 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest, | |
351 RendererInitiated) { | |
352 DataUrlNavigationTester(shell()).TestRedirectBlocked( | |
353 embedded_test_server()->GetURL("/simple_links.html"), GURL(kHtmlUrl)); | |
354 } | |
355 | |
356 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest, | |
357 WindowOpen_Block) { | |
358 DataUrlNavigationTester(shell()).TestWindowOpenBlocked( | |
359 embedded_test_server()->GetURL("/simple_page.html"), GURL(kHtmlUrl)); | |
360 } | |
361 | |
362 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest, | |
363 WindowOpen_OctetStream_Download) { | |
364 DataUrlNavigationTester(shell()).TestWindowOpenDownloadAllowed( | |
365 embedded_test_server()->GetURL("/simple_page.html"), | |
366 GURL(kOctetStreamUrl)); | |
367 } | |
368 | |
369 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest, | |
370 Redirect_OctetStream_Download) { | |
371 DataUrlNavigationTester(shell()).TestRedirectDownloadAllowed( | |
372 embedded_test_server()->GetURL("/simple_page.html"), | |
373 GURL(kOctetStreamUrl)); | |
374 } | |
375 | |
376 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest, | |
377 WindowOpen_UnknownMimeType_Download) { | |
378 DataUrlNavigationTester(shell()).TestWindowOpenDownloadAllowed( | |
379 embedded_test_server()->GetURL("/simple_page.html"), | |
380 GURL(kUnknownMimeTypeUrl)); | |
381 } | |
382 | |
383 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest, | |
384 Redirect_UnknownMimeType_Download) { | |
385 DataUrlNavigationTester(shell()).TestRedirectDownloadAllowed( | |
386 embedded_test_server()->GetURL("/simple_page.html"), | |
387 GURL(kUnknownMimeTypeUrl)); | |
388 } | |
389 | |
390 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest, | |
391 DirectNavigation_PDF_Allow) { | |
392 DataUrlNavigationTester(shell()).TestBrowserInitiatedToPDFAllowed(); | |
393 } | |
394 | |
395 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest, | |
396 WindowOpen_PDF_Block) { | |
397 DataUrlNavigationTester(shell()).TestWindowOpenBlocked( | |
398 embedded_test_server()->GetURL("/simple_page.html"), GURL(kPdfUrl)); | |
399 } | |
400 | |
401 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest, | |
402 Redirect_PDF_Block) { | |
403 DataUrlNavigationTester(shell()).TestRedirectBlocked( | |
404 embedded_test_server()->GetURL("/simple_page.html"), GURL(kPdfUrl)); | |
405 } | |
406 | |
407 } // content | |
OLD | NEW |