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