Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / components / nacl / renderer / json_manifest.cc
blobe2063acd1d6c87a826917db7b7f78845827341cf
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/nacl/renderer/json_manifest.h"
7 #include <set>
9 #include "base/containers/scoped_ptr_hash_map.h"
10 #include "base/lazy_instance.h"
11 #include "base/logging.h"
12 #include "base/macros.h"
13 #include "components/nacl/renderer/nexe_load_manager.h"
14 #include "third_party/jsoncpp/source/include/json/reader.h"
15 #include "third_party/jsoncpp/source/include/json/value.h"
16 #include "url/gurl.h"
18 namespace nacl {
20 namespace {
21 // Top-level section name keys
22 const char* const kProgramKey = "program";
23 const char* const kInterpreterKey = "interpreter";
24 const char* const kFilesKey = "files";
26 // ISA Dictionary keys
27 const char* const kX8632Key = "x86-32";
28 const char* const kX8632NonSFIKey = "x86-32-nonsfi";
29 const char* const kX8664Key = "x86-64";
30 const char* const kX8664NonSFIKey = "x86-64-nonsfi";
31 const char* const kArmKey = "arm";
32 const char* const kArmNonSFIKey = "arm-nonsfi";
33 const char* const kPortableKey = "portable";
35 // Url Resolution keys
36 const char* const kPnaclDebugKey = "pnacl-debug";
37 const char* const kPnaclTranslateKey = "pnacl-translate";
38 const char* const kUrlKey = "url";
40 // PNaCl keys
41 const char* const kOptLevelKey = "optlevel";
43 // Sample NaCl manifest file:
44 // {
45 // "program": {
46 // "x86-32": {"url": "myprogram_x86-32.nexe"},
47 // "x86-64": {"url": "myprogram_x86-64.nexe"},
48 // "arm": {"url": "myprogram_arm.nexe"}
49 // },
50 // "interpreter": {
51 // "x86-32": {"url": "interpreter_x86-32.nexe"},
52 // "x86-64": {"url": "interpreter_x86-64.nexe"},
53 // "arm": {"url": "interpreter_arm.nexe"}
54 // },
55 // "files": {
56 // "foo.txt": {
57 // "portable": {"url": "foo.txt"}
58 // },
59 // "bar.txt": {
60 // "x86-32": {"url": "x86-32/bar.txt"},
61 // "portable": {"url": "bar.txt"}
62 // },
63 // "libfoo.so": {
64 // "x86-64" : { "url": "..." }
65 // }
66 // }
67 // }
69 // Sample PNaCl manifest file:
70 // {
71 // "program": {
72 // "portable": {
73 // "pnacl-translate": {
74 // "url": "myprogram.pexe"
75 // },
76 // "pnacl-debug": {
77 // "url": "myprogram.debug.pexe",
78 // "opt_level": 0
79 // }
80 // }
81 // },
82 // "files": {
83 // "foo.txt": {
84 // "portable": {"url": "foo.txt"}
85 // },
86 // "bar.txt": {
87 // "portable": {"url": "bar.txt"}
88 // }
89 // }
90 // }
92 // Returns the key for the architecture in non-SFI mode.
93 std::string GetNonSFIKey(const std::string& sandbox_isa) {
94 return sandbox_isa + "-nonsfi";
97 // Looks up |property_name| in the vector |valid_names| with length
98 // |valid_name_count|. Returns true if |property_name| is found.
99 bool FindMatchingProperty(const std::string& property_name,
100 const char** valid_names,
101 size_t valid_name_count) {
102 for (size_t i = 0; i < valid_name_count; ++i) {
103 if (property_name == valid_names[i]) {
104 return true;
107 return false;
110 // Return true if this is a valid dictionary. Having only keys present in
111 // |valid_keys| and having at least the keys in |required_keys|.
112 // Error messages will be placed in |error_string|, given that the dictionary
113 // was the property value of |container_key|.
114 // E.g., "container_key" : dictionary
115 bool IsValidDictionary(const Json::Value& dictionary,
116 const std::string& container_key,
117 const std::string& parent_key,
118 const char** valid_keys,
119 size_t valid_key_count,
120 const char** required_keys,
121 size_t required_key_count,
122 std::string* error_string) {
123 if (!dictionary.isObject()) {
124 std::stringstream error_stream;
125 error_stream << parent_key << " property '" << container_key
126 << "' is non-dictionary value '"
127 << dictionary.toStyledString() << "'.";
128 *error_string = error_stream.str();
129 return false;
131 // Check for unknown dictionary members.
132 Json::Value::Members members = dictionary.getMemberNames();
133 for (size_t i = 0; i < members.size(); ++i) {
134 std::string property_name = members[i];
135 if (!FindMatchingProperty(property_name,
136 valid_keys,
137 valid_key_count)) {
138 // For forward compatibility, we do not prohibit other keys being in
139 // the dictionary.
140 VLOG(1) << "WARNING: '" << parent_key << "' property '"
141 << container_key << "' has unknown key '"
142 << property_name << "'.";
145 // Check for required members.
146 for (size_t i = 0; i < required_key_count; ++i) {
147 if (!dictionary.isMember(required_keys[i])) {
148 std::stringstream error_stream;
149 error_stream << parent_key << " property '" << container_key
150 << "' does not have required key: '"
151 << required_keys[i] << "'.";
152 *error_string = error_stream.str();
153 return false;
156 return true;
159 // Validate a "url" dictionary assuming it was resolved from container_key.
160 // E.g., "container_key" : { "url": "foo.txt" }
161 bool IsValidUrlSpec(const Json::Value& url_spec,
162 const std::string& container_key,
163 const std::string& parent_key,
164 const std::string& sandbox_isa,
165 std::string* error_string) {
166 static const char* kManifestUrlSpecRequired[] = {
167 kUrlKey
169 const char** urlSpecPlusOptional;
170 size_t urlSpecPlusOptionalLength;
171 if (sandbox_isa == kPortableKey) {
172 static const char* kPnaclUrlSpecPlusOptional[] = {
173 kUrlKey,
174 kOptLevelKey,
176 urlSpecPlusOptional = kPnaclUrlSpecPlusOptional;
177 urlSpecPlusOptionalLength = arraysize(kPnaclUrlSpecPlusOptional);
178 } else {
179 // URL specifications must not contain "pnacl-translate" keys.
180 // This prohibits NaCl clients from invoking PNaCl.
181 if (url_spec.isMember(kPnaclTranslateKey)) {
182 std::stringstream error_stream;
183 error_stream << "PNaCl-like NMF with application/x-nacl mimetype instead "
184 << "of x-pnacl mimetype (has " << kPnaclTranslateKey << ").";
185 *error_string = error_stream.str();
186 return false;
188 urlSpecPlusOptional = kManifestUrlSpecRequired;
189 urlSpecPlusOptionalLength = arraysize(kManifestUrlSpecRequired);
191 if (!IsValidDictionary(url_spec, container_key, parent_key,
192 urlSpecPlusOptional,
193 urlSpecPlusOptionalLength,
194 kManifestUrlSpecRequired,
195 arraysize(kManifestUrlSpecRequired),
196 error_string)) {
197 return false;
199 // Verify the correct types of the fields if they exist.
200 Json::Value url = url_spec[kUrlKey];
201 if (!url.isString()) {
202 std::stringstream error_stream;
203 error_stream << parent_key << " property '" << container_key <<
204 "' has non-string value '" << url.toStyledString() <<
205 "' for key '" << kUrlKey << "'.";
206 *error_string = error_stream.str();
207 return false;
209 Json::Value opt_level = url_spec[kOptLevelKey];
210 if (!opt_level.empty() && !opt_level.isNumeric()) {
211 std::stringstream error_stream;
212 error_stream << parent_key << " property '" << container_key <<
213 "' has non-numeric value '" << opt_level.toStyledString() <<
214 "' for key '" << kOptLevelKey << "'.";
215 *error_string = error_stream.str();
216 return false;
218 return true;
221 // Validate a "pnacl-translate" or "pnacl-debug" dictionary, assuming
222 // it was resolved from container_key.
223 // E.g., "container_key" : { "pnacl-translate" : URLSpec }
224 bool IsValidPnaclTranslateSpec(const Json::Value& pnacl_spec,
225 const std::string& container_key,
226 const std::string& parent_key,
227 const std::string& sandbox_isa,
228 std::string* error_string) {
229 static const char* kManifestPnaclSpecValid[] = {
230 kPnaclDebugKey,
231 kPnaclTranslateKey
233 static const char* kManifestPnaclSpecRequired[] = { kPnaclTranslateKey };
234 if (!IsValidDictionary(pnacl_spec, container_key, parent_key,
235 kManifestPnaclSpecValid,
236 arraysize(kManifestPnaclSpecValid),
237 kManifestPnaclSpecRequired,
238 arraysize(kManifestPnaclSpecRequired),
239 error_string)) {
240 return false;
242 Json::Value url_spec = pnacl_spec[kPnaclTranslateKey];
243 return IsValidUrlSpec(url_spec, kPnaclTranslateKey,
244 container_key, sandbox_isa, error_string);
247 // Validates that |dictionary| is a valid ISA dictionary. An ISA dictionary
248 // is validated to have keys from within the set of recognized ISAs. Unknown
249 // ISAs are allowed, but ignored and warnings are produced. It is also
250 // validated
251 // that it must have an entry to match the ISA specified in |sandbox_isa| or
252 // have a fallback 'portable' entry if there is no match. Returns true if
253 // |dictionary| is an ISA to URL map. Sets |error_info| to something
254 // descriptive if it fails.
255 bool IsValidISADictionary(const Json::Value& dictionary,
256 const std::string& parent_key,
257 const std::string& sandbox_isa,
258 bool must_find_matching_entry,
259 bool nonsfi_enabled,
260 JsonManifest::ErrorInfo* error_info) {
261 // An ISA to URL dictionary has to be an object.
262 if (!dictionary.isObject()) {
263 error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE;
264 error_info->string = std::string("manifest: ") + parent_key +
265 " property is not an ISA to URL dictionary";
266 return false;
268 // Build the set of reserved ISA dictionary keys.
269 const char** isaProperties;
270 size_t isaPropertiesLength;
271 if (sandbox_isa == kPortableKey) {
272 // The known values for PNaCl ISA dictionaries in the manifest.
273 static const char* kPnaclManifestISAProperties[] = {
274 kPortableKey
276 isaProperties = kPnaclManifestISAProperties;
277 isaPropertiesLength = arraysize(kPnaclManifestISAProperties);
278 } else {
279 // The known values for NaCl ISA dictionaries in the manifest.
280 static const char* kNaClManifestISAProperties[] = {
281 kX8632Key,
282 kX8632NonSFIKey,
283 kX8664Key,
284 kX8664NonSFIKey,
285 kArmKey,
286 kArmNonSFIKey,
287 // "portable" is here to allow checking that, if present, it can
288 // only refer to an URL, such as for a data file, and not to
289 // "pnacl-translate", which would cause the creation of a nexe.
290 kPortableKey
292 isaProperties = kNaClManifestISAProperties;
293 isaPropertiesLength = arraysize(kNaClManifestISAProperties);
295 // Check that entries in the dictionary are structurally correct.
296 Json::Value::Members members = dictionary.getMemberNames();
297 for (size_t i = 0; i < members.size(); ++i) {
298 std::string property_name = members[i];
299 Json::Value property_value = dictionary[property_name];
300 std::string error_string;
301 if (FindMatchingProperty(property_name,
302 isaProperties,
303 isaPropertiesLength)) {
304 // For NaCl, arch entries can only be
305 // "arch/portable" : URLSpec
306 // For PNaCl arch in "program" dictionary entries can be
307 // "portable" : { "pnacl-translate": URLSpec }
308 // or "portable" : { "pnacl-debug": URLSpec }
309 // For PNaCl arch elsewhere, dictionary entries can only be
310 // "portable" : URLSpec
311 if ((sandbox_isa != kPortableKey &&
312 !IsValidUrlSpec(property_value, property_name, parent_key,
313 sandbox_isa, &error_string)) ||
314 (sandbox_isa == kPortableKey &&
315 parent_key == kProgramKey &&
316 !IsValidPnaclTranslateSpec(property_value, property_name, parent_key,
317 sandbox_isa, &error_string)) ||
318 (sandbox_isa == kPortableKey &&
319 parent_key != kProgramKey &&
320 !IsValidUrlSpec(property_value, property_name, parent_key,
321 sandbox_isa, &error_string))) {
322 error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE;
323 error_info->string = "manifest: " + error_string;
324 return false;
326 } else {
327 // For forward compatibility, we do not prohibit other keys being in
328 // the dictionary, as they may be architectures supported in later
329 // versions. However, the value of these entries must be an URLSpec.
330 VLOG(1) << "IsValidISADictionary: unrecognized key '"
331 << property_name << "'.";
332 if (!IsValidUrlSpec(property_value, property_name, parent_key,
333 sandbox_isa, &error_string)) {
334 error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE;
335 error_info->string = "manifest: " + error_string;
336 return false;
341 if (sandbox_isa == kPortableKey) {
342 if (!dictionary.isMember(kPortableKey)) {
343 error_info->error = PP_NACL_ERROR_MANIFEST_PROGRAM_MISSING_ARCH;
344 error_info->string = "manifest: no version of " + parent_key +
345 " given for portable.";
346 return false;
348 } else if (must_find_matching_entry) {
349 // TODO(elijahtaylor) add ISA resolver here if we expand ISAs to include
350 // micro-architectures that can resolve to multiple valid sandboxes.
351 bool has_isa = dictionary.isMember(sandbox_isa);
352 bool has_nonsfi_isa =
353 nonsfi_enabled && dictionary.isMember(GetNonSFIKey(sandbox_isa));
354 bool has_portable = dictionary.isMember(kPortableKey);
356 if (!has_isa && !has_nonsfi_isa && !has_portable) {
357 error_info->error = PP_NACL_ERROR_MANIFEST_PROGRAM_MISSING_ARCH;
358 error_info->string = "manifest: no version of " + parent_key +
359 " given for current arch and no portable version found.";
360 return false;
363 return true;
366 void GrabUrlAndPnaclOptions(const Json::Value& url_spec,
367 std::string* url,
368 PP_PNaClOptions* pnacl_options) {
369 *url = url_spec[kUrlKey].asString();
370 pnacl_options->translate = PP_TRUE;
371 if (url_spec.isMember(kOptLevelKey)) {
372 int32_t opt_raw = url_spec[kOptLevelKey].asInt();
373 // Currently only allow 0 or 2, since that is what we test.
374 if (opt_raw <= 0)
375 pnacl_options->opt_level = 0;
376 else
377 pnacl_options->opt_level = 2;
381 } // namespace
383 typedef base::ScopedPtrHashMap<PP_Instance, nacl::JsonManifest> JsonManifestMap;
384 base::LazyInstance<JsonManifestMap> g_manifest_map = LAZY_INSTANCE_INITIALIZER;
386 void AddJsonManifest(PP_Instance instance, scoped_ptr<JsonManifest> manifest) {
387 g_manifest_map.Get().add(instance, manifest.Pass());
390 JsonManifest* GetJsonManifest(PP_Instance instance) {
391 return g_manifest_map.Get().get(instance);
394 void DeleteJsonManifest(PP_Instance instance) {
395 g_manifest_map.Get().erase(instance);
398 JsonManifest::JsonManifest(const std::string& manifest_base_url,
399 const std::string& sandbox_isa,
400 bool nonsfi_enabled,
401 bool pnacl_debug)
402 : manifest_base_url_(manifest_base_url),
403 sandbox_isa_(sandbox_isa),
404 nonsfi_enabled_(nonsfi_enabled),
405 pnacl_debug_(pnacl_debug) { }
407 bool JsonManifest::Init(const std::string& manifest_json,
408 ErrorInfo* error_info) {
409 CHECK(error_info);
411 Json::Reader reader;
412 if (!reader.parse(manifest_json, dictionary_)) {
413 std::string json_error = reader.getFormattedErrorMessages();
414 error_info->error = PP_NACL_ERROR_MANIFEST_PARSING;
415 error_info->string = "manifest JSON parsing failed: " + json_error;
416 return false;
418 // Parse has ensured the string was valid JSON. Check that it matches the
419 // manifest schema.
420 return MatchesSchema(error_info);
423 bool JsonManifest::GetProgramURL(std::string* full_url,
424 PP_PNaClOptions* pnacl_options,
425 bool* uses_nonsfi_mode,
426 ErrorInfo* error_info) const {
427 if (!full_url)
428 return false;
429 CHECK(pnacl_options);
430 CHECK(uses_nonsfi_mode);
431 CHECK(error_info);
433 const Json::Value& program = dictionary_[kProgramKey];
434 std::string nexe_url;
435 if (!GetURLFromISADictionary(program,
436 kProgramKey,
437 &nexe_url,
438 pnacl_options,
439 uses_nonsfi_mode,
440 error_info)) {
441 return false;
444 // The contents of the manifest are resolved relative to the manifest URL.
445 GURL base_gurl(manifest_base_url_);
446 if (!base_gurl.is_valid())
447 return false;
449 GURL resolved_gurl = base_gurl.Resolve(nexe_url);
450 if (!resolved_gurl.is_valid()) {
451 error_info->error = PP_NACL_ERROR_MANIFEST_RESOLVE_URL;
452 error_info->string =
453 "could not resolve url '" + nexe_url +
454 "' relative to manifest base url '" + manifest_base_url_.c_str() +
455 "'.";
456 return false;
458 *full_url = resolved_gurl.possibly_invalid_spec();
459 return true;
462 bool JsonManifest::ResolveKey(const std::string& key,
463 std::string* full_url,
464 PP_PNaClOptions* pnacl_options) const {
465 // key must be one of kProgramKey or kFileKey '/' file-section-key
466 if (full_url == NULL || pnacl_options == NULL)
467 return false;
469 if (key == kProgramKey)
470 return GetKeyUrl(dictionary_, key, full_url, pnacl_options);
472 std::string::const_iterator p = std::find(key.begin(), key.end(), '/');
473 if (p == key.end()) {
474 VLOG(1) << "ResolveKey failed: invalid key, no slash: " << key;
475 return false;
478 // generalize to permit other sections?
479 std::string prefix(key.begin(), p);
480 if (prefix != kFilesKey) {
481 VLOG(1) << "ResolveKey failed: invalid key, no \"files\" prefix: " << key;
482 return false;
485 const Json::Value& files = dictionary_[kFilesKey];
486 if (!files.isObject()) {
487 VLOG(1) << "ResolveKey failed: no \"files\" dictionary";
488 return false;
491 std::string rest(p + 1, key.end());
492 if (!files.isMember(rest)) {
493 VLOG(1) << "ResolveKey failed: no such \"files\" entry: " << key;
494 return false;
496 return GetKeyUrl(files, rest, full_url, pnacl_options);
499 bool JsonManifest::MatchesSchema(ErrorInfo* error_info) {
500 if (!dictionary_.isObject()) {
501 error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE;
502 error_info->string = "manifest: is not a json dictionary.";
503 return false;
505 Json::Value::Members members = dictionary_.getMemberNames();
506 for (size_t i = 0; i < members.size(); ++i) {
507 // The top level dictionary entries valid in the manifest file.
508 static const char* kManifestTopLevelProperties[] = { kProgramKey,
509 kInterpreterKey,
510 kFilesKey };
511 std::string property_name = members[i];
512 if (!FindMatchingProperty(property_name,
513 kManifestTopLevelProperties,
514 arraysize(kManifestTopLevelProperties))) {
515 VLOG(1) << "JsonManifest::MatchesSchema: WARNING: unknown top-level "
516 << "section '" << property_name << "' in manifest.";
520 // A manifest file must have a program section.
521 if (!dictionary_.isMember(kProgramKey)) {
522 error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE;
523 error_info->string = std::string("manifest: missing '") + kProgramKey +
524 "' section.";
525 return false;
528 // Validate the program section.
529 // There must be a matching (portable or sandbox_isa_) entry for program for
530 // NaCl.
531 if (!IsValidISADictionary(dictionary_[kProgramKey],
532 kProgramKey,
533 sandbox_isa_,
534 true,
535 nonsfi_enabled_,
536 error_info)) {
537 return false;
540 // Validate the interpreter section (if given).
541 // There must be a matching (portable or sandbox_isa_) entry for interpreter
542 // for NaCl.
543 if (dictionary_.isMember(kInterpreterKey)) {
544 if (!IsValidISADictionary(dictionary_[kInterpreterKey],
545 kInterpreterKey,
546 sandbox_isa_,
547 true,
548 nonsfi_enabled_,
549 error_info)) {
550 return false;
554 // Validate the file dictionary (if given).
555 // The "files" key does not require a matching (portable or sandbox_isa_)
556 // entry at schema validation time for NaCl. This allows manifests to
557 // specify resources that are only loaded for a particular sandbox_isa.
558 if (dictionary_.isMember(kFilesKey)) {
559 const Json::Value& files = dictionary_[kFilesKey];
560 if (!files.isObject()) {
561 error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE;
562 error_info->string = std::string("manifest: '") + kFilesKey +
563 "' is not a dictionary.";
565 Json::Value::Members members = files.getMemberNames();
566 for (size_t i = 0; i < members.size(); ++i) {
567 std::string file_name = members[i];
568 if (!IsValidISADictionary(files[file_name],
569 file_name,
570 sandbox_isa_,
571 false,
572 nonsfi_enabled_,
573 error_info)) {
574 return false;
578 return true;
581 bool JsonManifest::GetKeyUrl(const Json::Value& dictionary,
582 const std::string& key,
583 std::string* full_url,
584 PP_PNaClOptions* pnacl_options) const {
585 DCHECK(full_url && pnacl_options);
586 if (!dictionary.isMember(key)) {
587 VLOG(1) << "GetKeyUrl failed: file " << key << " not found in manifest.";
588 return false;
590 const Json::Value& isa_dict = dictionary[key];
591 std::string relative_url;
592 bool uses_nonsfi_mode;
593 ErrorInfo ignored_error_info;
594 if (!GetURLFromISADictionary(isa_dict, key, &relative_url,
595 pnacl_options, &uses_nonsfi_mode,
596 &ignored_error_info))
597 return false;
599 // The contents of the manifest are resolved relative to the manifest URL.
600 GURL base_gurl(manifest_base_url_);
601 if (!base_gurl.is_valid())
602 return false;
603 GURL resolved_gurl = base_gurl.Resolve(relative_url);
604 if (!resolved_gurl.is_valid())
605 return false;
606 *full_url = resolved_gurl.possibly_invalid_spec();
607 return true;
610 bool JsonManifest::GetURLFromISADictionary(const Json::Value& dictionary,
611 const std::string& parent_key,
612 std::string* url,
613 PP_PNaClOptions* pnacl_options,
614 bool* uses_nonsfi_mode,
615 ErrorInfo* error_info) const {
616 DCHECK(url && pnacl_options && error_info);
618 // When the application actually requests a resolved URL, we must have
619 // a matching entry (sandbox_isa_ or portable) for NaCl.
620 ErrorInfo ignored_error_info;
621 if (!IsValidISADictionary(dictionary, parent_key, sandbox_isa_, true,
622 nonsfi_enabled_, &ignored_error_info)) {
623 error_info->error = PP_NACL_ERROR_MANIFEST_RESOLVE_URL;
624 error_info->string = "architecture " + sandbox_isa_ +
625 " is not found for file " + parent_key;
626 return false;
629 // The call to IsValidISADictionary() above guarantees that either
630 // sandbox_isa_, its nonsfi mode, or kPortableKey is present in the
631 // dictionary.
632 *uses_nonsfi_mode = false;
633 std::string chosen_isa;
634 if (sandbox_isa_ == kPortableKey) {
635 chosen_isa = kPortableKey;
636 } else {
637 std::string nonsfi_isa = GetNonSFIKey(sandbox_isa_);
638 if (nonsfi_enabled_ && dictionary.isMember(nonsfi_isa)) {
639 chosen_isa = nonsfi_isa;
640 *uses_nonsfi_mode = true;
641 } else if (dictionary.isMember(sandbox_isa_)) {
642 chosen_isa = sandbox_isa_;
643 } else if (dictionary.isMember(kPortableKey)) {
644 chosen_isa = kPortableKey;
645 } else {
646 // Should not reach here, because the earlier IsValidISADictionary()
647 // call checked that the manifest covers the current architecture.
648 DCHECK(false);
649 return false;
653 const Json::Value& isa_spec = dictionary[chosen_isa];
654 // If the PNaCl debug flag is turned on, look for pnacl-debug entries first.
655 // If found, mark that it is a debug URL. Otherwise, fall back to
656 // checking for pnacl-translate URLs, etc. and don't mark it as a debug URL.
657 if (pnacl_debug_ && isa_spec.isMember(kPnaclDebugKey)) {
658 GrabUrlAndPnaclOptions(isa_spec[kPnaclDebugKey], url, pnacl_options);
659 pnacl_options->is_debug = PP_TRUE;
660 } else if (isa_spec.isMember(kPnaclTranslateKey)) {
661 GrabUrlAndPnaclOptions(isa_spec[kPnaclTranslateKey], url, pnacl_options);
662 } else {
663 // NaCl
664 *url = isa_spec[kUrlKey].asString();
665 pnacl_options->translate = PP_FALSE;
668 return true;
671 } // namespace nacl