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.
5 #include "ppapi/native_client/src/trusted/plugin/pnacl_resources.h"
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 "ppapi/c/pp_errors.h"
11 #include "ppapi/native_client/src/trusted/plugin/file_utils.h"
12 #include "ppapi/native_client/src/trusted/plugin/manifest.h"
13 #include "ppapi/native_client/src/trusted/plugin/plugin.h"
14 #include "ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h"
15 #include "ppapi/native_client/src/trusted/plugin/utility.h"
16 #include "third_party/jsoncpp/source/include/json/reader.h"
17 #include "third_party/jsoncpp/source/include/json/value.h"
21 static const char kPnaclComponentScheme
[] = "pnacl-component://";
22 const char PnaclUrls::kResourceInfoUrl
[] = "pnacl.json";
24 nacl::string
PnaclUrls::GetBaseUrl() {
25 return nacl::string(kPnaclComponentScheme
);
28 nacl::string
PnaclUrls::PrependPlatformPrefix(const nacl::string
& url
) {
29 return nacl::string(GetSandboxISA()) + "/" + url
;
32 // Determine if a URL is for a pnacl-component file, or if it is some other
33 // type of URL (e.g., http://, https://, chrome-extension://).
34 // The URL could be one of the other variants for shared libraries
35 // served from the web.
36 bool PnaclUrls::IsPnaclComponent(const nacl::string
& full_url
) {
37 return full_url
.find(kPnaclComponentScheme
, 0) == 0;
40 // Convert a URL to a filename accepted by GetReadonlyPnaclFd.
41 // Must be kept in sync with chrome/browser/nacl_host/nacl_file_host.
42 nacl::string
PnaclUrls::PnaclComponentURLToFilename(
43 const nacl::string
& full_url
) {
44 // strip component scheme.
45 nacl::string r
= full_url
.substr(
46 nacl::string(kPnaclComponentScheme
).length());
48 // Use white-listed-chars.
50 static const char* white_list
= "abcdefghijklmnopqrstuvwxyz0123456789_";
51 replace_pos
= r
.find_first_not_of(white_list
);
52 while(replace_pos
!= nacl::string::npos
) {
53 r
= r
.replace(replace_pos
, 1, "_");
54 replace_pos
= r
.find_first_not_of(white_list
);
59 //////////////////////////////////////////////////////////////////////
61 PnaclResources::~PnaclResources() {
62 for (std::map
<nacl::string
, nacl::DescWrapper
*>::iterator
63 i
= resource_wrappers_
.begin(), e
= resource_wrappers_
.end();
68 resource_wrappers_
.clear();
72 int32_t PnaclResources::GetPnaclFD(Plugin
* plugin
, const char* filename
) {
73 PP_FileHandle file_handle
=
74 plugin
->nacl_interface()->GetReadonlyPnaclFd(filename
);
75 if (file_handle
== PP_kInvalidFileHandle
)
79 //////// Now try the posix view.
80 int32_t posix_desc
= _open_osfhandle(reinterpret_cast<intptr_t>(file_handle
),
81 _O_RDONLY
| _O_BINARY
);
82 if (posix_desc
== -1) {
84 "PnaclResources::GetPnaclFD failed to convert HANDLE to posix\n"));
85 // Close the Windows HANDLE if it can't be converted.
86 CloseHandle(file_handle
);
94 nacl::DescWrapper
* PnaclResources::WrapperForUrl(const nacl::string
& url
) {
95 CHECK(resource_wrappers_
.find(url
) != resource_wrappers_
.end());
96 return resource_wrappers_
[url
];
99 void PnaclResources::ReadResourceInfo(
100 const nacl::string
& resource_info_url
,
101 const pp::CompletionCallback
& resource_info_read_cb
) {
102 PLUGIN_PRINTF(("PnaclResources::ReadResourceInfo\n"));
104 nacl::string full_url
;
105 ErrorInfo error_info
;
106 if (!manifest_
->ResolveURL(resource_info_url
, &full_url
, &error_info
)) {
107 ReadResourceInfoError(nacl::string("failed to resolve ") +
108 resource_info_url
+ ": " +
109 error_info
.message() + ".");
112 PLUGIN_PRINTF(("Resolved resources info url: %s\n", full_url
.c_str()));
113 nacl::string resource_info_filename
=
114 PnaclUrls::PnaclComponentURLToFilename(full_url
);
116 PLUGIN_PRINTF(("Pnacl-converted resources info url: %s\n",
117 resource_info_filename
.c_str()));
119 int32_t fd
= GetPnaclFD(plugin_
, resource_info_filename
.c_str());
121 // File-open failed. Assume this means that the file is
122 // not actually installed.
123 ReadResourceInfoError(
124 nacl::string("The Portable Native Client (pnacl) component is not "
125 "installed. Please consult chrome://components for more "
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
);
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");
148 // Done. Queue the completion callback.
149 pp::Core
* core
= pp::Module::Get()->core();
150 core
->CallOnMainThread(0, resource_info_read_cb
, PP_OK
);
153 void PnaclResources::ReadResourceInfoError(const nacl::string
& msg
) {
154 coordinator_
->ReportNonPpapiError(ERROR_PNACL_RESOURCE_FETCH
, msg
);
157 bool 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();
168 if (!json_data
.isObject()) {
169 errmsg
= nacl::string("Malformed JSON dictionary");
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()));
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()));
192 void PnaclResources::StartLoad(
193 const pp::CompletionCallback
& all_loaded_callback
) {
194 PLUGIN_PRINTF(("PnaclResources::StartLoad\n"));
196 std::vector
<nacl::string
> resource_urls
;
197 resource_urls
.push_back(GetLlcUrl());
198 resource_urls
.push_back(GetLdUrl());
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
,
210 coordinator_
->ReportNonPpapiError(
211 ERROR_PNACL_RESOURCE_FETCH
,
212 nacl::string("failed to resolve ") +
213 url_with_platform_prefix
+ ": " +
214 error_info
.message() + ".");
217 nacl::string filename
= PnaclUrls::PnaclComponentURLToFilename(full_url
);
219 int32_t fd
= PnaclResources::GetPnaclFD(plugin_
, filename
.c_str());
221 // File-open failed. Assume this means that the file is
222 // not actually installed. This shouldn't actually occur since
223 // ReadResourceInfo() should happen first, and error out.
224 coordinator_
->ReportNonPpapiError(
225 ERROR_PNACL_RESOURCE_FETCH
,
226 nacl::string("The Portable Native Client (pnacl) component is not "
227 "installed. Please consult chrome://components for more "
229 result
= PP_ERROR_FILENOTFOUND
;
232 resource_wrappers_
[resource_urls
[i
]] =
233 plugin_
->wrapper_factory()->MakeFileDesc(fd
, O_RDONLY
);
236 // We're done! Queue the callback.
237 pp::Core
* core
= pp::Module::Get()->core();
238 core
->CallOnMainThread(0, all_loaded_callback
, result
);
241 } // namespace plugin