Index: content/browser/frame_host/data_url_navigation_browsertest.cc |
diff --git a/content/browser/frame_host/data_url_navigation_browsertest.cc b/content/browser/frame_host/data_url_navigation_browsertest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..70cce0d5fabdf5fe2d5ad4a6245b8656707f05ec |
--- /dev/null |
+++ b/content/browser/frame_host/data_url_navigation_browsertest.cc |
@@ -0,0 +1,407 @@ |
+// Copyright 2017 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "base/command_line.h" |
+#include "base/strings/pattern.h" |
+#include "base/strings/utf_string_conversions.h" |
+#include "content/public/browser/browser_context.h" |
+#include "content/public/browser/navigation_entry.h" |
+#include "content/public/browser/plugin_service.h" |
+#include "content/public/browser/web_contents.h" |
+#include "content/public/common/content_switches.h" |
+#include "content/public/common/webplugininfo.h" |
+#include "content/public/test/browser_test_utils.h" |
+#include "content/public/test/content_browser_test.h" |
+#include "content/public/test/content_browser_test_utils.h" |
+#include "content/public/test/download_test_observer.h" |
+#include "content/public/test/test_navigation_observer.h" |
+#include "content/shell/browser/shell.h" |
+#include "net/test/embedded_test_server/embedded_test_server.h" |
+ |
+namespace content { |
+ |
+namespace { |
+const char kDataUrlBlockedPattern[] = |
+ "Not allowed to top-level navigate to resource:*"; |
+ |
+const char kHtmlUrl[] = "data:text/html, <html>test</html>"; |
+ |
+// Octet streams are always downloaded. |
+const char kOctetStreamUrl[] = "data:application/octet-stream,test"; |
+ |
+// Unknown mime types that aren't handled by plugins are always downloaded. |
+const char kUnknownMimeTypeUrl[] = "data:unknown/some-mime,test"; |
+ |
+// A "Hello World" PDF encoded as a data URL. Source of this PDF: |
+// ------------------------- |
+// %PDF-1.7 |
+// 1 0 obj << /Type /Page /Parent 3 0 R /Resources 5 0 R /Contents 2 0 R >> |
+// endobj |
+// 2 0 obj << /Length 51 >> |
+// stream BT |
+// /F1 12 Tf |
+// 1 0 0 1 100 20 Tm |
+// (Hello World)Tj |
+// ET |
+// endstream |
+// endobj |
+// 3 0 obj << /Type /Pages /Kids [ 1 0 R ] /Count 1 /MediaBox [ 0 0 300 50] >> |
+// endobj |
+// 4 0 obj << /Type /Font /Subtype /Type1 /Name /F1 /BaseFont/Arial >> |
+// endobj |
+// 5 0 obj << /ProcSet[/PDF/Text] /Font <</F1 4 0 R >> >> |
+// endobj |
+// 6 0 obj << /Type /Catalog /Pages 3 0 R >> |
+// endobj |
+// trailer << /Root 6 0 R >> |
+// ------------------------- |
+const char kPdfUrl[] = |
+ "data:application/pdf;base64,JVBERi0xLjcKMSAwIG9iaiA8PCAvVHlwZSAvUGFnZSAvUG" |
+ "FyZW50IDMgMCBSIC9SZXNvdXJjZXMgNSAwIFIgL0NvbnRlbnRzIDIgMCBSID4+CmVuZG9iagoy" |
+ "IDAgb2JqIDw8IC9MZW5ndGggNTEgPj4KIHN0cmVhbSBCVAogL0YxIDEyIFRmCiAxIDAgMCAxID" |
+ "EwMCAyMCBUbQogKEhlbGxvIFdvcmxkKVRqCiBFVAogZW5kc3RyZWFtCmVuZG9iagozIDAgb2Jq" |
+ "IDw8IC9UeXBlIC9QYWdlcyAvS2lkcyBbIDEgMCBSIF0gL0NvdW50IDEgL01lZGlhQm94IFsgMC" |
+ "AwIDMwMCA1MF0gPj4KZW5kb2JqCjQgMCBvYmogPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5" |
+ "cGUxIC9OYW1lIC9GMSAvQmFzZUZvbnQvQXJpYWwgPj4KZW5kb2JqCjUgMCBvYmogPDwgL1Byb2" |
+ "NTZXRbL1BERi9UZXh0XSAvRm9udCA8PC9GMSA0IDAgUiA+PiA+PgplbmRvYmoKNiAwIG9iaiA8" |
+ "PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMyAwIFIgPj4KZW5kb2JqCnRyYWlsZXIgPDwgL1Jvb3" |
+ "QgNiAwIFIgPj4K"; |
+ |
+// Helper class for testing data URL navigations with and without browser side |
+// navigation enabled. |
+class DataUrlNavigationTester { |
+ public: |
+ DataUrlNavigationTester(Shell* shell) : shell_(shell) {} |
+ |
+ // Tests that a direct navigation to a data URL doesn't show a console warning |
+ // and is not blocked. |
+ void TestBrowserInitiatedAllowed() { |
+ ConsoleObserverDelegate console_delegate(shell_->web_contents(), "FINISH"); |
+ shell_->web_contents()->SetDelegate(&console_delegate); |
+ |
+ NavigateToURL( |
+ shell_, |
+ GURL("data:text/html,<html><script>console.log('FINISH');</script>")); |
+ console_delegate.Wait(); |
+ EXPECT_TRUE(shell_->web_contents()->GetURL().SchemeIs(url::kDataScheme)); |
+ EXPECT_TRUE(shell_->web_contents() |
+ ->GetController() |
+ .GetLastCommittedEntry() |
+ ->GetURL() |
+ .SchemeIs(url::kDataScheme)); |
+ } |
+ |
+ // Tests that a direct navigation to a data URL with mime type PDF isn't |
+ // blocked. |
+ void TestBrowserInitiatedToPDFAllowed() { |
+ TestNavigationObserver observer(shell_->web_contents()); |
+ NavigateToURL(shell_, GURL(kPdfUrl)); |
+ EXPECT_EQ(GURL(kPdfUrl), observer.last_navigation_url()); |
+ EXPECT_TRUE(observer.last_navigation_succeeded()); |
+ EXPECT_TRUE(shell_->web_contents()->GetURL().SchemeIs(url::kDataScheme)); |
+ EXPECT_TRUE(shell_->web_contents() |
+ ->GetController() |
+ .GetLastCommittedEntry() |
+ ->GetURL() |
+ .SchemeIs(url::kDataScheme)); |
+ } |
+ |
+ // 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.
|
+ // and prints a console message. |
+ void TestWindowOpenBlocked(const GURL& original_url, const GURL& data_url) { |
+ NavigateToURL(shell_, original_url); |
+ |
+ ShellAddedObserver new_shell_observer; |
+ EXPECT_TRUE(ExecuteScript( |
+ shell_->web_contents(), |
+ base::StringPrintf("window.open('%s');", data_url.spec().c_str()))); |
+ Shell* new_shell = new_shell_observer.GetShell(); |
+ WaitForLoadStop(new_shell->web_contents()); |
+ EXPECT_TRUE(new_shell->web_contents()->GetURL().spec().empty()); |
+ // No navigation should commit. |
+ EXPECT_FALSE( |
+ new_shell->web_contents()->GetController().GetLastCommittedEntry()); |
+ } |
+ |
+ // Tests that a redirect from |original_url| to |data_url| is blocked and |
+ // prints a console message. |
+ 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
|
+ ASSERT_TRUE(data_url.SchemeIs("data")); |
+ NavigateToURL(shell_, original_url); |
+ ConsoleObserverDelegate console_delegate(shell_->web_contents(), |
+ kDataUrlBlockedPattern); |
+ shell_->web_contents()->SetDelegate(&console_delegate); |
+ EXPECT_TRUE(ExecuteScript(shell_->web_contents(), |
+ base::StringPrintf("window.location.href = '%s';", |
+ data_url.spec().c_str()))); |
+ console_delegate.Wait(); |
+ // Original page shouldn't navigate away. |
+ EXPECT_EQ(original_url, shell_->web_contents()->GetURL()); |
+ EXPECT_EQ(original_url, shell_->web_contents() |
+ ->GetController() |
+ .GetLastCommittedEntry() |
+ ->GetURL()); |
+ } |
+ |
+ // Tests that window.open to a data URL is not blocked if the mime type |
+ // indicates that the URL will be downloaded. |
+ void TestWindowOpenDownloadAllowed(const GURL& original_url, |
+ const GURL& data_url) { |
+ ASSERT_TRUE(data_url.SchemeIs("data")); |
+ NavigateToURL(shell_, original_url); |
+ |
+ ShellAddedObserver new_shell_observer; |
+ EXPECT_TRUE(ExecuteScript( |
+ shell_->web_contents(), |
+ base::StringPrintf("window.open('%s');", data_url.spec().c_str()))); |
+ Shell* new_shell = new_shell_observer.GetShell(); |
+ |
+ DownloadManager* download_manager = BrowserContext::GetDownloadManager( |
+ new_shell->web_contents()->GetBrowserContext()); |
+ DownloadTestObserverTerminal download_observer( |
+ download_manager, 1, DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL); |
+ |
+ WaitForLoadStop(new_shell->web_contents()); |
+ 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.
|
+ |
+ EXPECT_TRUE(new_shell->web_contents()->GetURL().spec().empty()); |
+ // No navigation should commit. |
+ EXPECT_FALSE( |
+ new_shell->web_contents()->GetController().GetLastCommittedEntry()); |
+ // Original page shouldn't navigate away. |
+ EXPECT_EQ(original_url, shell_->web_contents()->GetURL()); |
+ EXPECT_EQ(original_url, shell_->web_contents() |
+ ->GetController() |
+ .GetLastCommittedEntry() |
+ ->GetURL()); |
+ } |
+ |
+ // Tests that a redirect to a data URL is not blocked if the mime type |
+ // indicates that the URL will be downloaded. |
+ void TestRedirectDownloadAllowed(const GURL& original_url, |
+ const GURL& data_url) { |
+ ASSERT_TRUE(data_url.SchemeIs("data")); |
+ NavigateToURL(shell_, original_url); |
+ |
+ DownloadManager* download_manager = BrowserContext::GetDownloadManager( |
+ shell_->web_contents()->GetBrowserContext()); |
+ DownloadTestObserverTerminal download_observer( |
+ download_manager, 1, DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL); |
+ |
+ EXPECT_TRUE(ExecuteScript(shell_->web_contents(), |
+ base::StringPrintf("window.location.href = '%s';", |
+ data_url.spec().c_str()))); |
+ download_observer.WaitForFinished(); |
+ |
+ // Original page shouldn't navigate away. |
+ EXPECT_EQ(original_url, shell_->web_contents()->GetURL()); |
+ EXPECT_EQ(original_url, shell_->web_contents() |
+ ->GetController() |
+ .GetLastCommittedEntry() |
+ ->GetURL()); |
+ } |
+ |
+ private: |
+ Shell* const shell_; |
+}; |
+ |
+class ScopedPluginRegister { |
+ public: |
+ ScopedPluginRegister(content::PluginService* plugin_service) |
+ : plugin_service_(plugin_service) { |
+ const char kPluginName[] = "PDF"; |
+ const char kPdfMimeType[] = "application/pdf"; |
+ const char kPdfFileType[] = "pdf"; |
+ WebPluginInfo plugin_info; |
+ plugin_info.type = WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS; |
+ plugin_info.name = base::ASCIIToUTF16(kPluginName); |
+ plugin_info.mime_types.push_back( |
+ WebPluginMimeType(kPdfMimeType, kPdfFileType, std::string())); |
+ plugin_service_->RegisterInternalPlugin(plugin_info, false); |
+ plugin_service_->RefreshPlugins(); |
+ } |
+ |
+ ~ScopedPluginRegister() { |
+ std::vector<WebPluginInfo> plugins; |
+ plugin_service_->GetInternalPlugins(&plugins); |
+ EXPECT_EQ(1u, plugins.size()); |
+ plugin_service_->UnregisterInternalPlugin(plugins[0].path); |
+ plugin_service_->RefreshPlugins(); |
+ |
+ plugins.clear(); |
+ plugin_service_->GetInternalPlugins(&plugins); |
+ EXPECT_TRUE(plugins.empty()); |
+ } |
+ |
+ private: |
+ content::PluginService* plugin_service_; |
+}; |
+ |
+} // namespace |
+ |
+class DataUrlNavigationBrowserTest : public ContentBrowserTest { |
+ public: |
+ DataUrlNavigationBrowserTest() |
+ : scoped_plugin_register_(PluginService::GetInstance()) {} |
+ |
+ protected: |
+ void SetUpOnMainThread() override { |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ } |
+ |
+ private: |
+ ScopedPluginRegister scoped_plugin_register_; |
+}; |
+ |
+IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, BrowserInitiated) { |
+ DataUrlNavigationTester(shell()).TestBrowserInitiatedAllowed(); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, RendererInitiated) { |
+ DataUrlNavigationTester(shell()).TestRedirectBlocked( |
+ embedded_test_server()->GetURL("/simple_links.html"), GURL(kHtmlUrl)); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, WindowOpen_Block) { |
+ DataUrlNavigationTester(shell()).TestWindowOpenBlocked( |
+ embedded_test_server()->GetURL("/simple_page.html"), GURL(kHtmlUrl)); |
+} |
+ |
+// Test that window.open to a data URL is not blocked if the mime type indicates |
+// that the URL will be downloaded. |
+IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, |
+ WindowOpen_OctetStream_Download) { |
+ DataUrlNavigationTester(shell()).TestWindowOpenDownloadAllowed( |
+ embedded_test_server()->GetURL("/simple_page.html"), |
+ GURL(kOctetStreamUrl)); |
+} |
+ |
+// Test that a content initiated navigation to a data URL is not blocked if the |
+// mime type indicates that the URL will be downloaded. |
+IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, |
+ Redirect_OctetStream_Download) { |
+ DataUrlNavigationTester(shell()).TestRedirectDownloadAllowed( |
+ embedded_test_server()->GetURL("/simple_page.html"), |
+ GURL(kOctetStreamUrl)); |
+} |
+ |
+// Test that window.open to a data URL results in an allowed download if the URL |
+// has an unknown mime type. |
+IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, |
+ WindowOpen_UnknownMimeType_Download) { |
+ DataUrlNavigationTester(shell()).TestWindowOpenDownloadAllowed( |
+ embedded_test_server()->GetURL("/simple_page.html"), |
+ GURL(kUnknownMimeTypeUrl)); |
+} |
+ |
+// Test that redirect to a data URL results in an allowed download if the URL |
+// has an unknown mime type. |
+IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, |
+ Redirect_UnknownMimeType_Download) { |
+ DataUrlNavigationTester(shell()).TestRedirectDownloadAllowed( |
+ embedded_test_server()->GetURL("/simple_page.html"), |
+ GURL(kUnknownMimeTypeUrl)); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, |
+ DirectNavigation_PDF_Allow) { |
+ DataUrlNavigationTester(shell()).TestBrowserInitiatedToPDFAllowed(); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, WindowOpen_PDF_Block) { |
+ DataUrlNavigationTester(shell()).TestWindowOpenBlocked( |
+ embedded_test_server()->GetURL("/simple_page.html"), GURL(kPdfUrl)); |
+} |
+ |
+// Test that a content initiated navigation to a data URL should be blocked if |
+// the data URL has a mime type that will be handled by a plugin (PDF in this |
+// case). |
+IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, Redirect_PDF_Block) { |
+ DataUrlNavigationTester(shell()).TestRedirectBlocked( |
+ embedded_test_server()->GetURL("/simple_page.html"), GURL(kPdfUrl)); |
+} |
+ |
+// Same as DataUrlNavigationBrowserTest tests, except these tests have browser |
+// side navigation enabled. |
+class DataUrlBrowserSideNavigationBrowserTest : public ContentBrowserTest { |
+ public: |
+ DataUrlBrowserSideNavigationBrowserTest() |
+ : scoped_plugin_register_(PluginService::GetInstance()) {} |
+ |
+ protected: |
+ void SetUpCommandLine(base::CommandLine* command_line) override { |
+ command_line->AppendSwitch(switches::kEnableBrowserSideNavigation); |
+ } |
+ |
+ void SetUpOnMainThread() override { |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ } |
+ |
+ private: |
+ ScopedPluginRegister scoped_plugin_register_; |
+}; |
+ |
+IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest, |
+ BrowserInitiated) { |
+ DataUrlNavigationTester(shell()).TestBrowserInitiatedAllowed(); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest, |
+ RendererInitiated) { |
+ DataUrlNavigationTester(shell()).TestRedirectBlocked( |
+ embedded_test_server()->GetURL("/simple_links.html"), GURL(kHtmlUrl)); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest, |
+ WindowOpen_Block) { |
+ DataUrlNavigationTester(shell()).TestWindowOpenBlocked( |
+ embedded_test_server()->GetURL("/simple_page.html"), GURL(kHtmlUrl)); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest, |
+ WindowOpen_OctetStream_Download) { |
+ DataUrlNavigationTester(shell()).TestWindowOpenDownloadAllowed( |
+ embedded_test_server()->GetURL("/simple_page.html"), |
+ GURL(kOctetStreamUrl)); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest, |
+ Redirect_OctetStream_Download) { |
+ DataUrlNavigationTester(shell()).TestRedirectDownloadAllowed( |
+ embedded_test_server()->GetURL("/simple_page.html"), |
+ GURL(kOctetStreamUrl)); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest, |
+ WindowOpen_UnknownMimeType_Download) { |
+ DataUrlNavigationTester(shell()).TestWindowOpenDownloadAllowed( |
+ embedded_test_server()->GetURL("/simple_page.html"), |
+ GURL(kUnknownMimeTypeUrl)); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest, |
+ Redirect_UnknownMimeType_Download) { |
+ DataUrlNavigationTester(shell()).TestRedirectDownloadAllowed( |
+ embedded_test_server()->GetURL("/simple_page.html"), |
+ GURL(kUnknownMimeTypeUrl)); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest, |
+ DirectNavigation_PDF_Allow) { |
+ DataUrlNavigationTester(shell()).TestBrowserInitiatedToPDFAllowed(); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest, |
+ WindowOpen_PDF_Block) { |
+ DataUrlNavigationTester(shell()).TestWindowOpenBlocked( |
+ embedded_test_server()->GetURL("/simple_page.html"), GURL(kPdfUrl)); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest, |
+ Redirect_PDF_Block) { |
+ DataUrlNavigationTester(shell()).TestRedirectBlocked( |
+ embedded_test_server()->GetURL("/simple_page.html"), GURL(kPdfUrl)); |
+} |
+ |
+} // content |