| 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..d0c9abd652244ca6835ac17f09e060919b7e9e95
|
| --- /dev/null
|
| +++ b/content/browser/frame_host/data_url_navigation_browsertest.cc
|
| @@ -0,0 +1,409 @@
|
| +// 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
|
| + // 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) {
|
| + ASSERT_TRUE(data_url.SchemeIs("data"));
|
| + LOG(ERROR) << data_url.spec();
|
| + 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(),
|
| + //"window.open('data:application/octet-stream,test');"));
|
| + 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();
|
| +
|
| + 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
|
|
|