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