| // Copyright 2022 The Chromium Authors. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/plugins/plugin_info_host_impl.h" |
| |
| #include <stddef.h> |
| |
| #include <memory> |
| #include <string> |
| |
| #include "base/files/file_path.h" |
| #include "base/run_loop.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/test/gmock_move_support.h" |
| #include "base/test/mock_callback.h" |
| #include "build/branding_buildflags.h" |
| #include "chrome/browser/plugins/plugin_prefs.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| #include "chrome/common/chrome_content_client.h" |
| #include "chrome/common/plugin.mojom.h" |
| #include "chrome/test/base/in_process_browser_test.h" |
| #include "components/nacl/common/buildflags.h" |
| #include "content/public/browser/plugin_service.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "content/public/browser/render_process_host.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/common/webplugininfo.h" |
| #include "content/public/test/browser_test.h" |
| #include "pdf/buildflags.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/skia/include/core/SkColor.h" |
| #include "url/gurl.h" |
| #include "url/origin.h" |
| |
| #if BUILDFLAG(ENABLE_NACL) |
| #include "components/nacl/common/nacl_constants.h" |
| #include "ppapi/shared_impl/ppapi_permissions.h" |
| #endif // BUILDFLAG(ENABLE_NACL) |
| |
| #if BUILDFLAG(ENABLE_PDF) |
| #include "chrome/common/pdf_util.h" |
| #include "components/pdf/common/internal_plugin_helpers.h" |
| #endif // BUILDFLAG(ENABLE_PDF) |
| |
| namespace { |
| |
| using ::chrome::mojom::PluginInfo; |
| using ::chrome::mojom::PluginInfoHost; |
| using ::chrome::mojom::PluginInfoPtr; |
| using ::chrome::mojom::PluginStatus; |
| using ::content::WebPluginInfo; |
| using ::content::WebPluginMimeType; |
| using ::testing::Contains; |
| using ::testing::ElementsAre; |
| using ::testing::Field; |
| using ::testing::IsEmpty; |
| using ::testing::SizeIs; |
| |
| #if BUILDFLAG(ENABLE_PDF) |
| constexpr base::FilePath::CharType kPdfViewerExtensionPath[] = |
| FILE_PATH_LITERAL("chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/"); |
| #endif // BUILDFLAG(ENABLE_PDF) |
| |
| } // namespace |
| |
| class PluginInfoHostImplTest : public InProcessBrowserTest { |
| public: |
| void SetUpOnMainThread() override { |
| int active_render_process_id = browser() |
| ->tab_strip_model() |
| ->GetActiveWebContents() |
| ->GetPrimaryMainFrame() |
| ->GetProcess() |
| ->GetID(); |
| |
| plugin_info_host_impl_ = std::make_unique<PluginInfoHostImpl>( |
| active_render_process_id, browser()->profile()); |
| } |
| |
| void TearDownOnMainThread() override { plugin_info_host_impl_.reset(); } |
| |
| protected: |
| PluginInfoPtr GetPluginInfo(const GURL& url, |
| const url::Origin& origin, |
| const std::string& mime_type) { |
| PluginInfoPtr plugin_info; |
| |
| base::MockCallback<PluginInfoHost::GetPluginInfoCallback> mock_callback; |
| EXPECT_CALL(mock_callback, Run).WillOnce(MoveArg(&plugin_info)); |
| |
| base::RunLoop run_loop; |
| plugin_info_host_impl_->GetPluginInfo( |
| url, origin, mime_type, |
| mock_callback.Get().Then(run_loop.QuitClosure())); |
| run_loop.Run(); |
| |
| return plugin_info; |
| } |
| |
| void SetAlwaysOpenPdfExternally() { |
| PluginPrefs::GetForProfile(browser()->profile()) |
| ->SetAlwaysOpenPdfExternallyForTests(true); |
| } |
| |
| std::unique_ptr<PluginInfoHostImpl> plugin_info_host_impl_; |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(PluginInfoHostImplTest, CoverAllPlugins) { |
| // Note that "internal" plugins are the only type that can be registered with |
| // `content::PluginService` now. |
| std::vector<WebPluginInfo> plugins; |
| content::PluginService::GetInstance()->GetInternalPlugins(&plugins); |
| |
| size_t expected_plugin_count = 0; |
| |
| #if BUILDFLAG(ENABLE_NACL) |
| EXPECT_THAT(plugins, Contains(Field( |
| "path", &WebPluginInfo::path, |
| base::FilePath(nacl::kInternalNaClPluginFileName)))); |
| expected_plugin_count += 1; |
| #endif // BUILDFLAG_ENABLE_NACL) |
| |
| #if BUILDFLAG(ENABLE_PDF) |
| EXPECT_THAT(plugins, |
| Contains(Field("path", &WebPluginInfo::path, |
| base::FilePath(kPdfViewerExtensionPath)))); |
| EXPECT_THAT( |
| plugins, |
| Contains(Field("path", &WebPluginInfo::path, |
| base::FilePath(ChromeContentClient ::kPDFPluginPath)))); |
| expected_plugin_count += 2; |
| #endif // BUILDFLAG(ENABLE_PDF) |
| |
| EXPECT_THAT(plugins, SizeIs(expected_plugin_count)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PluginInfoHostImplTest, GetPluginInfoForFlash) { |
| PluginInfoPtr plugin_info = GetPluginInfo(GURL("fake.swf"), url::Origin(), |
| "application/x-shockwave-flash"); |
| ASSERT_TRUE(plugin_info); |
| |
| EXPECT_EQ(PluginStatus::kNotFound, plugin_info->status); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PluginInfoHostImplTest, GetPluginInfoForFutureSplash) { |
| PluginInfoPtr plugin_info = GetPluginInfo(GURL("fake.spl"), url::Origin(), |
| "application/futuresplash"); |
| ASSERT_TRUE(plugin_info); |
| |
| EXPECT_EQ(PluginStatus::kNotFound, plugin_info->status); |
| } |
| |
| #if BUILDFLAG(ENABLE_NACL) |
| IN_PROC_BROWSER_TEST_F(PluginInfoHostImplTest, GetPluginInfoForNaCl) { |
| const std::u16string kPluginName = base::UTF8ToUTF16(nacl::kNaClPluginName); |
| const base::FilePath kPluginPath = |
| base::FilePath(nacl::kInternalNaClPluginFileName); |
| |
| PluginInfoPtr plugin_info = GetPluginInfo( |
| GURL("fake-resource"), url::Origin(), nacl::kNaClPluginMimeType); |
| ASSERT_TRUE(plugin_info); |
| |
| EXPECT_EQ(PluginStatus::kPlayImportantContent, plugin_info->status); |
| EXPECT_EQ(nacl::kNaClPluginMimeType, plugin_info->actual_mime_type); |
| |
| // Group ID and name synthesized by `PluginFinder::GetPluginMetadata()`. |
| EXPECT_EQ(kPluginPath.BaseName().AsUTF8Unsafe(), |
| plugin_info->group_identifier); |
| EXPECT_EQ(kPluginName, plugin_info->group_name); |
| |
| // `WebPluginInfo` fields. |
| EXPECT_EQ(kPluginName, plugin_info->plugin.name); |
| EXPECT_EQ(kPluginPath, plugin_info->plugin.path); |
| EXPECT_EQ(u"", plugin_info->plugin.version); |
| EXPECT_EQ(u"", plugin_info->plugin.desc); |
| EXPECT_EQ(WebPluginInfo::PLUGIN_TYPE_PEPPER_IN_PROCESS, |
| plugin_info->plugin.type); |
| EXPECT_EQ(ppapi::PERMISSION_PRIVATE | ppapi::PERMISSION_DEV, |
| plugin_info->plugin.pepper_permissions); |
| EXPECT_EQ(WebPluginInfo::kDefaultBackgroundColor, |
| plugin_info->plugin.background_color); |
| |
| // Has both NaCl and Pnacl MIME types. |
| ASSERT_THAT(plugin_info->plugin.mime_types, SizeIs(2)); |
| |
| WebPluginMimeType nacl_mime_type = plugin_info->plugin.mime_types[0]; |
| EXPECT_EQ(nacl::kNaClPluginMimeType, nacl_mime_type.mime_type); |
| EXPECT_THAT(nacl_mime_type.file_extensions, |
| ElementsAre(nacl::kNaClPluginExtension)); |
| EXPECT_EQ(base::UTF8ToUTF16(nacl::kNaClPluginDescription), |
| nacl_mime_type.description); |
| |
| // Depends on modules registered by `extensions::NaClModulesHandler`. |
| EXPECT_THAT(nacl_mime_type.additional_params, IsEmpty()); |
| |
| WebPluginMimeType pnacl_mime_type = plugin_info->plugin.mime_types[1]; |
| EXPECT_EQ(nacl::kPnaclPluginMimeType, pnacl_mime_type.mime_type); |
| EXPECT_THAT(pnacl_mime_type.file_extensions, |
| ElementsAre(nacl::kPnaclPluginExtension)); |
| EXPECT_EQ(base::UTF8ToUTF16(nacl::kPnaclPluginDescription), |
| pnacl_mime_type.description); |
| EXPECT_THAT(pnacl_mime_type.additional_params, IsEmpty()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PluginInfoHostImplTest, GetPluginInfoForPnacl) { |
| const std::u16string kPluginName = base::UTF8ToUTF16(nacl::kNaClPluginName); |
| const base::FilePath kPluginPath = |
| base::FilePath(nacl::kInternalNaClPluginFileName); |
| |
| PluginInfoPtr plugin_info = GetPluginInfo( |
| GURL("fake-resource"), url::Origin(), nacl::kPnaclPluginMimeType); |
| ASSERT_TRUE(plugin_info); |
| |
| EXPECT_EQ(PluginStatus::kPlayImportantContent, plugin_info->status); |
| EXPECT_EQ(nacl::kPnaclPluginMimeType, plugin_info->actual_mime_type); |
| |
| // Group ID and name synthesized by `PluginFinder::GetPluginMetadata()`. |
| EXPECT_EQ(kPluginPath.BaseName().AsUTF8Unsafe(), |
| plugin_info->group_identifier); |
| EXPECT_EQ(kPluginName, plugin_info->group_name); |
| |
| // `WebPluginInfo` fields. |
| EXPECT_EQ(kPluginName, plugin_info->plugin.name); |
| EXPECT_EQ(kPluginPath, plugin_info->plugin.path); |
| EXPECT_EQ(u"", plugin_info->plugin.version); |
| EXPECT_EQ(u"", plugin_info->plugin.desc); |
| EXPECT_EQ(WebPluginInfo::PLUGIN_TYPE_PEPPER_IN_PROCESS, |
| plugin_info->plugin.type); |
| EXPECT_EQ(ppapi::PERMISSION_PRIVATE | ppapi::PERMISSION_DEV, |
| plugin_info->plugin.pepper_permissions); |
| EXPECT_EQ(WebPluginInfo::kDefaultBackgroundColor, |
| plugin_info->plugin.background_color); |
| |
| // Has both NaCl and Pnacl MIME types. |
| ASSERT_THAT(plugin_info->plugin.mime_types, SizeIs(2)); |
| |
| WebPluginMimeType nacl_mime_type = plugin_info->plugin.mime_types[0]; |
| EXPECT_EQ(nacl::kNaClPluginMimeType, nacl_mime_type.mime_type); |
| EXPECT_THAT(nacl_mime_type.file_extensions, |
| ElementsAre(nacl::kNaClPluginExtension)); |
| EXPECT_EQ(base::UTF8ToUTF16(nacl::kNaClPluginDescription), |
| nacl_mime_type.description); |
| |
| // Depends on modules registered by `extensions::NaClModulesHandler`. |
| EXPECT_THAT(nacl_mime_type.additional_params, IsEmpty()); |
| |
| WebPluginMimeType pnacl_mime_type = plugin_info->plugin.mime_types[1]; |
| EXPECT_EQ(nacl::kPnaclPluginMimeType, pnacl_mime_type.mime_type); |
| EXPECT_THAT(pnacl_mime_type.file_extensions, |
| ElementsAre(nacl::kPnaclPluginExtension)); |
| EXPECT_EQ(base::UTF8ToUTF16(nacl::kPnaclPluginDescription), |
| pnacl_mime_type.description); |
| |
| EXPECT_THAT(pnacl_mime_type.additional_params, IsEmpty()); |
| } |
| #endif // BUILDFLAG(ENABLE_NACL) |
| |
| #if BUILDFLAG(ENABLE_PDF) |
| IN_PROC_BROWSER_TEST_F(PluginInfoHostImplTest, |
| GetPluginInfoForPdfViewerExtension) { |
| const std::u16string kPluginName = |
| base::UTF8ToUTF16(ChromeContentClient::kPDFExtensionPluginName); |
| #if BUILDFLAG(GOOGLE_CHROME_BRANDING) |
| const std::string kGroupId = "google-chrome-pdf"; |
| #else |
| const std::string kGroupId = "chromium-pdf"; |
| #endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) |
| |
| PluginInfoPtr plugin_info = |
| GetPluginInfo(GURL("fake.pdf"), url::Origin(), kPDFMimeType); |
| ASSERT_TRUE(plugin_info); |
| |
| EXPECT_EQ(PluginStatus::kAllowed, plugin_info->status); |
| EXPECT_EQ(kPDFMimeType, plugin_info->actual_mime_type); |
| |
| // Group ID and name defined by `IDR_PLUGIN_DB_JSON`. |
| EXPECT_EQ(kGroupId, plugin_info->group_identifier); |
| EXPECT_EQ(kPluginName, plugin_info->group_name); |
| |
| // `WebPluginInfo` fields. |
| EXPECT_EQ(kPluginName, plugin_info->plugin.name); |
| EXPECT_EQ(base::FilePath(kPdfViewerExtensionPath), plugin_info->plugin.path); |
| EXPECT_EQ(u"", plugin_info->plugin.version); |
| EXPECT_EQ(u"", plugin_info->plugin.desc); |
| EXPECT_EQ(WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN, |
| plugin_info->plugin.type); |
| EXPECT_EQ(0, plugin_info->plugin.pepper_permissions); |
| |
| // Background color hard-coded in `MimeTypesHandler::GetBackgroundColor()`. |
| EXPECT_EQ(SkColorSetRGB(82, 86, 89), plugin_info->plugin.background_color); |
| |
| // Has PDF MIME type. |
| ASSERT_THAT(plugin_info->plugin.mime_types, SizeIs(1)); |
| |
| WebPluginMimeType mime_type = plugin_info->plugin.mime_types[0]; |
| EXPECT_EQ(kPDFMimeType, mime_type.mime_type); |
| EXPECT_THAT(mime_type.file_extensions, ElementsAre("pdf")); |
| EXPECT_EQ(u"", mime_type.description); |
| EXPECT_THAT(mime_type.additional_params, IsEmpty()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PluginInfoHostImplTest, |
| GetPluginInfoForPdfViewerExtensionWhenDisabled) { |
| SetAlwaysOpenPdfExternally(); |
| |
| PluginInfoPtr plugin_info = |
| GetPluginInfo(GURL("fake.pdf"), url::Origin(), kPDFMimeType); |
| ASSERT_TRUE(plugin_info); |
| |
| // PDF viewer extension is disabled by PDF content setting. |
| EXPECT_EQ(PluginStatus::kDisabled, plugin_info->status); |
| EXPECT_EQ(kPDFMimeType, plugin_info->actual_mime_type); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PluginInfoHostImplTest, |
| GetPluginInfoForPdfInternalPlugin) { |
| const std::u16string kPluginName = |
| base::UTF8ToUTF16(ChromeContentClient::kPDFInternalPluginName); |
| #if BUILDFLAG(GOOGLE_CHROME_BRANDING) |
| const std::string kGroupId = "google-chrome-pdf-plugin"; |
| #else |
| const std::string kGroupId = "chromium-pdf-plugin"; |
| #endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) |
| |
| PluginInfoPtr plugin_info = GetPluginInfo(GURL("fake.pdf"), url::Origin(), |
| pdf::kInternalPluginMimeType); |
| ASSERT_TRUE(plugin_info); |
| |
| EXPECT_EQ(PluginStatus::kAllowed, plugin_info->status); |
| EXPECT_EQ(pdf::kInternalPluginMimeType, plugin_info->actual_mime_type); |
| |
| // Group ID and name defined by `IDR_PLUGIN_DB_JSON`. |
| EXPECT_EQ(kGroupId, plugin_info->group_identifier); |
| EXPECT_EQ(kPluginName, plugin_info->group_name); |
| |
| // `WebPluginInfo` fields. |
| EXPECT_EQ(kPluginName, plugin_info->plugin.name); |
| EXPECT_EQ(base::FilePath(ChromeContentClient::kPDFPluginPath), |
| plugin_info->plugin.path); |
| EXPECT_EQ(u"", plugin_info->plugin.version); |
| EXPECT_EQ(u"Portable Document Format", plugin_info->plugin.desc); |
| EXPECT_EQ(WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS, |
| plugin_info->plugin.type); |
| EXPECT_EQ(0, plugin_info->plugin.pepper_permissions); |
| EXPECT_EQ(WebPluginInfo::kDefaultBackgroundColor, |
| plugin_info->plugin.background_color); |
| |
| // Has PDF MIME type. |
| ASSERT_THAT(plugin_info->plugin.mime_types, SizeIs(1)); |
| |
| WebPluginMimeType mime_type = plugin_info->plugin.mime_types[0]; |
| EXPECT_EQ(pdf::kInternalPluginMimeType, mime_type.mime_type); |
| EXPECT_THAT(mime_type.file_extensions, ElementsAre("pdf")); |
| EXPECT_EQ(u"Portable Document Format", mime_type.description); |
| EXPECT_THAT(mime_type.additional_params, IsEmpty()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PluginInfoHostImplTest, |
| GetPluginInfoForPdfInternalPluginWhenDisabled) { |
| SetAlwaysOpenPdfExternally(); |
| |
| PluginInfoPtr plugin_info = GetPluginInfo(GURL("fake.pdf"), url::Origin(), |
| pdf::kInternalPluginMimeType); |
| ASSERT_TRUE(plugin_info); |
| |
| // Internal PDF plugin is not affected by PDF content setting. |
| EXPECT_EQ(PluginStatus::kAllowed, plugin_info->status); |
| EXPECT_EQ(pdf::kInternalPluginMimeType, plugin_info->actual_mime_type); |
| } |
| #endif // BUILDFLAG(ENABLE_PDF) |