15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright (c) 2012 The Chromium Authors. All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Use of this source code is governed by a BSD-style license that can be
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * found in the LICENSE file.
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "ppapi/native_client/src/trusted/plugin/json_manifest.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "native_client/src/include/nacl_base.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "native_client/src/include/nacl_macros.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "native_client/src/include/nacl_string.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "native_client/src/include/portability.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "native_client/src/shared/platform/nacl_check.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/dev/url_util_dev.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/var.h"
20ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "ppapi/native_client/src/trusted/plugin/plugin_error.h"
21ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "ppapi/native_client/src/trusted/plugin/pnacl_options.h"
22ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "ppapi/native_client/src/trusted/plugin/utility.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/jsoncpp/source/include/json/reader.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace plugin {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Top-level section name keys
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* const kProgramKey =     "program";
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* const kInterpreterKey = "interpreter";
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* const kFilesKey =       "files";
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ISA Dictionary keys
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* const kX8632Key =       "x86-32";
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* const kX8664Key =       "x86-64";
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* const kArmKey =         "arm";
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* const kPortableKey =    "portable";
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Url Resolution keys
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* const kPnaclTranslateKey = "pnacl-translate";
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* const kUrlKey =            "url";
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
43ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// PNaCl keys
44ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochconst char* const kOptLevelKey = "optlevel";
45ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// DEPRECATED! TODO(jvoung): remove the error message after launch.
46ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochconst char* const kOptLevelKeyDeprecated = "-O";
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Sample NaCl manifest file:
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   "program": {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     "x86-32": {"url": "myprogram_x86-32.nexe"},
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     "x86-64": {"url": "myprogram_x86-64.nexe"},
537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)//     "arm": {"url": "myprogram_arm.nexe"}
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   },
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   "interpreter": {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     "x86-32": {"url": "interpreter_x86-32.nexe"},
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     "x86-64": {"url": "interpreter_x86-64.nexe"},
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     "arm": {"url": "interpreter_arm.nexe"}
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   },
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   "files": {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     "foo.txt": {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//       "portable": {"url": "foo.txt"}
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     },
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     "bar.txt": {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//       "x86-32": {"url": "x86-32/bar.txt"},
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//       "portable": {"url": "bar.txt"}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     },
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     "libfoo.so": {
697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)//       "x86-64" : { "url": "..." }
707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)//     }
717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)//   }
727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// }
737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// Sample PNaCl manifest file:
757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// {
767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)//   "program": {
777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)//     "portable": {
787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)//       "pnacl-translate": {
797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)//         "url": "myprogram.pexe",
80ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch//         "optlevel": 0
817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)//       }
827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)//     }
837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)//   },
847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)//   "files": {
857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)//     "foo.txt": {
867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)//       "portable": {"url": "foo.txt"}
877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)//     },
887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)//     "bar.txt": {
897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)//       "portable": {"url": "bar.txt"}
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     }
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   }
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// }
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Looks up |property_name| in the vector |valid_names| with length
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |valid_name_count|.  Returns true if |property_name| is found.
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FindMatchingProperty(const nacl::string& property_name,
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const char** valid_names,
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          size_t valid_name_count) {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < valid_name_count; ++i) {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (property_name == valid_names[i]) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return true if this is a valid dictionary.  Having only keys present in
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |valid_keys| and having at least the keys in |required_keys|.
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Error messages will be placed in |error_string|, given that the dictionary
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// was the property value of |container_key|.
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// E.g., "container_key" : dictionary
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsValidDictionary(const Json::Value& dictionary,
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const nacl::string& container_key,
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const nacl::string& parent_key,
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const char** valid_keys,
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       size_t valid_key_count,
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const char** required_keys,
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       size_t required_key_count,
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       nacl::string* error_string) {
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!dictionary.isObject()) {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nacl::stringstream error_stream;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_stream << parent_key << " property '" << container_key
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << "' is non-dictionary value '"
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << dictionary.toStyledString() << "'.";
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *error_string = error_stream.str();
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check for unknown dictionary members.
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Json::Value::Members members = dictionary.getMemberNames();
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < members.size(); ++i) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nacl::string property_name = members[i];
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!FindMatchingProperty(property_name,
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              valid_keys,
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              valid_key_count)) {
1357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // For forward compatibility, we do not prohibit other keys being in
1367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // the dictionary.
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PLUGIN_PRINTF(("WARNING: '%s' property '%s' has unknown key '%s'.\n",
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     parent_key.c_str(),
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     container_key.c_str(), property_name.c_str()));
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check for required members.
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < required_key_count; ++i) {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!dictionary.isMember(required_keys[i])) {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      nacl::stringstream error_stream;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error_stream << parent_key << " property '" << container_key
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   << "' does not have required key: '"
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   << required_keys[i] << "'.";
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *error_string = error_stream.str();
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Validate a "url" dictionary assuming it was resolved from container_key.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// E.g., "container_key" : { "url": "foo.txt" }
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsValidUrlSpec(const Json::Value& url_spec,
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    const nacl::string& container_key,
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    const nacl::string& parent_key,
1617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                    const nacl::string& sandbox_isa,
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    nacl::string* error_string) {
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const char* kManifestUrlSpecRequired[] = {
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kUrlKey
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  const char** urlSpecPlusOptional;
1677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  size_t urlSpecPlusOptionalLength;
1687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (sandbox_isa == kPortableKey) {
1697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    static const char* kPnaclUrlSpecPlusOptional[] = {
1707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      kUrlKey,
1717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      kOptLevelKey,
1727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    };
1737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    urlSpecPlusOptional = kPnaclUrlSpecPlusOptional;
1747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    urlSpecPlusOptionalLength = NACL_ARRAY_SIZE(kPnaclUrlSpecPlusOptional);
1757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  } else {
1767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    urlSpecPlusOptional = kManifestUrlSpecRequired;
1777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    urlSpecPlusOptionalLength = NACL_ARRAY_SIZE(kManifestUrlSpecRequired);
1787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsValidDictionary(url_spec, container_key, parent_key,
1807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                         urlSpecPlusOptional,
1817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                         urlSpecPlusOptionalLength,
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         kManifestUrlSpecRequired,
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         NACL_ARRAY_SIZE(kManifestUrlSpecRequired),
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         error_string)) {
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // URL specifications must not contain "pnacl-translate" keys.
1887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // This prohibits NaCl clients from invoking PNaCl.
1897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  Json::Value translate = url_spec[kPnaclTranslateKey];
1907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!translate.empty()) {
1917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    nacl::stringstream error_stream;
1927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    error_stream << parent_key << " property '" << container_key <<
1937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        "' has '" << kPnaclTranslateKey << "' inside URL spec.";
1947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    *error_string = error_stream.str();
1957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return false;
1967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
1977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Verify the correct types of the fields if they exist.
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Json::Value url = url_spec[kUrlKey];
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!url.isString()) {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nacl::stringstream error_stream;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_stream << parent_key << " property '" << container_key <<
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "' has non-string value '" << url.toStyledString() <<
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "' for key '" << kUrlKey << "'.";
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *error_string = error_stream.str();
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  Json::Value opt_level = url_spec[kOptLevelKey];
2087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!opt_level.empty() && !opt_level.isNumeric()) {
2097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    nacl::stringstream error_stream;
2107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    error_stream << parent_key << " property '" << container_key <<
2117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        "' has non-numeric value '" << opt_level.toStyledString() <<
2127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        "' for key '" << kOptLevelKey << "'.";
2137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    *error_string = error_stream.str();
2147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return false;
2157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
216ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (url_spec.isMember(kOptLevelKeyDeprecated)) {
217ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    nacl::stringstream error_stream;
218ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    error_stream << parent_key << " property '" << container_key <<
219ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        "' has deprecated key '" << kOptLevelKeyDeprecated <<
220ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        "' please use '" << kOptLevelKey << "' instead.";
221ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    *error_string = error_stream.str();
222ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return false;
223ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Validate a "pnacl-translate" dictionary, assuming it was resolved from
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// container_key. E.g., "container_key" : { "pnacl_translate" : URLSpec }
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsValidPnaclTranslateSpec(const Json::Value& pnacl_spec,
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const nacl::string& container_key,
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const nacl::string& parent_key,
2327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                               const nacl::string& sandbox_isa,
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               nacl::string* error_string) {
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const char* kManifestPnaclSpecProperties[] = {
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kPnaclTranslateKey
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsValidDictionary(pnacl_spec, container_key, parent_key,
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         kManifestPnaclSpecProperties,
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         NACL_ARRAY_SIZE(kManifestPnaclSpecProperties),
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         kManifestPnaclSpecProperties,
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         NACL_ARRAY_SIZE(kManifestPnaclSpecProperties),
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         error_string)) {
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Json::Value url_spec = pnacl_spec[kPnaclTranslateKey];
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsValidUrlSpec(url_spec, kPnaclTranslateKey,
2477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                      container_key, sandbox_isa, error_string)) {
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Validates that |dictionary| is a valid ISA dictionary.  An ISA dictionary
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is validated to have keys from within the set of recognized ISAs.  Unknown
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ISAs are allowed, but ignored and warnings are produced. It is also validated
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that it must have an entry to match the ISA specified in |sandbox_isa| or
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// have a fallback 'portable' entry if there is no match. Returns true if
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// |dictionary| is an ISA to URL map.  Sets |error_info| to something
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// descriptive if it fails.
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsValidISADictionary(const Json::Value& dictionary,
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const nacl::string& parent_key,
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const nacl::string& sandbox_isa,
2637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                          bool must_find_matching_entry,
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          ErrorInfo* error_info) {
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (error_info == NULL) return false;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // An ISA to URL dictionary has to be an object.
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!dictionary.isObject()) {
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    error_info->SetReport(ERROR_MANIFEST_SCHEMA_VALIDATE,
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          nacl::string("manifest: ") + parent_key +
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          " property is not an ISA to URL dictionary");
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Build the set of reserved ISA dictionary keys.
2757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  const char** isaProperties;
2767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  size_t isaPropertiesLength;
2777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (sandbox_isa == kPortableKey) {
2787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // The known values for PNaCl ISA dictionaries in the manifest.
2797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    static const char* kPnaclManifestISAProperties[] = {
2807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      kPortableKey
2817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    };
2827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    isaProperties = kPnaclManifestISAProperties;
2837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    isaPropertiesLength = NACL_ARRAY_SIZE(kPnaclManifestISAProperties);
2847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  } else {
2857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // The known values for NaCl ISA dictionaries in the manifest.
2867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    static const char* kNaClManifestISAProperties[] = {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kX8632Key,
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kX8664Key,
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kArmKey,
2907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // "portable" is here to allow checking that, if present, it can
2917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // only refer to an URL, such as for a data file, and not to
2927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // "pnacl-translate", which would cause the creation of a nexe.
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kPortableKey
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    };
2957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    isaProperties = kNaClManifestISAProperties;
2967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    isaPropertiesLength = NACL_ARRAY_SIZE(kNaClManifestISAProperties);
2977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
2987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Check that entries in the dictionary are structurally correct.
2997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  Json::Value::Members members = dictionary.getMemberNames();
3007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  for (size_t i = 0; i < members.size(); ++i) {
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nacl::string property_name = members[i];
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Json::Value property_value = dictionary[property_name];
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    nacl::string error_string;
3047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (FindMatchingProperty(property_name,
3057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                             isaProperties,
3067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                             isaPropertiesLength)) {
3077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // For NaCl, arch entries can only be
3087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      //     "arch/portable" : URLSpec
3097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // For PNaCl arch in "program" dictionary entries can only be
3107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      //     "portable" : { "pnacl-translate": URLSpec }
3117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // For PNaCl arch elsewhere, dictionary entries can only be
3127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      //     "portable" : URLSpec
3137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      if ((sandbox_isa != kPortableKey &&
3147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)           !IsValidUrlSpec(property_value, property_name, parent_key,
3157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                           sandbox_isa, &error_string)) ||
3167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          (sandbox_isa == kPortableKey &&
3177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)           parent_key == kProgramKey &&
3187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)           !IsValidPnaclTranslateSpec(property_value, property_name, parent_key,
3197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                      sandbox_isa, &error_string)) ||
3207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          (sandbox_isa == kPortableKey &&
3217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)           parent_key != kProgramKey &&
3227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)           !IsValidUrlSpec(property_value, property_name, parent_key,
3237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                           sandbox_isa, &error_string))) {
3247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        error_info->SetReport(ERROR_MANIFEST_SCHEMA_VALIDATE,
3257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                              nacl::string("manifest: ") + error_string);
3267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        return false;
3277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      }
3287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    } else {
3297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // For forward compatibility, we do not prohibit other keys being in
3307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // the dictionary, as they may be architectures supported in later
3317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // versions.  However, the value of these entries must be an URLSpec.
3327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      PLUGIN_PRINTF(("IsValidISADictionary: unrecognized key '%s'.\n",
3337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                     property_name.c_str()));
3347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      if (!IsValidUrlSpec(property_value, property_name, parent_key,
3357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                          sandbox_isa, &error_string)) {
3367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        error_info->SetReport(ERROR_MANIFEST_SCHEMA_VALIDATE,
3377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                              nacl::string("manifest: ") + error_string);
3387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        return false;
3397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      }
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (sandbox_isa == kPortableKey) {
3447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    bool has_portable = dictionary.isMember(kPortableKey);
3457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
3467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (!has_portable) {
3477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      error_info->SetReport(
3487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          ERROR_MANIFEST_PROGRAM_MISSING_ARCH,
3497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          nacl::string("manifest: no version of ") + parent_key +
3507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          " given for portable.");
3517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      return false;
3527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
3537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  } else if (must_find_matching_entry) {
354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // TODO(elijahtaylor) add ISA resolver here if we expand ISAs to include
355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // micro-architectures that can resolve to multiple valid sandboxes.
356c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bool has_isa = dictionary.isMember(sandbox_isa);
357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bool has_portable = dictionary.isMember(kPortableKey);
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
359c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!has_isa && !has_portable) {
360c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      error_info->SetReport(
361c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          ERROR_MANIFEST_PROGRAM_MISSING_ARCH,
362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          nacl::string("manifest: no version of ") + parent_key +
363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          " given for current arch and no portable version found.");
364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return false;
365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void GrabUrlAndPnaclOptions(const Json::Value& url_spec,
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            nacl::string* url,
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            PnaclOptions* pnacl_options) {
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *url = url_spec[kUrlKey].asString();
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (url_spec.isMember(kOptLevelKey)) {
376ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    int32_t opt_raw = url_spec[kOptLevelKey].asInt();
377ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // set_opt_level will normalize the values.
378ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    pnacl_options->set_opt_level(opt_raw);
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetURLFromISADictionary(const Json::Value& dictionary,
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             const nacl::string& parent_key,
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             const nacl::string& sandbox_isa,
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             nacl::string* url,
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             PnaclOptions* pnacl_options,
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             ErrorInfo* error_info) {
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (url == NULL || pnacl_options == NULL || error_info == NULL)
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // When the application actually requests a resolved URL, we must have
3927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // a matching entry (sandbox_isa or portable) for NaCl.
3937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!IsValidISADictionary(dictionary, parent_key, sandbox_isa, true,
3947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                            error_info)) {
395c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL,
396c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          "architecture " + sandbox_isa +
397c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          " is not found for file " + parent_key);
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
399c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *url = "";
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The call to IsValidISADictionary() above guarantees that either
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // sandbox_isa or kPortableKey is present in the dictionary.
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_portable = dictionary.isMember(kPortableKey);
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_isa = dictionary.isMember(sandbox_isa);
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  nacl::string chosen_isa;
4087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if ((sandbox_isa == kPortableKey) || (has_portable && !has_isa)) {
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chosen_isa = kPortableKey;
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chosen_isa = sandbox_isa;
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Json::Value& isa_spec = dictionary[chosen_isa];
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check if this requires a pnacl-translate, otherwise just grab the URL.
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We may have pnacl-translate for isa-specific bitcode for CPU tuning.
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (isa_spec.isMember(kPnaclTranslateKey)) {
4177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // PNaCl
4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    GrabUrlAndPnaclOptions(isa_spec[kPnaclTranslateKey], url, pnacl_options);
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    pnacl_options->set_translate(true);
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // NaCl
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *url = isa_spec[kUrlKey].asString();
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    pnacl_options->set_translate(false);
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetKeyUrl(const Json::Value& dictionary,
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               const nacl::string& key,
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               const nacl::string& sandbox_isa,
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               const Manifest* manifest,
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               nacl::string* full_url,
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               PnaclOptions* pnacl_options,
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               ErrorInfo* error_info) {
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(full_url != NULL && error_info != NULL);
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!dictionary.isMember(key)) {
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL,
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          "file key not found in manifest");
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Json::Value& isa_dict = dictionary[key];
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  nacl::string relative_url;
4447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!GetURLFromISADictionary(isa_dict, key, sandbox_isa, &relative_url,
4457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                               pnacl_options, error_info)) {
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return manifest->ResolveURL(relative_url, full_url, error_info);
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool JsonManifest::Init(const nacl::string& manifest_json,
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        ErrorInfo* error_info) {
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (error_info == NULL) {
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Json::Reader reader;
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!reader.parse(manifest_json, dictionary_)) {
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string json_error = reader.getFormatedErrorMessages();
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_info->SetReport(ERROR_MANIFEST_PARSING,
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          "manifest JSON parsing failed: " + json_error);
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Parse has ensured the string was valid JSON.  Check that it matches the
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // manifest schema.
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return MatchesSchema(error_info);
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool JsonManifest::MatchesSchema(ErrorInfo* error_info) {
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Var exception;
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (error_info == NULL) {
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!dictionary_.isObject()) {
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_info->SetReport(
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ERROR_MANIFEST_SCHEMA_VALIDATE,
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "manifest: is not a json dictionary.");
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Json::Value::Members members = dictionary_.getMemberNames();
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < members.size(); ++i) {
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The top level dictionary entries valid in the manifest file.
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static const char* kManifestTopLevelProperties[] = { kProgramKey,
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                         kInterpreterKey,
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                         kFilesKey };
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nacl::string property_name = members[i];
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!FindMatchingProperty(property_name,
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              kManifestTopLevelProperties,
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              NACL_ARRAY_SIZE(kManifestTopLevelProperties))) {
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PLUGIN_PRINTF(("JsonManifest::MatchesSchema: WARNING: unknown top-level "
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     "section '%s' in manifest.\n", property_name.c_str()));
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // A manifest file must have a program section.
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!dictionary_.isMember(kProgramKey)) {
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_info->SetReport(
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ERROR_MANIFEST_SCHEMA_VALIDATE,
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        nacl::string("manifest: missing '") + kProgramKey + "' section.");
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Validate the program section.
5057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // There must be a matching (portable or sandbox_isa_) entry for program for
5067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // NaCl.
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsValidISADictionary(dictionary_[kProgramKey],
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            kProgramKey,
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            sandbox_isa_,
5107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                            true,
5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            error_info)) {
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Validate the interpreter section (if given).
5167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // There must be a matching (portable or sandbox_isa_) entry for interpreter
5177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // for NaCl.
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (dictionary_.isMember(kInterpreterKey)) {
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!IsValidISADictionary(dictionary_[kInterpreterKey],
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              kInterpreterKey,
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              sandbox_isa_,
5227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                              true,
5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              error_info)) {
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Validate the file dictionary (if given).
5297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // The "files" key does not require a matching (portable or sandbox_isa_)
5307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // entry at schema validation time for NaCl.  This allows manifests to specify
5317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // resources that are only loaded for a particular sandbox_isa.
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (dictionary_.isMember(kFilesKey)) {
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Json::Value& files = dictionary_[kFilesKey];
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!files.isObject()) {
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error_info->SetReport(
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ERROR_MANIFEST_SCHEMA_VALIDATE,
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          nacl::string("manifest: '") + kFilesKey + "' is not a dictionary.");
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Json::Value::Members members = files.getMemberNames();
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < members.size(); ++i) {
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      nacl::string file_name = members[i];
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!IsValidISADictionary(files[file_name],
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                file_name,
5447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                sandbox_isa_,
5457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                false,
5462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                error_info)) {
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool JsonManifest::ResolveURL(const nacl::string& relative_url,
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              nacl::string* full_url,
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              ErrorInfo* error_info) const {
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The contents of the manifest are resolved relative to the manifest URL.
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(url_util_ != NULL);
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Var resolved_url =
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_util_->ResolveRelativeToURL(pp::Var(manifest_base_url_),
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      relative_url);
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!resolved_url.is_string()) {
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_info->SetReport(
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ERROR_MANIFEST_RESOLVE_URL,
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "could not resolve url '" + relative_url +
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "' relative to manifest base url '" + manifest_base_url_.c_str() +
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "'.");
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *full_url = resolved_url.AsString();
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool JsonManifest::GetProgramURL(nacl::string* full_url,
5762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 PnaclOptions* pnacl_options,
5772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 ErrorInfo* error_info) const {
5782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (full_url == NULL || pnacl_options == NULL || error_info == NULL)
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Json::Value program = dictionary_[kProgramKey];
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  nacl::string nexe_url;
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  nacl::string error_string;
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetURLFromISADictionary(program,
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               kProgramKey,
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               sandbox_isa_,
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               &nexe_url,
5902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               pnacl_options,
5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               error_info)) {
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ResolveURL(nexe_url, full_url, error_info);
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool JsonManifest::GetFileKeys(std::set<nacl::string>* keys) const {
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!dictionary_.isMember(kFilesKey)) {
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // trivial success: no keys when there is no "files" section.
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Json::Value& files = dictionary_[kFilesKey];
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(files.isObject());
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Json::Value::Members members = files.getMemberNames();
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < members.size(); ++i) {
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    keys->insert(members[i]);
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool JsonManifest::ResolveKey(const nacl::string& key,
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              nacl::string* full_url,
6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              PnaclOptions* pnacl_options,
6152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              ErrorInfo* error_info) const {
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NaClLog(3, "JsonManifest::ResolveKey(%s)\n", key.c_str());
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // key must be one of kProgramKey or kFileKey '/' file-section-key
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (full_url == NULL || pnacl_options == NULL || error_info == NULL)
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (key == kProgramKey) {
6237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return GetKeyUrl(dictionary_, key, sandbox_isa_, this, full_url,
6247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                     pnacl_options, error_info);
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  nacl::string::const_iterator p = find(key.begin(), key.end(), '/');
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (p == key.end()) {
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL,
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          nacl::string("ResolveKey: invalid key, no slash: ")
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          + key);
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // generalize to permit other sections?
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  nacl::string prefix(key.begin(), p);
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (prefix != kFilesKey) {
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL,
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          nacl::string("ResolveKey: invalid key: not \"files\""
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       " prefix: ") + key);
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  nacl::string rest(p + 1, key.end());
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Json::Value& files = dictionary_[kFilesKey];
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!files.isObject()) {
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_info->SetReport(
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ERROR_MANIFEST_RESOLVE_URL,
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        nacl::string("ResolveKey: no \"files\" dictionary"));
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!files.isMember(rest)) {
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_info->SetReport(
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ERROR_MANIFEST_RESOLVE_URL,
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        nacl::string("ResolveKey: no such \"files\" entry: ") + key);
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return GetKeyUrl(files, rest, sandbox_isa_, this, full_url, pnacl_options,
6597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                   error_info);
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace plugin
663