1 // Copyright 2013 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. 4 5 #include "extensions/common/manifest_handlers/requirements_info.h" 6 7 #include "base/lazy_instance.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "base/strings/utf_string_conversions.h" 10 #include "base/values.h" 11 #include "extensions/common/error_utils.h" 12 #include "extensions/common/manifest_constants.h" 13 14 namespace extensions { 15 16 namespace keys = manifest_keys; 17 namespace errors = manifest_errors; 18 19 RequirementsInfo::RequirementsInfo(const Manifest* manifest) 20 : webgl(false), 21 npapi(false), 22 window_shape(false) { 23 // Before parsing requirements from the manifest, automatically default the 24 // NPAPI plugin requirement based on whether it includes NPAPI plugins. 25 const base::ListValue* list_value = NULL; 26 npapi = manifest->GetList(keys::kPlugins, &list_value) && 27 !list_value->empty(); 28 } 29 30 RequirementsInfo::~RequirementsInfo() { 31 } 32 33 // static 34 const RequirementsInfo& RequirementsInfo::GetRequirements( 35 const Extension* extension) { 36 RequirementsInfo* info = static_cast<RequirementsInfo*>( 37 extension->GetManifestData(keys::kRequirements)); 38 39 // We should be guaranteed to have requirements, since they are parsed for all 40 // extension types. 41 CHECK(info); 42 return *info; 43 } 44 45 RequirementsHandler::RequirementsHandler() { 46 } 47 48 RequirementsHandler::~RequirementsHandler() { 49 } 50 51 const std::vector<std::string> RequirementsHandler::PrerequisiteKeys() const { 52 return SingleKey(keys::kPlugins); 53 } 54 55 const std::vector<std::string> RequirementsHandler::Keys() const { 56 return SingleKey(keys::kRequirements); 57 } 58 59 bool RequirementsHandler::AlwaysParseForType(Manifest::Type type) const { 60 return true; 61 } 62 63 bool RequirementsHandler::Parse(Extension* extension, base::string16* error) { 64 scoped_ptr<RequirementsInfo> requirements( 65 new RequirementsInfo(extension->manifest())); 66 67 if (!extension->manifest()->HasKey(keys::kRequirements)) { 68 extension->SetManifestData(keys::kRequirements, requirements.release()); 69 return true; 70 } 71 72 const base::DictionaryValue* requirements_value = NULL; 73 if (!extension->manifest()->GetDictionary(keys::kRequirements, 74 &requirements_value)) { 75 *error = base::ASCIIToUTF16(errors::kInvalidRequirements); 76 return false; 77 } 78 79 for (base::DictionaryValue::Iterator iter(*requirements_value); 80 !iter.IsAtEnd(); 81 iter.Advance()) { 82 const base::DictionaryValue* requirement_value; 83 if (!iter.value().GetAsDictionary(&requirement_value)) { 84 *error = ErrorUtils::FormatErrorMessageUTF16( 85 errors::kInvalidRequirement, iter.key()); 86 return false; 87 } 88 89 if (iter.key() == "plugins") { 90 for (base::DictionaryValue::Iterator plugin_iter(*requirement_value); 91 !plugin_iter.IsAtEnd(); plugin_iter.Advance()) { 92 bool plugin_required = false; 93 if (!plugin_iter.value().GetAsBoolean(&plugin_required)) { 94 *error = ErrorUtils::FormatErrorMessageUTF16( 95 errors::kInvalidRequirement, iter.key()); 96 return false; 97 } 98 if (plugin_iter.key() == "npapi") { 99 requirements->npapi = plugin_required; 100 } else { 101 *error = ErrorUtils::FormatErrorMessageUTF16( 102 errors::kInvalidRequirement, iter.key()); 103 return false; 104 } 105 } 106 } else if (iter.key() == "3D") { 107 const base::ListValue* features = NULL; 108 if (!requirement_value->GetListWithoutPathExpansion("features", 109 &features) || 110 !features) { 111 *error = ErrorUtils::FormatErrorMessageUTF16( 112 errors::kInvalidRequirement, iter.key()); 113 return false; 114 } 115 116 for (base::ListValue::const_iterator feature_iter = features->begin(); 117 feature_iter != features->end(); ++feature_iter) { 118 std::string feature; 119 if ((*feature_iter)->GetAsString(&feature)) { 120 if (feature == "webgl") { 121 requirements->webgl = true; 122 } else if (feature == "css3d") { 123 // css3d is always available, so no check is needed, but no error is 124 // generated. 125 } else { 126 *error = ErrorUtils::FormatErrorMessageUTF16( 127 errors::kInvalidRequirement, iter.key()); 128 return false; 129 } 130 } 131 } 132 } else if (iter.key() == "window") { 133 for (base::DictionaryValue::Iterator feature_iter(*requirement_value); 134 !feature_iter.IsAtEnd(); feature_iter.Advance()) { 135 bool feature_required = false; 136 if (!feature_iter.value().GetAsBoolean(&feature_required)) { 137 *error = ErrorUtils::FormatErrorMessageUTF16( 138 errors::kInvalidRequirement, iter.key()); 139 return false; 140 } 141 if (feature_iter.key() == "shape") { 142 requirements->window_shape = feature_required; 143 } else { 144 *error = ErrorUtils::FormatErrorMessageUTF16( 145 errors::kInvalidRequirement, iter.key()); 146 return false; 147 } 148 } 149 } else { 150 *error = base::ASCIIToUTF16(errors::kInvalidRequirements); 151 return false; 152 } 153 } 154 155 extension->SetManifestData(keys::kRequirements, requirements.release()); 156 return true; 157 } 158 159 } // namespace extensions 160