OLD | NEW |
---|---|
1 /* | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 * 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 * Use of this source code is governed by a BSD-style license that can be | 3 // found in the LICENSE file. |
4 * found in the LICENSE file. | |
5 */ | |
6 | 4 |
7 #include <algorithm> | 5 #include "components/nacl/renderer/json_manifest.h" |
8 | 6 |
9 #include "ppapi/native_client/src/trusted/plugin/json_manifest.h" | 7 #include <set> |
10 | 8 |
11 #include <stdlib.h> | 9 #include "base/logging.h" |
10 #include "base/macros.h" | |
11 #include "components/nacl/renderer/nexe_load_manager.h" | |
12 #include "third_party/jsoncpp/source/include/json/reader.h" | |
13 #include "third_party/jsoncpp/source/include/json/value.h" | |
14 #include "url/gurl.h" | |
12 | 15 |
13 #include "native_client/src/include/nacl_base.h" | 16 namespace nacl { |
14 #include "native_client/src/include/nacl_macros.h" | |
15 #include "native_client/src/include/nacl_string.h" | |
16 #include "native_client/src/include/portability.h" | |
17 #include "native_client/src/shared/platform/nacl_check.h" | |
18 #include "ppapi/c/private/ppb_nacl_private.h" | |
19 #include "ppapi/cpp/dev/url_util_dev.h" | |
20 #include "ppapi/cpp/var.h" | |
21 #include "ppapi/native_client/src/trusted/plugin/plugin_error.h" | |
22 #include "ppapi/native_client/src/trusted/plugin/utility.h" | |
23 #include "third_party/jsoncpp/source/include/json/reader.h" | |
bbudge
2014/05/01 23:32:33
Nice to get rid of all this!
| |
24 | |
25 namespace plugin { | |
26 | 17 |
27 namespace { | 18 namespace { |
28 // Top-level section name keys | 19 // Top-level section name keys |
29 const char* const kProgramKey = "program"; | 20 const char* const kProgramKey = "program"; |
30 const char* const kInterpreterKey = "interpreter"; | 21 const char* const kInterpreterKey = "interpreter"; |
31 const char* const kFilesKey = "files"; | 22 const char* const kFilesKey = "files"; |
32 | 23 |
33 // ISA Dictionary keys | 24 // ISA Dictionary keys |
34 const char* const kX8632Key = "x86-32"; | 25 const char* const kX8632Key = "x86-32"; |
35 const char* const kX8632NonSFIKey = "x86-32-nonsfi"; | 26 const char* const kX8632NonSFIKey = "x86-32-nonsfi"; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
90 // "foo.txt": { | 81 // "foo.txt": { |
91 // "portable": {"url": "foo.txt"} | 82 // "portable": {"url": "foo.txt"} |
92 // }, | 83 // }, |
93 // "bar.txt": { | 84 // "bar.txt": { |
94 // "portable": {"url": "bar.txt"} | 85 // "portable": {"url": "bar.txt"} |
95 // } | 86 // } |
96 // } | 87 // } |
97 // } | 88 // } |
98 | 89 |
99 // Returns the key for the architecture in non-SFI mode. | 90 // Returns the key for the architecture in non-SFI mode. |
100 nacl::string GetNonSFIKey(const nacl::string& sandbox_isa) { | 91 std::string GetNonSFIKey(const std::string& sandbox_isa) { |
101 return sandbox_isa + "-nonsfi"; | 92 return sandbox_isa + "-nonsfi"; |
102 } | 93 } |
103 | 94 |
104 // Looks up |property_name| in the vector |valid_names| with length | 95 // Looks up |property_name| in the vector |valid_names| with length |
105 // |valid_name_count|. Returns true if |property_name| is found. | 96 // |valid_name_count|. Returns true if |property_name| is found. |
106 bool FindMatchingProperty(const nacl::string& property_name, | 97 bool FindMatchingProperty(const std::string& property_name, |
107 const char** valid_names, | 98 const char** valid_names, |
108 size_t valid_name_count) { | 99 size_t valid_name_count) { |
109 for (size_t i = 0; i < valid_name_count; ++i) { | 100 for (size_t i = 0; i < valid_name_count; ++i) { |
110 if (property_name == valid_names[i]) { | 101 if (property_name == valid_names[i]) { |
111 return true; | 102 return true; |
112 } | 103 } |
113 } | 104 } |
114 return false; | 105 return false; |
115 } | 106 } |
116 | 107 |
117 // Return true if this is a valid dictionary. Having only keys present in | 108 // Return true if this is a valid dictionary. Having only keys present in |
118 // |valid_keys| and having at least the keys in |required_keys|. | 109 // |valid_keys| and having at least the keys in |required_keys|. |
119 // Error messages will be placed in |error_string|, given that the dictionary | 110 // Error messages will be placed in |error_string|, given that the dictionary |
120 // was the property value of |container_key|. | 111 // was the property value of |container_key|. |
121 // E.g., "container_key" : dictionary | 112 // E.g., "container_key" : dictionary |
122 bool IsValidDictionary(const Json::Value& dictionary, | 113 bool IsValidDictionary(const Json::Value& dictionary, |
123 const nacl::string& container_key, | 114 const std::string& container_key, |
124 const nacl::string& parent_key, | 115 const std::string& parent_key, |
125 const char** valid_keys, | 116 const char** valid_keys, |
126 size_t valid_key_count, | 117 size_t valid_key_count, |
127 const char** required_keys, | 118 const char** required_keys, |
128 size_t required_key_count, | 119 size_t required_key_count, |
129 nacl::string* error_string) { | 120 std::string* error_string) { |
130 if (!dictionary.isObject()) { | 121 if (!dictionary.isObject()) { |
131 nacl::stringstream error_stream; | 122 std::stringstream error_stream; |
132 error_stream << parent_key << " property '" << container_key | 123 error_stream << parent_key << " property '" << container_key |
133 << "' is non-dictionary value '" | 124 << "' is non-dictionary value '" |
134 << dictionary.toStyledString() << "'."; | 125 << dictionary.toStyledString() << "'."; |
135 *error_string = error_stream.str(); | 126 *error_string = error_stream.str(); |
136 return false; | 127 return false; |
137 } | 128 } |
138 // Check for unknown dictionary members. | 129 // Check for unknown dictionary members. |
139 Json::Value::Members members = dictionary.getMemberNames(); | 130 Json::Value::Members members = dictionary.getMemberNames(); |
140 for (size_t i = 0; i < members.size(); ++i) { | 131 for (size_t i = 0; i < members.size(); ++i) { |
141 nacl::string property_name = members[i]; | 132 std::string property_name = members[i]; |
142 if (!FindMatchingProperty(property_name, | 133 if (!FindMatchingProperty(property_name, |
143 valid_keys, | 134 valid_keys, |
144 valid_key_count)) { | 135 valid_key_count)) { |
145 // For forward compatibility, we do not prohibit other keys being in | 136 // For forward compatibility, we do not prohibit other keys being in |
146 // the dictionary. | 137 // the dictionary. |
147 PLUGIN_PRINTF(("WARNING: '%s' property '%s' has unknown key '%s'.\n", | 138 VLOG(1) << "WARNING: '" << parent_key << "' property '" |
148 parent_key.c_str(), | 139 << container_key << "' has unknown key '" |
149 container_key.c_str(), property_name.c_str())); | 140 << property_name << "'."; |
150 } | 141 } |
151 } | 142 } |
152 // Check for required members. | 143 // Check for required members. |
153 for (size_t i = 0; i < required_key_count; ++i) { | 144 for (size_t i = 0; i < required_key_count; ++i) { |
154 if (!dictionary.isMember(required_keys[i])) { | 145 if (!dictionary.isMember(required_keys[i])) { |
155 nacl::stringstream error_stream; | 146 std::stringstream error_stream; |
156 error_stream << parent_key << " property '" << container_key | 147 error_stream << parent_key << " property '" << container_key |
157 << "' does not have required key: '" | 148 << "' does not have required key: '" |
158 << required_keys[i] << "'."; | 149 << required_keys[i] << "'."; |
159 *error_string = error_stream.str(); | 150 *error_string = error_stream.str(); |
160 return false; | 151 return false; |
161 } | 152 } |
162 } | 153 } |
163 return true; | 154 return true; |
164 } | 155 } |
165 | 156 |
166 // Validate a "url" dictionary assuming it was resolved from container_key. | 157 // Validate a "url" dictionary assuming it was resolved from container_key. |
167 // E.g., "container_key" : { "url": "foo.txt" } | 158 // E.g., "container_key" : { "url": "foo.txt" } |
168 bool IsValidUrlSpec(const Json::Value& url_spec, | 159 bool IsValidUrlSpec(const Json::Value& url_spec, |
169 const nacl::string& container_key, | 160 const std::string& container_key, |
170 const nacl::string& parent_key, | 161 const std::string& parent_key, |
171 const nacl::string& sandbox_isa, | 162 const std::string& sandbox_isa, |
172 nacl::string* error_string) { | 163 std::string* error_string) { |
173 static const char* kManifestUrlSpecRequired[] = { | 164 static const char* kManifestUrlSpecRequired[] = { |
174 kUrlKey | 165 kUrlKey |
175 }; | 166 }; |
176 const char** urlSpecPlusOptional; | 167 const char** urlSpecPlusOptional; |
177 size_t urlSpecPlusOptionalLength; | 168 size_t urlSpecPlusOptionalLength; |
178 if (sandbox_isa == kPortableKey) { | 169 if (sandbox_isa == kPortableKey) { |
179 static const char* kPnaclUrlSpecPlusOptional[] = { | 170 static const char* kPnaclUrlSpecPlusOptional[] = { |
180 kUrlKey, | 171 kUrlKey, |
181 kOptLevelKey, | 172 kOptLevelKey, |
182 }; | 173 }; |
183 urlSpecPlusOptional = kPnaclUrlSpecPlusOptional; | 174 urlSpecPlusOptional = kPnaclUrlSpecPlusOptional; |
184 urlSpecPlusOptionalLength = NACL_ARRAY_SIZE(kPnaclUrlSpecPlusOptional); | 175 urlSpecPlusOptionalLength = arraysize(kPnaclUrlSpecPlusOptional); |
185 } else { | 176 } else { |
186 // URL specifications must not contain "pnacl-translate" keys. | 177 // URL specifications must not contain "pnacl-translate" keys. |
187 // This prohibits NaCl clients from invoking PNaCl. | 178 // This prohibits NaCl clients from invoking PNaCl. |
188 if (url_spec.isMember(kPnaclTranslateKey)) { | 179 if (url_spec.isMember(kPnaclTranslateKey)) { |
189 nacl::stringstream error_stream; | 180 std::stringstream error_stream; |
190 error_stream << "PNaCl-like NMF with application/x-nacl mimetype instead " | 181 error_stream << "PNaCl-like NMF with application/x-nacl mimetype instead " |
191 << "of x-pnacl mimetype (has " << kPnaclTranslateKey << ")."; | 182 << "of x-pnacl mimetype (has " << kPnaclTranslateKey << ")."; |
192 *error_string = error_stream.str(); | 183 *error_string = error_stream.str(); |
193 return false; | 184 return false; |
194 } | 185 } |
195 urlSpecPlusOptional = kManifestUrlSpecRequired; | 186 urlSpecPlusOptional = kManifestUrlSpecRequired; |
196 urlSpecPlusOptionalLength = NACL_ARRAY_SIZE(kManifestUrlSpecRequired); | 187 urlSpecPlusOptionalLength = arraysize(kManifestUrlSpecRequired); |
197 } | 188 } |
198 if (!IsValidDictionary(url_spec, container_key, parent_key, | 189 if (!IsValidDictionary(url_spec, container_key, parent_key, |
199 urlSpecPlusOptional, | 190 urlSpecPlusOptional, |
200 urlSpecPlusOptionalLength, | 191 urlSpecPlusOptionalLength, |
201 kManifestUrlSpecRequired, | 192 kManifestUrlSpecRequired, |
202 NACL_ARRAY_SIZE(kManifestUrlSpecRequired), | 193 arraysize(kManifestUrlSpecRequired), |
203 error_string)) { | 194 error_string)) { |
204 return false; | 195 return false; |
205 } | 196 } |
206 // Verify the correct types of the fields if they exist. | 197 // Verify the correct types of the fields if they exist. |
207 Json::Value url = url_spec[kUrlKey]; | 198 Json::Value url = url_spec[kUrlKey]; |
208 if (!url.isString()) { | 199 if (!url.isString()) { |
209 nacl::stringstream error_stream; | 200 std::stringstream error_stream; |
210 error_stream << parent_key << " property '" << container_key << | 201 error_stream << parent_key << " property '" << container_key << |
211 "' has non-string value '" << url.toStyledString() << | 202 "' has non-string value '" << url.toStyledString() << |
212 "' for key '" << kUrlKey << "'."; | 203 "' for key '" << kUrlKey << "'."; |
213 *error_string = error_stream.str(); | 204 *error_string = error_stream.str(); |
214 return false; | 205 return false; |
215 } | 206 } |
216 Json::Value opt_level = url_spec[kOptLevelKey]; | 207 Json::Value opt_level = url_spec[kOptLevelKey]; |
217 if (!opt_level.empty() && !opt_level.isNumeric()) { | 208 if (!opt_level.empty() && !opt_level.isNumeric()) { |
218 nacl::stringstream error_stream; | 209 std::stringstream error_stream; |
219 error_stream << parent_key << " property '" << container_key << | 210 error_stream << parent_key << " property '" << container_key << |
220 "' has non-numeric value '" << opt_level.toStyledString() << | 211 "' has non-numeric value '" << opt_level.toStyledString() << |
221 "' for key '" << kOptLevelKey << "'."; | 212 "' for key '" << kOptLevelKey << "'."; |
222 *error_string = error_stream.str(); | 213 *error_string = error_stream.str(); |
223 return false; | 214 return false; |
224 } | 215 } |
225 return true; | 216 return true; |
226 } | 217 } |
227 | 218 |
228 // Validate a "pnacl-translate" or "pnacl-debug" dictionary, assuming | 219 // Validate a "pnacl-translate" or "pnacl-debug" dictionary, assuming |
229 // it was resolved from container_key. | 220 // it was resolved from container_key. |
230 // E.g., "container_key" : { "pnacl-translate" : URLSpec } | 221 // E.g., "container_key" : { "pnacl-translate" : URLSpec } |
231 bool IsValidPnaclTranslateSpec(const Json::Value& pnacl_spec, | 222 bool IsValidPnaclTranslateSpec(const Json::Value& pnacl_spec, |
232 const nacl::string& container_key, | 223 const std::string& container_key, |
233 const nacl::string& parent_key, | 224 const std::string& parent_key, |
234 const nacl::string& sandbox_isa, | 225 const std::string& sandbox_isa, |
235 nacl::string* error_string) { | 226 std::string* error_string) { |
236 static const char* kManifestPnaclSpecValid[] = { | 227 static const char* kManifestPnaclSpecValid[] = { |
237 kPnaclDebugKey, | 228 kPnaclDebugKey, |
238 kPnaclTranslateKey | 229 kPnaclTranslateKey |
239 }; | 230 }; |
240 static const char* kManifestPnaclSpecRequired[] = { | 231 static const char* kManifestPnaclSpecRequired[] = { kPnaclTranslateKey }; |
241 kPnaclTranslateKey | |
242 }; | |
243 if (!IsValidDictionary(pnacl_spec, container_key, parent_key, | 232 if (!IsValidDictionary(pnacl_spec, container_key, parent_key, |
244 kManifestPnaclSpecValid, | 233 kManifestPnaclSpecValid, |
245 NACL_ARRAY_SIZE(kManifestPnaclSpecValid), | 234 arraysize(kManifestPnaclSpecValid), |
246 kManifestPnaclSpecRequired, | 235 kManifestPnaclSpecRequired, |
247 NACL_ARRAY_SIZE(kManifestPnaclSpecRequired), | 236 arraysize(kManifestPnaclSpecRequired), |
248 error_string)) { | 237 error_string)) { |
249 return false; | 238 return false; |
250 } | 239 } |
251 Json::Value url_spec = pnacl_spec[kPnaclTranslateKey]; | 240 Json::Value url_spec = pnacl_spec[kPnaclTranslateKey]; |
252 if (!IsValidUrlSpec(url_spec, kPnaclTranslateKey, | 241 return IsValidUrlSpec(url_spec, kPnaclTranslateKey, |
253 container_key, sandbox_isa, error_string)) { | 242 container_key, sandbox_isa, error_string); |
254 return false; | |
255 } | |
256 return true; | |
257 } | 243 } |
258 | 244 |
259 // Validates that |dictionary| is a valid ISA dictionary. An ISA dictionary | 245 // Validates that |dictionary| is a valid ISA dictionary. An ISA dictionary |
260 // is validated to have keys from within the set of recognized ISAs. Unknown | 246 // is validated to have keys from within the set of recognized ISAs. Unknown |
261 // ISAs are allowed, but ignored and warnings are produced. It is also validated | 247 // ISAs are allowed, but ignored and warnings are produced. It is also |
248 // validated | |
262 // that it must have an entry to match the ISA specified in |sandbox_isa| or | 249 // that it must have an entry to match the ISA specified in |sandbox_isa| or |
263 // have a fallback 'portable' entry if there is no match. Returns true if | 250 // have a fallback 'portable' entry if there is no match. Returns true if |
264 // |dictionary| is an ISA to URL map. Sets |error_info| to something | 251 // |dictionary| is an ISA to URL map. Sets |error_info| to something |
265 // descriptive if it fails. | 252 // descriptive if it fails. |
266 bool IsValidISADictionary(const Json::Value& dictionary, | 253 bool IsValidISADictionary(const Json::Value& dictionary, |
267 const nacl::string& parent_key, | 254 const std::string& parent_key, |
268 const nacl::string& sandbox_isa, | 255 const std::string& sandbox_isa, |
269 bool must_find_matching_entry, | 256 bool must_find_matching_entry, |
270 bool nonsfi_enabled, | 257 bool nonsfi_enabled, |
271 ErrorInfo* error_info) { | 258 JsonManifest::ErrorInfo* error_info) { |
272 if (error_info == NULL) return false; | |
273 | |
274 // An ISA to URL dictionary has to be an object. | 259 // An ISA to URL dictionary has to be an object. |
275 if (!dictionary.isObject()) { | 260 if (!dictionary.isObject()) { |
276 error_info->SetReport(PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE, | 261 error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE; |
277 nacl::string("manifest: ") + parent_key + | 262 error_info->string = std::string("manifest: ") + parent_key + |
278 " property is not an ISA to URL dictionary"); | 263 " property is not an ISA to URL dictionary"; |
279 return false; | 264 return false; |
280 } | 265 } |
281 // Build the set of reserved ISA dictionary keys. | 266 // Build the set of reserved ISA dictionary keys. |
282 const char** isaProperties; | 267 const char** isaProperties; |
283 size_t isaPropertiesLength; | 268 size_t isaPropertiesLength; |
284 if (sandbox_isa == kPortableKey) { | 269 if (sandbox_isa == kPortableKey) { |
285 // The known values for PNaCl ISA dictionaries in the manifest. | 270 // The known values for PNaCl ISA dictionaries in the manifest. |
286 static const char* kPnaclManifestISAProperties[] = { | 271 static const char* kPnaclManifestISAProperties[] = { |
287 kPortableKey | 272 kPortableKey |
288 }; | 273 }; |
289 isaProperties = kPnaclManifestISAProperties; | 274 isaProperties = kPnaclManifestISAProperties; |
290 isaPropertiesLength = NACL_ARRAY_SIZE(kPnaclManifestISAProperties); | 275 isaPropertiesLength = arraysize(kPnaclManifestISAProperties); |
291 } else { | 276 } else { |
292 // The known values for NaCl ISA dictionaries in the manifest. | 277 // The known values for NaCl ISA dictionaries in the manifest. |
293 static const char* kNaClManifestISAProperties[] = { | 278 static const char* kNaClManifestISAProperties[] = { |
294 kX8632Key, | 279 kX8632Key, |
295 kX8632NonSFIKey, | 280 kX8632NonSFIKey, |
296 kX8664Key, | 281 kX8664Key, |
297 kX8664NonSFIKey, | 282 kX8664NonSFIKey, |
298 kArmKey, | 283 kArmKey, |
299 kArmNonSFIKey, | 284 kArmNonSFIKey, |
300 // "portable" is here to allow checking that, if present, it can | 285 // "portable" is here to allow checking that, if present, it can |
301 // only refer to an URL, such as for a data file, and not to | 286 // only refer to an URL, such as for a data file, and not to |
302 // "pnacl-translate", which would cause the creation of a nexe. | 287 // "pnacl-translate", which would cause the creation of a nexe. |
303 kPortableKey | 288 kPortableKey |
304 }; | 289 }; |
305 isaProperties = kNaClManifestISAProperties; | 290 isaProperties = kNaClManifestISAProperties; |
306 isaPropertiesLength = NACL_ARRAY_SIZE(kNaClManifestISAProperties); | 291 isaPropertiesLength = arraysize(kNaClManifestISAProperties); |
307 } | 292 } |
308 // Check that entries in the dictionary are structurally correct. | 293 // Check that entries in the dictionary are structurally correct. |
309 Json::Value::Members members = dictionary.getMemberNames(); | 294 Json::Value::Members members = dictionary.getMemberNames(); |
310 for (size_t i = 0; i < members.size(); ++i) { | 295 for (size_t i = 0; i < members.size(); ++i) { |
311 nacl::string property_name = members[i]; | 296 std::string property_name = members[i]; |
312 Json::Value property_value = dictionary[property_name]; | 297 Json::Value property_value = dictionary[property_name]; |
313 nacl::string error_string; | 298 std::string error_string; |
314 if (FindMatchingProperty(property_name, | 299 if (FindMatchingProperty(property_name, |
315 isaProperties, | 300 isaProperties, |
316 isaPropertiesLength)) { | 301 isaPropertiesLength)) { |
317 // For NaCl, arch entries can only be | 302 // For NaCl, arch entries can only be |
318 // "arch/portable" : URLSpec | 303 // "arch/portable" : URLSpec |
319 // For PNaCl arch in "program" dictionary entries can be | 304 // For PNaCl arch in "program" dictionary entries can be |
320 // "portable" : { "pnacl-translate": URLSpec } | 305 // "portable" : { "pnacl-translate": URLSpec } |
321 // or "portable" : { "pnacl-debug": URLSpec } | 306 // or "portable" : { "pnacl-debug": URLSpec } |
322 // For PNaCl arch elsewhere, dictionary entries can only be | 307 // For PNaCl arch elsewhere, dictionary entries can only be |
323 // "portable" : URLSpec | 308 // "portable" : URLSpec |
324 if ((sandbox_isa != kPortableKey && | 309 if ((sandbox_isa != kPortableKey && |
325 !IsValidUrlSpec(property_value, property_name, parent_key, | 310 !IsValidUrlSpec(property_value, property_name, parent_key, |
326 sandbox_isa, &error_string)) || | 311 sandbox_isa, &error_string)) || |
327 (sandbox_isa == kPortableKey && | 312 (sandbox_isa == kPortableKey && |
328 parent_key == kProgramKey && | 313 parent_key == kProgramKey && |
329 !IsValidPnaclTranslateSpec(property_value, property_name, parent_key, | 314 !IsValidPnaclTranslateSpec(property_value, property_name, parent_key, |
330 sandbox_isa, &error_string)) || | 315 sandbox_isa, &error_string)) || |
331 (sandbox_isa == kPortableKey && | 316 (sandbox_isa == kPortableKey && |
332 parent_key != kProgramKey && | 317 parent_key != kProgramKey && |
333 !IsValidUrlSpec(property_value, property_name, parent_key, | 318 !IsValidUrlSpec(property_value, property_name, parent_key, |
334 sandbox_isa, &error_string))) { | 319 sandbox_isa, &error_string))) { |
335 error_info->SetReport(PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE, | 320 error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE; |
336 nacl::string("manifest: ") + error_string); | 321 error_info->string = "manifest: " + error_string; |
337 return false; | 322 return false; |
338 } | 323 } |
339 } else { | 324 } else { |
340 // For forward compatibility, we do not prohibit other keys being in | 325 // For forward compatibility, we do not prohibit other keys being in |
341 // the dictionary, as they may be architectures supported in later | 326 // the dictionary, as they may be architectures supported in later |
342 // versions. However, the value of these entries must be an URLSpec. | 327 // versions. However, the value of these entries must be an URLSpec. |
343 PLUGIN_PRINTF(("IsValidISADictionary: unrecognized key '%s'.\n", | 328 VLOG(1) << "IsValidISADictionary: unrecognized key '" |
344 property_name.c_str())); | 329 << property_name << "'."; |
345 if (!IsValidUrlSpec(property_value, property_name, parent_key, | 330 if (!IsValidUrlSpec(property_value, property_name, parent_key, |
346 sandbox_isa, &error_string)) { | 331 sandbox_isa, &error_string)) { |
347 error_info->SetReport(PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE, | 332 error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE; |
348 nacl::string("manifest: ") + error_string); | 333 error_info->string = "manifest: " + error_string; |
349 return false; | 334 return false; |
350 } | 335 } |
351 } | 336 } |
352 } | 337 } |
353 | 338 |
354 if (sandbox_isa == kPortableKey) { | 339 if (sandbox_isa == kPortableKey) { |
355 bool has_portable = dictionary.isMember(kPortableKey); | 340 if (!dictionary.isMember(kPortableKey)) { |
356 | 341 error_info->error = PP_NACL_ERROR_MANIFEST_PROGRAM_MISSING_ARCH; |
357 if (!has_portable) { | 342 error_info->string = "manifest: no version of " + parent_key + |
358 error_info->SetReport( | 343 " given for portable."; |
359 PP_NACL_ERROR_MANIFEST_PROGRAM_MISSING_ARCH, | |
360 nacl::string("manifest: no version of ") + parent_key + | |
361 " given for portable."); | |
362 return false; | 344 return false; |
363 } | 345 } |
364 } else if (must_find_matching_entry) { | 346 } else if (must_find_matching_entry) { |
365 // TODO(elijahtaylor) add ISA resolver here if we expand ISAs to include | 347 // TODO(elijahtaylor) add ISA resolver here if we expand ISAs to include |
366 // micro-architectures that can resolve to multiple valid sandboxes. | 348 // micro-architectures that can resolve to multiple valid sandboxes. |
367 bool has_isa = dictionary.isMember(sandbox_isa); | 349 bool has_isa = dictionary.isMember(sandbox_isa); |
368 bool has_nonsfi_isa = | 350 bool has_nonsfi_isa = |
369 nonsfi_enabled && dictionary.isMember(GetNonSFIKey(sandbox_isa)); | 351 nonsfi_enabled && dictionary.isMember(GetNonSFIKey(sandbox_isa)); |
370 bool has_portable = dictionary.isMember(kPortableKey); | 352 bool has_portable = dictionary.isMember(kPortableKey); |
371 | 353 |
372 if (!has_isa && !has_nonsfi_isa && !has_portable) { | 354 if (!has_isa && !has_nonsfi_isa && !has_portable) { |
373 error_info->SetReport( | 355 error_info->error = PP_NACL_ERROR_MANIFEST_PROGRAM_MISSING_ARCH; |
374 PP_NACL_ERROR_MANIFEST_PROGRAM_MISSING_ARCH, | 356 error_info->string = "manifest: no version of " + parent_key + |
375 nacl::string("manifest: no version of ") + parent_key + | 357 " given for current arch and no portable version found."; |
376 " given for current arch and no portable version found."); | |
377 return false; | 358 return false; |
378 } | 359 } |
379 } | 360 } |
380 | |
381 return true; | 361 return true; |
382 } | 362 } |
383 | 363 |
384 void GrabUrlAndPNaClOptions(const Json::Value& url_spec, | 364 void GrabUrlAndPnaclOptions(const Json::Value& url_spec, |
385 nacl::string* url, | 365 std::string* url, |
386 PP_PNaClOptions* pnacl_options) { | 366 PP_PNaClOptions* pnacl_options) { |
387 *url = url_spec[kUrlKey].asString(); | 367 *url = url_spec[kUrlKey].asString(); |
388 pnacl_options->translate = PP_TRUE; | 368 pnacl_options->translate = PP_TRUE; |
389 if (url_spec.isMember(kOptLevelKey)) { | 369 if (url_spec.isMember(kOptLevelKey)) { |
390 int32_t opt_raw = url_spec[kOptLevelKey].asInt(); | 370 int32_t opt_raw = url_spec[kOptLevelKey].asInt(); |
391 int32_t opt_level; | |
392 // Currently only allow 0 or 2, since that is what we test. | 371 // Currently only allow 0 or 2, since that is what we test. |
393 if (opt_raw <= 0) | 372 if (opt_raw <= 0) |
394 opt_level = 0; | 373 pnacl_options->opt_level = 0; |
395 else | 374 else |
396 opt_level = 2; | 375 pnacl_options->opt_level = 2; |
397 pnacl_options->opt_level = opt_level; | |
398 } | 376 } |
399 } | 377 } |
400 | 378 |
401 } // namespace | 379 } // namespace |
402 | 380 |
403 bool JsonManifest::Init(const nacl::string& manifest_json, | 381 JsonManifest::JsonManifest(const std::string& manifest_base_url, |
382 const std::string& sandbox_isa, | |
383 bool nonsfi_enabled, | |
384 bool pnacl_debug) | |
385 : manifest_base_url_(manifest_base_url), | |
386 sandbox_isa_(sandbox_isa), | |
387 nonsfi_enabled_(nonsfi_enabled), | |
388 pnacl_debug_(pnacl_debug) { } | |
389 | |
390 bool JsonManifest::Init(const std::string& manifest_json, | |
404 ErrorInfo* error_info) { | 391 ErrorInfo* error_info) { |
405 if (error_info == NULL) { | 392 CHECK(error_info); |
406 return false; | 393 |
407 } | |
408 Json::Reader reader; | 394 Json::Reader reader; |
409 if (!reader.parse(manifest_json, dictionary_)) { | 395 if (!reader.parse(manifest_json, dictionary_)) { |
410 std::string json_error = reader.getFormatedErrorMessages(); | 396 std::string json_error = reader.getFormattedErrorMessages(); |
411 error_info->SetReport(PP_NACL_ERROR_MANIFEST_PARSING, | 397 error_info->error = PP_NACL_ERROR_MANIFEST_PARSING; |
412 "manifest JSON parsing failed: " + json_error); | 398 error_info->string = "manifest JSON parsing failed: " + json_error; |
413 return false; | 399 return false; |
414 } | 400 } |
415 // Parse has ensured the string was valid JSON. Check that it matches the | 401 // Parse has ensured the string was valid JSON. Check that it matches the |
416 // manifest schema. | 402 // manifest schema. |
417 return MatchesSchema(error_info); | 403 return MatchesSchema(error_info); |
418 } | 404 } |
419 | 405 |
420 bool JsonManifest::MatchesSchema(ErrorInfo* error_info) { | 406 bool JsonManifest::GetProgramURL(std::string* full_url, |
421 pp::Var exception; | 407 PP_PNaClOptions* pnacl_options, |
422 if (error_info == NULL) { | 408 bool* uses_nonsfi_mode, |
409 ErrorInfo* error_info) const { | |
410 if (!full_url) | |
411 return false; | |
412 CHECK(pnacl_options); | |
413 CHECK(uses_nonsfi_mode); | |
414 CHECK(error_info); | |
415 | |
416 const Json::Value& program = dictionary_[kProgramKey]; | |
417 std::string nexe_url; | |
418 if (!GetURLFromISADictionary(program, | |
419 kProgramKey, | |
420 &nexe_url, | |
421 pnacl_options, | |
422 uses_nonsfi_mode, | |
423 error_info)) { | |
423 return false; | 424 return false; |
424 } | 425 } |
426 | |
427 // The contents of the manifest are resolved relative to the manifest URL. | |
428 GURL base_gurl(manifest_base_url_); | |
429 if (!base_gurl.is_valid()) | |
430 return false; | |
431 | |
432 GURL resolved_gurl = base_gurl.Resolve(nexe_url); | |
433 if (!resolved_gurl.is_valid()) { | |
434 error_info->error = PP_NACL_ERROR_MANIFEST_RESOLVE_URL; | |
435 error_info->string = | |
436 "could not resolve url '" + nexe_url + | |
437 "' relative to manifest base url '" + manifest_base_url_.c_str() + | |
438 "'."; | |
439 return false; | |
440 } | |
441 *full_url = resolved_gurl.possibly_invalid_spec(); | |
442 return true; | |
443 } | |
444 | |
445 bool JsonManifest::ResolveKey(const std::string& key, | |
446 std::string* full_url, | |
447 PP_PNaClOptions* pnacl_options) const { | |
448 // key must be one of kProgramKey or kFileKey '/' file-section-key | |
449 if (full_url == NULL || pnacl_options == NULL) | |
450 return false; | |
451 | |
452 if (key == kProgramKey) | |
453 return GetKeyUrl(dictionary_, key, full_url, pnacl_options); | |
454 | |
455 std::string::const_iterator p = find(key.begin(), key.end(), '/'); | |
456 if (p == key.end()) { | |
457 VLOG(1) << "ResolveKey failed: invalid key, no slash: " << key; | |
458 return false; | |
459 } | |
460 | |
461 // generalize to permit other sections? | |
462 std::string prefix(key.begin(), p); | |
463 if (prefix != kFilesKey) { | |
464 VLOG(1) << "ResolveKey failed: invalid key, no \"files\" prefix: " << key; | |
465 return false; | |
466 } | |
467 | |
468 const Json::Value& files = dictionary_[kFilesKey]; | |
469 if (!files.isObject()) { | |
470 VLOG(1) << "ResolveKey failed: no \"files\" dictionary"; | |
471 return false; | |
472 } | |
473 | |
474 std::string rest(p + 1, key.end()); | |
475 if (!files.isMember(rest)) { | |
476 VLOG(1) << "ResolveKey failed: no such \"files\" entry: " << key; | |
477 return false; | |
478 } | |
479 return GetKeyUrl(files, rest, full_url, pnacl_options); | |
480 } | |
481 | |
482 bool JsonManifest::MatchesSchema(ErrorInfo* error_info) { | |
425 if (!dictionary_.isObject()) { | 483 if (!dictionary_.isObject()) { |
426 error_info->SetReport( | 484 error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE; |
427 PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE, | 485 error_info->string = "manifest: is not a json dictionary."; |
428 "manifest: is not a json dictionary."); | |
429 return false; | 486 return false; |
430 } | 487 } |
431 Json::Value::Members members = dictionary_.getMemberNames(); | 488 Json::Value::Members members = dictionary_.getMemberNames(); |
432 for (size_t i = 0; i < members.size(); ++i) { | 489 for (size_t i = 0; i < members.size(); ++i) { |
433 // The top level dictionary entries valid in the manifest file. | 490 // The top level dictionary entries valid in the manifest file. |
434 static const char* kManifestTopLevelProperties[] = { kProgramKey, | 491 static const char* kManifestTopLevelProperties[] = { kProgramKey, |
435 kInterpreterKey, | 492 kInterpreterKey, |
436 kFilesKey }; | 493 kFilesKey }; |
437 nacl::string property_name = members[i]; | 494 std::string property_name = members[i]; |
438 if (!FindMatchingProperty(property_name, | 495 if (!FindMatchingProperty(property_name, |
439 kManifestTopLevelProperties, | 496 kManifestTopLevelProperties, |
440 NACL_ARRAY_SIZE(kManifestTopLevelProperties))) { | 497 arraysize(kManifestTopLevelProperties))) { |
441 PLUGIN_PRINTF(("JsonManifest::MatchesSchema: WARNING: unknown top-level " | 498 VLOG(1) << "JsonManifest::MatchesSchema: WARNING: unknown top-level " |
442 "section '%s' in manifest.\n", property_name.c_str())); | 499 << "section '" << property_name << "' in manifest."; |
443 } | 500 } |
444 } | 501 } |
445 | 502 |
446 // A manifest file must have a program section. | 503 // A manifest file must have a program section. |
447 if (!dictionary_.isMember(kProgramKey)) { | 504 if (!dictionary_.isMember(kProgramKey)) { |
448 error_info->SetReport( | 505 error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE; |
449 PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE, | 506 error_info->string = std::string("manifest: missing '") + kProgramKey + |
450 nacl::string("manifest: missing '") + kProgramKey + "' section."); | 507 "' section."; |
451 return false; | 508 return false; |
452 } | 509 } |
453 | 510 |
454 // Validate the program section. | 511 // Validate the program section. |
455 // There must be a matching (portable or sandbox_isa_) entry for program for | 512 // There must be a matching (portable or sandbox_isa_) entry for program for |
456 // NaCl. | 513 // NaCl. |
457 if (!IsValidISADictionary(dictionary_[kProgramKey], | 514 if (!IsValidISADictionary(dictionary_[kProgramKey], |
458 kProgramKey, | 515 kProgramKey, |
459 sandbox_isa_, | 516 sandbox_isa_, |
460 true, | 517 true, |
(...skipping 11 matching lines...) Expand all Loading... | |
472 sandbox_isa_, | 529 sandbox_isa_, |
473 true, | 530 true, |
474 nonsfi_enabled_, | 531 nonsfi_enabled_, |
475 error_info)) { | 532 error_info)) { |
476 return false; | 533 return false; |
477 } | 534 } |
478 } | 535 } |
479 | 536 |
480 // Validate the file dictionary (if given). | 537 // Validate the file dictionary (if given). |
481 // The "files" key does not require a matching (portable or sandbox_isa_) | 538 // The "files" key does not require a matching (portable or sandbox_isa_) |
482 // entry at schema validation time for NaCl. This allows manifests to specify | 539 // entry at schema validation time for NaCl. This allows manifests to |
483 // resources that are only loaded for a particular sandbox_isa. | 540 // specify resources that are only loaded for a particular sandbox_isa. |
484 if (dictionary_.isMember(kFilesKey)) { | 541 if (dictionary_.isMember(kFilesKey)) { |
485 const Json::Value& files = dictionary_[kFilesKey]; | 542 const Json::Value& files = dictionary_[kFilesKey]; |
486 if (!files.isObject()) { | 543 if (!files.isObject()) { |
487 error_info->SetReport( | 544 error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE; |
488 PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE, | 545 error_info->string = std::string("manifest: '") + kFilesKey + |
489 nacl::string("manifest: '") + kFilesKey + "' is not a dictionary."); | 546 "' is not a dictionary."; |
490 } | 547 } |
491 Json::Value::Members members = files.getMemberNames(); | 548 Json::Value::Members members = files.getMemberNames(); |
492 for (size_t i = 0; i < members.size(); ++i) { | 549 for (size_t i = 0; i < members.size(); ++i) { |
493 nacl::string file_name = members[i]; | 550 std::string file_name = members[i]; |
494 if (!IsValidISADictionary(files[file_name], | 551 if (!IsValidISADictionary(files[file_name], |
495 file_name, | 552 file_name, |
496 sandbox_isa_, | 553 sandbox_isa_, |
497 false, | 554 false, |
498 nonsfi_enabled_, | 555 nonsfi_enabled_, |
499 error_info)) { | 556 error_info)) { |
500 return false; | 557 return false; |
501 } | 558 } |
502 } | 559 } |
503 } | 560 } |
561 return true; | |
562 } | |
504 | 563 |
564 bool JsonManifest::GetKeyUrl(const Json::Value& dictionary, | |
565 const std::string& key, | |
566 std::string* full_url, | |
567 PP_PNaClOptions* pnacl_options) const { | |
568 DCHECK(full_url && pnacl_options); | |
569 if (!dictionary.isMember(key)) { | |
570 VLOG(1) << "GetKeyUrl failed: file " << key << " not found in manifest."; | |
571 return false; | |
572 } | |
573 const Json::Value& isa_dict = dictionary[key]; | |
574 std::string relative_url; | |
575 bool uses_nonsfi_mode; | |
576 ErrorInfo ignored_error_info; | |
577 if (!GetURLFromISADictionary(isa_dict, key, &relative_url, | |
578 pnacl_options, &uses_nonsfi_mode, | |
579 &ignored_error_info)) | |
580 return false; | |
581 | |
582 // The contents of the manifest are resolved relative to the manifest URL. | |
583 GURL base_gurl(manifest_base_url_); | |
584 if (!base_gurl.is_valid()) | |
585 return false; | |
586 GURL resolved_gurl = base_gurl.Resolve(relative_url); | |
587 if (!resolved_gurl.is_valid()) | |
588 return false; | |
589 *full_url = resolved_gurl.possibly_invalid_spec(); | |
505 return true; | 590 return true; |
506 } | 591 } |
507 | 592 |
508 bool JsonManifest::GetURLFromISADictionary(const Json::Value& dictionary, | 593 bool JsonManifest::GetURLFromISADictionary(const Json::Value& dictionary, |
509 const nacl::string& parent_key, | 594 const std::string& parent_key, |
510 nacl::string* url, | 595 std::string* url, |
511 PP_PNaClOptions* pnacl_options, | 596 PP_PNaClOptions* pnacl_options, |
512 bool* uses_nonsfi_mode, | 597 bool* uses_nonsfi_mode, |
513 ErrorInfo* error_info) const { | 598 ErrorInfo* error_info) const { |
514 DCHECK(url != NULL && pnacl_options != NULL && error_info != NULL); | 599 DCHECK(url && pnacl_options && error_info); |
515 | 600 |
516 // When the application actually requests a resolved URL, we must have | 601 // When the application actually requests a resolved URL, we must have |
517 // a matching entry (sandbox_isa_ or portable) for NaCl. | 602 // a matching entry (sandbox_isa_ or portable) for NaCl. |
518 ErrorInfo ignored_error_info; | 603 ErrorInfo ignored_error_info; |
519 if (!IsValidISADictionary(dictionary, parent_key, sandbox_isa_, true, | 604 if (!IsValidISADictionary(dictionary, parent_key, sandbox_isa_, true, |
520 nonsfi_enabled_, &ignored_error_info)) { | 605 nonsfi_enabled_, &ignored_error_info)) { |
521 error_info->SetReport(PP_NACL_ERROR_MANIFEST_RESOLVE_URL, | 606 error_info->error = PP_NACL_ERROR_MANIFEST_RESOLVE_URL; |
522 "architecture " + sandbox_isa_ + | 607 error_info->string = "architecture " + sandbox_isa_ + |
523 " is not found for file " + parent_key); | 608 " is not found for file " + parent_key; |
524 return false; | 609 return false; |
525 } | 610 } |
526 | 611 |
527 // The call to IsValidISADictionary() above guarantees that either | 612 // The call to IsValidISADictionary() above guarantees that either |
528 // sandbox_isa_, its nonsfi mode, or kPortableKey is present in the | 613 // sandbox_isa_, its nonsfi mode, or kPortableKey is present in the |
529 // dictionary. | 614 // dictionary. |
530 *uses_nonsfi_mode = false; | 615 *uses_nonsfi_mode = false; |
531 nacl::string chosen_isa; | 616 std::string chosen_isa; |
532 if (sandbox_isa_ == kPortableKey) { | 617 if (sandbox_isa_ == kPortableKey) { |
533 chosen_isa = kPortableKey; | 618 chosen_isa = kPortableKey; |
534 } else { | 619 } else { |
535 nacl::string nonsfi_isa = GetNonSFIKey(sandbox_isa_); | 620 std::string nonsfi_isa = GetNonSFIKey(sandbox_isa_); |
536 if (nonsfi_enabled_ && dictionary.isMember(nonsfi_isa)) { | 621 if (nonsfi_enabled_ && dictionary.isMember(nonsfi_isa)) { |
537 chosen_isa = nonsfi_isa; | 622 chosen_isa = nonsfi_isa; |
538 *uses_nonsfi_mode = true; | 623 *uses_nonsfi_mode = true; |
539 } else if (dictionary.isMember(sandbox_isa_)) { | 624 } else if (dictionary.isMember(sandbox_isa_)) { |
540 chosen_isa = sandbox_isa_; | 625 chosen_isa = sandbox_isa_; |
541 } else if (dictionary.isMember(kPortableKey)) { | 626 } else if (dictionary.isMember(kPortableKey)) { |
542 chosen_isa = kPortableKey; | 627 chosen_isa = kPortableKey; |
543 } else { | 628 } else { |
544 // Should not reach here, because the earlier IsValidISADictionary() | 629 // Should not reach here, because the earlier IsValidISADictionary() |
545 // call checked that the manifest covers the current architecture. | 630 // call checked that the manifest covers the current architecture. |
546 DCHECK(false); | 631 DCHECK(false); |
632 return false; | |
547 } | 633 } |
548 } | 634 } |
549 | 635 |
550 const Json::Value& isa_spec = dictionary[chosen_isa]; | 636 const Json::Value& isa_spec = dictionary[chosen_isa]; |
551 // If the PNaCl debug flag is turned on, look for pnacl-debug entries first. | 637 // If the PNaCl debug flag is turned on, look for pnacl-debug entries first. |
552 // If found, mark that it is a debug URL. Otherwise, fall back to | 638 // If found, mark that it is a debug URL. Otherwise, fall back to |
553 // checking for pnacl-translate URLs, etc. and don't mark it as a debug URL. | 639 // checking for pnacl-translate URLs, etc. and don't mark it as a debug URL. |
554 if (pnacl_debug_ && isa_spec.isMember(kPnaclDebugKey)) { | 640 if (pnacl_debug_ && isa_spec.isMember(kPnaclDebugKey)) { |
555 GrabUrlAndPNaClOptions(isa_spec[kPnaclDebugKey], url, pnacl_options); | 641 GrabUrlAndPnaclOptions(isa_spec[kPnaclDebugKey], url, pnacl_options); |
556 pnacl_options->is_debug = PP_TRUE; | 642 pnacl_options->is_debug = PP_TRUE; |
557 } else if (isa_spec.isMember(kPnaclTranslateKey)) { | 643 } else if (isa_spec.isMember(kPnaclTranslateKey)) { |
558 GrabUrlAndPNaClOptions(isa_spec[kPnaclTranslateKey], url, pnacl_options); | 644 GrabUrlAndPnaclOptions(isa_spec[kPnaclTranslateKey], url, pnacl_options); |
559 } else { | 645 } else { |
560 // NaCl | 646 // NaCl |
561 *url = isa_spec[kUrlKey].asString(); | 647 *url = isa_spec[kUrlKey].asString(); |
562 pnacl_options->translate = PP_FALSE; | 648 pnacl_options->translate = PP_FALSE; |
563 } | 649 } |
564 | 650 |
565 return true; | 651 return true; |
566 } | 652 } |
567 | 653 |
568 bool JsonManifest::GetKeyUrl(const Json::Value& dictionary, | 654 } // namespace nacl |
569 const nacl::string& key, | |
570 nacl::string* full_url, | |
571 PP_PNaClOptions* pnacl_options) const { | |
572 DCHECK(full_url != NULL && pnacl_options != NULL); | |
573 if (!dictionary.isMember(key)) { | |
574 PLUGIN_PRINTF(("file key not found in manifest")); | |
575 return false; | |
576 } | |
577 const Json::Value& isa_dict = dictionary[key]; | |
578 nacl::string relative_url; | |
579 bool uses_nonsfi_mode; | |
580 | |
581 // We ignore the error_info we receive here but it's needed for the calls | |
582 // below. | |
583 ErrorInfo error_info; | |
584 | |
585 if (!GetURLFromISADictionary(isa_dict, key, &relative_url, | |
586 pnacl_options, &uses_nonsfi_mode, &error_info)) { | |
587 return false; | |
588 } | |
589 return ResolveURL(relative_url, full_url, &error_info); | |
590 } | |
591 | |
592 bool JsonManifest::GetProgramURL(nacl::string* full_url, | |
593 PP_PNaClOptions* pnacl_options, | |
594 bool* uses_nonsfi_mode, | |
595 ErrorInfo* error_info) const { | |
596 if (full_url == NULL || pnacl_options == NULL || error_info == NULL) | |
597 return false; | |
598 | |
599 const Json::Value& program = dictionary_[kProgramKey]; | |
600 nacl::string nexe_url; | |
601 if (!GetURLFromISADictionary(program, | |
602 kProgramKey, | |
603 &nexe_url, | |
604 pnacl_options, | |
605 uses_nonsfi_mode, | |
606 error_info)) { | |
607 return false; | |
608 } | |
609 return ResolveURL(nexe_url, full_url, error_info); | |
610 } | |
611 | |
612 bool JsonManifest::ResolveKey(const nacl::string& key, | |
613 nacl::string* full_url, | |
614 PP_PNaClOptions* pnacl_options) const { | |
615 NaClLog(3, "JsonManifest::ResolveKey(%s)\n", key.c_str()); | |
616 // key must be one of kProgramKey or kFileKey '/' file-section-key | |
617 | |
618 if (full_url == NULL || pnacl_options == NULL) | |
619 return false; | |
620 | |
621 if (key == kProgramKey) | |
622 return GetKeyUrl(dictionary_, key, full_url, pnacl_options); | |
623 nacl::string::const_iterator p = find(key.begin(), key.end(), '/'); | |
624 if (p == key.end()) { | |
625 std::string err = "ResolveKey: invalid key, no slash: " + key; | |
626 PLUGIN_PRINTF((err.c_str())); | |
627 return false; | |
628 } | |
629 | |
630 // generalize to permit other sections? | |
631 nacl::string prefix(key.begin(), p); | |
632 if (prefix != kFilesKey) { | |
633 std::string err = "ResolveKey: invalid key: no \"files\" prefix: " + key; | |
634 PLUGIN_PRINTF((err.c_str())); | |
635 return false; | |
636 } | |
637 | |
638 nacl::string rest(p + 1, key.end()); | |
639 | |
640 const Json::Value& files = dictionary_[kFilesKey]; | |
641 if (!files.isObject()) { | |
642 std::string err = "ResolveKey: no \"files\" dictionary"; | |
643 PLUGIN_PRINTF((err.c_str())); | |
644 return false; | |
645 } | |
646 if (!files.isMember(rest)) { | |
647 std::string err = "ResolveKey: no such \"files\" entry: " + key; | |
648 PLUGIN_PRINTF((err.c_str())); | |
649 return false; | |
650 } | |
651 return GetKeyUrl(files, rest, full_url, pnacl_options); | |
652 } | |
653 | |
654 bool JsonManifest::ResolveURL(const nacl::string& relative_url, | |
655 nacl::string* full_url, | |
656 ErrorInfo* error_info) const { | |
657 // The contents of the manifest are resolved relative to the manifest URL. | |
658 CHECK(url_util_ != NULL); | |
659 pp::Var resolved_url = | |
660 url_util_->ResolveRelativeToURL(pp::Var(manifest_base_url_), | |
661 relative_url); | |
662 if (!resolved_url.is_string()) { | |
663 error_info->SetReport( | |
664 PP_NACL_ERROR_MANIFEST_RESOLVE_URL, | |
665 "could not resolve url '" + relative_url + | |
666 "' relative to manifest base url '" + manifest_base_url_.c_str() + | |
667 "'."); | |
668 return false; | |
669 } | |
670 *full_url = resolved_url.AsString(); | |
671 return true; | |
672 } | |
673 | |
674 } // namespace plugin | |
OLD | NEW |