Chromium Code Reviews| 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 |