pnacl_resources.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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/manifest.h" 11#include "native_client/src/trusted/plugin/plugin.h" 12#include "native_client/src/trusted/plugin/pnacl_coordinator.h" 13#include "native_client/src/trusted/plugin/utility.h" 14 15#include "ppapi/c/pp_errors.h" 16 17namespace plugin { 18 19static const char kExtensionOrigin[] = 20 "chrome-extension://gcodniebolpnpaiggndmcmmfpldlknih/"; 21static const char kPnaclComponentID[] = 22 "pnacl-component://"; 23const char PnaclUrls::kLlcUrl[] = "llc.nexe"; 24const char PnaclUrls::kLdUrl[] = "ld.nexe"; 25 26bool PnaclUrls::UsePnaclExtension(const Plugin* plugin) { 27 // TODO(jvoung): remove extension stuff if we aren't using it. 28 return false; 29} 30 31nacl::string PnaclUrls::GetBaseUrl(bool use_extension) { 32 if (use_extension) { 33 return nacl::string(kExtensionOrigin) + GetSandboxISA() + "/"; 34 } else { 35 return nacl::string(kPnaclComponentID) + GetSandboxISA() + "/"; 36 } 37} 38 39bool PnaclUrls::IsPnaclComponent(const nacl::string& full_url) { 40 return full_url.find(kPnaclComponentID, 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 componentID. 48 nacl::string r = full_url.substr(nacl::string(kPnaclComponentID).length()); 49 50 // Use white-listed-chars. 51 size_t replace_pos; 52 static const char* white_list = "abcdefghijklmnopqrstuvwxyz0123456789_"; 53 replace_pos = r.find_first_not_of(white_list); 54 while(replace_pos != nacl::string::npos) { 55 r = r.replace(replace_pos, 1, "_"); 56 replace_pos = r.find_first_not_of(white_list); 57 } 58 return r; 59} 60 61////////////////////////////////////////////////////////////////////// 62 63PnaclResources::~PnaclResources() { 64 for (std::map<nacl::string, nacl::DescWrapper*>::iterator 65 i = resource_wrappers_.begin(), e = resource_wrappers_.end(); 66 i != e; 67 ++i) { 68 delete i->second; 69 } 70 resource_wrappers_.clear(); 71} 72 73// static 74int32_t PnaclResources::GetPnaclFD(Plugin* plugin, const char* filename) { 75 PP_FileHandle file_handle = 76 plugin->nacl_interface()->GetReadonlyPnaclFd(filename); 77 if (file_handle == PP_kInvalidFileHandle) 78 return -1; 79 80#if NACL_WINDOWS 81 //////// Now try the posix view. 82 int32_t posix_desc = _open_osfhandle(reinterpret_cast<intptr_t>(file_handle), 83 _O_RDONLY | _O_BINARY); 84 if (posix_desc == -1) { 85 PLUGIN_PRINTF(( 86 "PnaclResources::GetPnaclFD failed to convert HANDLE to posix\n")); 87 // Close the Windows HANDLE if it can't be converted. 88 CloseHandle(file_handle); 89 } 90 return posix_desc; 91#else 92 return file_handle; 93#endif 94} 95 96nacl::DescWrapper* PnaclResources::WrapperForUrl(const nacl::string& url) { 97 CHECK(resource_wrappers_.find(url) != resource_wrappers_.end()); 98 return resource_wrappers_[url]; 99} 100 101void PnaclResources::StartLoad() { 102 PLUGIN_PRINTF(("PnaclResources::StartLoad\n")); 103 104 CHECK(resource_urls_.size() > 0); 105 if (PnaclUrls::UsePnaclExtension(plugin_)) { 106 PLUGIN_PRINTF(("PnaclResources::StartLoad -- PNaCl chrome extension.\n")); 107 // Do a URL fetch. 108 // Create a counter (barrier) callback to track when all of the resources 109 // are loaded. 110 uint32_t resource_count = static_cast<uint32_t>(resource_urls_.size()); 111 delayed_callback_.reset( 112 new DelayedCallback(all_loaded_callback_, resource_count)); 113 114 // Schedule the downloads. 115 for (size_t i = 0; i < resource_urls_.size(); ++i) { 116 nacl::string full_url; 117 ErrorInfo error_info; 118 if (!manifest_->ResolveURL(resource_urls_[i], &full_url, &error_info)) { 119 coordinator_->ReportNonPpapiError( 120 ERROR_PNACL_RESOURCE_FETCH, 121 nacl::string("failed to resolve ") + 122 resource_urls_[i] + ": " + 123 error_info.message() + "."); 124 break; 125 } 126 pp::CompletionCallback ready_callback = 127 callback_factory_.NewCallback( 128 &PnaclResources::ResourceReady, 129 resource_urls_[i], 130 full_url); 131 if (!plugin_->StreamAsFile(full_url, 132 ready_callback.pp_completion_callback())) { 133 coordinator_->ReportNonPpapiError( 134 ERROR_PNACL_RESOURCE_FETCH, 135 nacl::string("failed to download ") + 136 resource_urls_[i] + "."); 137 break; 138 } 139 } 140 } else { 141 PLUGIN_PRINTF(("PnaclResources::StartLoad -- local install of PNaCl.\n")); 142 // Do a blocking load of each of the resources. 143 int32_t result = PP_OK; 144 for (size_t i = 0; i < resource_urls_.size(); ++i) { 145 const nacl::string& url = resource_urls_[i]; 146 nacl::string full_url; 147 ErrorInfo error_info; 148 if (!manifest_->ResolveURL(resource_urls_[i], &full_url, &error_info)) { 149 coordinator_->ReportNonPpapiError( 150 ERROR_PNACL_RESOURCE_FETCH, 151 nacl::string("failed to resolve ") + 152 url + ": " + 153 error_info.message() + "."); 154 break; 155 } 156 nacl::string filename = PnaclUrls::PnaclComponentURLToFilename(full_url); 157 158 int32_t fd = PnaclResources::GetPnaclFD(plugin_, filename.c_str()); 159 if (fd < 0) { 160 coordinator_->ReportNonPpapiError( 161 ERROR_PNACL_RESOURCE_FETCH, 162 nacl::string("PnaclLocalResources::StartLoad failed for: ") + 163 filename); 164 result = PP_ERROR_FILENOTFOUND; 165 break; 166 } else { 167 resource_wrappers_[url] = 168 plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY); 169 } 170 } 171 // We're done! Queue the callback. 172 pp::Core* core = pp::Module::Get()->core(); 173 core->CallOnMainThread(0, all_loaded_callback_, result); 174 } 175} 176 177void PnaclResources::ResourceReady(int32_t pp_error, 178 const nacl::string& url, 179 const nacl::string& full_url) { 180 PLUGIN_PRINTF(("PnaclResources::ResourceReady (pp_error=%" 181 NACL_PRId32", url=%s)\n", pp_error, url.c_str())); 182 // pp_error is checked by GetLoadedFileDesc. 183 int32_t fd = coordinator_->GetLoadedFileDesc(pp_error, 184 full_url, 185 "resource " + url); 186 if (fd < 0) { 187 coordinator_->ReportPpapiError(ERROR_PNACL_RESOURCE_FETCH, 188 pp_error, 189 "PnaclResources::ResourceReady failed."); 190 } else { 191 resource_wrappers_[url] = 192 plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY); 193 delayed_callback_->RunIfTime(); 194 } 195} 196 197} // namespace plugin 198