atom_content_client.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. // Copyright (c) 2014 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "atom/app/atom_content_client.h"
  5. #include <string>
  6. #include <utility>
  7. #include <vector>
  8. #include "atom/browser/browser.h"
  9. #include "atom/common/atom_version.h"
  10. #include "atom/common/chrome_version.h"
  11. #include "atom/common/options_switches.h"
  12. #include "base/command_line.h"
  13. #include "base/files/file_util.h"
  14. #include "base/strings/string_split.h"
  15. #include "base/strings/string_util.h"
  16. #include "base/strings/stringprintf.h"
  17. #include "base/strings/utf_string_conversions.h"
  18. #include "content/public/common/content_constants.h"
  19. #include "content/public/common/content_switches.h"
  20. #include "content/public/common/pepper_plugin_info.h"
  21. #include "content/public/common/user_agent.h"
  22. #include "electron/buildflags/buildflags.h"
  23. #include "ppapi/shared_impl/ppapi_permissions.h"
  24. #include "ui/base/l10n/l10n_util.h"
  25. #include "url/url_constants.h"
  26. // In SHARED_INTERMEDIATE_DIR.
  27. #include "widevine_cdm_version.h" // NOLINT(build/include)
  28. #if defined(WIDEVINE_CDM_AVAILABLE)
  29. #include "base/native_library.h"
  30. #include "content/public/common/cdm_info.h"
  31. #include "media/base/video_codecs.h"
  32. #endif // defined(WIDEVINE_CDM_AVAILABLE)
  33. #if BUILDFLAG(ENABLE_PDF_VIEWER)
  34. #include "atom/common/atom_constants.h"
  35. #include "pdf/pdf.h"
  36. #endif // BUILDFLAG(ENABLE_PDF_VIEWER)
  37. namespace atom {
  38. namespace {
  39. #if defined(WIDEVINE_CDM_AVAILABLE)
  40. bool IsWidevineAvailable(
  41. base::FilePath* cdm_path,
  42. std::vector<media::VideoCodec>* codecs_supported,
  43. base::flat_set<media::CdmSessionType>* session_types_supported,
  44. base::flat_set<media::EncryptionMode>* modes_supported) {
  45. static enum {
  46. NOT_CHECKED,
  47. FOUND,
  48. NOT_FOUND,
  49. } widevine_cdm_file_check = NOT_CHECKED;
  50. if (widevine_cdm_file_check == NOT_CHECKED) {
  51. base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
  52. *cdm_path = command_line->GetSwitchValuePath(switches::kWidevineCdmPath);
  53. if (!cdm_path->empty()) {
  54. *cdm_path = cdm_path->AppendASCII(
  55. base::GetNativeLibraryName(kWidevineCdmLibraryName));
  56. widevine_cdm_file_check = base::PathExists(*cdm_path) ? FOUND : NOT_FOUND;
  57. }
  58. }
  59. if (widevine_cdm_file_check == FOUND) {
  60. // Add the supported codecs as if they came from the component manifest.
  61. // This list must match the CDM that is being bundled with Chrome.
  62. codecs_supported->push_back(media::VideoCodec::kCodecVP8);
  63. codecs_supported->push_back(media::VideoCodec::kCodecVP9);
  64. #if BUILDFLAG(USE_PROPRIETARY_CODECS)
  65. codecs_supported->push_back(media::VideoCodec::kCodecH264);
  66. #endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
  67. // TODO(crbug.com/767941): Push persistent-license support info here once
  68. // we check in a new CDM that supports it on Linux.
  69. session_types_supported->insert(media::CdmSessionType::kTemporary);
  70. #if defined(OS_CHROMEOS)
  71. session_types_supported->insert(media::CdmSessionType::kPersistentLicense);
  72. #endif // defined(OS_CHROMEOS)
  73. modes_supported->insert(media::EncryptionMode::kCenc);
  74. return true;
  75. }
  76. return false;
  77. }
  78. #endif // defined(WIDEVINE_CDM_AVAILABLE)
  79. #if BUILDFLAG(ENABLE_PEPPER_FLASH)
  80. content::PepperPluginInfo CreatePepperFlashInfo(const base::FilePath& path,
  81. const std::string& version) {
  82. content::PepperPluginInfo plugin;
  83. plugin.is_out_of_process = true;
  84. plugin.name = content::kFlashPluginName;
  85. plugin.path = path;
  86. plugin.permissions = ppapi::PERMISSION_ALL_BITS;
  87. std::vector<std::string> flash_version_numbers = base::SplitString(
  88. version, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
  89. if (flash_version_numbers.empty())
  90. flash_version_numbers.push_back("11");
  91. // |SplitString()| puts in an empty string given an empty string. :(
  92. else if (flash_version_numbers[0].empty())
  93. flash_version_numbers[0] = "11";
  94. if (flash_version_numbers.size() < 2)
  95. flash_version_numbers.push_back("2");
  96. if (flash_version_numbers.size() < 3)
  97. flash_version_numbers.push_back("999");
  98. if (flash_version_numbers.size() < 4)
  99. flash_version_numbers.push_back("999");
  100. // E.g., "Shockwave Flash 10.2 r154":
  101. plugin.description = plugin.name + " " + flash_version_numbers[0] + "." +
  102. flash_version_numbers[1] + " r" +
  103. flash_version_numbers[2];
  104. plugin.version = base::JoinString(flash_version_numbers, ".");
  105. content::WebPluginMimeType swf_mime_type(content::kFlashPluginSwfMimeType,
  106. content::kFlashPluginSwfExtension,
  107. content::kFlashPluginSwfDescription);
  108. plugin.mime_types.push_back(swf_mime_type);
  109. content::WebPluginMimeType spl_mime_type(content::kFlashPluginSplMimeType,
  110. content::kFlashPluginSplExtension,
  111. content::kFlashPluginSplDescription);
  112. plugin.mime_types.push_back(spl_mime_type);
  113. return plugin;
  114. }
  115. void AddPepperFlashFromCommandLine(
  116. base::CommandLine* command_line,
  117. std::vector<content::PepperPluginInfo>* plugins) {
  118. base::FilePath flash_path =
  119. command_line->GetSwitchValuePath(switches::kPpapiFlashPath);
  120. if (flash_path.empty())
  121. return;
  122. auto flash_version =
  123. command_line->GetSwitchValueASCII(switches::kPpapiFlashVersion);
  124. plugins->push_back(CreatePepperFlashInfo(flash_path, flash_version));
  125. }
  126. #endif // BUILDFLAG(ENABLE_PEPPER_FLASH)
  127. void ComputeBuiltInPlugins(std::vector<content::PepperPluginInfo>* plugins) {
  128. #if BUILDFLAG(ENABLE_PDF_VIEWER)
  129. content::PepperPluginInfo pdf_info;
  130. pdf_info.is_internal = true;
  131. pdf_info.is_out_of_process = true;
  132. pdf_info.name = "Chromium PDF Viewer";
  133. pdf_info.description = "Portable Document Format";
  134. pdf_info.path = base::FilePath::FromUTF8Unsafe(kPdfPluginPath);
  135. content::WebPluginMimeType pdf_mime_type(kPdfPluginMimeType, "pdf",
  136. "Portable Document Format");
  137. pdf_info.mime_types.push_back(pdf_mime_type);
  138. pdf_info.internal_entry_points.get_interface = chrome_pdf::PPP_GetInterface;
  139. pdf_info.internal_entry_points.initialize_module =
  140. chrome_pdf::PPP_InitializeModule;
  141. pdf_info.internal_entry_points.shutdown_module =
  142. chrome_pdf::PPP_ShutdownModule;
  143. pdf_info.permissions = ppapi::PERMISSION_PRIVATE | ppapi::PERMISSION_DEV;
  144. plugins->push_back(pdf_info);
  145. #endif // BUILDFLAG(ENABLE_PDF_VIEWER)
  146. }
  147. void AppendDelimitedSwitchToVector(const base::StringPiece cmd_switch,
  148. std::vector<std::string>* append_me) {
  149. auto* command_line = base::CommandLine::ForCurrentProcess();
  150. auto switch_value = command_line->GetSwitchValueASCII(cmd_switch);
  151. if (!switch_value.empty()) {
  152. constexpr base::StringPiece delimiter(",", 1);
  153. auto tokens =
  154. base::SplitString(switch_value, delimiter, base::TRIM_WHITESPACE,
  155. base::SPLIT_WANT_NONEMPTY);
  156. append_me->reserve(append_me->size() + tokens.size());
  157. std::move(std::begin(tokens), std::end(tokens),
  158. std::back_inserter(*append_me));
  159. }
  160. }
  161. std::string RemoveWhitespace(const std::string& str) {
  162. std::string trimmed;
  163. if (base::RemoveChars(str, " ", &trimmed))
  164. return trimmed;
  165. else
  166. return str;
  167. }
  168. bool IsBrowserProcess() {
  169. const base::CommandLine* command_line =
  170. base::CommandLine::ForCurrentProcess();
  171. std::string process_type =
  172. command_line->GetSwitchValueASCII(::switches::kProcessType);
  173. return process_type.empty();
  174. }
  175. std::string BuildDefaultUserAgent() {
  176. return "Chrome/" CHROME_VERSION_STRING " " ATOM_PRODUCT_NAME
  177. "/" ATOM_VERSION_STRING;
  178. }
  179. } // namespace
  180. AtomContentClient::AtomContentClient() {}
  181. AtomContentClient::~AtomContentClient() {}
  182. std::string AtomContentClient::GetProduct() const {
  183. return "Chrome/" CHROME_VERSION_STRING;
  184. }
  185. std::string AtomContentClient::GetUserAgent() const {
  186. if (IsBrowserProcess()) {
  187. if (user_agent_override_.empty()) {
  188. auto* browser = Browser::Get();
  189. std::string name = RemoveWhitespace(browser->GetName());
  190. std::string user_agent;
  191. if (name == ATOM_PRODUCT_NAME) {
  192. user_agent = BuildDefaultUserAgent();
  193. } else {
  194. user_agent = base::StringPrintf(
  195. "%s/%s Chrome/%s " ATOM_PRODUCT_NAME "/" ATOM_VERSION_STRING,
  196. name.c_str(), browser->GetVersion().c_str(), CHROME_VERSION_STRING);
  197. }
  198. return content::BuildUserAgentFromProduct(user_agent);
  199. }
  200. return user_agent_override_;
  201. }
  202. // In a renderer process the user agent should be provided on the CLI
  203. // If it's not we just fallback to the default one, this should never happen
  204. // but we want to handle it gracefully
  205. const base::CommandLine* command_line =
  206. base::CommandLine::ForCurrentProcess();
  207. std::string cli_user_agent = command_line->GetSwitchValueASCII("user-agent");
  208. if (cli_user_agent.empty())
  209. return BuildDefaultUserAgent();
  210. return cli_user_agent;
  211. }
  212. void AtomContentClient::SetUserAgent(const std::string& user_agent) {
  213. user_agent_override_ = user_agent;
  214. }
  215. base::string16 AtomContentClient::GetLocalizedString(int message_id) const {
  216. return l10n_util::GetStringUTF16(message_id);
  217. }
  218. void AtomContentClient::AddAdditionalSchemes(Schemes* schemes) {
  219. AppendDelimitedSwitchToVector(switches::kRegisterServiceWorkerSchemes,
  220. &schemes->service_worker_schemes);
  221. AppendDelimitedSwitchToVector(switches::kSecureSchemes,
  222. &schemes->secure_schemes);
  223. schemes->standard_schemes.push_back("chrome-extension");
  224. schemes->service_worker_schemes.push_back(url::kFileScheme);
  225. }
  226. void AtomContentClient::AddPepperPlugins(
  227. std::vector<content::PepperPluginInfo>* plugins) {
  228. #if BUILDFLAG(ENABLE_PEPPER_FLASH)
  229. base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
  230. AddPepperFlashFromCommandLine(command_line, plugins);
  231. #endif // BUILDFLAG(ENABLE_PEPPER_FLASH)
  232. ComputeBuiltInPlugins(plugins);
  233. }
  234. void AtomContentClient::AddContentDecryptionModules(
  235. std::vector<content::CdmInfo>* cdms,
  236. std::vector<media::CdmHostFilePath>* cdm_host_file_paths) {
  237. if (cdms) {
  238. #if defined(WIDEVINE_CDM_AVAILABLE)
  239. base::FilePath cdm_path;
  240. std::vector<media::VideoCodec> video_codecs_supported;
  241. base::flat_set<media::CdmSessionType> session_types_supported;
  242. base::flat_set<media::EncryptionMode> encryption_modes_supported;
  243. if (IsWidevineAvailable(&cdm_path, &video_codecs_supported,
  244. &session_types_supported,
  245. &encryption_modes_supported)) {
  246. base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
  247. auto cdm_version_string =
  248. command_line->GetSwitchValueASCII(switches::kWidevineCdmVersion);
  249. // CdmInfo needs |path| to be the actual Widevine library,
  250. // not the adapter, so adjust as necessary. It will be in the
  251. // same directory as the installed adapter.
  252. const base::Version version(cdm_version_string);
  253. DCHECK(version.IsValid());
  254. content::CdmCapability capability(
  255. video_codecs_supported, encryption_modes_supported,
  256. session_types_supported, base::flat_set<media::CdmProxy::Protocol>());
  257. cdms->push_back(content::CdmInfo(
  258. kWidevineCdmDisplayName, kWidevineCdmGuid, version, cdm_path,
  259. kWidevineCdmFileSystemId, capability, kWidevineKeySystem, false));
  260. }
  261. #endif // defined(WIDEVINE_CDM_AVAILABLE)
  262. }
  263. }
  264. } // namespace atom