From 541504c8a4e6792499278d94ee0a9114f2de4b5c Mon Sep 17 00:00:00 2001 From: Jeremy Rose Date: Tue, 12 Apr 2022 02:09:30 -0700 Subject: [PATCH] fix: backport unseasoned pdf support to 18.x (#33664) --- BUILD.gn | 2 + chromium_src/BUILD.gn | 24 +++--- shell/app/electron_content_client.cc | 11 +-- shell/browser/electron_api_ipc_handler_impl.h | 1 + shell/browser/electron_browser_client.cc | 41 +++++++++ shell/browser/electron_browser_client.h | 6 ++ ...ectron_web_contents_utility_handler_impl.h | 1 + shell/common/electron_constants.cc | 3 +- shell/common/electron_constants.h | 4 +- shell/renderer/renderer_client_base.cc | 83 +++++++++++++++++-- shell/renderer/renderer_client_base.h | 3 + 11 files changed, 153 insertions(+), 26 deletions(-) diff --git a/BUILD.gn b/BUILD.gn index f3ce86f6b408e..d5ac6987873cd 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -694,6 +694,8 @@ source_set("electron_lib") { deps += [ "//chrome/browser/resources/pdf:resources", "//components/pdf/browser", + "//components/pdf/browser:interceptors", + "//components/pdf/common", "//components/pdf/renderer", "//pdf:pdf_ppapi", ] diff --git a/chromium_src/BUILD.gn b/chromium_src/BUILD.gn index 4c048a63aef2e..b49dde05fb9ed 100644 --- a/chromium_src/BUILD.gn +++ b/chromium_src/BUILD.gn @@ -298,13 +298,21 @@ static_library("chrome") { if (enable_pdf_viewer) { sources += [ + "//chrome/browser/pdf/chrome_pdf_stream_delegate.cc", + "//chrome/browser/pdf/chrome_pdf_stream_delegate.h", "//chrome/browser/pdf/pdf_extension_util.cc", "//chrome/browser/pdf/pdf_extension_util.h", "//chrome/browser/pdf/pdf_frame_util.cc", "//chrome/browser/pdf/pdf_frame_util.h", + "//chrome/browser/plugins/pdf_iframe_navigation_throttle.cc", + "//chrome/browser/plugins/pdf_iframe_navigation_throttle.h", "//chrome/renderer/pepper/chrome_pdf_print_client.cc", "//chrome/renderer/pepper/chrome_pdf_print_client.h", ] + deps += [ + "//components/pdf/browser", + "//components/pdf/renderer", + ] } } @@ -332,15 +340,6 @@ source_set("plugins") { "//chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.cc", "//chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.h", ] - deps += [ - "//media:media_buildflags", - "//ppapi/buildflags", - "//ppapi/proxy:ipc", - "//services/device/public/mojom", - ] - if (enable_pdf_viewer) { - deps += [ "//components/pdf/browser" ] - } # renderer side sources += [ @@ -351,17 +350,18 @@ source_set("plugins") { "//chrome/renderer/pepper/pepper_shared_memory_message_filter.cc", "//chrome/renderer/pepper/pepper_shared_memory_message_filter.h", ] - if (enable_pdf_viewer) { - deps += [ "//components/pdf/renderer" ] - } + deps += [ "//components/strings", "//media:media_buildflags", + "//ppapi/buildflags", "//ppapi/host", "//ppapi/proxy", "//ppapi/proxy:ipc", "//ppapi/shared_impl", + "//services/device/public/mojom", "//skia", + "//storage/browser", ] } diff --git a/shell/app/electron_content_client.cc b/shell/app/electron_content_client.cc index 14e0c0c372833..767c4ea2a0ba1 100644 --- a/shell/app/electron_content_client.cc +++ b/shell/app/electron_content_client.cc @@ -34,6 +34,8 @@ #endif // defined(WIDEVINE_CDM_AVAILABLE) #if BUILDFLAG(ENABLE_PDF_VIEWER) +#include "chrome/common/pdf_util.h" +#include "components/pdf/common/internal_plugin_helpers.h" #include "pdf/pdf.h" // nogncheck #include "pdf/pdf_ppapi.h" // nogncheck #include "shell/common/electron_constants.h" @@ -107,11 +109,11 @@ void ComputeBuiltInPlugins(std::vector* plugins) { content::PepperPluginInfo pdf_info; pdf_info.is_internal = true; pdf_info.is_out_of_process = true; - pdf_info.name = "Chromium PDF Viewer"; + pdf_info.name = kPDFInternalPluginName; pdf_info.description = "Portable Document Format"; // This isn't a real file path; it's just used as a unique identifier. pdf_info.path = base::FilePath(kPdfPluginPath); - content::WebPluginMimeType pdf_mime_type(kPdfPluginMimeType, "pdf", + content::WebPluginMimeType pdf_mime_type(pdf::kInternalPluginMimeType, "pdf", "Portable Document Format"); pdf_info.mime_types.push_back(pdf_mime_type); pdf_info.internal_entry_points.get_interface = chrome_pdf::PPP_GetInterface; @@ -128,12 +130,11 @@ void ComputeBuiltInPlugins(std::vector* plugins) { // here. content::WebPluginInfo info; info.type = content::WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN; - info.name = u"Chromium PDF Viewer"; + info.name = base::ASCIIToUTF16(kPDFExtensionPluginName); // This isn't a real file path; it's just used as a unique identifier. info.path = base::FilePath::FromUTF8Unsafe(extension_misc::kPdfExtensionId); info.background_color = content::WebPluginInfo::kDefaultBackgroundColor; - info.mime_types.emplace_back("application/pdf", "pdf", - "Portable Document Format"); + info.mime_types.emplace_back(kPDFMimeType, "pdf", "Portable Document Format"); content::PluginService::GetInstance()->RefreshPlugins(); content::PluginService::GetInstance()->RegisterInternalPlugin(info, true); #endif // BUILDFLAG(ENABLE_PDF_VIEWER) diff --git a/shell/browser/electron_api_ipc_handler_impl.h b/shell/browser/electron_api_ipc_handler_impl.h index 7cddf88bedc4a..222f42bed1be6 100644 --- a/shell/browser/electron_api_ipc_handler_impl.h +++ b/shell/browser/electron_api_ipc_handler_impl.h @@ -11,6 +11,7 @@ #include "base/memory/weak_ptr.h" #include "content/public/browser/web_contents_observer.h" #include "electron/shell/common/api/api.mojom.h" +#include "mojo/public/cpp/bindings/associated_receiver.h" #include "shell/browser/api/electron_api_web_contents.h" namespace content { diff --git a/shell/browser/electron_browser_client.cc b/shell/browser/electron_browser_client.cc index 5c051c5ded390..e4818fee6af51 100644 --- a/shell/browser/electron_browser_client.cc +++ b/shell/browser/electron_browser_client.cc @@ -46,6 +46,7 @@ #include "content/public/browser/site_instance.h" #include "content/public/browser/tts_controller.h" #include "content/public/browser/tts_platform.h" +#include "content/public/browser/url_loader_request_interceptor.h" #include "content/public/common/content_descriptors.h" #include "content/public/common/content_paths.h" #include "content/public/common/content_switches.h" @@ -204,7 +205,12 @@ #endif #if BUILDFLAG(ENABLE_PDF_VIEWER) +#include "chrome/browser/pdf/chrome_pdf_stream_delegate.h" +#include "chrome/browser/plugins/pdf_iframe_navigation_throttle.h" // nogncheck +#include "components/pdf/browser/pdf_navigation_throttle.h" +#include "components/pdf/browser/pdf_url_loader_request_interceptor.h" #include "components/pdf/browser/pdf_web_contents_helper.h" // nogncheck +#include "components/pdf/common/internal_plugin_helpers.h" #endif using content::BrowserThread; @@ -1048,6 +1054,18 @@ ElectronBrowserClient::CreateThrottlesForNavigation( std::make_unique(handle)); #endif +#if BUILDFLAG(ENABLE_PDF_VIEWER) + std::unique_ptr pdf_iframe_throttle = + PDFIFrameNavigationThrottle::MaybeCreateThrottleFor(handle); + if (pdf_iframe_throttle) + throttles.push_back(std::move(pdf_iframe_throttle)); + std::unique_ptr pdf_throttle = + pdf::PdfNavigationThrottle::MaybeCreateThrottleFor( + handle, std::make_unique()); + if (pdf_throttle) + throttles.push_back(std::move(pdf_throttle)); +#endif + return throttles; } @@ -1452,6 +1470,26 @@ bool ElectronBrowserClient::WillCreateURLLoaderFactory( return true; } +std::vector> +ElectronBrowserClient::WillCreateURLLoaderRequestInterceptors( + content::NavigationUIData* navigation_ui_data, + int frame_tree_node_id, + const scoped_refptr& + network_loader_factory) { + std::vector> + interceptors; +#if BUILDFLAG(ENABLE_PDF_VIEWER) + { + std::unique_ptr pdf_interceptor = + pdf::PdfURLLoaderRequestInterceptor::MaybeCreateInterceptor( + frame_tree_node_id, std::make_unique()); + if (pdf_interceptor) + interceptors.push_back(std::move(pdf_interceptor)); + } +#endif + return interceptors; +} + void ElectronBrowserClient::OverrideURLLoaderFactoryParams( content::BrowserContext* browser_context, const url::Origin& origin, @@ -1725,6 +1763,9 @@ ElectronBrowserClient::GetPluginMimeTypesWithExternalHandlers( auto map = PluginUtils::GetMimeTypeToExtensionIdMap(browser_context); for (const auto& pair : map) mime_types.insert(pair.first); +#endif +#if BUILDFLAG(ENABLE_PDF_VIEWER) + mime_types.insert(pdf::kInternalPluginMimeType); #endif return mime_types; } diff --git a/shell/browser/electron_browser_client.h b/shell/browser/electron_browser_client.h index 730fc07e687e8..c0b9827d4cf24 100644 --- a/shell/browser/electron_browser_client.h +++ b/shell/browser/electron_browser_client.h @@ -227,6 +227,12 @@ class ElectronBrowserClient : public content::ContentBrowserClient, bool* bypass_redirect_checks, bool* disable_secure_dns, network::mojom::URLLoaderFactoryOverridePtr* factory_override) override; + std::vector> + WillCreateURLLoaderRequestInterceptors( + content::NavigationUIData* navigation_ui_data, + int frame_tree_node_id, + const scoped_refptr& + network_loader_factory) override; bool ShouldTreatURLSchemeAsFirstPartyWhenTopLevel( base::StringPiece scheme, bool is_embedded_origin_secure) override; diff --git a/shell/browser/electron_web_contents_utility_handler_impl.h b/shell/browser/electron_web_contents_utility_handler_impl.h index 30a9baa40f835..819c818fcae54 100644 --- a/shell/browser/electron_web_contents_utility_handler_impl.h +++ b/shell/browser/electron_web_contents_utility_handler_impl.h @@ -11,6 +11,7 @@ #include "base/memory/weak_ptr.h" #include "content/public/browser/web_contents_observer.h" #include "electron/shell/common/api/api.mojom.h" +#include "mojo/public/cpp/bindings/associated_receiver.h" #include "shell/browser/api/electron_api_web_contents.h" namespace content { diff --git a/shell/common/electron_constants.cc b/shell/common/electron_constants.cc index 5d53425a3fc52..3d6eda0e9eea8 100644 --- a/shell/common/electron_constants.cc +++ b/shell/common/electron_constants.cc @@ -30,7 +30,8 @@ const char kRunAsNode[] = "ELECTRON_RUN_AS_NODE"; #endif #if BUILDFLAG(ENABLE_PDF_VIEWER) -const char kPdfPluginMimeType[] = "application/x-google-chrome-pdf"; +const char kPDFExtensionPluginName[] = "Chromium PDF Viewer"; +const char kPDFInternalPluginName[] = "Chromium PDF Plugin"; const base::FilePath::CharType kPdfPluginPath[] = FILE_PATH_LITERAL("internal-pdf-viewer"); #endif // BUILDFLAG(ENABLE_PDF_VIEWER) diff --git a/shell/common/electron_constants.h b/shell/common/electron_constants.h index b91b70e683632..4218b3e47ffc7 100644 --- a/shell/common/electron_constants.h +++ b/shell/common/electron_constants.h @@ -30,8 +30,8 @@ extern const char kRunAsNode[]; #endif #if BUILDFLAG(ENABLE_PDF_VIEWER) -// The MIME type used for the PDF plugin. -extern const char kPdfPluginMimeType[]; +extern const char kPDFExtensionPluginName[]; +extern const char kPDFInternalPluginName[]; extern const base::FilePath::CharType kPdfPluginPath[]; #endif // BUILDFLAG(ENABLE_PDF_VIEWER) diff --git a/shell/renderer/renderer_client_base.cc b/shell/renderer/renderer_client_base.cc index 98f79468c5445..6a36fc06274ef 100644 --- a/shell/renderer/renderer_client_base.cc +++ b/shell/renderer/renderer_client_base.cc @@ -62,6 +62,10 @@ #endif #if BUILDFLAG(ENABLE_PDF_VIEWER) +#include "chrome/common/pdf_util.h" +#include "components/pdf/common/internal_plugin_helpers.h" +#include "components/pdf/renderer/internal_plugin_renderer_helpers.h" +#include "components/pdf/renderer/pdf_internal_plugin_delegate.h" #include "shell/common/electron_constants.h" #endif // BUILDFLAG(ENABLE_PDF_VIEWER) @@ -105,6 +109,25 @@ std::vector ParseSchemesCLISwitch(base::CommandLine* command_line, base::SPLIT_WANT_NONEMPTY); } +#if BUILDFLAG(ENABLE_PDF_VIEWER) +class ChromePdfInternalPluginDelegate final + : public pdf::PdfInternalPluginDelegate { + public: + ChromePdfInternalPluginDelegate() = default; + ChromePdfInternalPluginDelegate(const ChromePdfInternalPluginDelegate&) = + delete; + ChromePdfInternalPluginDelegate& operator=( + const ChromePdfInternalPluginDelegate&) = delete; + ~ChromePdfInternalPluginDelegate() override = default; + + // `pdf::PdfInternalPluginDelegate`: + bool IsAllowedOrigin(const url::Origin& origin) const override { + return origin.scheme() == extensions::kExtensionScheme && + origin.host() == extension_misc::kPdfExtensionId; + } +}; +#endif // BUILDFLAG(ENABLE_PDF_VIEWER) + // static RendererClientBase* g_renderer_client_base = nullptr; @@ -315,10 +338,23 @@ bool RendererClientBase::OverrideCreatePlugin( content::RenderFrame* render_frame, const blink::WebPluginParams& params, blink::WebPlugin** plugin) { - if (params.mime_type.Utf8() == content::kBrowserPluginMimeType || #if BUILDFLAG(ENABLE_PDF_VIEWER) - params.mime_type.Utf8() == kPdfPluginMimeType || + if (params.mime_type.Utf8() == pdf::kInternalPluginMimeType) { + content::WebPluginInfo info; + info.type = content::WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS; + info.name = base::ASCIIToUTF16(kPDFInternalPluginName); + info.path = base::FilePath(kPdfPluginPath); + info.background_color = content::WebPluginInfo::kDefaultBackgroundColor; + info.mime_types.emplace_back(pdf::kInternalPluginMimeType, "pdf", + "Portable Document Format"); + *plugin = pdf::CreateInternalPlugin( + info, std::move(params), render_frame, + std::make_unique()); + return true; + } #endif // BUILDFLAG(ENABLE_PDF_VIEWER) + + if (params.mime_type.Utf8() == content::kBrowserPluginMimeType || render_frame->GetBlinkPreferences().enable_plugins) return false; @@ -355,16 +391,34 @@ bool RendererClientBase::IsPluginHandledExternally( #if BUILDFLAG(ENABLE_PDF_VIEWER) DCHECK(plugin_element.HasHTMLTagName("object") || plugin_element.HasHTMLTagName("embed")); + if (mime_type == pdf::kInternalPluginMimeType) { + if (IsPdfInternalPluginAllowedOrigin( + render_frame->GetWebFrame()->GetSecurityOrigin())) { + return true; + } + + content::WebPluginInfo info; + info.type = content::WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS; + info.name = base::ASCIIToUTF16(kPDFInternalPluginName); + info.path = base::FilePath(kPdfPluginPath); + info.background_color = content::WebPluginInfo::kDefaultBackgroundColor; + info.mime_types.emplace_back(pdf::kInternalPluginMimeType, "pdf", + "Portable Document Format"); + return extensions::MimeHandlerViewContainerManager::Get( + content::RenderFrame::FromWebFrame( + plugin_element.GetDocument().GetFrame()), + true /* create_if_does_not_exist */) + ->CreateFrameContainer(plugin_element, original_url, mime_type, info); + } + // TODO(nornagon): this info should be shared with the data in // electron_content_client.cc / ComputeBuiltInPlugins. content::WebPluginInfo info; info.type = content::WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN; - const char16_t kPDFExtensionPluginName[] = u"Chromium PDF Viewer"; - info.name = kPDFExtensionPluginName; + info.name = base::ASCIIToUTF16(kPDFExtensionPluginName); info.path = base::FilePath::FromUTF8Unsafe(extension_misc::kPdfExtensionId); info.background_color = content::WebPluginInfo::kDefaultBackgroundColor; - info.mime_types.emplace_back("application/pdf", "pdf", - "Portable Document Format"); + info.mime_types.emplace_back(kPDFMimeType, "pdf", "Portable Document Format"); return extensions::MimeHandlerViewContainerManager::Get( content::RenderFrame::FromWebFrame( plugin_element.GetDocument().GetFrame()), @@ -381,6 +435,23 @@ bool RendererClientBase::IsOriginIsolatedPepperPlugin( return true; } +v8::Local RendererClientBase::GetScriptableObject( + const blink::WebElement& plugin_element, + v8::Isolate* isolate) { +#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS) + // If there is a MimeHandlerView that can provide the scriptable object then + // MaybeCreateMimeHandlerView must have been called before and a container + // manager should exist. + auto* container_manager = extensions::MimeHandlerViewContainerManager::Get( + content::RenderFrame::FromWebFrame( + plugin_element.GetDocument().GetFrame()), + false /* create_if_does_not_exist */); + if (container_manager) + return container_manager->GetScriptableObject(plugin_element, isolate); +#endif + return v8::Local(); +} + std::unique_ptr RendererClientBase::CreatePrescientNetworking( content::RenderFrame* render_frame) { diff --git a/shell/renderer/renderer_client_base.h b/shell/renderer/renderer_client_base.h index d830c6db5f88f..84acea819e8c6 100644 --- a/shell/renderer/renderer_client_base.h +++ b/shell/renderer/renderer_client_base.h @@ -112,6 +112,9 @@ class RendererClientBase : public content::ContentRendererClient const GURL& original_url, const std::string& mime_type) override; bool IsOriginIsolatedPepperPlugin(const base::FilePath& plugin_path) override; + v8::Local GetScriptableObject( + const blink::WebElement& plugin_element, + v8::Isolate* isolate) override; void RunScriptsAtDocumentStart(content::RenderFrame* render_frame) override; void RunScriptsAtDocumentEnd(content::RenderFrame* render_frame) override;