1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/escape.h"
#include "base/test/bind.h"
#include "chrome/browser/plugins/chrome_plugin_service_filter.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/pdf_util.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/plugin_service.h"
#include "content/public/browser/plugin_service_filter.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/prerender_test_util.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "url/gurl.h"
using content::JsReplace;
using content::RenderFrameHost;
using content::TestNavigationManager;
using content::WebContents;
using content::test::PrerenderHostObserver;
using content::test::PrerenderHostRegistryObserver;
// We'll use this to block the PDF plugin from loading to force the HTML
// fallback in the NavigationThrottle.
class BlockAllPluginServiceFilter : public content::PluginServiceFilter {
public:
bool IsPluginAvailable(content::BrowserContext* browser_context,
const content::WebPluginInfo& plugin) override {
return false;
}
bool CanLoadPlugin(int render_process_id,
const base::FilePath& path) override {
return false;
}
};
class PDFIFrameNavigationThrottleBrowserTest : public InProcessBrowserTest {
public:
PDFIFrameNavigationThrottleBrowserTest()
: prerender_helper_(base::BindRepeating(
&PDFIFrameNavigationThrottleBrowserTest::web_contents,
base::Unretained(this))) {}
content::WebContents* web_contents() {
return browser()->tab_strip_model()->GetActiveWebContents();
}
void SetUp() override {
prerender_helper_.RegisterServerRequestMonitor(embedded_test_server());
InProcessBrowserTest::SetUp();
}
void SetUpOnMainThread() override {
InProcessBrowserTest::SetUpOnMainThread();
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(embedded_test_server()->Start());
content::PluginService* plugin_service =
content::PluginService::GetInstance();
plugin_service->Init();
old_plugin_service_filter_ = plugin_service->GetFilter();
plugin_service->SetFilter(&block_all_plugins_);
}
void TearDownOnMainThread() override {
ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
content::PluginService::GetInstance()->SetFilter(
old_plugin_service_filter_);
InProcessBrowserTest::TearDownOnMainThread();
}
protected:
content::test::PrerenderTestHelper prerender_helper_;
raw_ptr<content::PluginServiceFilter> old_plugin_service_filter_;
BlockAllPluginServiceFilter block_all_plugins_;
};
// TODO(crbug.com/40180674): The PDF viewer cannot currently be prerendered
// correctly. Once this is supported, this test should be re-enabled. This test
// checks that the throttle is able to navigate the iframe'd PDF to the fallback
// HTML content even while it is prerendering.
IN_PROC_BROWSER_TEST_F(PDFIFrameNavigationThrottleBrowserTest,
DISABLED_HTMLFallbackInPrerender) {
const GURL kUrl(embedded_test_server()->GetURL("/empty.html"));
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), kUrl));
const GURL kPrerenderUrl =
embedded_test_server()->GetURL("/pdf/test-iframe.html");
const GURL kPdfUrl =
embedded_test_server()->GetURL("/pdf/test-bookmarks.pdf");
const std::string html = GetPDFPlaceholderHTML(kPdfUrl);
const GURL kFallbackPdfUrl("data:text/html," + base::EscapePath(html));
TestNavigationManager pdf_navigation(web_contents(), kFallbackPdfUrl);
// Trigger a prerender of a page containing an iframe with a pdf file.
{
PrerenderHostRegistryObserver registry_observer(*web_contents());
prerender_helper_.AddPrerenderAsync(kPrerenderUrl);
registry_observer.WaitForTrigger(kPrerenderUrl);
}
// The PDFIFrameNavigationThrottle will cancel the navigation to the pdf file
// and navigate the frame anew to a fallback data: URL. Since its in a
// prerendering frame tree, and data: URLs are cross-origin with the main
// frame, we expect the navigation to be deferred during WillStartRequest
// until the prerender is activated.
{
ASSERT_TRUE(pdf_navigation.WaitForFirstYieldAfterDidStartNavigation());
EXPECT_FALSE(pdf_navigation.GetNavigationHandle()->HasCommitted());
EXPECT_TRUE(pdf_navigation.GetNavigationHandle()->IsDeferredForTesting());
}
// Now navigate the primary page to the prerendered URL so that we activate
// the prerender.
{
PrerenderHostObserver prerender_observer(*web_contents(), kPrerenderUrl);
ASSERT_TRUE(ExecJs(web_contents()->GetPrimaryMainFrame(),
JsReplace("location = $1", kPrerenderUrl)));
prerender_observer.WaitForActivation();
}
// Now that we're activated, the fallback navigation should be able to
// finish. The initial PDF navigation should be cancelled by the throttle and
// fallback content loaded in its place.
{
ASSERT_TRUE(pdf_navigation.WaitForNavigationFinished());
EXPECT_TRUE(pdf_navigation.was_committed());
EXPECT_TRUE(pdf_navigation.was_successful());
content::RenderFrameHost* child_frame =
ChildFrameAt(web_contents()->GetPrimaryMainFrame(), 0);
ASSERT_TRUE(child_frame);
EXPECT_EQ(child_frame->GetLastCommittedURL(), kFallbackPdfUrl);
}
}
|