| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 * Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 * 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 |
| 4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
| 5 */ | 5 */ |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "native_client/src/trusted/plugin/json_manifest.h" | 9 #include "native_client/src/trusted/plugin/json_manifest.h" |
| 10 | 10 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 // ISA Dictionary keys | 32 // ISA Dictionary keys |
| 33 const char* const kX8632Key = "x86-32"; | 33 const char* const kX8632Key = "x86-32"; |
| 34 const char* const kX8664Key = "x86-64"; | 34 const char* const kX8664Key = "x86-64"; |
| 35 const char* const kArmKey = "arm"; | 35 const char* const kArmKey = "arm"; |
| 36 const char* const kPortableKey = "portable"; | 36 const char* const kPortableKey = "portable"; |
| 37 | 37 |
| 38 // Url Resolution keys | 38 // Url Resolution keys |
| 39 const char* const kPnaclTranslateKey = "pnacl-translate"; | 39 const char* const kPnaclTranslateKey = "pnacl-translate"; |
| 40 const char* const kUrlKey = "url"; | 40 const char* const kUrlKey = "url"; |
| 41 | 41 |
| 42 // Cache support keys |
| 43 const char* const kCacheIdentityKey = "sha256"; |
| 44 |
| 42 // Sample manifest file: | 45 // Sample manifest file: |
| 43 // { | 46 // { |
| 44 // "program": { | 47 // "program": { |
| 45 // "x86-32": {"url": "myprogram_x86-32.nexe"}, | 48 // "x86-32": {"url": "myprogram_x86-32.nexe"}, |
| 46 // "x86-64": {"url": "myprogram_x86-64.nexe"}, | 49 // "x86-64": {"url": "myprogram_x86-64.nexe"}, |
| 47 // "arm": {"url": "myprogram_arm.nexe"}, | 50 // "arm": {"url": "myprogram_arm.nexe"}, |
| 48 // "portable": {"pnacl-translate": {"url": "myprogram.pexe"} } | 51 // "portable": { |
| 52 // "pnacl-translate": { |
| 53 // "url": "myprogram.pexe", |
| 54 // "sha256": "..." |
| 55 // } |
| 56 // } |
| 49 // }, | 57 // }, |
| 50 // "interpreter": { | 58 // "interpreter": { |
| 51 // "x86-32": {"url": "interpreter_x86-32.nexe"}, | 59 // "x86-32": {"url": "interpreter_x86-32.nexe"}, |
| 52 // "x86-64": {"url": "interpreter_x86-64.nexe"}, | 60 // "x86-64": {"url": "interpreter_x86-64.nexe"}, |
| 53 // "arm": {"url": "interpreter_arm.nexe"} | 61 // "arm": {"url": "interpreter_arm.nexe"} |
| 54 // }, | 62 // }, |
| 55 // "files": { | 63 // "files": { |
| 56 // "foo.txt": { | 64 // "foo.txt": { |
| 57 // "portable": {"url": "foo.txt"} | 65 // "portable": {"url": "foo.txt"} |
| 58 // }, | 66 // }, |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 129 } | 137 } |
| 130 return true; | 138 return true; |
| 131 } | 139 } |
| 132 | 140 |
| 133 // Validate a "url" dictionary assuming it was resolved from container_key. | 141 // Validate a "url" dictionary assuming it was resolved from container_key. |
| 134 // E.g., "container_key" : { "url": "foo.txt" } | 142 // E.g., "container_key" : { "url": "foo.txt" } |
| 135 bool IsValidUrlSpec(const Json::Value& url_spec, | 143 bool IsValidUrlSpec(const Json::Value& url_spec, |
| 136 const nacl::string& container_key, | 144 const nacl::string& container_key, |
| 137 const nacl::string& parent_key, | 145 const nacl::string& parent_key, |
| 138 nacl::string* error_string) { | 146 nacl::string* error_string) { |
| 139 static const char* kManifestUrlSpecProperties[] = { | 147 static const char* kManifestUrlSpecRequired[] = { |
| 140 kUrlKey | 148 kUrlKey |
| 141 }; | 149 }; |
| 150 static const char* kManifestUrlSpecPlusOptional[] = { |
| 151 kUrlKey, |
| 152 kCacheIdentityKey |
| 153 }; |
| 142 if (!IsValidDictionary(url_spec, container_key, parent_key, | 154 if (!IsValidDictionary(url_spec, container_key, parent_key, |
| 143 kManifestUrlSpecProperties, | 155 kManifestUrlSpecPlusOptional, |
| 144 NACL_ARRAY_SIZE(kManifestUrlSpecProperties), | 156 NACL_ARRAY_SIZE(kManifestUrlSpecPlusOptional), |
| 145 kManifestUrlSpecProperties, | 157 kManifestUrlSpecRequired, |
| 146 NACL_ARRAY_SIZE(kManifestUrlSpecProperties), | 158 NACL_ARRAY_SIZE(kManifestUrlSpecRequired), |
| 147 error_string)) { | 159 error_string)) { |
| 148 return false; | 160 return false; |
| 149 } | 161 } |
| 150 Json::Value url = url_spec[kUrlKey]; | 162 Json::Value url = url_spec[kUrlKey]; |
| 151 if (!url.isString()) { | 163 if (!url.isString()) { |
| 152 nacl::stringstream error_stream; | 164 nacl::stringstream error_stream; |
| 153 error_stream << parent_key << " property '" << container_key << | 165 error_stream << parent_key << " property '" << container_key << |
| 154 "' has non-string value '" << url.toStyledString() << | 166 "' has non-string value '" << url.toStyledString() << |
| 155 "' for key '" << kUrlKey << "'."; | 167 "' for key '" << kUrlKey << "'."; |
| 156 *error_string = error_stream.str(); | 168 *error_string = error_stream.str(); |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 239 | 251 |
| 240 if (!has_isa && !has_portable) { | 252 if (!has_isa && !has_portable) { |
| 241 *error_string = parent_key + | 253 *error_string = parent_key + |
| 242 " no version given for current arch and no portable version found."; | 254 " no version given for current arch and no portable version found."; |
| 243 return false; | 255 return false; |
| 244 } | 256 } |
| 245 | 257 |
| 246 return true; | 258 return true; |
| 247 } | 259 } |
| 248 | 260 |
| 261 void GrabUrlAndCacheIdentity(const Json::Value& url_spec, |
| 262 nacl::string* url, |
| 263 nacl::string* cache_identity) { |
| 264 *url = url_spec[kUrlKey].asString(); |
| 265 if (url_spec.isMember(kCacheIdentityKey)) { |
| 266 *cache_identity = url_spec[kCacheIdentityKey].asString(); |
| 267 } |
| 268 } |
| 269 |
| 249 bool GetURLFromISADictionary(const Json::Value& dictionary, | 270 bool GetURLFromISADictionary(const Json::Value& dictionary, |
| 250 const nacl::string& parent_key, | 271 const nacl::string& parent_key, |
| 251 const nacl::string& sandbox_isa, | 272 const nacl::string& sandbox_isa, |
| 252 bool prefer_portable, | 273 bool prefer_portable, |
| 253 nacl::string* url, | 274 nacl::string* url, |
| 275 nacl::string* cache_identity, |
| 254 nacl::string* error_string, | 276 nacl::string* error_string, |
| 255 bool* pnacl_translate) { | 277 bool* pnacl_translate) { |
| 256 if (url == NULL || error_string == NULL || pnacl_translate == NULL) | 278 if (url == NULL || cache_identity == NULL || |
| 279 error_string == NULL || pnacl_translate == NULL) |
| 257 return false; | 280 return false; |
| 258 | 281 |
| 259 if (!IsValidISADictionary(dictionary, parent_key, sandbox_isa, error_string)) | 282 if (!IsValidISADictionary(dictionary, parent_key, sandbox_isa, error_string)) |
| 260 return false; | 283 return false; |
| 261 | 284 |
| 285 *url = ""; |
| 286 *cache_identity = ""; |
| 287 *pnacl_translate = false; |
| 288 |
| 262 // The call to IsValidISADictionary() above guarantees that either | 289 // The call to IsValidISADictionary() above guarantees that either |
| 263 // sandbox_isa or kPortableKey is present in the dictionary. | 290 // sandbox_isa or kPortableKey is present in the dictionary. |
| 264 bool has_portable = dictionary.isMember(kPortableKey); | 291 bool has_portable = dictionary.isMember(kPortableKey); |
| 265 bool has_isa = dictionary.isMember(sandbox_isa); | 292 bool has_isa = dictionary.isMember(sandbox_isa); |
| 266 nacl::string chosen_isa; | 293 nacl::string chosen_isa; |
| 267 if ((has_portable && prefer_portable) || !has_isa) { | 294 if ((has_portable && prefer_portable) || !has_isa) { |
| 268 chosen_isa = kPortableKey; | 295 chosen_isa = kPortableKey; |
| 269 } else { | 296 } else { |
| 270 chosen_isa = sandbox_isa; | 297 chosen_isa = sandbox_isa; |
| 271 } | 298 } |
| 272 const Json::Value& isa_spec = dictionary[chosen_isa]; | 299 const Json::Value& isa_spec = dictionary[chosen_isa]; |
| 273 // Check if this requires a pnacl-translate, otherwise just grab the URL. | 300 // Check if this requires a pnacl-translate, otherwise just grab the URL. |
| 274 // We may have pnacl-translate for isa-specific bitcode for CPU tuning. | 301 // We may have pnacl-translate for isa-specific bitcode for CPU tuning. |
| 275 if (isa_spec.isMember(kPnaclTranslateKey)) { | 302 if (isa_spec.isMember(kPnaclTranslateKey)) { |
| 276 *url = isa_spec[kPnaclTranslateKey][kUrlKey].asString(); | 303 GrabUrlAndCacheIdentity(isa_spec[kPnaclTranslateKey], url, cache_identity); |
| 277 *pnacl_translate = true; | 304 *pnacl_translate = true; |
| 278 } else { | 305 } else { |
| 279 *url = isa_spec[kUrlKey].asString(); | 306 GrabUrlAndCacheIdentity(isa_spec, url, cache_identity); |
| 280 *pnacl_translate = false; | 307 *pnacl_translate = false; |
| 281 } | 308 } |
| 309 |
| 282 return true; | 310 return true; |
| 283 } | 311 } |
| 284 | 312 |
| 285 bool GetKeyUrl(const Json::Value& dictionary, | 313 bool GetKeyUrl(const Json::Value& dictionary, |
| 286 const nacl::string& key, | 314 const nacl::string& key, |
| 287 const nacl::string& sandbox_isa, | 315 const nacl::string& sandbox_isa, |
| 288 const Manifest* manifest, | 316 const Manifest* manifest, |
| 289 bool prefer_portable, | 317 bool prefer_portable, |
| 290 nacl::string* full_url, | 318 nacl::string* full_url, |
| 319 nacl::string* cache_identity, |
| 291 ErrorInfo* error_info, | 320 ErrorInfo* error_info, |
| 292 bool* pnacl_translate) { | 321 bool* pnacl_translate) { |
| 293 CHECK(full_url != NULL && error_info != NULL); | 322 CHECK(full_url != NULL && error_info != NULL); |
| 294 *full_url = ""; | |
| 295 *pnacl_translate = false; | |
| 296 if (!dictionary.isMember(key)) { | 323 if (!dictionary.isMember(key)) { |
| 297 error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL, | 324 error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL, |
| 298 "file key not found in manifest"); | 325 "file key not found in manifest"); |
| 299 return false; | 326 return false; |
| 300 } | 327 } |
| 301 const Json::Value& isa_dict = dictionary[key]; | 328 const Json::Value& isa_dict = dictionary[key]; |
| 302 nacl::string error_string; | 329 nacl::string error_string; |
| 303 nacl::string relative_url; | 330 nacl::string relative_url; |
| 304 if (!GetURLFromISADictionary(isa_dict, key, sandbox_isa, prefer_portable, | 331 if (!GetURLFromISADictionary(isa_dict, key, sandbox_isa, prefer_portable, |
| 305 &relative_url, &error_string, pnacl_translate)) { | 332 &relative_url, cache_identity, |
| 333 &error_string, pnacl_translate)) { |
| 306 error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL, | 334 error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL, |
| 307 key + nacl::string(" manifest resolution error: ") + | 335 key + nacl::string(" manifest resolution error: ") + |
| 308 error_string); | 336 error_string); |
| 309 return false; | 337 return false; |
| 310 } | 338 } |
| 311 return manifest->ResolveURL(relative_url, full_url, error_info); | 339 return manifest->ResolveURL(relative_url, full_url, error_info); |
| 312 } | 340 } |
| 313 | 341 |
| 314 } // namespace | 342 } // namespace |
| 315 | 343 |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 430 "could not resolve url '" + relative_url + | 458 "could not resolve url '" + relative_url + |
| 431 "' relative to manifest base url '" + manifest_base_url_.c_str() + | 459 "' relative to manifest base url '" + manifest_base_url_.c_str() + |
| 432 "'."); | 460 "'."); |
| 433 return false; | 461 return false; |
| 434 } | 462 } |
| 435 *full_url = resolved_url.AsString(); | 463 *full_url = resolved_url.AsString(); |
| 436 return true; | 464 return true; |
| 437 } | 465 } |
| 438 | 466 |
| 439 bool JsonManifest::GetProgramURL(nacl::string* full_url, | 467 bool JsonManifest::GetProgramURL(nacl::string* full_url, |
| 468 nacl::string* cache_identity, |
| 440 ErrorInfo* error_info, | 469 ErrorInfo* error_info, |
| 441 bool* pnacl_translate) const { | 470 bool* pnacl_translate) const { |
| 442 if (full_url == NULL || error_info == NULL || pnacl_translate == NULL) | 471 if (full_url == NULL || cache_identity == NULL || |
| 472 error_info == NULL || pnacl_translate == NULL) |
| 443 return false; | 473 return false; |
| 444 | 474 |
| 445 Json::Value program = dictionary_[kProgramKey]; | 475 Json::Value program = dictionary_[kProgramKey]; |
| 446 | 476 |
| 447 nacl::string nexe_url; | 477 nacl::string nexe_url; |
| 448 nacl::string error_string; | 478 nacl::string error_string; |
| 449 | 479 |
| 450 if (!GetURLFromISADictionary(program, | 480 if (!GetURLFromISADictionary(program, |
| 451 kProgramKey, | 481 kProgramKey, |
| 452 sandbox_isa_, | 482 sandbox_isa_, |
| 453 prefer_portable_, | 483 prefer_portable_, |
| 454 &nexe_url, | 484 &nexe_url, |
| 485 cache_identity, |
| 455 &error_string, | 486 &error_string, |
| 456 pnacl_translate)) { | 487 pnacl_translate)) { |
| 457 error_info->SetReport(ERROR_MANIFEST_GET_NEXE_URL, | 488 error_info->SetReport(ERROR_MANIFEST_GET_NEXE_URL, |
| 458 nacl::string("program:") + sandbox_isa_ + | 489 nacl::string("program:") + sandbox_isa_ + |
| 459 error_string); | 490 error_string); |
| 460 return false; | 491 return false; |
| 461 } | 492 } |
| 462 | 493 |
| 463 return ResolveURL(nexe_url, full_url, error_info); | 494 return ResolveURL(nexe_url, full_url, error_info); |
| 464 } | 495 } |
| 465 | 496 |
| 466 bool JsonManifest::GetFileKeys(std::set<nacl::string>* keys) const { | 497 bool JsonManifest::GetFileKeys(std::set<nacl::string>* keys) const { |
| 467 if (!dictionary_.isMember(kFilesKey)) { | 498 if (!dictionary_.isMember(kFilesKey)) { |
| 468 // trivial success: no keys when there is no "files" section. | 499 // trivial success: no keys when there is no "files" section. |
| 469 return true; | 500 return true; |
| 470 } | 501 } |
| 471 const Json::Value& files = dictionary_[kFilesKey]; | 502 const Json::Value& files = dictionary_[kFilesKey]; |
| 472 CHECK(files.isObject()); | 503 CHECK(files.isObject()); |
| 473 Json::Value::Members members = files.getMemberNames(); | 504 Json::Value::Members members = files.getMemberNames(); |
| 474 for (size_t i = 0; i < members.size(); ++i) { | 505 for (size_t i = 0; i < members.size(); ++i) { |
| 475 keys->insert(members[i]); | 506 keys->insert(members[i]); |
| 476 } | 507 } |
| 477 return true; | 508 return true; |
| 478 } | 509 } |
| 479 | 510 |
| 480 bool JsonManifest::ResolveKey(const nacl::string& key, | 511 bool JsonManifest::ResolveKey(const nacl::string& key, |
| 481 nacl::string* full_url, | 512 nacl::string* full_url, |
| 513 nacl::string* cache_identity, |
| 482 ErrorInfo* error_info, | 514 ErrorInfo* error_info, |
| 483 bool* pnacl_translate) const { | 515 bool* pnacl_translate) const { |
| 484 NaClLog(3, "JsonManifest::ResolveKey(%s)\n", key.c_str()); | 516 NaClLog(3, "JsonManifest::ResolveKey(%s)\n", key.c_str()); |
| 485 // key must be one of kProgramKey or kFileKey '/' file-section-key | 517 // key must be one of kProgramKey or kFileKey '/' file-section-key |
| 486 | 518 |
| 487 if (full_url == NULL || error_info == NULL || pnacl_translate == NULL) | 519 if (full_url == NULL || cache_identity == NULL || |
| 520 error_info == NULL || pnacl_translate == NULL) |
| 488 return false; | 521 return false; |
| 489 | 522 |
| 490 *full_url = ""; | |
| 491 *pnacl_translate = false; | |
| 492 if (key == kProgramKey) { | 523 if (key == kProgramKey) { |
| 493 return GetKeyUrl(dictionary_, key, sandbox_isa_, this, prefer_portable_, | 524 return GetKeyUrl(dictionary_, key, sandbox_isa_, this, prefer_portable_, |
| 494 full_url, error_info, pnacl_translate); | 525 full_url, cache_identity, error_info, pnacl_translate); |
| 495 } | 526 } |
| 496 nacl::string::const_iterator p = find(key.begin(), key.end(), '/'); | 527 nacl::string::const_iterator p = find(key.begin(), key.end(), '/'); |
| 497 if (p == key.end()) { | 528 if (p == key.end()) { |
| 498 error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL, | 529 error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL, |
| 499 nacl::string("ResolveKey: invalid key, no slash: ") | 530 nacl::string("ResolveKey: invalid key, no slash: ") |
| 500 + key); | 531 + key); |
| 501 return false; | 532 return false; |
| 502 } | 533 } |
| 503 | 534 |
| 504 // generalize to permit other sections? | 535 // generalize to permit other sections? |
| (...skipping 14 matching lines...) Expand all Loading... |
| 519 nacl::string("ResolveKey: no \"files\" dictionary")); | 550 nacl::string("ResolveKey: no \"files\" dictionary")); |
| 520 return false; | 551 return false; |
| 521 } | 552 } |
| 522 if (!files.isMember(rest)) { | 553 if (!files.isMember(rest)) { |
| 523 error_info->SetReport( | 554 error_info->SetReport( |
| 524 ERROR_MANIFEST_RESOLVE_URL, | 555 ERROR_MANIFEST_RESOLVE_URL, |
| 525 nacl::string("ResolveKey: no such \"files\" entry: ") + key); | 556 nacl::string("ResolveKey: no such \"files\" entry: ") + key); |
| 526 return false; | 557 return false; |
| 527 } | 558 } |
| 528 return GetKeyUrl(files, rest, sandbox_isa_, this, prefer_portable_, | 559 return GetKeyUrl(files, rest, sandbox_isa_, this, prefer_portable_, |
| 529 full_url, error_info, pnacl_translate); | 560 full_url, cache_identity, error_info, pnacl_translate); |
| 530 } | 561 } |
| 531 | 562 |
| 532 } // namespace plugin | 563 } // namespace plugin |
| OLD | NEW |