1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "extensions/shell/browser/shell_nacl_browser_delegate.h" 6 7 #include <string> 8 9 #include "base/base_paths.h" 10 #include "base/command_line.h" 11 #include "base/path_service.h" 12 #include "base/strings/string_split.h" 13 #include "base/strings/string_util.h" 14 #include "content/public/browser/browser_context.h" 15 #include "content/public/browser/browser_thread.h" 16 #include "content/public/browser/render_frame_host.h" 17 #include "content/public/browser/site_instance.h" 18 #include "extensions/browser/extension_system.h" 19 #include "extensions/browser/info_map.h" 20 #include "extensions/browser/process_manager.h" 21 #include "extensions/common/constants.h" 22 #include "extensions/common/extension.h" 23 #include "extensions/common/url_pattern.h" 24 #include "extensions/shell/common/version.h" // Generated file. 25 #include "ppapi/c/private/ppb_nacl_private.h" 26 #include "url/gurl.h" 27 28 using content::BrowserContext; 29 using content::BrowserThread; 30 using content::BrowserPpapiHost; 31 32 namespace extensions { 33 namespace { 34 35 // Handles an extension's NaCl process transitioning in or out of idle state by 36 // relaying the state to the extension's process manager. See Chrome's 37 // NaClBrowserDelegateImpl for another example. 38 void OnKeepaliveOnUIThread( 39 const BrowserPpapiHost::OnKeepaliveInstanceData& instance_data, 40 const base::FilePath& profile_data_directory) { 41 DCHECK_CURRENTLY_ON(BrowserThread::UI); 42 43 // Only one instance will exist for NaCl embeds, even when more than one 44 // embed of the same plugin exists on the same page. 45 DCHECK(instance_data.size() == 1); 46 if (instance_data.size() < 1) 47 return; 48 49 ProcessManager::OnKeepaliveFromPlugin(instance_data[0].render_process_id, 50 instance_data[0].render_frame_id, 51 instance_data[0].document_url.host()); 52 } 53 54 // Calls OnKeepaliveOnUIThread on UI thread. 55 void OnKeepalive(const BrowserPpapiHost::OnKeepaliveInstanceData& instance_data, 56 const base::FilePath& profile_data_directory) { 57 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); 58 BrowserThread::PostTask( 59 BrowserThread::UI, 60 FROM_HERE, 61 base::Bind( 62 &OnKeepaliveOnUIThread, instance_data, profile_data_directory)); 63 } 64 65 } // namespace 66 67 ShellNaClBrowserDelegate::ShellNaClBrowserDelegate(BrowserContext* context) 68 : browser_context_(context) { 69 DCHECK(browser_context_); 70 } 71 72 ShellNaClBrowserDelegate::~ShellNaClBrowserDelegate() { 73 } 74 75 void ShellNaClBrowserDelegate::ShowMissingArchInfobar(int render_process_id, 76 int render_view_id) { 77 // app_shell does not have infobars. 78 LOG(ERROR) << "Missing architecture for pid " << render_process_id; 79 } 80 81 bool ShellNaClBrowserDelegate::DialogsAreSuppressed() { 82 return false; 83 } 84 85 bool ShellNaClBrowserDelegate::GetCacheDirectory(base::FilePath* cache_dir) { 86 // Just use the general cache directory, not a subdirectory like Chrome does. 87 #if defined(OS_POSIX) 88 return PathService::Get(base::DIR_CACHE, cache_dir); 89 #elif defined(OS_WIN) 90 // TODO(yoz): Find an appropriate persistent directory to use here. 91 return PathService::Get(base::DIR_TEMP, cache_dir); 92 #endif 93 } 94 95 bool ShellNaClBrowserDelegate::GetPluginDirectory(base::FilePath* plugin_dir) { 96 // On Posix, plugins are in the module directory. 97 return PathService::Get(base::DIR_MODULE, plugin_dir); 98 } 99 100 bool ShellNaClBrowserDelegate::GetPnaclDirectory(base::FilePath* pnacl_dir) { 101 // On Posix, the pnacl directory is inside the plugin directory. 102 base::FilePath plugin_dir; 103 if (!GetPluginDirectory(&plugin_dir)) 104 return false; 105 *pnacl_dir = plugin_dir.Append(FILE_PATH_LITERAL("pnacl")); 106 return true; 107 } 108 109 bool ShellNaClBrowserDelegate::GetUserDirectory(base::FilePath* user_dir) { 110 base::FilePath path = browser_context_->GetPath(); 111 if (!path.empty()) { 112 *user_dir = path; 113 return true; 114 } 115 return false; 116 } 117 118 std::string ShellNaClBrowserDelegate::GetVersionString() const { 119 // A version change triggers an update of the NaCl validation caches. 120 // Example version: "39.0.2129.0 (290550)". 121 return PRODUCT_VERSION " (" LAST_CHANGE ")"; 122 } 123 124 ppapi::host::HostFactory* ShellNaClBrowserDelegate::CreatePpapiHostFactory( 125 content::BrowserPpapiHost* ppapi_host) { 126 return NULL; 127 } 128 129 void ShellNaClBrowserDelegate::SetDebugPatterns(std::string debug_patterns) { 130 // No debugger support. Developers should use Chrome for debugging. 131 } 132 133 bool ShellNaClBrowserDelegate::URLMatchesDebugPatterns( 134 const GURL& manifest_url) { 135 // No debugger support. Developers should use Chrome for debugging. 136 return false; 137 } 138 139 // This function is security sensitive. Be sure to check with a security 140 // person before you modify it. 141 // TODO(jamescook): Refactor this code into the extensions module so it can 142 // be shared with Chrome's NaClBrowserDelegateImpl. http://crbug.com/403017 143 bool ShellNaClBrowserDelegate::MapUrlToLocalFilePath( 144 const GURL& file_url, 145 bool use_blocking_api, 146 const base::FilePath& profile_directory, 147 base::FilePath* file_path) { 148 scoped_refptr<InfoMap> info_map = 149 ExtensionSystem::Get(browser_context_)->info_map(); 150 // Check that the URL is recognized by the extension system. 151 const Extension* extension = 152 info_map->extensions().GetExtensionOrAppByURL(file_url); 153 if (!extension) 154 return false; 155 156 // This is a short-cut which avoids calling a blocking file operation 157 // (GetFilePath()), so that this can be called on the IO thread. It only 158 // handles a subset of the urls. 159 if (!use_blocking_api) { 160 if (file_url.SchemeIs(kExtensionScheme)) { 161 std::string path = file_url.path(); 162 base::TrimString(path, "/", &path); // Remove first slash 163 *file_path = extension->path().AppendASCII(path); 164 return true; 165 } 166 return false; 167 } 168 169 // Check that the URL references a resource in the extension. 170 // NOTE: app_shell does not support shared modules. 171 ExtensionResource resource = extension->GetResource(file_url.path()); 172 if (resource.empty()) 173 return false; 174 175 // GetFilePath is a blocking function call. 176 const base::FilePath resource_file_path = resource.GetFilePath(); 177 if (resource_file_path.empty()) 178 return false; 179 180 *file_path = resource_file_path; 181 return true; 182 } 183 184 content::BrowserPpapiHost::OnKeepaliveCallback 185 ShellNaClBrowserDelegate::GetOnKeepaliveCallback() { 186 return base::Bind(&OnKeepalive); 187 } 188 189 bool ShellNaClBrowserDelegate::IsNonSfiModeAllowed( 190 const base::FilePath& profile_directory, 191 const GURL& manifest_url) { 192 return false; 193 } 194 195 } // namespace extensions 196