pnacl_resources.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
1// Copyright (c) 2012 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 "native_client/src/trusted/plugin/pnacl_resources.h" 6 7#include "native_client/src/include/portability_io.h" 8#include "native_client/src/shared/platform/nacl_check.h" 9#include "native_client/src/trusted/desc/nacl_desc_wrapper.h" 10#include "native_client/src/trusted/plugin/file_utils.h" 11#include "native_client/src/trusted/plugin/manifest.h" 12#include "native_client/src/trusted/plugin/plugin.h" 13#include "native_client/src/trusted/plugin/pnacl_coordinator.h" 14#include "native_client/src/trusted/plugin/utility.h" 15#include "ppapi/c/pp_errors.h" 16#include "third_party/jsoncpp/source/include/json/reader.h" 17#include "third_party/jsoncpp/source/include/json/value.h" 18 19namespace plugin { 20 21static const char kPnaclComponentScheme[] = "pnacl-component://"; 22const char PnaclUrls::kResourceInfoUrl[] = "pnacl.json"; 23 24const char PnaclResources::kDefaultLlcName[] = "llc.nexe"; 25const char PnaclResources::kDefaultLdName[] = "ld.nexe"; 26 27nacl::string PnaclUrls::GetBaseUrl() { 28 return nacl::string(kPnaclComponentScheme); 29} 30 31nacl::string PnaclUrls::PrependPlatformPrefix(const nacl::string& url) { 32 return nacl::string(GetSandboxISA()) + "/" + url; 33} 34 35// Determine if a URL is for a pnacl-component file, or if it is some other 36// type of URL (e.g., http://, https://, chrome-extension://). 37// The URL could be one of the other variants for shared libraries 38// served from the web. 39bool PnaclUrls::IsPnaclComponent(const nacl::string& full_url) { 40 return full_url.find(kPnaclComponentScheme, 0) == 0; 41} 42 43// Convert a URL to a filename accepted by GetReadonlyPnaclFd. 44// Must be kept in sync with chrome/browser/nacl_host/nacl_file_host. 45nacl::string PnaclUrls::PnaclComponentURLToFilename( 46 const nacl::string& full_url) { 47 // strip component scheme. 48 nacl::string r = full_url.substr( 49 nacl::string(kPnaclComponentScheme).length()); 50 51 // Use white-listed-chars. 52 size_t replace_pos; 53 static const char* white_list = "abcdefghijklmnopqrstuvwxyz0123456789_"; 54 replace_pos = r.find_first_not_of(white_list); 55 while(replace_pos != nacl::string::npos) { 56 r = r.replace(replace_pos, 1, "_"); 57 replace_pos = r.find_first_not_of(white_list); 58 } 59 return r; 60} 61 62////////////////////////////////////////////////////////////////////// 63 64PnaclResources::~PnaclResources() { 65 for (std::map<nacl::string, nacl::DescWrapper*>::iterator 66 i = resource_wrappers_.begin(), e = resource_wrappers_.end(); 67 i != e; 68 ++i) { 69 delete i->second; 70 } 71 resource_wrappers_.clear(); 72} 73 74// static 75int32_t PnaclResources::GetPnaclFD(Plugin* plugin, const char* filename) { 76 PP_FileHandle file_handle = 77 plugin->nacl_interface()->GetReadonlyPnaclFd(filename); 78 if (file_handle == PP_kInvalidFileHandle) 79 return -1; 80 81#if NACL_WINDOWS 82 //////// Now try the posix view. 83 int32_t posix_desc = _open_osfhandle(reinterpret_cast<intptr_t>(file_handle), 84 _O_RDONLY | _O_BINARY); 85 if (posix_desc == -1) { 86 PLUGIN_PRINTF(( 87 "PnaclResources::GetPnaclFD failed to convert HANDLE to posix\n")); 88 // Close the Windows HANDLE if it can't be converted. 89 CloseHandle(file_handle); 90 } 91 return posix_desc; 92#else 93 return file_handle; 94#endif 95} 96 97nacl::DescWrapper* PnaclResources::WrapperForUrl(const nacl::string& url) { 98 CHECK(resource_wrappers_.find(url) != resource_wrappers_.end()); 99 return resource_wrappers_[url]; 100} 101 102void PnaclResources::ReadResourceInfo( 103 const nacl::string& resource_info_url, 104 const pp::CompletionCallback& resource_info_read_cb) { 105 PLUGIN_PRINTF(("PnaclResources::ReadResourceInfo\n")); 106 107 nacl::string full_url; 108 ErrorInfo error_info; 109 if (!manifest_->ResolveURL(resource_info_url, &full_url, &error_info)) { 110 ReadResourceInfoError(nacl::string("failed to resolve ") + 111 resource_info_url + ": " + 112 error_info.message() + "."); 113 return; 114 } 115 PLUGIN_PRINTF(("Resolved resources info url: %s\n", full_url.c_str())); 116 nacl::string resource_info_filename = 117 PnaclUrls::PnaclComponentURLToFilename(full_url); 118 119 PLUGIN_PRINTF(("Pnacl-converted resources info url: %s\n", 120 resource_info_filename.c_str())); 121 122 int32_t fd = GetPnaclFD(plugin_, resource_info_filename.c_str()); 123 if (fd < 0) { 124 ReadResourceInfoError( 125 nacl::string("PnaclResources::ReadResourceInfo failed for: ") + 126 resource_info_filename); 127 return; 128 } 129 130 nacl::string json_buffer; 131 file_utils::StatusCode status = file_utils::SlurpFile(fd, json_buffer); 132 if (status != file_utils::PLUGIN_FILE_SUCCESS) { 133 ReadResourceInfoError( 134 nacl::string("PnaclResources::ReadResourceInfo reading " 135 "failed for: ") + resource_info_filename); 136 return; 137 } 138 139 // Finally, we have the resource info JSON data in json_buffer. 140 PLUGIN_PRINTF(("Resource info JSON data:\n%s\n", json_buffer.c_str())); 141 nacl::string error_message; 142 if (!ParseResourceInfo(json_buffer, error_message)) { 143 ReadResourceInfoError(nacl::string("Parsing resource info failed: ") + 144 error_message + "\n"); 145 return; 146 } 147 148 // Done. Queue the completion callback. 149 pp::Core* core = pp::Module::Get()->core(); 150 core->CallOnMainThread(0, resource_info_read_cb, PP_OK); 151} 152 153void PnaclResources::ReadResourceInfoError(const nacl::string& msg) { 154 coordinator_->ReportNonPpapiError(ERROR_PNACL_RESOURCE_FETCH, msg); 155} 156 157bool PnaclResources::ParseResourceInfo(const nacl::string& buf, 158 nacl::string& errmsg) { 159 // Expect the JSON file to contain a top-level object (dictionary). 160 Json::Reader json_reader; 161 Json::Value json_data; 162 if (!json_reader.parse(buf, json_data)) { 163 errmsg = nacl::string("JSON parse error: ") + 164 json_reader.getFormatedErrorMessages(); 165 return false; 166 } 167 168 if (!json_data.isObject()) { 169 errmsg = nacl::string("Malformed JSON dictionary"); 170 return false; 171 } 172 173 if (json_data.isMember("pnacl-llc-name")) { 174 Json::Value json_name = json_data["pnacl-llc-name"]; 175 if (json_name.isString()) { 176 llc_tool_name = json_name.asString(); 177 PLUGIN_PRINTF(("Set llc_tool_name=%s\n", llc_tool_name.c_str())); 178 } 179 } 180 181 if (json_data.isMember("pnacl-ld-name")) { 182 Json::Value json_name = json_data["pnacl-ld-name"]; 183 if (json_name.isString()) { 184 ld_tool_name = json_name.asString(); 185 PLUGIN_PRINTF(("Set ld_tool_name=%s\n", ld_tool_name.c_str())); 186 } 187 } 188 189 return true; 190} 191 192void PnaclResources::StartLoad( 193 const pp::CompletionCallback& all_loaded_callback) { 194 PLUGIN_PRINTF(("PnaclResources::StartLoad\n")); 195 196 std::vector<nacl::string> resource_urls; 197 resource_urls.push_back(GetLlcUrl()); 198 resource_urls.push_back(GetLdUrl()); 199 200 PLUGIN_PRINTF(("PnaclResources::StartLoad -- local install of PNaCl.\n")); 201 // Do a blocking load of each of the resources. 202 int32_t result = PP_OK; 203 for (size_t i = 0; i < resource_urls.size(); ++i) { 204 const nacl::string& url_with_platform_prefix = 205 PnaclUrls::PrependPlatformPrefix(resource_urls[i]); 206 nacl::string full_url; 207 ErrorInfo error_info; 208 if (!manifest_->ResolveURL(url_with_platform_prefix, &full_url, 209 &error_info)) { 210 coordinator_->ReportNonPpapiError( 211 ERROR_PNACL_RESOURCE_FETCH, 212 nacl::string("failed to resolve ") + 213 url_with_platform_prefix + ": " + 214 error_info.message() + "."); 215 break; 216 } 217 nacl::string filename = PnaclUrls::PnaclComponentURLToFilename(full_url); 218 219 int32_t fd = PnaclResources::GetPnaclFD(plugin_, filename.c_str()); 220 if (fd < 0) { 221 coordinator_->ReportNonPpapiError( 222 ERROR_PNACL_RESOURCE_FETCH, 223 nacl::string("PnaclResources::StartLoad failed for: ") + 224 filename + " (PNaCl not installed? Check chrome://nacl)"); 225 result = PP_ERROR_FILENOTFOUND; 226 break; 227 } else { 228 resource_wrappers_[resource_urls[i]] = 229 plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY); 230 } 231 } 232 // We're done! Queue the callback. 233 pp::Core* core = pp::Module::Get()->core(); 234 core->CallOnMainThread(0, all_loaded_callback, result); 235} 236 237} // namespace plugin 238