| Index: trunk/src/components/nacl/renderer/json_manifest.cc
|
| ===================================================================
|
| --- trunk/src/components/nacl/renderer/json_manifest.cc (revision 268257)
|
| +++ trunk/src/components/nacl/renderer/json_manifest.cc (working copy)
|
| @@ -1,654 +0,0 @@
|
| -// Copyright 2014 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "components/nacl/renderer/json_manifest.h"
|
| -
|
| -#include <set>
|
| -
|
| -#include "base/logging.h"
|
| -#include "base/macros.h"
|
| -#include "components/nacl/renderer/nexe_load_manager.h"
|
| -#include "third_party/jsoncpp/source/include/json/reader.h"
|
| -#include "third_party/jsoncpp/source/include/json/value.h"
|
| -#include "url/gurl.h"
|
| -
|
| -namespace nacl {
|
| -
|
| -namespace {
|
| -// Top-level section name keys
|
| -const char* const kProgramKey = "program";
|
| -const char* const kInterpreterKey = "interpreter";
|
| -const char* const kFilesKey = "files";
|
| -
|
| -// ISA Dictionary keys
|
| -const char* const kX8632Key = "x86-32";
|
| -const char* const kX8632NonSFIKey = "x86-32-nonsfi";
|
| -const char* const kX8664Key = "x86-64";
|
| -const char* const kX8664NonSFIKey = "x86-64-nonsfi";
|
| -const char* const kArmKey = "arm";
|
| -const char* const kArmNonSFIKey = "arm-nonsfi";
|
| -const char* const kPortableKey = "portable";
|
| -
|
| -// Url Resolution keys
|
| -const char* const kPnaclDebugKey = "pnacl-debug";
|
| -const char* const kPnaclTranslateKey = "pnacl-translate";
|
| -const char* const kUrlKey = "url";
|
| -
|
| -// PNaCl keys
|
| -const char* const kOptLevelKey = "optlevel";
|
| -
|
| -// Sample NaCl manifest file:
|
| -// {
|
| -// "program": {
|
| -// "x86-32": {"url": "myprogram_x86-32.nexe"},
|
| -// "x86-64": {"url": "myprogram_x86-64.nexe"},
|
| -// "arm": {"url": "myprogram_arm.nexe"}
|
| -// },
|
| -// "interpreter": {
|
| -// "x86-32": {"url": "interpreter_x86-32.nexe"},
|
| -// "x86-64": {"url": "interpreter_x86-64.nexe"},
|
| -// "arm": {"url": "interpreter_arm.nexe"}
|
| -// },
|
| -// "files": {
|
| -// "foo.txt": {
|
| -// "portable": {"url": "foo.txt"}
|
| -// },
|
| -// "bar.txt": {
|
| -// "x86-32": {"url": "x86-32/bar.txt"},
|
| -// "portable": {"url": "bar.txt"}
|
| -// },
|
| -// "libfoo.so": {
|
| -// "x86-64" : { "url": "..." }
|
| -// }
|
| -// }
|
| -// }
|
| -
|
| -// Sample PNaCl manifest file:
|
| -// {
|
| -// "program": {
|
| -// "portable": {
|
| -// "pnacl-translate": {
|
| -// "url": "myprogram.pexe"
|
| -// },
|
| -// "pnacl-debug": {
|
| -// "url": "myprogram.debug.pexe",
|
| -// "opt_level": 0
|
| -// }
|
| -// }
|
| -// },
|
| -// "files": {
|
| -// "foo.txt": {
|
| -// "portable": {"url": "foo.txt"}
|
| -// },
|
| -// "bar.txt": {
|
| -// "portable": {"url": "bar.txt"}
|
| -// }
|
| -// }
|
| -// }
|
| -
|
| -// Returns the key for the architecture in non-SFI mode.
|
| -std::string GetNonSFIKey(const std::string& sandbox_isa) {
|
| - return sandbox_isa + "-nonsfi";
|
| -}
|
| -
|
| -// Looks up |property_name| in the vector |valid_names| with length
|
| -// |valid_name_count|. Returns true if |property_name| is found.
|
| -bool FindMatchingProperty(const std::string& property_name,
|
| - const char** valid_names,
|
| - size_t valid_name_count) {
|
| - for (size_t i = 0; i < valid_name_count; ++i) {
|
| - if (property_name == valid_names[i]) {
|
| - return true;
|
| - }
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -// Return true if this is a valid dictionary. Having only keys present in
|
| -// |valid_keys| and having at least the keys in |required_keys|.
|
| -// Error messages will be placed in |error_string|, given that the dictionary
|
| -// was the property value of |container_key|.
|
| -// E.g., "container_key" : dictionary
|
| -bool IsValidDictionary(const Json::Value& dictionary,
|
| - const std::string& container_key,
|
| - const std::string& parent_key,
|
| - const char** valid_keys,
|
| - size_t valid_key_count,
|
| - const char** required_keys,
|
| - size_t required_key_count,
|
| - std::string* error_string) {
|
| - if (!dictionary.isObject()) {
|
| - std::stringstream error_stream;
|
| - error_stream << parent_key << " property '" << container_key
|
| - << "' is non-dictionary value '"
|
| - << dictionary.toStyledString() << "'.";
|
| - *error_string = error_stream.str();
|
| - return false;
|
| - }
|
| - // Check for unknown dictionary members.
|
| - Json::Value::Members members = dictionary.getMemberNames();
|
| - for (size_t i = 0; i < members.size(); ++i) {
|
| - std::string property_name = members[i];
|
| - if (!FindMatchingProperty(property_name,
|
| - valid_keys,
|
| - valid_key_count)) {
|
| - // For forward compatibility, we do not prohibit other keys being in
|
| - // the dictionary.
|
| - VLOG(1) << "WARNING: '" << parent_key << "' property '"
|
| - << container_key << "' has unknown key '"
|
| - << property_name << "'.";
|
| - }
|
| - }
|
| - // Check for required members.
|
| - for (size_t i = 0; i < required_key_count; ++i) {
|
| - if (!dictionary.isMember(required_keys[i])) {
|
| - std::stringstream error_stream;
|
| - error_stream << parent_key << " property '" << container_key
|
| - << "' does not have required key: '"
|
| - << required_keys[i] << "'.";
|
| - *error_string = error_stream.str();
|
| - return false;
|
| - }
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -// Validate a "url" dictionary assuming it was resolved from container_key.
|
| -// E.g., "container_key" : { "url": "foo.txt" }
|
| -bool IsValidUrlSpec(const Json::Value& url_spec,
|
| - const std::string& container_key,
|
| - const std::string& parent_key,
|
| - const std::string& sandbox_isa,
|
| - std::string* error_string) {
|
| - static const char* kManifestUrlSpecRequired[] = {
|
| - kUrlKey
|
| - };
|
| - const char** urlSpecPlusOptional;
|
| - size_t urlSpecPlusOptionalLength;
|
| - if (sandbox_isa == kPortableKey) {
|
| - static const char* kPnaclUrlSpecPlusOptional[] = {
|
| - kUrlKey,
|
| - kOptLevelKey,
|
| - };
|
| - urlSpecPlusOptional = kPnaclUrlSpecPlusOptional;
|
| - urlSpecPlusOptionalLength = arraysize(kPnaclUrlSpecPlusOptional);
|
| - } else {
|
| - // URL specifications must not contain "pnacl-translate" keys.
|
| - // This prohibits NaCl clients from invoking PNaCl.
|
| - if (url_spec.isMember(kPnaclTranslateKey)) {
|
| - std::stringstream error_stream;
|
| - error_stream << "PNaCl-like NMF with application/x-nacl mimetype instead "
|
| - << "of x-pnacl mimetype (has " << kPnaclTranslateKey << ").";
|
| - *error_string = error_stream.str();
|
| - return false;
|
| - }
|
| - urlSpecPlusOptional = kManifestUrlSpecRequired;
|
| - urlSpecPlusOptionalLength = arraysize(kManifestUrlSpecRequired);
|
| - }
|
| - if (!IsValidDictionary(url_spec, container_key, parent_key,
|
| - urlSpecPlusOptional,
|
| - urlSpecPlusOptionalLength,
|
| - kManifestUrlSpecRequired,
|
| - arraysize(kManifestUrlSpecRequired),
|
| - error_string)) {
|
| - return false;
|
| - }
|
| - // Verify the correct types of the fields if they exist.
|
| - Json::Value url = url_spec[kUrlKey];
|
| - if (!url.isString()) {
|
| - std::stringstream error_stream;
|
| - error_stream << parent_key << " property '" << container_key <<
|
| - "' has non-string value '" << url.toStyledString() <<
|
| - "' for key '" << kUrlKey << "'.";
|
| - *error_string = error_stream.str();
|
| - return false;
|
| - }
|
| - Json::Value opt_level = url_spec[kOptLevelKey];
|
| - if (!opt_level.empty() && !opt_level.isNumeric()) {
|
| - std::stringstream error_stream;
|
| - error_stream << parent_key << " property '" << container_key <<
|
| - "' has non-numeric value '" << opt_level.toStyledString() <<
|
| - "' for key '" << kOptLevelKey << "'.";
|
| - *error_string = error_stream.str();
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -// Validate a "pnacl-translate" or "pnacl-debug" dictionary, assuming
|
| -// it was resolved from container_key.
|
| -// E.g., "container_key" : { "pnacl-translate" : URLSpec }
|
| -bool IsValidPnaclTranslateSpec(const Json::Value& pnacl_spec,
|
| - const std::string& container_key,
|
| - const std::string& parent_key,
|
| - const std::string& sandbox_isa,
|
| - std::string* error_string) {
|
| - static const char* kManifestPnaclSpecValid[] = {
|
| - kPnaclDebugKey,
|
| - kPnaclTranslateKey
|
| - };
|
| - static const char* kManifestPnaclSpecRequired[] = { kPnaclTranslateKey };
|
| - if (!IsValidDictionary(pnacl_spec, container_key, parent_key,
|
| - kManifestPnaclSpecValid,
|
| - arraysize(kManifestPnaclSpecValid),
|
| - kManifestPnaclSpecRequired,
|
| - arraysize(kManifestPnaclSpecRequired),
|
| - error_string)) {
|
| - return false;
|
| - }
|
| - Json::Value url_spec = pnacl_spec[kPnaclTranslateKey];
|
| - return IsValidUrlSpec(url_spec, kPnaclTranslateKey,
|
| - container_key, sandbox_isa, error_string);
|
| -}
|
| -
|
| -// Validates that |dictionary| is a valid ISA dictionary. An ISA dictionary
|
| -// is validated to have keys from within the set of recognized ISAs. Unknown
|
| -// ISAs are allowed, but ignored and warnings are produced. It is also
|
| -// validated
|
| -// that it must have an entry to match the ISA specified in |sandbox_isa| or
|
| -// have a fallback 'portable' entry if there is no match. Returns true if
|
| -// |dictionary| is an ISA to URL map. Sets |error_info| to something
|
| -// descriptive if it fails.
|
| -bool IsValidISADictionary(const Json::Value& dictionary,
|
| - const std::string& parent_key,
|
| - const std::string& sandbox_isa,
|
| - bool must_find_matching_entry,
|
| - bool nonsfi_enabled,
|
| - JsonManifest::ErrorInfo* error_info) {
|
| - // An ISA to URL dictionary has to be an object.
|
| - if (!dictionary.isObject()) {
|
| - error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE;
|
| - error_info->string = std::string("manifest: ") + parent_key +
|
| - " property is not an ISA to URL dictionary";
|
| - return false;
|
| - }
|
| - // Build the set of reserved ISA dictionary keys.
|
| - const char** isaProperties;
|
| - size_t isaPropertiesLength;
|
| - if (sandbox_isa == kPortableKey) {
|
| - // The known values for PNaCl ISA dictionaries in the manifest.
|
| - static const char* kPnaclManifestISAProperties[] = {
|
| - kPortableKey
|
| - };
|
| - isaProperties = kPnaclManifestISAProperties;
|
| - isaPropertiesLength = arraysize(kPnaclManifestISAProperties);
|
| - } else {
|
| - // The known values for NaCl ISA dictionaries in the manifest.
|
| - static const char* kNaClManifestISAProperties[] = {
|
| - kX8632Key,
|
| - kX8632NonSFIKey,
|
| - kX8664Key,
|
| - kX8664NonSFIKey,
|
| - kArmKey,
|
| - kArmNonSFIKey,
|
| - // "portable" is here to allow checking that, if present, it can
|
| - // only refer to an URL, such as for a data file, and not to
|
| - // "pnacl-translate", which would cause the creation of a nexe.
|
| - kPortableKey
|
| - };
|
| - isaProperties = kNaClManifestISAProperties;
|
| - isaPropertiesLength = arraysize(kNaClManifestISAProperties);
|
| - }
|
| - // Check that entries in the dictionary are structurally correct.
|
| - Json::Value::Members members = dictionary.getMemberNames();
|
| - for (size_t i = 0; i < members.size(); ++i) {
|
| - std::string property_name = members[i];
|
| - Json::Value property_value = dictionary[property_name];
|
| - std::string error_string;
|
| - if (FindMatchingProperty(property_name,
|
| - isaProperties,
|
| - isaPropertiesLength)) {
|
| - // For NaCl, arch entries can only be
|
| - // "arch/portable" : URLSpec
|
| - // For PNaCl arch in "program" dictionary entries can be
|
| - // "portable" : { "pnacl-translate": URLSpec }
|
| - // or "portable" : { "pnacl-debug": URLSpec }
|
| - // For PNaCl arch elsewhere, dictionary entries can only be
|
| - // "portable" : URLSpec
|
| - if ((sandbox_isa != kPortableKey &&
|
| - !IsValidUrlSpec(property_value, property_name, parent_key,
|
| - sandbox_isa, &error_string)) ||
|
| - (sandbox_isa == kPortableKey &&
|
| - parent_key == kProgramKey &&
|
| - !IsValidPnaclTranslateSpec(property_value, property_name, parent_key,
|
| - sandbox_isa, &error_string)) ||
|
| - (sandbox_isa == kPortableKey &&
|
| - parent_key != kProgramKey &&
|
| - !IsValidUrlSpec(property_value, property_name, parent_key,
|
| - sandbox_isa, &error_string))) {
|
| - error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE;
|
| - error_info->string = "manifest: " + error_string;
|
| - return false;
|
| - }
|
| - } else {
|
| - // For forward compatibility, we do not prohibit other keys being in
|
| - // the dictionary, as they may be architectures supported in later
|
| - // versions. However, the value of these entries must be an URLSpec.
|
| - VLOG(1) << "IsValidISADictionary: unrecognized key '"
|
| - << property_name << "'.";
|
| - if (!IsValidUrlSpec(property_value, property_name, parent_key,
|
| - sandbox_isa, &error_string)) {
|
| - error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE;
|
| - error_info->string = "manifest: " + error_string;
|
| - return false;
|
| - }
|
| - }
|
| - }
|
| -
|
| - if (sandbox_isa == kPortableKey) {
|
| - if (!dictionary.isMember(kPortableKey)) {
|
| - error_info->error = PP_NACL_ERROR_MANIFEST_PROGRAM_MISSING_ARCH;
|
| - error_info->string = "manifest: no version of " + parent_key +
|
| - " given for portable.";
|
| - return false;
|
| - }
|
| - } else if (must_find_matching_entry) {
|
| - // TODO(elijahtaylor) add ISA resolver here if we expand ISAs to include
|
| - // micro-architectures that can resolve to multiple valid sandboxes.
|
| - bool has_isa = dictionary.isMember(sandbox_isa);
|
| - bool has_nonsfi_isa =
|
| - nonsfi_enabled && dictionary.isMember(GetNonSFIKey(sandbox_isa));
|
| - bool has_portable = dictionary.isMember(kPortableKey);
|
| -
|
| - if (!has_isa && !has_nonsfi_isa && !has_portable) {
|
| - error_info->error = PP_NACL_ERROR_MANIFEST_PROGRAM_MISSING_ARCH;
|
| - error_info->string = "manifest: no version of " + parent_key +
|
| - " given for current arch and no portable version found.";
|
| - return false;
|
| - }
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -void GrabUrlAndPnaclOptions(const Json::Value& url_spec,
|
| - std::string* url,
|
| - PP_PNaClOptions* pnacl_options) {
|
| - *url = url_spec[kUrlKey].asString();
|
| - pnacl_options->translate = PP_TRUE;
|
| - if (url_spec.isMember(kOptLevelKey)) {
|
| - int32_t opt_raw = url_spec[kOptLevelKey].asInt();
|
| - // Currently only allow 0 or 2, since that is what we test.
|
| - if (opt_raw <= 0)
|
| - pnacl_options->opt_level = 0;
|
| - else
|
| - pnacl_options->opt_level = 2;
|
| - }
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -JsonManifest::JsonManifest(const std::string& manifest_base_url,
|
| - const std::string& sandbox_isa,
|
| - bool nonsfi_enabled,
|
| - bool pnacl_debug)
|
| - : manifest_base_url_(manifest_base_url),
|
| - sandbox_isa_(sandbox_isa),
|
| - nonsfi_enabled_(nonsfi_enabled),
|
| - pnacl_debug_(pnacl_debug) { }
|
| -
|
| -bool JsonManifest::Init(const std::string& manifest_json,
|
| - ErrorInfo* error_info) {
|
| - CHECK(error_info);
|
| -
|
| - Json::Reader reader;
|
| - if (!reader.parse(manifest_json, dictionary_)) {
|
| - std::string json_error = reader.getFormattedErrorMessages();
|
| - error_info->error = PP_NACL_ERROR_MANIFEST_PARSING;
|
| - error_info->string = "manifest JSON parsing failed: " + json_error;
|
| - return false;
|
| - }
|
| - // Parse has ensured the string was valid JSON. Check that it matches the
|
| - // manifest schema.
|
| - return MatchesSchema(error_info);
|
| -}
|
| -
|
| -bool JsonManifest::GetProgramURL(std::string* full_url,
|
| - PP_PNaClOptions* pnacl_options,
|
| - bool* uses_nonsfi_mode,
|
| - ErrorInfo* error_info) const {
|
| - if (!full_url)
|
| - return false;
|
| - CHECK(pnacl_options);
|
| - CHECK(uses_nonsfi_mode);
|
| - CHECK(error_info);
|
| -
|
| - const Json::Value& program = dictionary_[kProgramKey];
|
| - std::string nexe_url;
|
| - if (!GetURLFromISADictionary(program,
|
| - kProgramKey,
|
| - &nexe_url,
|
| - pnacl_options,
|
| - uses_nonsfi_mode,
|
| - error_info)) {
|
| - return false;
|
| - }
|
| -
|
| - // The contents of the manifest are resolved relative to the manifest URL.
|
| - GURL base_gurl(manifest_base_url_);
|
| - if (!base_gurl.is_valid())
|
| - return false;
|
| -
|
| - GURL resolved_gurl = base_gurl.Resolve(nexe_url);
|
| - if (!resolved_gurl.is_valid()) {
|
| - error_info->error = PP_NACL_ERROR_MANIFEST_RESOLVE_URL;
|
| - error_info->string =
|
| - "could not resolve url '" + nexe_url +
|
| - "' relative to manifest base url '" + manifest_base_url_.c_str() +
|
| - "'.";
|
| - return false;
|
| - }
|
| - *full_url = resolved_gurl.possibly_invalid_spec();
|
| - return true;
|
| -}
|
| -
|
| -bool JsonManifest::ResolveKey(const std::string& key,
|
| - std::string* full_url,
|
| - PP_PNaClOptions* pnacl_options) const {
|
| - // key must be one of kProgramKey or kFileKey '/' file-section-key
|
| - if (full_url == NULL || pnacl_options == NULL)
|
| - return false;
|
| -
|
| - if (key == kProgramKey)
|
| - return GetKeyUrl(dictionary_, key, full_url, pnacl_options);
|
| -
|
| - std::string::const_iterator p = find(key.begin(), key.end(), '/');
|
| - if (p == key.end()) {
|
| - VLOG(1) << "ResolveKey failed: invalid key, no slash: " << key;
|
| - return false;
|
| - }
|
| -
|
| - // generalize to permit other sections?
|
| - std::string prefix(key.begin(), p);
|
| - if (prefix != kFilesKey) {
|
| - VLOG(1) << "ResolveKey failed: invalid key, no \"files\" prefix: " << key;
|
| - return false;
|
| - }
|
| -
|
| - const Json::Value& files = dictionary_[kFilesKey];
|
| - if (!files.isObject()) {
|
| - VLOG(1) << "ResolveKey failed: no \"files\" dictionary";
|
| - return false;
|
| - }
|
| -
|
| - std::string rest(p + 1, key.end());
|
| - if (!files.isMember(rest)) {
|
| - VLOG(1) << "ResolveKey failed: no such \"files\" entry: " << key;
|
| - return false;
|
| - }
|
| - return GetKeyUrl(files, rest, full_url, pnacl_options);
|
| -}
|
| -
|
| -bool JsonManifest::MatchesSchema(ErrorInfo* error_info) {
|
| - if (!dictionary_.isObject()) {
|
| - error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE;
|
| - error_info->string = "manifest: is not a json dictionary.";
|
| - return false;
|
| - }
|
| - Json::Value::Members members = dictionary_.getMemberNames();
|
| - for (size_t i = 0; i < members.size(); ++i) {
|
| - // The top level dictionary entries valid in the manifest file.
|
| - static const char* kManifestTopLevelProperties[] = { kProgramKey,
|
| - kInterpreterKey,
|
| - kFilesKey };
|
| - std::string property_name = members[i];
|
| - if (!FindMatchingProperty(property_name,
|
| - kManifestTopLevelProperties,
|
| - arraysize(kManifestTopLevelProperties))) {
|
| - VLOG(1) << "JsonManifest::MatchesSchema: WARNING: unknown top-level "
|
| - << "section '" << property_name << "' in manifest.";
|
| - }
|
| - }
|
| -
|
| - // A manifest file must have a program section.
|
| - if (!dictionary_.isMember(kProgramKey)) {
|
| - error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE;
|
| - error_info->string = std::string("manifest: missing '") + kProgramKey +
|
| - "' section.";
|
| - return false;
|
| - }
|
| -
|
| - // Validate the program section.
|
| - // There must be a matching (portable or sandbox_isa_) entry for program for
|
| - // NaCl.
|
| - if (!IsValidISADictionary(dictionary_[kProgramKey],
|
| - kProgramKey,
|
| - sandbox_isa_,
|
| - true,
|
| - nonsfi_enabled_,
|
| - error_info)) {
|
| - return false;
|
| - }
|
| -
|
| - // Validate the interpreter section (if given).
|
| - // There must be a matching (portable or sandbox_isa_) entry for interpreter
|
| - // for NaCl.
|
| - if (dictionary_.isMember(kInterpreterKey)) {
|
| - if (!IsValidISADictionary(dictionary_[kInterpreterKey],
|
| - kInterpreterKey,
|
| - sandbox_isa_,
|
| - true,
|
| - nonsfi_enabled_,
|
| - error_info)) {
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - // Validate the file dictionary (if given).
|
| - // The "files" key does not require a matching (portable or sandbox_isa_)
|
| - // entry at schema validation time for NaCl. This allows manifests to
|
| - // specify resources that are only loaded for a particular sandbox_isa.
|
| - if (dictionary_.isMember(kFilesKey)) {
|
| - const Json::Value& files = dictionary_[kFilesKey];
|
| - if (!files.isObject()) {
|
| - error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE;
|
| - error_info->string = std::string("manifest: '") + kFilesKey +
|
| - "' is not a dictionary.";
|
| - }
|
| - Json::Value::Members members = files.getMemberNames();
|
| - for (size_t i = 0; i < members.size(); ++i) {
|
| - std::string file_name = members[i];
|
| - if (!IsValidISADictionary(files[file_name],
|
| - file_name,
|
| - sandbox_isa_,
|
| - false,
|
| - nonsfi_enabled_,
|
| - error_info)) {
|
| - return false;
|
| - }
|
| - }
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool JsonManifest::GetKeyUrl(const Json::Value& dictionary,
|
| - const std::string& key,
|
| - std::string* full_url,
|
| - PP_PNaClOptions* pnacl_options) const {
|
| - DCHECK(full_url && pnacl_options);
|
| - if (!dictionary.isMember(key)) {
|
| - VLOG(1) << "GetKeyUrl failed: file " << key << " not found in manifest.";
|
| - return false;
|
| - }
|
| - const Json::Value& isa_dict = dictionary[key];
|
| - std::string relative_url;
|
| - bool uses_nonsfi_mode;
|
| - ErrorInfo ignored_error_info;
|
| - if (!GetURLFromISADictionary(isa_dict, key, &relative_url,
|
| - pnacl_options, &uses_nonsfi_mode,
|
| - &ignored_error_info))
|
| - return false;
|
| -
|
| - // The contents of the manifest are resolved relative to the manifest URL.
|
| - GURL base_gurl(manifest_base_url_);
|
| - if (!base_gurl.is_valid())
|
| - return false;
|
| - GURL resolved_gurl = base_gurl.Resolve(relative_url);
|
| - if (!resolved_gurl.is_valid())
|
| - return false;
|
| - *full_url = resolved_gurl.possibly_invalid_spec();
|
| - return true;
|
| -}
|
| -
|
| -bool JsonManifest::GetURLFromISADictionary(const Json::Value& dictionary,
|
| - const std::string& parent_key,
|
| - std::string* url,
|
| - PP_PNaClOptions* pnacl_options,
|
| - bool* uses_nonsfi_mode,
|
| - ErrorInfo* error_info) const {
|
| - DCHECK(url && pnacl_options && error_info);
|
| -
|
| - // When the application actually requests a resolved URL, we must have
|
| - // a matching entry (sandbox_isa_ or portable) for NaCl.
|
| - ErrorInfo ignored_error_info;
|
| - if (!IsValidISADictionary(dictionary, parent_key, sandbox_isa_, true,
|
| - nonsfi_enabled_, &ignored_error_info)) {
|
| - error_info->error = PP_NACL_ERROR_MANIFEST_RESOLVE_URL;
|
| - error_info->string = "architecture " + sandbox_isa_ +
|
| - " is not found for file " + parent_key;
|
| - return false;
|
| - }
|
| -
|
| - // The call to IsValidISADictionary() above guarantees that either
|
| - // sandbox_isa_, its nonsfi mode, or kPortableKey is present in the
|
| - // dictionary.
|
| - *uses_nonsfi_mode = false;
|
| - std::string chosen_isa;
|
| - if (sandbox_isa_ == kPortableKey) {
|
| - chosen_isa = kPortableKey;
|
| - } else {
|
| - std::string nonsfi_isa = GetNonSFIKey(sandbox_isa_);
|
| - if (nonsfi_enabled_ && dictionary.isMember(nonsfi_isa)) {
|
| - chosen_isa = nonsfi_isa;
|
| - *uses_nonsfi_mode = true;
|
| - } else if (dictionary.isMember(sandbox_isa_)) {
|
| - chosen_isa = sandbox_isa_;
|
| - } else if (dictionary.isMember(kPortableKey)) {
|
| - chosen_isa = kPortableKey;
|
| - } else {
|
| - // Should not reach here, because the earlier IsValidISADictionary()
|
| - // call checked that the manifest covers the current architecture.
|
| - DCHECK(false);
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - const Json::Value& isa_spec = dictionary[chosen_isa];
|
| - // If the PNaCl debug flag is turned on, look for pnacl-debug entries first.
|
| - // If found, mark that it is a debug URL. Otherwise, fall back to
|
| - // checking for pnacl-translate URLs, etc. and don't mark it as a debug URL.
|
| - if (pnacl_debug_ && isa_spec.isMember(kPnaclDebugKey)) {
|
| - GrabUrlAndPnaclOptions(isa_spec[kPnaclDebugKey], url, pnacl_options);
|
| - pnacl_options->is_debug = PP_TRUE;
|
| - } else if (isa_spec.isMember(kPnaclTranslateKey)) {
|
| - GrabUrlAndPnaclOptions(isa_spec[kPnaclTranslateKey], url, pnacl_options);
|
| - } else {
|
| - // NaCl
|
| - *url = isa_spec[kUrlKey].asString();
|
| - pnacl_options->translate = PP_FALSE;
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -} // namespace nacl
|
|
|