Home | History | Annotate | Download | only in renderer
      1 // Copyright 2013 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 "components/nacl/renderer/ppb_nacl_private_impl.h"
      6 
      7 #include <numeric>
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "base/bind.h"
     12 #include "base/bind_helpers.h"
     13 #include "base/command_line.h"
     14 #include "base/containers/scoped_ptr_hash_map.h"
     15 #include "base/cpu.h"
     16 #include "base/lazy_instance.h"
     17 #include "base/logging.h"
     18 #include "base/rand_util.h"
     19 #include "components/nacl/common/nacl_host_messages.h"
     20 #include "components/nacl/common/nacl_messages.h"
     21 #include "components/nacl/common/nacl_nonsfi_util.h"
     22 #include "components/nacl/common/nacl_switches.h"
     23 #include "components/nacl/common/nacl_types.h"
     24 #include "components/nacl/renderer/file_downloader.h"
     25 #include "components/nacl/renderer/histogram.h"
     26 #include "components/nacl/renderer/json_manifest.h"
     27 #include "components/nacl/renderer/manifest_downloader.h"
     28 #include "components/nacl/renderer/manifest_service_channel.h"
     29 #include "components/nacl/renderer/nexe_load_manager.h"
     30 #include "components/nacl/renderer/pnacl_translation_resource_host.h"
     31 #include "components/nacl/renderer/progress_event.h"
     32 #include "components/nacl/renderer/sandbox_arch.h"
     33 #include "components/nacl/renderer/trusted_plugin_channel.h"
     34 #include "content/public/common/content_client.h"
     35 #include "content/public/common/content_switches.h"
     36 #include "content/public/common/sandbox_init.h"
     37 #include "content/public/renderer/pepper_plugin_instance.h"
     38 #include "content/public/renderer/render_thread.h"
     39 #include "content/public/renderer/render_view.h"
     40 #include "content/public/renderer/renderer_ppapi_host.h"
     41 #include "native_client/src/public/imc_types.h"
     42 #include "net/base/data_url.h"
     43 #include "net/base/net_errors.h"
     44 #include "net/http/http_util.h"
     45 #include "ppapi/c/pp_bool.h"
     46 #include "ppapi/c/private/pp_file_handle.h"
     47 #include "ppapi/shared_impl/ppapi_globals.h"
     48 #include "ppapi/shared_impl/ppapi_permissions.h"
     49 #include "ppapi/shared_impl/ppapi_preferences.h"
     50 #include "ppapi/shared_impl/var.h"
     51 #include "ppapi/shared_impl/var_tracker.h"
     52 #include "ppapi/thunk/enter.h"
     53 #include "third_party/WebKit/public/platform/WebURLLoader.h"
     54 #include "third_party/WebKit/public/web/WebDocument.h"
     55 #include "third_party/WebKit/public/web/WebElement.h"
     56 #include "third_party/WebKit/public/web/WebLocalFrame.h"
     57 #include "third_party/WebKit/public/web/WebPluginContainer.h"
     58 #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
     59 #include "third_party/WebKit/public/web/WebURLLoaderOptions.h"
     60 #include "third_party/jsoncpp/source/include/json/reader.h"
     61 #include "third_party/jsoncpp/source/include/json/value.h"
     62 
     63 namespace nacl {
     64 namespace {
     65 
     66 // The pseudo-architecture used to indicate portable native client.
     67 const char* const kPortableArch = "portable";
     68 
     69 // The base URL for resources used by the PNaCl translator processes.
     70 const char* kPNaClTranslatorBaseUrl = "chrome://pnacl-translator/";
     71 
     72 base::LazyInstance<scoped_refptr<PnaclTranslationResourceHost> >
     73     g_pnacl_resource_host = LAZY_INSTANCE_INITIALIZER;
     74 
     75 bool InitializePnaclResourceHost() {
     76   // Must run on the main thread.
     77   content::RenderThread* render_thread = content::RenderThread::Get();
     78   if (!render_thread)
     79     return false;
     80   if (!g_pnacl_resource_host.Get()) {
     81     g_pnacl_resource_host.Get() = new PnaclTranslationResourceHost(
     82         render_thread->GetIOMessageLoopProxy());
     83     render_thread->AddFilter(g_pnacl_resource_host.Get());
     84   }
     85   return true;
     86 }
     87 
     88 struct InstanceInfo {
     89   InstanceInfo() : plugin_pid(base::kNullProcessId), plugin_child_id(0) {}
     90   GURL url;
     91   ppapi::PpapiPermissions permissions;
     92   base::ProcessId plugin_pid;
     93   int plugin_child_id;
     94   IPC::ChannelHandle channel_handle;
     95 };
     96 
     97 typedef std::map<PP_Instance, InstanceInfo> InstanceInfoMap;
     98 
     99 base::LazyInstance<InstanceInfoMap> g_instance_info =
    100     LAZY_INSTANCE_INITIALIZER;
    101 
    102 typedef base::ScopedPtrHashMap<PP_Instance, NexeLoadManager>
    103     NexeLoadManagerMap;
    104 
    105 base::LazyInstance<NexeLoadManagerMap> g_load_manager_map =
    106     LAZY_INSTANCE_INITIALIZER;
    107 
    108 nacl::NexeLoadManager* GetNexeLoadManager(PP_Instance instance) {
    109   NexeLoadManagerMap& map = g_load_manager_map.Get();
    110   NexeLoadManagerMap::iterator iter = map.find(instance);
    111   if (iter != map.end())
    112     return iter->second;
    113   return NULL;
    114 }
    115 
    116 int GetRoutingID(PP_Instance instance) {
    117   // Check that we are on the main renderer thread.
    118   DCHECK(content::RenderThread::Get());
    119   content::RendererPpapiHost *host =
    120       content::RendererPpapiHost::GetForPPInstance(instance);
    121   if (!host)
    122     return 0;
    123   return host->GetRoutingIDForWidget(instance);
    124 }
    125 
    126 // Returns whether the channel_handle is valid or not.
    127 bool IsValidChannelHandle(const IPC::ChannelHandle& channel_handle) {
    128   if (channel_handle.name.empty()) {
    129     return false;
    130   }
    131 
    132 #if defined(OS_POSIX)
    133   if (channel_handle.socket.fd == -1) {
    134     return false;
    135   }
    136 #endif
    137 
    138   return true;
    139 }
    140 
    141 void PostPPCompletionCallback(PP_CompletionCallback callback,
    142                               int32_t status) {
    143   ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(
    144       FROM_HERE,
    145       base::Bind(callback.func, callback.user_data, status));
    146 }
    147 
    148 // Thin adapter from PPP_ManifestService to ManifestServiceChannel::Delegate.
    149 // Note that user_data is managed by the caller of LaunchSelLdr. Please see
    150 // also PP_ManifestService's comment for more details about resource
    151 // management.
    152 class ManifestServiceProxy : public ManifestServiceChannel::Delegate {
    153  public:
    154   ManifestServiceProxy(const PPP_ManifestService* manifest_service,
    155                        void* user_data)
    156       : manifest_service_(*manifest_service),
    157         user_data_(user_data) {
    158   }
    159 
    160   virtual ~ManifestServiceProxy() {
    161     Quit();
    162   }
    163 
    164   virtual void StartupInitializationComplete() OVERRIDE {
    165     if (!user_data_)
    166       return;
    167 
    168     if (!PP_ToBool(
    169             manifest_service_.StartupInitializationComplete(user_data_))) {
    170       user_data_ = NULL;
    171     }
    172   }
    173 
    174   virtual void OpenResource(
    175       const std::string& key,
    176       const ManifestServiceChannel::OpenResourceCallback& callback) OVERRIDE {
    177     if (!user_data_)
    178       return;
    179 
    180     // The allocated callback will be freed in DidOpenResource, which is always
    181     // called regardless whether OpenResource() succeeds or fails.
    182     if (!PP_ToBool(manifest_service_.OpenResource(
    183             user_data_,
    184             key.c_str(),
    185             DidOpenResource,
    186             new ManifestServiceChannel::OpenResourceCallback(callback)))) {
    187       user_data_ = NULL;
    188     }
    189   }
    190 
    191  private:
    192   static void DidOpenResource(void* user_data, PP_FileHandle file_handle) {
    193     scoped_ptr<ManifestServiceChannel::OpenResourceCallback> callback(
    194         static_cast<ManifestServiceChannel::OpenResourceCallback*>(user_data));
    195     callback->Run(file_handle);
    196   }
    197 
    198   void Quit() {
    199     if (!user_data_)
    200       return;
    201 
    202     bool result = PP_ToBool(manifest_service_.Quit(user_data_));
    203     DCHECK(!result);
    204     user_data_ = NULL;
    205   }
    206 
    207   PPP_ManifestService manifest_service_;
    208   void* user_data_;
    209   DISALLOW_COPY_AND_ASSIGN(ManifestServiceProxy);
    210 };
    211 
    212 blink::WebURLLoader* CreateWebURLLoader(const blink::WebDocument& document,
    213                                         const GURL& gurl) {
    214   blink::WebURLLoaderOptions options;
    215   options.untrustedHTTP = true;
    216 
    217   // Options settings here follow the original behavior in the trusted
    218   // plugin and PepperURLLoaderHost.
    219   if (document.securityOrigin().canRequest(gurl)) {
    220     options.allowCredentials = true;
    221   } else {
    222     // Allow CORS.
    223     options.crossOriginRequestPolicy =
    224         blink::WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl;
    225   }
    226   return document.frame()->createAssociatedURLLoader(options);
    227 }
    228 
    229 blink::WebURLRequest CreateWebURLRequest(const blink::WebDocument& document,
    230                                          const GURL& gurl) {
    231   blink::WebURLRequest request;
    232   request.initialize();
    233   request.setURL(gurl);
    234   request.setFirstPartyForCookies(document.firstPartyForCookies());
    235   return request;
    236 }
    237 
    238 int32_t FileDownloaderToPepperError(FileDownloader::Status status) {
    239   switch (status) {
    240     case FileDownloader::SUCCESS:
    241       return PP_OK;
    242     case FileDownloader::ACCESS_DENIED:
    243       return PP_ERROR_NOACCESS;
    244     case FileDownloader::FAILED:
    245       return PP_ERROR_FAILED;
    246     // No default case, to catch unhandled Status values.
    247   }
    248   return PP_ERROR_FAILED;
    249 }
    250 
    251 // Launch NaCl's sel_ldr process.
    252 void LaunchSelLdr(PP_Instance instance,
    253                   PP_Bool main_service_runtime,
    254                   const char* alleged_url,
    255                   PP_Bool uses_irt,
    256                   PP_Bool uses_ppapi,
    257                   PP_Bool uses_nonsfi_mode,
    258                   PP_Bool enable_ppapi_dev,
    259                   PP_Bool enable_dyncode_syscalls,
    260                   PP_Bool enable_exception_handling,
    261                   PP_Bool enable_crash_throttling,
    262                   const PPP_ManifestService* manifest_service_interface,
    263                   void* manifest_service_user_data,
    264                   void* imc_handle,
    265                   PP_CompletionCallback callback) {
    266   CHECK(ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->
    267             BelongsToCurrentThread());
    268 
    269   // Create the manifest service proxy here, so on error case, it will be
    270   // destructed (without passing it to ManifestServiceChannel), and QUIT
    271   // will be called in its destructor so that the caller of this function
    272   // can free manifest_service_user_data properly.
    273   scoped_ptr<ManifestServiceChannel::Delegate> manifest_service_proxy(
    274       new ManifestServiceProxy(manifest_service_interface,
    275                                manifest_service_user_data));
    276 
    277   FileDescriptor result_socket;
    278   IPC::Sender* sender = content::RenderThread::Get();
    279   DCHECK(sender);
    280   int routing_id = 0;
    281   // If the nexe uses ppapi APIs, we need a routing ID.
    282   // To get the routing ID, we must be on the main thread.
    283   // Some nexes do not use ppapi and launch from the background thread,
    284   // so those nexes can skip finding a routing_id.
    285   if (uses_ppapi) {
    286     routing_id = GetRoutingID(instance);
    287     if (!routing_id) {
    288       ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(
    289           FROM_HERE,
    290           base::Bind(callback.func, callback.user_data,
    291                      static_cast<int32_t>(PP_ERROR_FAILED)));
    292       return;
    293     }
    294   }
    295 
    296   InstanceInfo instance_info;
    297   instance_info.url = GURL(alleged_url);
    298 
    299   uint32_t perm_bits = ppapi::PERMISSION_NONE;
    300   // Conditionally block 'Dev' interfaces. We do this for the NaCl process, so
    301   // it's clearer to developers when they are using 'Dev' inappropriately. We
    302   // must also check on the trusted side of the proxy.
    303   if (enable_ppapi_dev)
    304     perm_bits |= ppapi::PERMISSION_DEV;
    305   instance_info.permissions =
    306       ppapi::PpapiPermissions::GetForCommandLine(perm_bits);
    307   std::string error_message_string;
    308   NaClLaunchResult launch_result;
    309 
    310   if (!sender->Send(new NaClHostMsg_LaunchNaCl(
    311           NaClLaunchParams(instance_info.url.spec(),
    312                            routing_id,
    313                            perm_bits,
    314                            PP_ToBool(uses_irt),
    315                            PP_ToBool(uses_nonsfi_mode),
    316                            PP_ToBool(enable_dyncode_syscalls),
    317                            PP_ToBool(enable_exception_handling),
    318                            PP_ToBool(enable_crash_throttling)),
    319           &launch_result,
    320           &error_message_string))) {
    321     ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(
    322         FROM_HERE,
    323         base::Bind(callback.func, callback.user_data,
    324                    static_cast<int32_t>(PP_ERROR_FAILED)));
    325     return;
    326   }
    327 
    328   if (!error_message_string.empty()) {
    329     if (PP_ToBool(main_service_runtime)) {
    330       NexeLoadManager* load_manager = GetNexeLoadManager(instance);
    331       if (load_manager) {
    332         load_manager->ReportLoadError(PP_NACL_ERROR_SEL_LDR_LAUNCH,
    333                                       "ServiceRuntime: failed to start",
    334                                       error_message_string);
    335       }
    336     }
    337     ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(
    338         FROM_HERE,
    339         base::Bind(callback.func, callback.user_data,
    340                    static_cast<int32_t>(PP_ERROR_FAILED)));
    341     return;
    342   }
    343   result_socket = launch_result.imc_channel_handle;
    344   instance_info.channel_handle = launch_result.ppapi_ipc_channel_handle;
    345   instance_info.plugin_pid = launch_result.plugin_pid;
    346   instance_info.plugin_child_id = launch_result.plugin_child_id;
    347 
    348   // Don't save instance_info if channel handle is invalid.
    349   if (IsValidChannelHandle(instance_info.channel_handle))
    350     g_instance_info.Get()[instance] = instance_info;
    351 
    352   *(static_cast<NaClHandle*>(imc_handle)) = ToNativeHandle(result_socket);
    353 
    354   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
    355   DCHECK(load_manager);
    356   if (!load_manager) {
    357     PostPPCompletionCallback(callback, PP_ERROR_FAILED);
    358     return;
    359   }
    360 
    361   // Create the trusted plugin channel.
    362   if (IsValidChannelHandle(launch_result.trusted_ipc_channel_handle)) {
    363     scoped_ptr<TrustedPluginChannel> trusted_plugin_channel(
    364         new TrustedPluginChannel(
    365             launch_result.trusted_ipc_channel_handle));
    366     load_manager->set_trusted_plugin_channel(trusted_plugin_channel.Pass());
    367   } else {
    368     PostPPCompletionCallback(callback, PP_ERROR_FAILED);
    369     return;
    370   }
    371 
    372   // Create the manifest service handle as well.
    373   // For security hardening, disable the IPCs for open_resource() when they
    374   // aren't needed.  PNaCl doesn't expose open_resource(), and the new
    375   // open_resource() IPCs are currently only used for Non-SFI NaCl so far,
    376   // not SFI NaCl. Note that enable_dyncode_syscalls is true if and only if
    377   // the plugin is a non-PNaCl plugin.
    378   if (load_manager &&
    379       enable_dyncode_syscalls &&
    380       uses_nonsfi_mode &&
    381       IsValidChannelHandle(
    382           launch_result.manifest_service_ipc_channel_handle)) {
    383     scoped_ptr<ManifestServiceChannel> manifest_service_channel(
    384         new ManifestServiceChannel(
    385             launch_result.manifest_service_ipc_channel_handle,
    386             base::Bind(&PostPPCompletionCallback, callback),
    387             manifest_service_proxy.Pass(),
    388             content::RenderThread::Get()->GetShutdownEvent()));
    389     load_manager->set_manifest_service_channel(
    390         manifest_service_channel.Pass());
    391   } else {
    392     // Currently, manifest service works only on linux/non-SFI mode.
    393     // On other platforms, the socket will not be created, and thus this
    394     // condition needs to be handled as success.
    395     PostPPCompletionCallback(callback, PP_OK);
    396   }
    397 }
    398 
    399 PP_Bool StartPpapiProxy(PP_Instance instance) {
    400   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
    401   DCHECK(load_manager);
    402   if (!load_manager)
    403     return PP_FALSE;
    404 
    405   content::PepperPluginInstance* plugin_instance =
    406       content::PepperPluginInstance::Get(instance);
    407   if (!plugin_instance) {
    408     DLOG(ERROR) << "GetInstance() failed";
    409     return PP_FALSE;
    410   }
    411 
    412   InstanceInfoMap& map = g_instance_info.Get();
    413   InstanceInfoMap::iterator it = map.find(instance);
    414   if (it == map.end()) {
    415     DLOG(ERROR) << "Could not find instance ID";
    416     return PP_FALSE;
    417   }
    418   InstanceInfo instance_info = it->second;
    419   map.erase(it);
    420 
    421   PP_ExternalPluginResult result = plugin_instance->SwitchToOutOfProcessProxy(
    422       base::FilePath().AppendASCII(instance_info.url.spec()),
    423       instance_info.permissions,
    424       instance_info.channel_handle,
    425       instance_info.plugin_pid,
    426       instance_info.plugin_child_id);
    427 
    428   if (result == PP_EXTERNAL_PLUGIN_OK) {
    429     // Log the amound of time that has passed between the trusted plugin being
    430     // initialized and the untrusted plugin being initialized.  This is
    431     // (roughly) the cost of using NaCl, in terms of startup time.
    432     load_manager->ReportStartupOverhead();
    433     return PP_TRUE;
    434   } else if (result == PP_EXTERNAL_PLUGIN_ERROR_MODULE) {
    435     load_manager->ReportLoadError(PP_NACL_ERROR_START_PROXY_MODULE,
    436                                   "could not initialize module.");
    437   } else if (result == PP_EXTERNAL_PLUGIN_ERROR_INSTANCE) {
    438     load_manager->ReportLoadError(PP_NACL_ERROR_START_PROXY_MODULE,
    439                                   "could not create instance.");
    440   }
    441   return PP_FALSE;
    442 }
    443 
    444 int UrandomFD(void) {
    445 #if defined(OS_POSIX)
    446   return base::GetUrandomFD();
    447 #else
    448   return -1;
    449 #endif
    450 }
    451 
    452 PP_Bool Are3DInterfacesDisabled() {
    453   return PP_FromBool(CommandLine::ForCurrentProcess()->HasSwitch(
    454                          switches::kDisable3DAPIs));
    455 }
    456 
    457 int32_t BrokerDuplicateHandle(PP_FileHandle source_handle,
    458                               uint32_t process_id,
    459                               PP_FileHandle* target_handle,
    460                               uint32_t desired_access,
    461                               uint32_t options) {
    462 #if defined(OS_WIN)
    463   return content::BrokerDuplicateHandle(source_handle, process_id,
    464                                         target_handle, desired_access,
    465                                         options);
    466 #else
    467   return 0;
    468 #endif
    469 }
    470 
    471 // Convert a URL to a filename for GetReadonlyPnaclFd.
    472 // Must be kept in sync with PnaclCanOpenFile() in
    473 // components/nacl/browser/nacl_file_host.cc.
    474 std::string PnaclComponentURLToFilename(const std::string& url) {
    475   // PNaCl component URLs aren't arbitrary URLs; they are always either
    476   // generated from ManifestResolveKey or PnaclResources::ReadResourceInfo.
    477   // So, it's safe to just use string parsing operations here instead of
    478   // URL-parsing ones.
    479   DCHECK(StartsWithASCII(url, kPNaClTranslatorBaseUrl, true));
    480   std::string r = url.substr(std::string(kPNaClTranslatorBaseUrl).length());
    481 
    482   // Use white-listed-chars.
    483   size_t replace_pos;
    484   static const char* white_list = "abcdefghijklmnopqrstuvwxyz0123456789_";
    485   replace_pos = r.find_first_not_of(white_list);
    486   while(replace_pos != std::string::npos) {
    487     r = r.replace(replace_pos, 1, "_");
    488     replace_pos = r.find_first_not_of(white_list);
    489   }
    490   return r;
    491 }
    492 
    493 PP_FileHandle GetReadonlyPnaclFd(const char* url) {
    494   std::string filename = PnaclComponentURLToFilename(url);
    495   IPC::PlatformFileForTransit out_fd = IPC::InvalidPlatformFileForTransit();
    496   IPC::Sender* sender = content::RenderThread::Get();
    497   DCHECK(sender);
    498   if (!sender->Send(new NaClHostMsg_GetReadonlyPnaclFD(
    499           std::string(filename),
    500           &out_fd))) {
    501     return PP_kInvalidFileHandle;
    502   }
    503   if (out_fd == IPC::InvalidPlatformFileForTransit()) {
    504     return PP_kInvalidFileHandle;
    505   }
    506   return IPC::PlatformFileForTransitToPlatformFile(out_fd);
    507 }
    508 
    509 PP_FileHandle CreateTemporaryFile(PP_Instance instance) {
    510   IPC::PlatformFileForTransit transit_fd = IPC::InvalidPlatformFileForTransit();
    511   IPC::Sender* sender = content::RenderThread::Get();
    512   DCHECK(sender);
    513   if (!sender->Send(new NaClHostMsg_NaClCreateTemporaryFile(
    514           &transit_fd))) {
    515     return PP_kInvalidFileHandle;
    516   }
    517 
    518   if (transit_fd == IPC::InvalidPlatformFileForTransit()) {
    519     return PP_kInvalidFileHandle;
    520   }
    521 
    522   return IPC::PlatformFileForTransitToPlatformFile(transit_fd);
    523 }
    524 
    525 int32_t GetNumberOfProcessors() {
    526   int32_t num_processors;
    527   IPC::Sender* sender = content::RenderThread::Get();
    528   DCHECK(sender);
    529   if(!sender->Send(new NaClHostMsg_NaClGetNumProcessors(&num_processors))) {
    530     return 1;
    531   }
    532   return num_processors;
    533 }
    534 
    535 PP_Bool PPIsNonSFIModeEnabled() {
    536   return PP_FromBool(IsNonSFIModeEnabled());
    537 }
    538 
    539 int32_t GetNexeFd(PP_Instance instance,
    540                   const char* pexe_url,
    541                   uint32_t abi_version,
    542                   uint32_t opt_level,
    543                   const char* http_headers_param,
    544                   const char* extra_flags,
    545                   PP_Bool* is_hit,
    546                   PP_FileHandle* handle,
    547                   struct PP_CompletionCallback callback) {
    548   ppapi::thunk::EnterInstance enter(instance, callback);
    549   if (enter.failed())
    550     return enter.retval();
    551   if (!pexe_url || !is_hit || !handle)
    552     return enter.SetResult(PP_ERROR_BADARGUMENT);
    553   if (!InitializePnaclResourceHost())
    554     return enter.SetResult(PP_ERROR_FAILED);
    555 
    556   std::string http_headers(http_headers_param);
    557   net::HttpUtil::HeadersIterator iter(
    558       http_headers.begin(), http_headers.end(), "\r\n");
    559 
    560   std::string last_modified;
    561   std::string etag;
    562   bool has_no_store_header = false;
    563   while (iter.GetNext()) {
    564     if (StringToLowerASCII(iter.name()) == "last-modified")
    565       last_modified = iter.values();
    566     if (StringToLowerASCII(iter.name()) == "etag")
    567       etag = iter.values();
    568     if (StringToLowerASCII(iter.name()) == "cache-control") {
    569       net::HttpUtil::ValuesIterator values_iter(
    570           iter.values_begin(), iter.values_end(), ',');
    571       while (values_iter.GetNext()) {
    572         if (StringToLowerASCII(values_iter.value()) == "no-store")
    573           has_no_store_header = true;
    574       }
    575     }
    576   }
    577 
    578   base::Time last_modified_time;
    579   // If FromString fails, it doesn't touch last_modified_time and we just send
    580   // the default-constructed null value.
    581   base::Time::FromString(last_modified.c_str(), &last_modified_time);
    582 
    583   PnaclCacheInfo cache_info;
    584   cache_info.pexe_url = GURL(pexe_url);
    585   cache_info.abi_version = abi_version;
    586   cache_info.opt_level = opt_level;
    587   cache_info.last_modified = last_modified_time;
    588   cache_info.etag = etag;
    589   cache_info.has_no_store_header = has_no_store_header;
    590   cache_info.sandbox_isa = GetSandboxArch();
    591   cache_info.extra_flags = std::string(extra_flags);
    592 
    593   g_pnacl_resource_host.Get()->RequestNexeFd(
    594       GetRoutingID(instance),
    595       instance,
    596       cache_info,
    597       is_hit,
    598       handle,
    599       enter.callback());
    600 
    601   return enter.SetResult(PP_OK_COMPLETIONPENDING);
    602 }
    603 
    604 void ReportTranslationFinished(PP_Instance instance,
    605                                PP_Bool success,
    606                                int32_t opt_level,
    607                                int64_t pexe_size,
    608                                int64_t compile_time_us,
    609                                int64_t total_time_us) {
    610   if (success == PP_TRUE) {
    611     static const int32_t kUnknownOptLevel = 4;
    612     if (opt_level < 0 || opt_level > 3)
    613       opt_level = kUnknownOptLevel;
    614     HistogramEnumerate("NaCl.Options.PNaCl.OptLevel",
    615                        opt_level,
    616                        kUnknownOptLevel + 1);
    617     HistogramKBPerSec("NaCl.Perf.PNaClLoadTime.CompileKBPerSec",
    618                       pexe_size / 1024,
    619                       compile_time_us);
    620     HistogramSizeKB("NaCl.Perf.Size.Pexe", pexe_size / 1024);
    621 
    622     HistogramTimeTranslation("NaCl.Perf.PNaClLoadTime.TotalUncachedTime",
    623                              total_time_us / 1000);
    624     HistogramKBPerSec("NaCl.Perf.PNaClLoadTime.TotalUncachedKBPerSec",
    625                       pexe_size / 1024,
    626                       total_time_us);
    627   }
    628 
    629   // If the resource host isn't initialized, don't try to do that here.
    630   // Just return because something is already very wrong.
    631   if (g_pnacl_resource_host.Get() == NULL)
    632     return;
    633   g_pnacl_resource_host.Get()->ReportTranslationFinished(instance, success);
    634 }
    635 
    636 PP_FileHandle OpenNaClExecutable(PP_Instance instance,
    637                                  const char* file_url,
    638                                  uint64_t* nonce_lo,
    639                                  uint64_t* nonce_hi) {
    640   // Fast path only works for installed file URLs.
    641   GURL gurl(file_url);
    642   if (!gurl.SchemeIs("chrome-extension"))
    643     return PP_kInvalidFileHandle;
    644 
    645   content::PepperPluginInstance* plugin_instance =
    646       content::PepperPluginInstance::Get(instance);
    647   // IMPORTANT: Make sure the document can request the given URL. If we don't
    648   // check, a malicious app could probe the extension system. This enforces a
    649   // same-origin policy which prevents the app from requesting resources from
    650   // another app.
    651   blink::WebSecurityOrigin security_origin =
    652       plugin_instance->GetContainer()->element().document().securityOrigin();
    653   if (!security_origin.canRequest(gurl))
    654     return PP_kInvalidFileHandle;
    655 
    656   IPC::PlatformFileForTransit out_fd = IPC::InvalidPlatformFileForTransit();
    657   IPC::Sender* sender = content::RenderThread::Get();
    658   DCHECK(sender);
    659   *nonce_lo = 0;
    660   *nonce_hi = 0;
    661   base::FilePath file_path;
    662   if (!sender->Send(
    663       new NaClHostMsg_OpenNaClExecutable(GetRoutingID(instance),
    664                                          GURL(file_url),
    665                                          &out_fd,
    666                                          nonce_lo,
    667                                          nonce_hi))) {
    668     return PP_kInvalidFileHandle;
    669   }
    670 
    671   if (out_fd == IPC::InvalidPlatformFileForTransit())
    672     return PP_kInvalidFileHandle;
    673 
    674   return IPC::PlatformFileForTransitToPlatformFile(out_fd);
    675 }
    676 
    677 void DispatchEvent(PP_Instance instance,
    678                    PP_NaClEventType event_type,
    679                    const char *resource_url,
    680                    PP_Bool length_is_computable,
    681                    uint64_t loaded_bytes,
    682                    uint64_t total_bytes) {
    683   ProgressEvent event(event_type,
    684                       resource_url,
    685                       PP_ToBool(length_is_computable),
    686                       loaded_bytes,
    687                       total_bytes);
    688   DispatchProgressEvent(instance, event);
    689 }
    690 
    691 void ReportLoadSuccess(PP_Instance instance,
    692                        const char* url,
    693                        uint64_t loaded_bytes,
    694                        uint64_t total_bytes) {
    695   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
    696   if (load_manager)
    697     load_manager->ReportLoadSuccess(url, loaded_bytes, total_bytes);
    698 }
    699 
    700 void ReportLoadError(PP_Instance instance,
    701                      PP_NaClError error,
    702                      const char* error_message) {
    703   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
    704   if (load_manager)
    705     load_manager->ReportLoadError(error, error_message);
    706 }
    707 
    708 void ReportLoadAbort(PP_Instance instance) {
    709   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
    710   if (load_manager)
    711     load_manager->ReportLoadAbort();
    712 }
    713 
    714 void NexeDidCrash(PP_Instance instance, const char* crash_log) {
    715   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
    716   if (load_manager)
    717     load_manager->NexeDidCrash(crash_log);
    718 }
    719 
    720 void InstanceCreated(PP_Instance instance) {
    721   scoped_ptr<NexeLoadManager> new_load_manager(new NexeLoadManager(instance));
    722   NexeLoadManagerMap& map = g_load_manager_map.Get();
    723   DLOG_IF(ERROR, map.count(instance) != 0) << "Instance count should be 0";
    724   map.add(instance, new_load_manager.Pass());
    725 }
    726 
    727 void InstanceDestroyed(PP_Instance instance) {
    728   DeleteJsonManifest(instance);
    729 
    730   NexeLoadManagerMap& map = g_load_manager_map.Get();
    731   DLOG_IF(ERROR, map.count(instance) == 0) << "Could not find instance ID";
    732   // The erase may call NexeLoadManager's destructor prior to removing it from
    733   // the map. In that case, it is possible for the trusted Plugin to re-enter
    734   // the NexeLoadManager (e.g., by calling ReportLoadError). Passing out the
    735   // NexeLoadManager to a local scoped_ptr just ensures that its entry is gone
    736   // from the map prior to the destructor being invoked.
    737   scoped_ptr<NexeLoadManager> temp(map.take(instance));
    738   map.erase(instance);
    739 }
    740 
    741 PP_Bool NaClDebugEnabledForURL(const char* alleged_nmf_url) {
    742   if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableNaClDebug))
    743     return PP_FALSE;
    744   bool should_debug;
    745   IPC::Sender* sender = content::RenderThread::Get();
    746   DCHECK(sender);
    747   if(!sender->Send(new NaClHostMsg_NaClDebugEnabledForURL(
    748          GURL(alleged_nmf_url),
    749          &should_debug))) {
    750     return PP_FALSE;
    751   }
    752   return PP_FromBool(should_debug);
    753 }
    754 
    755 void LogToConsole(PP_Instance instance, const char* message) {
    756   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
    757   DCHECK(load_manager);
    758   if (load_manager)
    759     load_manager->LogToConsole(std::string(message));
    760 }
    761 
    762 PP_NaClReadyState GetNaClReadyState(PP_Instance instance) {
    763   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
    764   DCHECK(load_manager);
    765   if (load_manager)
    766     return load_manager->nacl_ready_state();
    767   return PP_NACL_READY_STATE_UNSENT;
    768 }
    769 
    770 int32_t GetExitStatus(PP_Instance instance) {
    771   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
    772   DCHECK(load_manager);
    773   if (load_manager)
    774     return load_manager->exit_status();
    775   return -1;
    776 }
    777 
    778 void SetExitStatus(PP_Instance instance, int32_t exit_status) {
    779   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
    780   DCHECK(load_manager);
    781   if (load_manager)
    782     return load_manager->set_exit_status(exit_status);
    783 }
    784 
    785 void Vlog(const char* message) {
    786   VLOG(1) << message;
    787 }
    788 
    789 void InitializePlugin(PP_Instance instance,
    790                       uint32_t argc,
    791                       const char* argn[],
    792                       const char* argv[]) {
    793   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
    794   DCHECK(load_manager);
    795   if (load_manager)
    796     load_manager->InitializePlugin(argc, argn, argv);
    797 }
    798 
    799 int64_t GetNexeSize(PP_Instance instance) {
    800   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
    801   DCHECK(load_manager);
    802   if (load_manager)
    803     return load_manager->nexe_size();
    804   return 0;
    805 }
    806 
    807 void DownloadManifestToBuffer(PP_Instance instance,
    808                               struct PP_CompletionCallback callback);
    809 
    810 bool CreateJsonManifest(PP_Instance instance,
    811                         const std::string& manifest_url,
    812                         const std::string& manifest_data);
    813 
    814 void RequestNaClManifest(PP_Instance instance,
    815                          PP_CompletionCallback callback) {
    816   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
    817   DCHECK(load_manager);
    818   if (!load_manager) {
    819     ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(
    820         FROM_HERE,
    821         base::Bind(callback.func, callback.user_data,
    822                    static_cast<int32_t>(PP_ERROR_FAILED)));
    823     return;
    824   }
    825 
    826   std::string url = load_manager->GetManifestURLArgument();
    827   if (url.empty() || !load_manager->RequestNaClManifest(url)) {
    828     ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(
    829         FROM_HERE,
    830         base::Bind(callback.func, callback.user_data,
    831                    static_cast<int32_t>(PP_ERROR_FAILED)));
    832     return;
    833   }
    834 
    835   const GURL& base_url = load_manager->manifest_base_url();
    836   if (base_url.SchemeIs("data")) {
    837     GURL gurl(base_url);
    838     std::string mime_type;
    839     std::string charset;
    840     std::string data;
    841     int32_t error = PP_ERROR_FAILED;
    842     if (net::DataURL::Parse(gurl, &mime_type, &charset, &data)) {
    843       if (data.size() <= ManifestDownloader::kNaClManifestMaxFileBytes) {
    844         if (CreateJsonManifest(instance, base_url.spec(), data))
    845           error = PP_OK;
    846       } else {
    847         load_manager->ReportLoadError(PP_NACL_ERROR_MANIFEST_TOO_LARGE,
    848                                       "manifest file too large.");
    849       }
    850     } else {
    851       load_manager->ReportLoadError(PP_NACL_ERROR_MANIFEST_LOAD_URL,
    852                                     "could not load manifest url.");
    853     }
    854     ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(
    855         FROM_HERE,
    856         base::Bind(callback.func, callback.user_data, error));
    857   } else {
    858     DownloadManifestToBuffer(instance, callback);
    859   }
    860 }
    861 
    862 PP_Var GetManifestBaseURL(PP_Instance instance) {
    863   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
    864   DCHECK(load_manager);
    865   if (!load_manager)
    866     return PP_MakeUndefined();
    867   const GURL& gurl = load_manager->manifest_base_url();
    868   if (!gurl.is_valid())
    869     return PP_MakeUndefined();
    870   return ppapi::StringVar::StringToPPVar(gurl.spec());
    871 }
    872 
    873 void ProcessNaClManifest(PP_Instance instance, const char* program_url) {
    874   nacl::NexeLoadManager* load_manager = GetNexeLoadManager(instance);
    875   if (load_manager)
    876     load_manager->ProcessNaClManifest(program_url);
    877 }
    878 
    879 PP_Bool DevInterfacesEnabled(PP_Instance instance) {
    880   nacl::NexeLoadManager* load_manager = GetNexeLoadManager(instance);
    881   if (load_manager)
    882     return PP_FromBool(load_manager->DevInterfacesEnabled());
    883   return PP_FALSE;
    884 }
    885 
    886 void DownloadManifestToBufferCompletion(PP_Instance instance,
    887                                         struct PP_CompletionCallback callback,
    888                                         base::Time start_time,
    889                                         PP_NaClError pp_nacl_error,
    890                                         const std::string& data);
    891 
    892 void DownloadManifestToBuffer(PP_Instance instance,
    893                               struct PP_CompletionCallback callback) {
    894   nacl::NexeLoadManager* load_manager = GetNexeLoadManager(instance);
    895   DCHECK(load_manager);
    896   content::PepperPluginInstance* plugin_instance =
    897       content::PepperPluginInstance::Get(instance);
    898   if (!load_manager || !plugin_instance) {
    899     ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(
    900         FROM_HERE,
    901         base::Bind(callback.func, callback.user_data,
    902                    static_cast<int32_t>(PP_ERROR_FAILED)));
    903   }
    904   const blink::WebDocument& document =
    905       plugin_instance->GetContainer()->element().document();
    906 
    907   const GURL& gurl = load_manager->manifest_base_url();
    908   scoped_ptr<blink::WebURLLoader> url_loader(
    909       CreateWebURLLoader(document, gurl));
    910   blink::WebURLRequest request = CreateWebURLRequest(document, gurl);
    911 
    912   // ManifestDownloader deletes itself after invoking the callback.
    913   ManifestDownloader* manifest_downloader = new ManifestDownloader(
    914       url_loader.Pass(),
    915       load_manager->is_installed(),
    916       base::Bind(DownloadManifestToBufferCompletion,
    917                  instance, callback, base::Time::Now()));
    918   manifest_downloader->Load(request);
    919 }
    920 
    921 void DownloadManifestToBufferCompletion(PP_Instance instance,
    922                                         struct PP_CompletionCallback callback,
    923                                         base::Time start_time,
    924                                         PP_NaClError pp_nacl_error,
    925                                         const std::string& data) {
    926   base::TimeDelta download_time = base::Time::Now() - start_time;
    927   HistogramTimeSmall("NaCl.Perf.StartupTime.ManifestDownload",
    928                      download_time.InMilliseconds());
    929 
    930   nacl::NexeLoadManager* load_manager = GetNexeLoadManager(instance);
    931   if (!load_manager) {
    932     callback.func(callback.user_data, PP_ERROR_ABORTED);
    933     return;
    934   }
    935 
    936   int32_t pp_error;
    937   switch (pp_nacl_error) {
    938     case PP_NACL_ERROR_LOAD_SUCCESS:
    939       pp_error = PP_OK;
    940       break;
    941     case PP_NACL_ERROR_MANIFEST_LOAD_URL:
    942       pp_error = PP_ERROR_FAILED;
    943       load_manager->ReportLoadError(PP_NACL_ERROR_MANIFEST_LOAD_URL,
    944                                     "could not load manifest url.");
    945       break;
    946     case PP_NACL_ERROR_MANIFEST_TOO_LARGE:
    947       pp_error = PP_ERROR_FILETOOBIG;
    948       load_manager->ReportLoadError(PP_NACL_ERROR_MANIFEST_TOO_LARGE,
    949                                     "manifest file too large.");
    950       break;
    951     case PP_NACL_ERROR_MANIFEST_NOACCESS_URL:
    952       pp_error = PP_ERROR_NOACCESS;
    953       load_manager->ReportLoadError(PP_NACL_ERROR_MANIFEST_NOACCESS_URL,
    954                                     "access to manifest url was denied.");
    955       break;
    956     default:
    957       NOTREACHED();
    958       pp_error = PP_ERROR_FAILED;
    959       load_manager->ReportLoadError(PP_NACL_ERROR_MANIFEST_LOAD_URL,
    960                                     "could not load manifest url.");
    961   }
    962 
    963   if (pp_error == PP_OK) {
    964     std::string base_url = load_manager->manifest_base_url().spec();
    965     if (!CreateJsonManifest(instance, base_url, data))
    966       pp_error = PP_ERROR_FAILED;
    967   }
    968   callback.func(callback.user_data, pp_error);
    969 }
    970 
    971 bool CreateJsonManifest(PP_Instance instance,
    972                         const std::string& manifest_url,
    973                         const std::string& manifest_data) {
    974   HistogramSizeKB("NaCl.Perf.Size.Manifest",
    975                   static_cast<int32_t>(manifest_data.length() / 1024));
    976 
    977   nacl::NexeLoadManager* load_manager = GetNexeLoadManager(instance);
    978   if (!load_manager)
    979     return false;
    980 
    981   const char* isa_type;
    982   if (load_manager->IsPNaCl())
    983     isa_type = kPortableArch;
    984   else
    985     isa_type = GetSandboxArch();
    986 
    987   scoped_ptr<nacl::JsonManifest> j(
    988       new nacl::JsonManifest(
    989           manifest_url.c_str(),
    990           isa_type,
    991           IsNonSFIModeEnabled(),
    992           PP_ToBool(NaClDebugEnabledForURL(manifest_url.c_str()))));
    993   JsonManifest::ErrorInfo error_info;
    994   if (j->Init(manifest_data.c_str(), &error_info)) {
    995     AddJsonManifest(instance, j.Pass());
    996     return true;
    997   }
    998   load_manager->ReportLoadError(error_info.error, error_info.string);
    999   return false;
   1000 }
   1001 
   1002 PP_Bool ManifestGetProgramURL(PP_Instance instance,
   1003                               PP_Var* pp_full_url,
   1004                               PP_PNaClOptions* pnacl_options,
   1005                               PP_Bool* pp_uses_nonsfi_mode) {
   1006   nacl::NexeLoadManager* load_manager = GetNexeLoadManager(instance);
   1007 
   1008   JsonManifest* manifest = GetJsonManifest(instance);
   1009   if (manifest == NULL)
   1010     return PP_FALSE;
   1011 
   1012   bool uses_nonsfi_mode;
   1013   std::string full_url;
   1014   JsonManifest::ErrorInfo error_info;
   1015   if (manifest->GetProgramURL(&full_url, pnacl_options, &uses_nonsfi_mode,
   1016                               &error_info)) {
   1017     *pp_full_url = ppapi::StringVar::StringToPPVar(full_url);
   1018     *pp_uses_nonsfi_mode = PP_FromBool(uses_nonsfi_mode);
   1019     return PP_TRUE;
   1020   }
   1021 
   1022   if (load_manager)
   1023     load_manager->ReportLoadError(error_info.error, error_info.string);
   1024   return PP_FALSE;
   1025 }
   1026 
   1027 bool ManifestResolveKey(PP_Instance instance,
   1028                         bool is_helper_process,
   1029                         const std::string& key,
   1030                         std::string* full_url,
   1031                         PP_PNaClOptions* pnacl_options) {
   1032   // For "helper" processes (llc and ld), we resolve keys manually as there is
   1033   // no existing .nmf file to parse.
   1034   if (is_helper_process) {
   1035     pnacl_options->translate = PP_FALSE;
   1036     // We can only resolve keys in the files/ namespace.
   1037     const std::string kFilesPrefix = "files/";
   1038     if (key.find(kFilesPrefix) == std::string::npos) {
   1039       nacl::NexeLoadManager* load_manager = GetNexeLoadManager(instance);
   1040       if (load_manager)
   1041         load_manager->ReportLoadError(PP_NACL_ERROR_MANIFEST_RESOLVE_URL,
   1042                                       "key did not start with files/");
   1043       return false;
   1044     }
   1045     std::string key_basename = key.substr(kFilesPrefix.length());
   1046     *full_url = std::string(kPNaClTranslatorBaseUrl) + GetSandboxArch() + "/" +
   1047                 key_basename;
   1048     return true;
   1049   }
   1050 
   1051   JsonManifest* manifest = GetJsonManifest(instance);
   1052   if (manifest == NULL)
   1053     return false;
   1054 
   1055   return manifest->ResolveKey(key, full_url, pnacl_options);
   1056 }
   1057 
   1058 PP_Bool ExternalManifestResolveKey(PP_Instance instance,
   1059                                    PP_Bool is_helper_process,
   1060                                    const char* key,
   1061                                    PP_Var* pp_full_url,
   1062                                    PP_PNaClOptions* pnacl_options) {
   1063   std::string full_url;
   1064   bool ok = ManifestResolveKey(instance,
   1065                                PP_ToBool(is_helper_process),
   1066                                std::string(key),
   1067                                &full_url,
   1068                                pnacl_options);
   1069   if (ok)
   1070     *pp_full_url = ppapi::StringVar::StringToPPVar(full_url);
   1071   return PP_FromBool(ok);
   1072 }
   1073 
   1074 PP_Bool GetPNaClResourceInfo(PP_Instance instance,
   1075                              const char* filename,
   1076                              PP_Var* llc_tool_name,
   1077                              PP_Var* ld_tool_name) {
   1078   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
   1079   DCHECK(load_manager);
   1080   if (!load_manager)
   1081     return PP_FALSE;
   1082 
   1083   base::File file(GetReadonlyPnaclFd(filename));
   1084   if (!file.IsValid()) {
   1085     load_manager->ReportLoadError(
   1086         PP_NACL_ERROR_PNACL_RESOURCE_FETCH,
   1087         "The Portable Native Client (pnacl) component is not "
   1088         "installed. Please consult chrome://components for more "
   1089         "information.");
   1090     return PP_FALSE;
   1091   }
   1092 
   1093   base::File::Info file_info;
   1094   if (!file.GetInfo(&file_info)) {
   1095     load_manager->ReportLoadError(
   1096         PP_NACL_ERROR_PNACL_RESOURCE_FETCH,
   1097         std::string("GetPNaClResourceInfo, GetFileInfo failed for: ") +
   1098             filename);
   1099     return PP_FALSE;
   1100   }
   1101 
   1102   if (file_info.size > 1 << 20) {
   1103     load_manager->ReportLoadError(
   1104         PP_NACL_ERROR_PNACL_RESOURCE_FETCH,
   1105         std::string("GetPNaClResourceInfo, file too large: ") + filename);
   1106     return PP_FALSE;
   1107   }
   1108 
   1109   scoped_ptr<char[]> buffer(new char[file_info.size + 1]);
   1110   if (buffer.get() == NULL) {
   1111     load_manager->ReportLoadError(
   1112         PP_NACL_ERROR_PNACL_RESOURCE_FETCH,
   1113         std::string("GetPNaClResourceInfo, couldn't allocate for: ") +
   1114             filename);
   1115     return PP_FALSE;
   1116   }
   1117 
   1118   int rc = file.Read(0, buffer.get(), file_info.size);
   1119   if (rc < 0) {
   1120     load_manager->ReportLoadError(
   1121         PP_NACL_ERROR_PNACL_RESOURCE_FETCH,
   1122         std::string("GetPNaClResourceInfo, reading failed for: ") + filename);
   1123     return PP_FALSE;
   1124   }
   1125 
   1126   // Null-terminate the bytes we we read from the file.
   1127   buffer.get()[rc] = 0;
   1128 
   1129   // Expect the JSON file to contain a top-level object (dictionary).
   1130   Json::Reader json_reader;
   1131   Json::Value json_data;
   1132   if (!json_reader.parse(buffer.get(), json_data)) {
   1133     load_manager->ReportLoadError(
   1134         PP_NACL_ERROR_PNACL_RESOURCE_FETCH,
   1135         std::string("Parsing resource info failed: JSON parse error: ") +
   1136             json_reader.getFormattedErrorMessages());
   1137     return PP_FALSE;
   1138   }
   1139 
   1140   if (!json_data.isObject()) {
   1141     load_manager->ReportLoadError(
   1142         PP_NACL_ERROR_PNACL_RESOURCE_FETCH,
   1143         "Parsing resource info failed: Malformed JSON dictionary");
   1144     return PP_FALSE;
   1145   }
   1146 
   1147   if (json_data.isMember("pnacl-llc-name")) {
   1148     Json::Value json_name = json_data["pnacl-llc-name"];
   1149     if (json_name.isString()) {
   1150       std::string llc_tool_name_str = json_name.asString();
   1151       *llc_tool_name = ppapi::StringVar::StringToPPVar(llc_tool_name_str);
   1152     }
   1153   }
   1154 
   1155   if (json_data.isMember("pnacl-ld-name")) {
   1156     Json::Value json_name = json_data["pnacl-ld-name"];
   1157     if (json_name.isString()) {
   1158       std::string ld_tool_name_str = json_name.asString();
   1159       *ld_tool_name = ppapi::StringVar::StringToPPVar(ld_tool_name_str);
   1160     }
   1161   }
   1162   return PP_TRUE;
   1163 }
   1164 
   1165 // Helper to std::accumulate that creates a comma-separated list from the input.
   1166 std::string CommaAccumulator(const std::string &lhs, const std::string &rhs) {
   1167   if (lhs.empty())
   1168     return rhs;
   1169   return lhs + "," + rhs;
   1170 }
   1171 
   1172 PP_Var GetCpuFeatureAttrs() {
   1173   // PNaCl's translator from pexe to nexe can be told exactly what
   1174   // capabilities the user's machine has because the pexe to nexe
   1175   // translation is specific to the machine, and CPU information goes
   1176   // into the translation cache. This allows the translator to generate
   1177   // faster code.
   1178   //
   1179   // Care must be taken to avoid instructions which aren't supported by
   1180   // the NaCl sandbox. Ideally the translator would do this, but there's
   1181   // no point in not doing the whitelist here.
   1182   //
   1183   // TODO(jfb) Some features are missing, either because the NaCl
   1184   //           sandbox doesn't support them, because base::CPU doesn't
   1185   //           detect them, or because they don't help vector shuffles
   1186   //           (and we omit them because it simplifies testing). Add the
   1187   //           other features.
   1188   //
   1189   // TODO(jfb) The following is x86-specific. The base::CPU class
   1190   //           doesn't handle other architectures very well, and we
   1191   //           should at least detect the presence of ARM's integer
   1192   //           divide.
   1193   std::vector<std::string> attrs;
   1194   base::CPU cpu;
   1195 
   1196   // On x86, SSE features are ordered: the most recent one implies the
   1197   // others. Care is taken here to only specify the latest SSE version,
   1198   // whereas non-SSE features don't follow this model: POPCNT is
   1199   // effectively always implied by SSE4.2 but has to be specified
   1200   // separately.
   1201   //
   1202   // TODO: AVX2, AVX, SSE 4.2.
   1203   if (cpu.has_sse41()) attrs.push_back("+sse4.1");
   1204   // TODO: SSE 4A, SSE 4.
   1205   else if (cpu.has_ssse3()) attrs.push_back("+ssse3");
   1206   // TODO: SSE 3
   1207   else if (cpu.has_sse2()) attrs.push_back("+sse2");
   1208 
   1209   // TODO: AES, POPCNT, LZCNT, ...
   1210 
   1211   return ppapi::StringVar::StringToPPVar(std::accumulate(
   1212       attrs.begin(), attrs.end(), std::string(), CommaAccumulator));
   1213 }
   1214 
   1215 void PostMessageToJavaScriptMainThread(PP_Instance instance,
   1216                                        const std::string& message) {
   1217   content::PepperPluginInstance* plugin_instance =
   1218       content::PepperPluginInstance::Get(instance);
   1219   if (plugin_instance) {
   1220     PP_Var message_var = ppapi::StringVar::StringToPPVar(message);
   1221     plugin_instance->PostMessageToJavaScript(message_var);
   1222     ppapi::PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(message_var);
   1223   }
   1224 }
   1225 
   1226 void PostMessageToJavaScript(PP_Instance instance, const char* message) {
   1227   ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(
   1228       FROM_HERE,
   1229       base::Bind(&PostMessageToJavaScriptMainThread,
   1230                  instance,
   1231                  std::string(message)));
   1232 }
   1233 
   1234 // Encapsulates some of the state for a call to DownloadNexe to prevent
   1235 // argument lists from getting too long.
   1236 struct DownloadNexeRequest {
   1237   PP_Instance instance;
   1238   std::string url;
   1239   PP_CompletionCallback callback;
   1240   base::Time start_time;
   1241 };
   1242 
   1243 // A utility class to ensure that we don't send progress events more often than
   1244 // every 10ms for a given file.
   1245 class ProgressEventRateLimiter {
   1246  public:
   1247   explicit ProgressEventRateLimiter(PP_Instance instance)
   1248       : instance_(instance) { }
   1249 
   1250   void ReportProgress(const std::string& url,
   1251                       int64_t total_bytes_received,
   1252                       int64_t total_bytes_to_be_received) {
   1253     base::Time now = base::Time::Now();
   1254     if (now - last_event_ > base::TimeDelta::FromMilliseconds(10)) {
   1255       DispatchProgressEvent(instance_,
   1256                             ProgressEvent(PP_NACL_EVENT_PROGRESS,
   1257                                           url,
   1258                                           total_bytes_to_be_received >= 0,
   1259                                           total_bytes_received,
   1260                                           total_bytes_to_be_received));
   1261       last_event_ = now;
   1262     }
   1263   }
   1264 
   1265  private:
   1266   PP_Instance instance_;
   1267   base::Time last_event_;
   1268 };
   1269 
   1270 void DownloadNexeCompletion(const DownloadNexeRequest& request,
   1271                             PP_NaClFileInfo* out_file_info,
   1272                             FileDownloader::Status status,
   1273                             base::File target_file,
   1274                             int http_status);
   1275 
   1276 void DownloadNexe(PP_Instance instance,
   1277                   const char* url,
   1278                   PP_NaClFileInfo* out_file_info,
   1279                   PP_CompletionCallback callback) {
   1280   CHECK(url);
   1281   CHECK(out_file_info);
   1282   DownloadNexeRequest request;
   1283   request.instance = instance;
   1284   request.url = url;
   1285   request.callback = callback;
   1286   request.start_time = base::Time::Now();
   1287 
   1288   // Try the fast path for retrieving the file first.
   1289   PP_FileHandle handle = OpenNaClExecutable(instance,
   1290                                             url,
   1291                                             &out_file_info->token_lo,
   1292                                             &out_file_info->token_hi);
   1293   if (handle != PP_kInvalidFileHandle) {
   1294     DownloadNexeCompletion(request,
   1295                            out_file_info,
   1296                            FileDownloader::SUCCESS,
   1297                            base::File(handle),
   1298                            200);
   1299     return;
   1300   }
   1301 
   1302   // The fast path didn't work, we'll fetch the file using URLLoader and write
   1303   // it to local storage.
   1304   base::File target_file(CreateTemporaryFile(instance));
   1305   GURL gurl(url);
   1306 
   1307   content::PepperPluginInstance* plugin_instance =
   1308       content::PepperPluginInstance::Get(instance);
   1309   if (!plugin_instance) {
   1310     ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(
   1311         FROM_HERE,
   1312         base::Bind(callback.func, callback.user_data,
   1313                    static_cast<int32_t>(PP_ERROR_FAILED)));
   1314   }
   1315   const blink::WebDocument& document =
   1316       plugin_instance->GetContainer()->element().document();
   1317   scoped_ptr<blink::WebURLLoader> url_loader(
   1318       CreateWebURLLoader(document, gurl));
   1319   blink::WebURLRequest url_request = CreateWebURLRequest(document, gurl);
   1320 
   1321   ProgressEventRateLimiter* tracker = new ProgressEventRateLimiter(instance);
   1322 
   1323   // FileDownloader deletes itself after invoking DownloadNexeCompletion.
   1324   FileDownloader* file_downloader = new FileDownloader(
   1325       url_loader.Pass(),
   1326       target_file.Pass(),
   1327       base::Bind(&DownloadNexeCompletion, request, out_file_info),
   1328       base::Bind(&ProgressEventRateLimiter::ReportProgress,
   1329                  base::Owned(tracker), url));
   1330   file_downloader->Load(url_request);
   1331 }
   1332 
   1333 void DownloadNexeCompletion(const DownloadNexeRequest& request,
   1334                             PP_NaClFileInfo* out_file_info,
   1335                             FileDownloader::Status status,
   1336                             base::File target_file,
   1337                             int http_status) {
   1338   int32_t pp_error = FileDownloaderToPepperError(status);
   1339   int64_t bytes_read = -1;
   1340   if (pp_error == PP_OK && target_file.IsValid()) {
   1341     base::File::Info info;
   1342     if (target_file.GetInfo(&info))
   1343       bytes_read = info.size;
   1344   }
   1345 
   1346   if (bytes_read == -1) {
   1347     target_file.Close();
   1348     pp_error = PP_ERROR_FAILED;
   1349   }
   1350 
   1351   base::TimeDelta download_time = base::Time::Now() - request.start_time;
   1352 
   1353   NexeLoadManager* load_manager = GetNexeLoadManager(request.instance);
   1354   if (load_manager) {
   1355     load_manager->NexeFileDidOpen(pp_error,
   1356                                   target_file,
   1357                                   http_status,
   1358                                   bytes_read,
   1359                                   request.url,
   1360                                   download_time);
   1361   }
   1362 
   1363   if (pp_error == PP_OK && target_file.IsValid())
   1364     out_file_info->handle = target_file.TakePlatformFile();
   1365   else
   1366     out_file_info->handle = PP_kInvalidFileHandle;
   1367 
   1368   request.callback.func(request.callback.user_data, pp_error);
   1369 }
   1370 
   1371 void DownloadFileCompletion(PP_NaClFileInfo* file_info,
   1372                             PP_CompletionCallback callback,
   1373                             FileDownloader::Status status,
   1374                             base::File file,
   1375                             int http_status) {
   1376   int32_t pp_error = FileDownloaderToPepperError(status);
   1377   if (pp_error == PP_OK) {
   1378     file_info->handle = file.TakePlatformFile();
   1379     file_info->token_lo = 0;
   1380     file_info->token_hi = 0;
   1381   }
   1382   callback.func(callback.user_data, pp_error);
   1383 }
   1384 
   1385 void DownloadFile(PP_Instance instance,
   1386                   const char* url,
   1387                   struct PP_NaClFileInfo* file_info,
   1388                   struct PP_CompletionCallback callback) {
   1389   CHECK(url);
   1390   CHECK(file_info);
   1391 
   1392   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
   1393   DCHECK(load_manager);
   1394   if (!load_manager) {
   1395     ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(
   1396         FROM_HERE,
   1397         base::Bind(callback.func, callback.user_data,
   1398                    static_cast<int32_t>(PP_ERROR_FAILED)));
   1399     return;
   1400   }
   1401 
   1402   // Handle special PNaCl support files which are installed on the user's
   1403   // machine.
   1404   std::string url_string(url);
   1405   if (url_string.find(kPNaClTranslatorBaseUrl, 0) == 0) {
   1406     PP_FileHandle handle = GetReadonlyPnaclFd(url);
   1407     if (handle == PP_kInvalidFileHandle) {
   1408       ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(
   1409           FROM_HERE,
   1410           base::Bind(callback.func, callback.user_data,
   1411                      static_cast<int32_t>(PP_ERROR_FAILED)));
   1412       return;
   1413     }
   1414     // TODO(ncbray): enable the fast loading and validation paths for this type
   1415     // of file.
   1416     file_info->handle = handle;
   1417     file_info->token_lo = 0;
   1418     file_info->token_hi = 0;
   1419     ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(
   1420         FROM_HERE,
   1421         base::Bind(callback.func, callback.user_data,
   1422                    static_cast<int32_t>(PP_OK)));
   1423     return;
   1424   }
   1425 
   1426   // We have to ensure that this url resolves relative to the plugin base url
   1427   // before downloading it.
   1428   const GURL& test_gurl = load_manager->plugin_base_url().Resolve(url);
   1429   if (!test_gurl.is_valid()) {
   1430     ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(
   1431         FROM_HERE,
   1432         base::Bind(callback.func, callback.user_data,
   1433                    static_cast<int32_t>(PP_ERROR_FAILED)));
   1434     return;
   1435   }
   1436 
   1437   // Try the fast path for retrieving the file first.
   1438   uint64_t file_token_lo = 0;
   1439   uint64_t file_token_hi = 0;
   1440   PP_FileHandle file_handle = OpenNaClExecutable(instance,
   1441                                                  url,
   1442                                                  &file_token_lo,
   1443                                                  &file_token_hi);
   1444   if (file_handle != PP_kInvalidFileHandle) {
   1445     file_info->handle = file_handle;
   1446     file_info->token_lo = file_token_lo;
   1447     file_info->token_hi = file_token_hi;
   1448     ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(
   1449         FROM_HERE,
   1450         base::Bind(callback.func, callback.user_data,
   1451                    static_cast<int32_t>(PP_OK)));
   1452     return;
   1453   }
   1454 
   1455   // The fast path didn't work, we'll fetch the file using URLLoader and write
   1456   // it to local storage.
   1457   base::File target_file(CreateTemporaryFile(instance));
   1458   GURL gurl(url);
   1459 
   1460   content::PepperPluginInstance* plugin_instance =
   1461       content::PepperPluginInstance::Get(instance);
   1462   if (!plugin_instance) {
   1463     ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(
   1464         FROM_HERE,
   1465         base::Bind(callback.func, callback.user_data,
   1466                    static_cast<int32_t>(PP_ERROR_FAILED)));
   1467   }
   1468   const blink::WebDocument& document =
   1469       plugin_instance->GetContainer()->element().document();
   1470   scoped_ptr<blink::WebURLLoader> url_loader(
   1471       CreateWebURLLoader(document, gurl));
   1472   blink::WebURLRequest url_request = CreateWebURLRequest(document, gurl);
   1473 
   1474   ProgressEventRateLimiter* tracker = new ProgressEventRateLimiter(instance);
   1475 
   1476   // FileDownloader deletes itself after invoking DownloadNexeCompletion.
   1477   FileDownloader* file_downloader = new FileDownloader(
   1478       url_loader.Pass(),
   1479       target_file.Pass(),
   1480       base::Bind(&DownloadFileCompletion, file_info, callback),
   1481       base::Bind(&ProgressEventRateLimiter::ReportProgress,
   1482                  base::Owned(tracker), url));
   1483   file_downloader->Load(url_request);
   1484 }
   1485 
   1486 void ReportSelLdrStatus(PP_Instance instance,
   1487                         int32_t load_status,
   1488                         int32_t max_status) {
   1489   HistogramEnumerate("NaCl.LoadStatus.SelLdr", load_status, max_status);
   1490   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
   1491   DCHECK(load_manager);
   1492   if (!load_manager)
   1493     return;
   1494 
   1495   // Gather data to see if being installed changes load outcomes.
   1496   const char* name = load_manager->is_installed() ?
   1497       "NaCl.LoadStatus.SelLdr.InstalledApp" :
   1498       "NaCl.LoadStatus.SelLdr.NotInstalledApp";
   1499   HistogramEnumerate(name, load_status, max_status);
   1500 }
   1501 
   1502 void LogTranslateTime(const char* histogram_name,
   1503                       int64_t time_in_us) {
   1504   ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(
   1505       FROM_HERE,
   1506       base::Bind(&HistogramTimeTranslation,
   1507                  std::string(histogram_name),
   1508                  time_in_us / 1000));
   1509 }
   1510 
   1511 const PPB_NaCl_Private nacl_interface = {
   1512   &LaunchSelLdr,
   1513   &StartPpapiProxy,
   1514   &UrandomFD,
   1515   &Are3DInterfacesDisabled,
   1516   &BrokerDuplicateHandle,
   1517   &GetReadonlyPnaclFd,
   1518   &CreateTemporaryFile,
   1519   &GetNumberOfProcessors,
   1520   &PPIsNonSFIModeEnabled,
   1521   &GetNexeFd,
   1522   &ReportTranslationFinished,
   1523   &DispatchEvent,
   1524   &ReportLoadSuccess,
   1525   &ReportLoadError,
   1526   &ReportLoadAbort,
   1527   &NexeDidCrash,
   1528   &InstanceCreated,
   1529   &InstanceDestroyed,
   1530   &NaClDebugEnabledForURL,
   1531   &GetSandboxArch,
   1532   &LogToConsole,
   1533   &GetNaClReadyState,
   1534   &GetExitStatus,
   1535   &SetExitStatus,
   1536   &Vlog,
   1537   &InitializePlugin,
   1538   &GetNexeSize,
   1539   &RequestNaClManifest,
   1540   &GetManifestBaseURL,
   1541   &ProcessNaClManifest,
   1542   &DevInterfacesEnabled,
   1543   &ManifestGetProgramURL,
   1544   &ExternalManifestResolveKey,
   1545   &GetPNaClResourceInfo,
   1546   &GetCpuFeatureAttrs,
   1547   &PostMessageToJavaScript,
   1548   &DownloadNexe,
   1549   &DownloadFile,
   1550   &ReportSelLdrStatus,
   1551   &LogTranslateTime
   1552 };
   1553 
   1554 }  // namespace
   1555 
   1556 const PPB_NaCl_Private* GetNaClPrivateInterface() {
   1557   return &nacl_interface;
   1558 }
   1559 
   1560 }  // namespace nacl
   1561