Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/common/extensions/api/extension_api.h" | 5 #include "chrome/common/extensions/api/extension_api.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| 11 #include "base/json/json_reader.h" | 11 #include "base/json/json_reader.h" |
| 12 #include "base/json/json_writer.h" | |
| 13 #include "base/lazy_instance.h" | |
| 12 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/string_number_conversions.h" | |
| 13 #include "base/string_split.h" | 16 #include "base/string_split.h" |
| 14 #include "base/string_util.h" | 17 #include "base/string_util.h" |
| 15 #include "base/values.h" | 18 #include "base/values.h" |
| 16 #include "chrome/common/extensions/api/generated_schemas.h" | 19 #include "chrome/common/extensions/api/generated_schemas.h" |
| 17 #include "chrome/common/extensions/extension.h" | 20 #include "chrome/common/extensions/extension.h" |
| 18 #include "chrome/common/extensions/extension_permission_set.h" | 21 #include "chrome/common/extensions/extension_permission_set.h" |
| 22 #include "chrome/common/extensions/simple_feature_provider.h" | |
| 23 #include "content/public/browser/browser_thread.h" | |
| 19 #include "googleurl/src/gurl.h" | 24 #include "googleurl/src/gurl.h" |
| 20 #include "grit/common_resources.h" | 25 #include "grit/common_resources.h" |
| 21 #include "ui/base/resource/resource_bundle.h" | 26 #include "ui/base/resource/resource_bundle.h" |
| 22 | 27 |
| 23 using base::DictionaryValue; | 28 using base::DictionaryValue; |
| 24 using base::ListValue; | 29 using base::ListValue; |
| 25 using base::Value; | 30 using base::Value; |
| 31 using content::BrowserThread; | |
| 26 | 32 |
| 27 namespace extensions { | 33 namespace extensions { |
| 28 | 34 |
| 29 using api::GeneratedSchemas; | 35 using api::GeneratedSchemas; |
| 30 | 36 |
| 31 namespace { | 37 namespace { |
| 32 | 38 |
| 39 const char* kChildKinds[] = { | |
| 40 "functions", | |
| 41 "events" | |
| 42 }; | |
| 43 | |
| 33 // Returns whether the list at |name_space_node|.|child_kind| contains any | 44 // Returns whether the list at |name_space_node|.|child_kind| contains any |
| 34 // children with an { "unprivileged": true } property. | 45 // children with an { "unprivileged": true } property. |
| 35 bool HasUnprivilegedChild(const DictionaryValue* name_space_node, | 46 bool HasUnprivilegedChild(const DictionaryValue* name_space_node, |
| 36 const std::string& child_kind) { | 47 const std::string& child_kind) { |
| 37 ListValue* child_list = NULL; | 48 ListValue* child_list = NULL; |
| 38 name_space_node->GetList(child_kind, &child_list); | 49 name_space_node->GetList(child_kind, &child_list); |
| 39 if (!child_list) | 50 if (!child_list) |
| 40 return false; | 51 return false; |
| 41 | 52 |
| 42 for (size_t i = 0; i < child_list->GetSize(); ++i) { | 53 for (size_t i = 0; i < child_list->GetSize(); ++i) { |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 60 base::JSONReader::ReadAndReturnError( | 71 base::JSONReader::ReadAndReturnError( |
| 61 schema.as_string(), | 72 schema.as_string(), |
| 62 false, // allow trailing commas | 73 false, // allow trailing commas |
| 63 NULL, // error code | 74 NULL, // error code |
| 64 &error_message)); | 75 &error_message)); |
| 65 CHECK(result.get()) << error_message; | 76 CHECK(result.get()) << error_message; |
| 66 CHECK(result->IsType(Value::TYPE_LIST)); | 77 CHECK(result->IsType(Value::TYPE_LIST)); |
| 67 return scoped_ptr<ListValue>(static_cast<ListValue*>(result.release())); | 78 return scoped_ptr<ListValue>(static_cast<ListValue*>(result.release())); |
| 68 } | 79 } |
| 69 | 80 |
| 81 DictionaryValue* FindListItem(const ListValue* list, | |
| 82 const std::string& property_name, | |
| 83 const std::string& property_value) { | |
| 84 for (size_t i = 0; i < list->GetSize(); ++i) { | |
| 85 DictionaryValue* item = NULL; | |
| 86 CHECK(list->GetDictionary(i, &item)) | |
| 87 << property_value << "/" << property_name; | |
| 88 std::string value; | |
| 89 if (item->GetString(property_name, &value) && value == property_value) | |
| 90 return item; | |
| 91 } | |
| 92 | |
| 93 return NULL; | |
| 94 } | |
| 95 | |
| 96 const DictionaryValue* GetSchemaChild(const DictionaryValue* schema_node, | |
| 97 const std::string& child_name) { | |
| 98 DictionaryValue* child_node = NULL; | |
| 99 for (size_t i = 0; i < arraysize(kChildKinds); ++i) { | |
| 100 ListValue* list_node = NULL; | |
| 101 if (!schema_node->GetList(kChildKinds[i], &list_node)) | |
| 102 continue; | |
| 103 child_node = FindListItem(list_node, "name", child_name); | |
| 104 if (child_node) | |
| 105 return child_node; | |
| 106 } | |
| 107 | |
| 108 return NULL; | |
| 109 } | |
| 110 | |
| 111 struct Static { | |
| 112 Static() | |
| 113 : api(ExtensionAPI::CreateWithDefaultConfiguration()) { | |
| 114 } | |
| 115 scoped_ptr<ExtensionAPI> api; | |
| 116 }; | |
| 117 | |
| 118 base::LazyInstance<Static> g_lazy_instance = LAZY_INSTANCE_INITIALIZER; | |
| 119 | |
| 70 } // namespace | 120 } // namespace |
| 71 | 121 |
| 72 // static | 122 // static |
| 73 ExtensionAPI* ExtensionAPI::GetInstance() { | 123 ExtensionAPI* ExtensionAPI::GetSharedInstance() { |
| 74 return Singleton<ExtensionAPI>::get(); | 124 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 125 return g_lazy_instance.Get().api.get(); | |
| 126 } | |
| 127 | |
| 128 // static | |
| 129 ExtensionAPI* ExtensionAPI::CreateWithDefaultConfiguration() { | |
| 130 ExtensionAPI* api = new ExtensionAPI(); | |
| 131 api->InitDefaultConfiguration(); | |
| 132 return api; | |
| 133 } | |
| 134 | |
| 135 // static | |
| 136 void ExtensionAPI::SplitDependencyName(const std::string& full_name, | |
| 137 std::string* feature_type, | |
| 138 std::string* feature_name) { | |
| 139 size_t colon_index = full_name.find(':'); | |
| 140 if (colon_index == std::string::npos) { | |
| 141 // TODO(aa): Remove this code when all API descriptions have been updated. | |
| 142 *feature_type = "api"; | |
| 143 *feature_name = full_name; | |
| 144 return; | |
| 145 } | |
| 146 | |
| 147 *feature_type = full_name.substr(0, colon_index); | |
| 148 *feature_name = full_name.substr(colon_index + 1); | |
| 75 } | 149 } |
| 76 | 150 |
| 77 void ExtensionAPI::LoadSchema(const base::StringPiece& schema) { | 151 void ExtensionAPI::LoadSchema(const base::StringPiece& schema) { |
| 78 scoped_ptr<ListValue> schema_list(LoadSchemaList(schema)); | 152 scoped_ptr<ListValue> schema_list(LoadSchemaList(schema)); |
| 79 std::string schema_namespace; | 153 std::string schema_namespace; |
| 80 | 154 |
| 81 while (!schema_list->empty()) { | 155 while (!schema_list->empty()) { |
| 82 const DictionaryValue* schema = NULL; | 156 const DictionaryValue* schema = NULL; |
| 83 { | 157 { |
| 84 Value* value = NULL; | 158 Value* value = NULL; |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 108 if (schema->GetList("matches", &matches)) { | 182 if (schema->GetList("matches", &matches)) { |
| 109 URLPatternSet pattern_set; | 183 URLPatternSet pattern_set; |
| 110 for (size_t i = 0; i < matches->GetSize(); ++i) { | 184 for (size_t i = 0; i < matches->GetSize(); ++i) { |
| 111 std::string pattern; | 185 std::string pattern; |
| 112 CHECK(matches->GetString(i, &pattern)); | 186 CHECK(matches->GetString(i, &pattern)); |
| 113 pattern_set.AddPattern( | 187 pattern_set.AddPattern( |
| 114 URLPattern(UserScript::kValidUserScriptSchemes, pattern)); | 188 URLPattern(UserScript::kValidUserScriptSchemes, pattern)); |
| 115 } | 189 } |
| 116 url_matching_apis_[schema_namespace] = pattern_set; | 190 url_matching_apis_[schema_namespace] = pattern_set; |
| 117 } | 191 } |
| 192 | |
| 193 // Populate feature maps. | |
| 194 // TODO(aa): Consider not storing features that can never run on the current | |
| 195 // machine (e.g., because of platform restrictions). | |
| 196 bool uses_feature_system = false; | |
| 197 schema->GetBoolean("uses_feature_system", &uses_feature_system); | |
| 198 if (!uses_feature_system) | |
| 199 continue; | |
| 200 | |
| 201 Feature* feature = new Feature(); | |
| 202 feature->set_name(schema_namespace); | |
| 203 feature->Parse(schema); | |
| 204 | |
| 205 FeatureMap* schema_features = new FeatureMap(); | |
| 206 CHECK(features_.insert( | |
| 207 std::make_pair(schema_namespace, | |
| 208 make_linked_ptr(schema_features))).second); | |
| 209 CHECK(schema_features->insert( | |
| 210 std::make_pair("", make_linked_ptr(feature))).second); | |
| 211 | |
| 212 for (size_t i = 0; i < arraysize(kChildKinds); ++i) { | |
| 213 ListValue* child_list = NULL; | |
| 214 schema->GetList(kChildKinds[i], &child_list); | |
| 215 if (!child_list) | |
| 216 continue; | |
| 217 | |
| 218 for (size_t j = 0; j < child_list->GetSize(); ++j) { | |
| 219 DictionaryValue* child = NULL; | |
| 220 CHECK(child_list->GetDictionary(j, &child)); | |
| 221 | |
| 222 scoped_ptr<Feature> child_feature(new Feature(*feature)); | |
| 223 child_feature->Parse(child); | |
| 224 if (child_feature->Equals(*feature)) | |
| 225 continue; // no need to store no-op features | |
| 226 | |
| 227 std::string child_name; | |
| 228 CHECK(child->GetString("name", &child_name)); | |
| 229 child_feature->set_name(schema_namespace + "." + child_name); | |
| 230 CHECK(schema_features->insert( | |
| 231 std::make_pair(child_name, | |
| 232 make_linked_ptr(child_feature.release()))).second); | |
| 233 } | |
| 234 } | |
| 118 } | 235 } |
| 119 } | 236 } |
| 120 | 237 |
| 121 ExtensionAPI::ExtensionAPI() { | 238 ExtensionAPI::ExtensionAPI() { |
| 239 RegisterDependencyProvider("api", this); | |
| 240 | |
| 241 // TODO(aa): Can remove this when all JSON files are converted. | |
| 242 RegisterDependencyProvider("", this); | |
| 243 } | |
| 244 | |
| 245 ExtensionAPI::~ExtensionAPI() { | |
| 246 } | |
| 247 | |
| 248 void ExtensionAPI::InitDefaultConfiguration() { | |
|
Matt Perry
2012/04/04 18:38:47
This method is called when you create a new Extens
Aaron Boodman
2012/04/04 18:41:27
It doesn't actually do any reading. ReadFromResour
| |
| 249 RegisterDependencyProvider( | |
| 250 "manifest", SimpleFeatureProvider::GetManifestFeatures()); | |
| 251 RegisterDependencyProvider( | |
| 252 "permission", SimpleFeatureProvider::GetPermissionFeatures()); | |
| 253 | |
| 122 // Schemas to be loaded from resources. | 254 // Schemas to be loaded from resources. |
| 123 unloaded_schemas_["app"] = ReadFromResource( | 255 CHECK(unloaded_schemas_.empty()); |
| 124 IDR_EXTENSION_API_JSON_APP); | 256 RegisterSchema("app", ReadFromResource( |
| 125 unloaded_schemas_["bookmarks"] = ReadFromResource( | 257 IDR_EXTENSION_API_JSON_APP)); |
| 126 IDR_EXTENSION_API_JSON_BOOKMARKS); | 258 RegisterSchema("bookmarks", ReadFromResource( |
| 127 unloaded_schemas_["browserAction"] = ReadFromResource( | 259 IDR_EXTENSION_API_JSON_BOOKMARKS)); |
| 128 IDR_EXTENSION_API_JSON_BROWSERACTION); | 260 RegisterSchema("browserAction", ReadFromResource( |
| 129 unloaded_schemas_["browsingData"] = ReadFromResource( | 261 IDR_EXTENSION_API_JSON_BROWSERACTION)); |
| 130 IDR_EXTENSION_API_JSON_BROWSINGDATA); | 262 RegisterSchema("browsingData", ReadFromResource( |
| 131 unloaded_schemas_["chromeAuthPrivate"] = ReadFromResource( | 263 IDR_EXTENSION_API_JSON_BROWSINGDATA)); |
| 132 IDR_EXTENSION_API_JSON_CHROMEAUTHPRIVATE); | 264 RegisterSchema("chromeAuthPrivate", ReadFromResource( |
| 133 unloaded_schemas_["chromeosInfoPrivate"] = ReadFromResource( | 265 IDR_EXTENSION_API_JSON_CHROMEAUTHPRIVATE)); |
| 134 IDR_EXTENSION_API_JSON_CHROMEOSINFOPRIVATE); | 266 RegisterSchema("chromeosInfoPrivate", ReadFromResource( |
| 135 unloaded_schemas_["contentSettings"] = ReadFromResource( | 267 IDR_EXTENSION_API_JSON_CHROMEOSINFOPRIVATE)); |
| 136 IDR_EXTENSION_API_JSON_CONTENTSETTINGS); | 268 RegisterSchema("contentSettings", ReadFromResource( |
| 137 unloaded_schemas_["contextMenus"] = ReadFromResource( | 269 IDR_EXTENSION_API_JSON_CONTENTSETTINGS)); |
| 138 IDR_EXTENSION_API_JSON_CONTEXTMENUS); | 270 RegisterSchema("contextMenus", ReadFromResource( |
| 139 unloaded_schemas_["cookies"] = ReadFromResource( | 271 IDR_EXTENSION_API_JSON_CONTEXTMENUS)); |
| 140 IDR_EXTENSION_API_JSON_COOKIES); | 272 RegisterSchema("cookies", ReadFromResource( |
| 141 unloaded_schemas_["debugger"] = ReadFromResource( | 273 IDR_EXTENSION_API_JSON_COOKIES)); |
| 142 IDR_EXTENSION_API_JSON_DEBUGGER); | 274 RegisterSchema("debugger", ReadFromResource( |
| 143 unloaded_schemas_["devtools"] = ReadFromResource( | 275 IDR_EXTENSION_API_JSON_DEBUGGER)); |
| 144 IDR_EXTENSION_API_JSON_DEVTOOLS); | 276 RegisterSchema("devtools", ReadFromResource( |
| 145 unloaded_schemas_["experimental.accessibility"] = ReadFromResource( | 277 IDR_EXTENSION_API_JSON_DEVTOOLS)); |
| 146 IDR_EXTENSION_API_JSON_EXPERIMENTAL_ACCESSIBILITY); | 278 RegisterSchema("experimental.accessibility", ReadFromResource( |
| 147 unloaded_schemas_["experimental.alarms"] = ReadFromResource( | 279 IDR_EXTENSION_API_JSON_EXPERIMENTAL_ACCESSIBILITY)); |
| 148 IDR_EXTENSION_API_JSON_EXPERIMENTAL_ALARMS); | 280 RegisterSchema("experimental.alarms", ReadFromResource( |
| 149 unloaded_schemas_["experimental.app"] = ReadFromResource( | 281 IDR_EXTENSION_API_JSON_EXPERIMENTAL_ALARMS)); |
| 150 IDR_EXTENSION_API_JSON_EXPERIMENTAL_APP); | 282 RegisterSchema("experimental.app", ReadFromResource( |
| 151 unloaded_schemas_["experimental.bookmarkManager"] = ReadFromResource( | 283 IDR_EXTENSION_API_JSON_EXPERIMENTAL_APP)); |
| 152 IDR_EXTENSION_API_JSON_EXPERIMENTAL_BOOKMARKMANAGER); | 284 RegisterSchema("experimental.bookmarkManager", ReadFromResource( |
| 153 unloaded_schemas_["experimental.declarative"] = ReadFromResource( | 285 IDR_EXTENSION_API_JSON_EXPERIMENTAL_BOOKMARKMANAGER)); |
| 154 IDR_EXTENSION_API_JSON_EXPERIMENTAL_DECLARATIVE); | 286 RegisterSchema("experimental.declarative", ReadFromResource( |
| 155 unloaded_schemas_["experimental.downloads"] = ReadFromResource( | 287 IDR_EXTENSION_API_JSON_EXPERIMENTAL_DECLARATIVE)); |
| 156 IDR_EXTENSION_API_JSON_EXPERIMENTAL_DOWNLOADS); | 288 RegisterSchema("experimental.downloads", ReadFromResource( |
| 157 unloaded_schemas_["experimental.extension"] = ReadFromResource( | 289 IDR_EXTENSION_API_JSON_EXPERIMENTAL_DOWNLOADS)); |
| 158 IDR_EXTENSION_API_JSON_EXPERIMENTAL_EXTENSION); | 290 RegisterSchema("experimental.extension", ReadFromResource( |
| 159 unloaded_schemas_["experimental.fontSettings"] = ReadFromResource( | 291 IDR_EXTENSION_API_JSON_EXPERIMENTAL_EXTENSION)); |
| 160 IDR_EXTENSION_API_JSON_EXPERIMENTAL_FONTSSETTINGS); | 292 RegisterSchema("experimental.fontSettings", ReadFromResource( |
| 161 unloaded_schemas_["experimental.identity"] = ReadFromResource( | 293 IDR_EXTENSION_API_JSON_EXPERIMENTAL_FONTSSETTINGS)); |
| 162 IDR_EXTENSION_API_JSON_EXPERIMENTAL_IDENTITY); | 294 RegisterSchema("experimental.identity", ReadFromResource( |
| 163 unloaded_schemas_["experimental.infobars"] = ReadFromResource( | 295 IDR_EXTENSION_API_JSON_EXPERIMENTAL_IDENTITY)); |
| 164 IDR_EXTENSION_API_JSON_EXPERIMENTAL_INFOBARS); | 296 RegisterSchema("experimental.infobars", ReadFromResource( |
| 165 unloaded_schemas_["experimental.input.ui"] = ReadFromResource( | 297 IDR_EXTENSION_API_JSON_EXPERIMENTAL_INFOBARS)); |
| 166 IDR_EXTENSION_API_JSON_EXPERIMENTAL_INPUT_UI); | 298 RegisterSchema("experimental.input.ui", ReadFromResource( |
| 167 unloaded_schemas_["experimental.input.virtualKeyboard"] = ReadFromResource( | 299 IDR_EXTENSION_API_JSON_EXPERIMENTAL_INPUT_UI)); |
| 168 IDR_EXTENSION_API_JSON_EXPERIMENTAL_INPUT_VIRTUALKEYBOARD); | 300 RegisterSchema("experimental.input.virtualKeyboard", ReadFromResource( |
| 169 unloaded_schemas_["experimental.keybinding"] = ReadFromResource( | 301 IDR_EXTENSION_API_JSON_EXPERIMENTAL_INPUT_VIRTUALKEYBOARD)); |
| 170 IDR_EXTENSION_API_JSON_EXPERIMENTAL_KEYBINDING); | 302 RegisterSchema("experimental.keybinding", ReadFromResource( |
| 171 unloaded_schemas_["experimental.managedMode"] = ReadFromResource( | 303 IDR_EXTENSION_API_JSON_EXPERIMENTAL_KEYBINDING)); |
| 172 IDR_EXTENSION_API_JSON_EXPERIMENTAL_MANAGEDMODE); | 304 RegisterSchema("experimental.managedMode", ReadFromResource( |
| 173 unloaded_schemas_["experimental.offscreenTabs"] = ReadFromResource( | 305 IDR_EXTENSION_API_JSON_EXPERIMENTAL_MANAGEDMODE)); |
| 174 IDR_EXTENSION_API_JSON_EXPERIMENTAL_OFFSCREENTABS); | 306 RegisterSchema("experimental.offscreenTabs", ReadFromResource( |
| 175 unloaded_schemas_["experimental.processes"] = ReadFromResource( | 307 IDR_EXTENSION_API_JSON_EXPERIMENTAL_OFFSCREENTABS)); |
| 176 IDR_EXTENSION_API_JSON_EXPERIMENTAL_PROCESSES); | 308 RegisterSchema("experimental.processes", ReadFromResource( |
| 177 unloaded_schemas_["experimental.rlz"] = ReadFromResource( | 309 IDR_EXTENSION_API_JSON_EXPERIMENTAL_PROCESSES)); |
| 178 IDR_EXTENSION_API_JSON_EXPERIMENTAL_RLZ); | 310 RegisterSchema("experimental.rlz", ReadFromResource( |
| 179 unloaded_schemas_["experimental.serial"] = ReadFromResource( | 311 IDR_EXTENSION_API_JSON_EXPERIMENTAL_RLZ)); |
| 180 IDR_EXTENSION_API_JSON_EXPERIMENTAL_SERIAL); | 312 RegisterSchema("experimental.serial", ReadFromResource( |
| 181 unloaded_schemas_["experimental.socket"] = ReadFromResource( | 313 IDR_EXTENSION_API_JSON_EXPERIMENTAL_SERIAL)); |
| 182 IDR_EXTENSION_API_JSON_EXPERIMENTAL_SOCKET); | 314 RegisterSchema("experimental.socket", ReadFromResource( |
| 183 unloaded_schemas_["experimental.speechInput"] = ReadFromResource( | 315 IDR_EXTENSION_API_JSON_EXPERIMENTAL_SOCKET)); |
| 184 IDR_EXTENSION_API_JSON_EXPERIMENTAL_SPEECHINPUT); | 316 RegisterSchema("experimental.speechInput", ReadFromResource( |
| 185 unloaded_schemas_["experimental.webRequest"] = ReadFromResource( | 317 IDR_EXTENSION_API_JSON_EXPERIMENTAL_SPEECHINPUT)); |
| 186 IDR_EXTENSION_API_JSON_EXPERIMENTAL_WEBREQUEST); | 318 RegisterSchema("experimental.webRequest", ReadFromResource( |
| 187 unloaded_schemas_["extension"] = ReadFromResource( | 319 IDR_EXTENSION_API_JSON_EXPERIMENTAL_WEBREQUEST)); |
| 188 IDR_EXTENSION_API_JSON_EXTENSION); | 320 RegisterSchema("extension", ReadFromResource( |
| 189 unloaded_schemas_["fileBrowserHandler"] = ReadFromResource( | 321 IDR_EXTENSION_API_JSON_EXTENSION)); |
| 190 IDR_EXTENSION_API_JSON_FILEBROWSERHANDLER); | 322 RegisterSchema("fileBrowserHandler", ReadFromResource( |
| 191 unloaded_schemas_["fileBrowserPrivate"] = ReadFromResource( | 323 IDR_EXTENSION_API_JSON_FILEBROWSERHANDLER)); |
| 192 IDR_EXTENSION_API_JSON_FILEBROWSERPRIVATE); | 324 RegisterSchema("fileBrowserPrivate", ReadFromResource( |
| 193 unloaded_schemas_["history"] = ReadFromResource( | 325 IDR_EXTENSION_API_JSON_FILEBROWSERPRIVATE)); |
| 194 IDR_EXTENSION_API_JSON_HISTORY); | 326 RegisterSchema("history", ReadFromResource( |
| 195 unloaded_schemas_["i18n"] = ReadFromResource( | 327 IDR_EXTENSION_API_JSON_HISTORY)); |
| 196 IDR_EXTENSION_API_JSON_I18N); | 328 RegisterSchema("i18n", ReadFromResource( |
| 197 unloaded_schemas_["idle"] = ReadFromResource( | 329 IDR_EXTENSION_API_JSON_I18N)); |
| 198 IDR_EXTENSION_API_JSON_IDLE); | 330 RegisterSchema("idle", ReadFromResource( |
| 199 unloaded_schemas_["input.ime"] = ReadFromResource( | 331 IDR_EXTENSION_API_JSON_IDLE)); |
| 200 IDR_EXTENSION_API_JSON_INPUT_IME); | 332 RegisterSchema("input.ime", ReadFromResource( |
| 201 unloaded_schemas_["inputMethodPrivate"] = ReadFromResource( | 333 IDR_EXTENSION_API_JSON_INPUT_IME)); |
| 202 IDR_EXTENSION_API_JSON_INPUTMETHODPRIVATE); | 334 RegisterSchema("inputMethodPrivate", ReadFromResource( |
| 203 unloaded_schemas_["management"] = ReadFromResource( | 335 IDR_EXTENSION_API_JSON_INPUTMETHODPRIVATE)); |
| 204 IDR_EXTENSION_API_JSON_MANAGEMENT); | 336 RegisterSchema("management", ReadFromResource( |
| 205 unloaded_schemas_["mediaPlayerPrivate"] = ReadFromResource( | 337 IDR_EXTENSION_API_JSON_MANAGEMENT)); |
| 206 IDR_EXTENSION_API_JSON_MEDIAPLAYERPRIVATE); | 338 RegisterSchema("mediaPlayerPrivate", ReadFromResource( |
| 207 unloaded_schemas_["metricsPrivate"] = ReadFromResource( | 339 IDR_EXTENSION_API_JSON_MEDIAPLAYERPRIVATE)); |
| 208 IDR_EXTENSION_API_JSON_METRICSPRIVATE); | 340 RegisterSchema("metricsPrivate", ReadFromResource( |
| 209 unloaded_schemas_["offersPrivate"] = ReadFromResource( | 341 IDR_EXTENSION_API_JSON_METRICSPRIVATE)); |
| 210 IDR_EXTENSION_API_JSON_OFFERSPRIVATE); | 342 RegisterSchema("offersPrivate", ReadFromResource( |
| 211 unloaded_schemas_["omnibox"] = ReadFromResource( | 343 IDR_EXTENSION_API_JSON_OFFERSPRIVATE)); |
| 212 IDR_EXTENSION_API_JSON_OMNIBOX); | 344 RegisterSchema("omnibox", ReadFromResource( |
| 213 unloaded_schemas_["pageAction"] = ReadFromResource( | 345 IDR_EXTENSION_API_JSON_OMNIBOX)); |
| 214 IDR_EXTENSION_API_JSON_PAGEACTION); | 346 RegisterSchema("pageAction", ReadFromResource( |
| 215 unloaded_schemas_["pageActions"] = ReadFromResource( | 347 IDR_EXTENSION_API_JSON_PAGEACTION)); |
| 216 IDR_EXTENSION_API_JSON_PAGEACTIONS); | 348 RegisterSchema("pageActions", ReadFromResource( |
| 217 unloaded_schemas_["pageCapture"] = ReadFromResource( | 349 IDR_EXTENSION_API_JSON_PAGEACTIONS)); |
| 218 IDR_EXTENSION_API_JSON_PAGECAPTURE); | 350 RegisterSchema("pageCapture", ReadFromResource( |
| 219 unloaded_schemas_["permissions"] = ReadFromResource( | 351 IDR_EXTENSION_API_JSON_PAGECAPTURE)); |
| 220 IDR_EXTENSION_API_JSON_PERMISSIONS); | 352 RegisterSchema("permissions", ReadFromResource( |
| 221 unloaded_schemas_["privacy"] = ReadFromResource( | 353 IDR_EXTENSION_API_JSON_PERMISSIONS)); |
| 222 IDR_EXTENSION_API_JSON_PRIVACY); | 354 RegisterSchema("privacy", ReadFromResource( |
| 223 unloaded_schemas_["proxy"] = ReadFromResource( | 355 IDR_EXTENSION_API_JSON_PRIVACY)); |
| 224 IDR_EXTENSION_API_JSON_PROXY); | 356 RegisterSchema("proxy", ReadFromResource( |
| 225 unloaded_schemas_["storage"] = ReadFromResource( | 357 IDR_EXTENSION_API_JSON_PROXY)); |
| 226 IDR_EXTENSION_API_JSON_STORAGE); | 358 RegisterSchema("storage", ReadFromResource( |
| 227 unloaded_schemas_["systemPrivate"] = ReadFromResource( | 359 IDR_EXTENSION_API_JSON_STORAGE)); |
| 228 IDR_EXTENSION_API_JSON_SYSTEMPRIVATE); | 360 RegisterSchema("systemPrivate", ReadFromResource( |
| 229 unloaded_schemas_["tabs"] = ReadFromResource( | 361 IDR_EXTENSION_API_JSON_SYSTEMPRIVATE)); |
| 230 IDR_EXTENSION_API_JSON_TABS); | 362 RegisterSchema("tabs", ReadFromResource( |
| 231 unloaded_schemas_["terminalPrivate"] = ReadFromResource( | 363 IDR_EXTENSION_API_JSON_TABS)); |
| 232 IDR_EXTENSION_API_JSON_TERMINALPRIVATE); | 364 RegisterSchema("terminalPrivate", ReadFromResource( |
| 233 unloaded_schemas_["test"] = ReadFromResource( | 365 IDR_EXTENSION_API_JSON_TERMINALPRIVATE)); |
| 234 IDR_EXTENSION_API_JSON_TEST); | 366 RegisterSchema("test", ReadFromResource( |
| 235 unloaded_schemas_["topSites"] = ReadFromResource( | 367 IDR_EXTENSION_API_JSON_TEST)); |
| 236 IDR_EXTENSION_API_JSON_TOPSITES); | 368 RegisterSchema("topSites", ReadFromResource( |
| 237 unloaded_schemas_["ttsEngine"] = ReadFromResource( | 369 IDR_EXTENSION_API_JSON_TOPSITES)); |
| 238 IDR_EXTENSION_API_JSON_TTSENGINE); | 370 RegisterSchema("ttsEngine", ReadFromResource( |
| 239 unloaded_schemas_["tts"] = ReadFromResource( | 371 IDR_EXTENSION_API_JSON_TTSENGINE)); |
| 240 IDR_EXTENSION_API_JSON_TTS); | 372 RegisterSchema("tts", ReadFromResource( |
| 241 unloaded_schemas_["types"] = ReadFromResource( | 373 IDR_EXTENSION_API_JSON_TTS)); |
| 242 IDR_EXTENSION_API_JSON_TYPES); | 374 RegisterSchema("types", ReadFromResource( |
| 243 unloaded_schemas_["webNavigation"] = ReadFromResource( | 375 IDR_EXTENSION_API_JSON_TYPES)); |
| 244 IDR_EXTENSION_API_JSON_WEBNAVIGATION); | 376 RegisterSchema("webNavigation", ReadFromResource( |
| 245 unloaded_schemas_["webRequest"] = ReadFromResource( | 377 IDR_EXTENSION_API_JSON_WEBNAVIGATION)); |
| 246 IDR_EXTENSION_API_JSON_WEBREQUEST); | 378 RegisterSchema("webRequest", ReadFromResource( |
| 247 unloaded_schemas_["webSocketProxyPrivate"] = ReadFromResource( | 379 IDR_EXTENSION_API_JSON_WEBREQUEST)); |
| 248 IDR_EXTENSION_API_JSON_WEBSOCKETPROXYPRIVATE); | 380 RegisterSchema("webSocketProxyPrivate", ReadFromResource( |
| 249 unloaded_schemas_["webstore"] = ReadFromResource( | 381 IDR_EXTENSION_API_JSON_WEBSOCKETPROXYPRIVATE)); |
| 250 IDR_EXTENSION_API_JSON_WEBSTORE); | 382 RegisterSchema("webstore", ReadFromResource( |
| 251 unloaded_schemas_["webstorePrivate"] = ReadFromResource( | 383 IDR_EXTENSION_API_JSON_WEBSTORE)); |
| 252 IDR_EXTENSION_API_JSON_WEBSTOREPRIVATE); | 384 RegisterSchema("webstorePrivate", ReadFromResource( |
| 253 unloaded_schemas_["windows"] = ReadFromResource( | 385 IDR_EXTENSION_API_JSON_WEBSTOREPRIVATE)); |
| 254 IDR_EXTENSION_API_JSON_WINDOWS); | 386 RegisterSchema("windows", ReadFromResource( |
| 387 IDR_EXTENSION_API_JSON_WINDOWS)); | |
| 255 | 388 |
| 256 // Schemas to be loaded via JSON generated from IDL files. | 389 // Schemas to be loaded via JSON generated from IDL files. |
| 257 GeneratedSchemas::Get(&unloaded_schemas_); | 390 GeneratedSchemas::Get(&unloaded_schemas_); |
| 258 } | 391 } |
| 259 | 392 |
| 260 ExtensionAPI::~ExtensionAPI() { | 393 void ExtensionAPI::RegisterSchema(const std::string& name, |
| 394 const base::StringPiece& source) { | |
| 395 unloaded_schemas_[name] = source; | |
| 396 } | |
| 397 | |
| 398 void ExtensionAPI::RegisterDependencyProvider(const std::string& name, | |
| 399 FeatureProvider* provider) { | |
| 400 dependency_providers_[name] = provider; | |
| 401 } | |
| 402 | |
| 403 bool ExtensionAPI::IsAvailable(const std::string& full_name, | |
| 404 const Extension* extension, | |
| 405 Feature::Context context) { | |
| 406 std::set<std::string> dependency_names; | |
| 407 dependency_names.insert(full_name); | |
| 408 ResolveDependencies(&dependency_names); | |
| 409 | |
| 410 for (std::set<std::string>::iterator iter = dependency_names.begin(); | |
| 411 iter != dependency_names.end(); ++iter) { | |
| 412 scoped_ptr<Feature> feature(GetFeatureDependency(full_name)); | |
| 413 CHECK(feature.get()) << *iter; | |
| 414 | |
| 415 Feature::Availability availability = | |
| 416 feature->IsAvailableToContext(extension, context); | |
| 417 if (availability != Feature::IS_AVAILABLE) | |
| 418 return false; | |
| 419 } | |
| 420 | |
| 421 return true; | |
| 261 } | 422 } |
| 262 | 423 |
| 263 bool ExtensionAPI::IsPrivileged(const std::string& full_name) { | 424 bool ExtensionAPI::IsPrivileged(const std::string& full_name) { |
| 264 std::string api_name; | |
| 265 std::string child_name; | 425 std::string child_name; |
| 266 | 426 std::string api_name = GetAPINameFromFullName(full_name, &child_name); |
| 267 { | 427 |
| 268 std::vector<std::string> split; | 428 // First try to use the feature system. |
| 269 base::SplitString(full_name, '.', &split); | 429 scoped_ptr<Feature> feature(GetFeature(full_name)); |
| 270 std::reverse(split.begin(), split.end()); | 430 if (feature.get()) { |
| 271 CHECK(!split.empty()); // |full_name| was empty or only whitespace. | 431 // An API is 'privileged' if it or any of its dependencies can only be run |
| 272 | 432 // in a blessed context. |
| 273 api_name = split.back(); | 433 std::set<std::string> resolved_dependencies; |
| 274 split.pop_back(); | 434 resolved_dependencies.insert(full_name); |
| 275 if (api_name == "experimental") { | 435 ResolveDependencies(&resolved_dependencies); |
| 276 CHECK(!split.empty()); // |full_name| was "experimental" alone. | 436 for (std::set<std::string>::iterator iter = resolved_dependencies.begin(); |
| 277 api_name += "." + split.back(); | 437 iter != resolved_dependencies.end(); ++iter) { |
| 278 split.pop_back(); | 438 scoped_ptr<Feature> dependency(GetFeatureDependency(*iter)); |
| 439 for (std::set<Feature::Context>::iterator context = | |
| 440 dependency->contexts()->begin(); | |
| 441 context != dependency->contexts()->end(); ++context) { | |
| 442 if (*context != Feature::BLESSED_EXTENSION_CONTEXT) | |
| 443 return false; | |
| 444 } | |
| 279 } | 445 } |
| 280 | 446 return true; |
| 281 // This only really works properly if split.size() == 1, however: | |
| 282 // - if it's empty, it's ok to leave child_name empty; presumably there's | |
| 283 // no functions or events with empty names. | |
| 284 // - if it's > 1, we can just do our best. | |
| 285 if (split.size() > 0) | |
| 286 child_name = split[0]; | |
| 287 } | 447 } |
| 288 | 448 |
| 289 // GetSchema to ensure that it gets loaded before any checks. | 449 // If this API hasn't been converted yet, fall back to the old system. |
| 290 const DictionaryValue* schema = GetSchema(api_name); | |
| 291 | |
| 292 if (completely_unprivileged_apis_.count(api_name)) | 450 if (completely_unprivileged_apis_.count(api_name)) |
| 293 return false; | 451 return false; |
| 294 | 452 |
| 295 if (partially_unprivileged_apis_.count(api_name)) { | 453 const DictionaryValue* schema = GetSchema(api_name); |
| 296 return IsChildNamePrivileged(schema, "functions", child_name) && | 454 if (partially_unprivileged_apis_.count(api_name)) |
| 297 IsChildNamePrivileged(schema, "events", child_name); | 455 return IsChildNamePrivileged(schema, child_name); |
| 298 } | |
| 299 | 456 |
| 300 return true; | 457 return true; |
| 301 } | 458 } |
| 302 | 459 |
| 303 DictionaryValue* ExtensionAPI::FindListItem( | |
| 304 const ListValue* list, | |
| 305 const std::string& property_name, | |
| 306 const std::string& property_value) { | |
| 307 for (size_t i = 0; i < list->GetSize(); ++i) { | |
| 308 DictionaryValue* item = NULL; | |
| 309 CHECK(list->GetDictionary(i, &item)) | |
| 310 << property_value << "/" << property_name; | |
| 311 std::string value; | |
| 312 if (item->GetString(property_name, &value) && value == property_value) | |
| 313 return item; | |
| 314 } | |
| 315 | |
| 316 return NULL; | |
| 317 } | |
| 318 | |
| 319 bool ExtensionAPI::IsChildNamePrivileged(const DictionaryValue* name_space_node, | 460 bool ExtensionAPI::IsChildNamePrivileged(const DictionaryValue* name_space_node, |
| 320 const std::string& child_kind, | |
| 321 const std::string& child_name) { | 461 const std::string& child_name) { |
| 322 ListValue* child_list = NULL; | |
| 323 name_space_node->GetList(child_kind, &child_list); | |
| 324 if (!child_list) | |
| 325 return true; | |
| 326 | |
| 327 bool unprivileged = false; | 462 bool unprivileged = false; |
| 328 DictionaryValue* child = FindListItem(child_list, "name", child_name); | 463 const DictionaryValue* child = GetSchemaChild(name_space_node, child_name); |
| 329 if (!child || !child->GetBoolean("unprivileged", &unprivileged)) | 464 if (!child || !child->GetBoolean("unprivileged", &unprivileged)) |
| 330 return true; | 465 return true; |
| 331 | 466 |
| 332 return !unprivileged; | 467 return !unprivileged; |
| 333 } | 468 } |
| 334 | 469 |
| 335 const DictionaryValue* ExtensionAPI::GetSchema(const std::string& api_name) { | 470 const DictionaryValue* ExtensionAPI::GetSchema(const std::string& full_name) { |
| 336 SchemaMap::const_iterator maybe_schema = schemas_.find(api_name); | 471 std::string child_name; |
| 337 if (maybe_schema != schemas_.end()) | 472 std::string api_name = GetAPINameFromFullName(full_name, &child_name); |
| 338 return maybe_schema->second.get(); | 473 |
| 339 | 474 const DictionaryValue* result = NULL; |
| 340 // Might not have loaded yet; or might just not exist. | 475 SchemaMap::iterator maybe_schema = schemas_.find(api_name); |
| 341 std::map<std::string, base::StringPiece>::iterator maybe_schema_resource = | 476 if (maybe_schema != schemas_.end()) { |
| 342 unloaded_schemas_.find(api_name); | 477 result = maybe_schema->second.get(); |
| 343 if (maybe_schema_resource == unloaded_schemas_.end()) | 478 } else { |
| 344 return NULL; | 479 // Might not have loaded yet; or might just not exist. |
| 345 | 480 std::map<std::string, base::StringPiece>::iterator maybe_schema_resource = |
| 346 LoadSchema(maybe_schema_resource->second); | 481 unloaded_schemas_.find(api_name); |
| 347 maybe_schema = schemas_.find(api_name); | 482 if (maybe_schema_resource == unloaded_schemas_.end()) |
| 348 CHECK(schemas_.end() != maybe_schema); | 483 return NULL; |
| 349 return maybe_schema->second.get(); | 484 |
| 485 LoadSchema(maybe_schema_resource->second); | |
| 486 maybe_schema = schemas_.find(api_name); | |
| 487 CHECK(schemas_.end() != maybe_schema); | |
| 488 result = maybe_schema->second.get(); | |
| 489 } | |
| 490 | |
| 491 if (!child_name.empty()) | |
| 492 result = GetSchemaChild(result, child_name); | |
| 493 | |
| 494 return result; | |
| 350 } | 495 } |
| 351 | 496 |
| 352 scoped_ptr<std::set<std::string> > ExtensionAPI::GetAPIsForContext( | 497 scoped_ptr<std::set<std::string> > ExtensionAPI::GetAPIsForContext( |
| 353 Feature::Context context, const Extension* extension, const GURL& url) { | 498 Feature::Context context, const Extension* extension, const GURL& url) { |
| 354 // We're forced to load all schemas now because we need to know the metadata | 499 // We're forced to load all schemas now because we need to know the metadata |
| 355 // about every API -- and the metadata is stored in the schemas themselves. | 500 // about every API -- and the metadata is stored in the schemas themselves. |
| 356 // This is a shame. | 501 // This is a shame. |
| 357 // TODO(aa/kalman): store metadata in a separate file and don't load all | 502 // TODO(aa/kalman): store metadata in a separate file and don't load all |
| 358 // schemas. | 503 // schemas. |
| 359 LoadAllSchemas(); | 504 LoadAllSchemas(); |
| 360 | 505 |
| 361 scoped_ptr<std::set<std::string> > result(new std::set<std::string>()); | 506 std::set<std::string> temp_result; |
| 362 | 507 |
| 508 // First handle all the APIs that have been converted to the feature system. | |
| 509 if (extension) { | |
| 510 for (APIFeatureMap::iterator iter = features_.begin(); | |
| 511 iter != features_.end(); ++iter) { | |
| 512 if (IsAvailable(iter->first, extension, context)) | |
| 513 temp_result.insert(iter->first); | |
| 514 } | |
| 515 } | |
| 516 | |
| 517 // Second, fall back to the old way. | |
| 518 // TODO(aa): Remove this when all APIs have been converted. | |
| 363 switch (context) { | 519 switch (context) { |
| 364 case Feature::UNSPECIFIED_CONTEXT: | 520 case Feature::UNSPECIFIED_CONTEXT: |
| 365 break; | 521 break; |
| 366 | 522 |
| 367 case Feature::BLESSED_EXTENSION_CONTEXT: | 523 case Feature::BLESSED_EXTENSION_CONTEXT: |
| 368 // Availability is determined by the permissions of the extension. | 524 // Availability is determined by the permissions of the extension. |
| 369 CHECK(extension); | 525 CHECK(extension); |
| 370 GetAllowedAPIs(extension, result.get()); | 526 GetAllowedAPIs(extension, &temp_result); |
| 371 ResolveDependencies(result.get()); | 527 ResolveDependencies(&temp_result); |
| 372 break; | 528 break; |
| 373 | 529 |
| 374 case Feature::UNBLESSED_EXTENSION_CONTEXT: | 530 case Feature::UNBLESSED_EXTENSION_CONTEXT: |
| 375 case Feature::CONTENT_SCRIPT_CONTEXT: | 531 case Feature::CONTENT_SCRIPT_CONTEXT: |
| 376 // Same as BLESSED_EXTENSION_CONTEXT, but only those APIs that are | 532 // Same as BLESSED_EXTENSION_CONTEXT, but only those APIs that are |
| 377 // unprivileged. | 533 // unprivileged. |
| 378 CHECK(extension); | 534 CHECK(extension); |
| 379 GetAllowedAPIs(extension, result.get()); | 535 GetAllowedAPIs(extension, &temp_result); |
| 380 // Resolving dependencies before removing unprivileged APIs means that | 536 // Resolving dependencies before removing unprivileged APIs means that |
| 381 // some unprivileged APIs may have unrealised dependencies. Too bad! | 537 // some unprivileged APIs may have unrealised dependencies. Too bad! |
| 382 ResolveDependencies(result.get()); | 538 ResolveDependencies(&temp_result); |
| 383 RemovePrivilegedAPIs(result.get()); | 539 RemovePrivilegedAPIs(&temp_result); |
| 384 break; | 540 break; |
| 385 | 541 |
| 386 case Feature::WEB_PAGE_CONTEXT: | 542 case Feature::WEB_PAGE_CONTEXT: |
| 387 // Availablility is determined by the url. | 543 // Availablility is determined by the url. |
| 388 CHECK(url.is_valid()); | 544 CHECK(url.is_valid()); |
| 389 GetAPIsMatchingURL(url, result.get()); | 545 GetAPIsMatchingURL(url, &temp_result); |
| 390 break; | 546 break; |
| 391 } | 547 } |
| 392 | 548 |
| 549 // Filter out all non-API features and remove the feature type part of the | |
| 550 // name. | |
| 551 scoped_ptr<std::set<std::string> > result(new std::set<std::string>()); | |
| 552 for (std::set<std::string>::iterator iter = temp_result.begin(); | |
| 553 iter != temp_result.end(); ++iter) { | |
| 554 std::string feature_type; | |
| 555 std::string feature_name; | |
| 556 SplitDependencyName(*iter, &feature_type, &feature_name); | |
| 557 if (feature_type == "api") | |
| 558 result->insert(feature_name); | |
| 559 } | |
| 560 | |
| 393 return result.Pass(); | 561 return result.Pass(); |
| 394 } | 562 } |
| 395 | 563 |
| 564 scoped_ptr<Feature> ExtensionAPI::GetFeature(const std::string& full_name) { | |
| 565 // Ensure it's loaded. | |
| 566 GetSchema(full_name); | |
| 567 | |
| 568 std::string child_name; | |
| 569 std::string api_namespace = GetAPINameFromFullName(full_name, &child_name); | |
| 570 | |
| 571 APIFeatureMap::iterator api_features = features_.find(api_namespace); | |
| 572 if (api_features == features_.end()) | |
| 573 return scoped_ptr<Feature>(NULL); | |
| 574 | |
| 575 scoped_ptr<Feature> result; | |
| 576 FeatureMap::iterator child_feature = api_features->second->find(child_name); | |
| 577 if (child_feature != api_features->second->end()) { | |
| 578 // TODO(aa): Argh, having FeatureProvider return a scoped pointer was a | |
| 579 // mistake. See: crbug.com/120068. | |
| 580 result.reset(new Feature(*child_feature->second)); | |
| 581 } else { | |
| 582 FeatureMap::iterator parent_feature = api_features->second->find(""); | |
| 583 CHECK(parent_feature != api_features->second->end()); | |
| 584 result.reset(new Feature(*parent_feature->second)); | |
| 585 } | |
| 586 | |
| 587 if (result->contexts()->empty()) { | |
| 588 result.reset(); | |
| 589 LOG(ERROR) << "API feature '" << full_name | |
| 590 << "' must specify at least one context."; | |
| 591 } | |
| 592 | |
| 593 return result.Pass(); | |
| 594 } | |
| 595 | |
| 596 scoped_ptr<Feature> ExtensionAPI::GetFeatureDependency( | |
| 597 const std::string& full_name) { | |
| 598 std::string feature_type; | |
| 599 std::string feature_name; | |
| 600 SplitDependencyName(full_name, &feature_type, &feature_name); | |
| 601 | |
| 602 FeatureProviderMap::iterator provider = | |
| 603 dependency_providers_.find(feature_type); | |
| 604 CHECK(provider != dependency_providers_.end()) << full_name; | |
| 605 | |
| 606 scoped_ptr<Feature> feature(provider->second->GetFeature(feature_name)); | |
| 607 CHECK(feature.get()) << full_name; | |
| 608 | |
| 609 return feature.Pass(); | |
| 610 } | |
| 611 | |
| 612 std::string ExtensionAPI::GetAPINameFromFullName(const std::string& full_name, | |
| 613 std::string* child_name) { | |
| 614 std::string api_name_candidate = full_name; | |
| 615 while (true) { | |
| 616 if (features_.find(api_name_candidate) != features_.end() || | |
| 617 schemas_.find(api_name_candidate) != schemas_.end() || | |
| 618 unloaded_schemas_.find(api_name_candidate) != unloaded_schemas_.end()) { | |
| 619 std::string result = api_name_candidate; | |
| 620 | |
| 621 if (child_name) { | |
| 622 if (result.length() < full_name.length()) | |
| 623 *child_name = full_name.substr(result.length() + 1); | |
| 624 else | |
| 625 *child_name = ""; | |
| 626 } | |
| 627 | |
| 628 return result; | |
| 629 } | |
| 630 | |
| 631 size_t last_dot_index = api_name_candidate.rfind('.'); | |
| 632 if (last_dot_index == std::string::npos) | |
| 633 break; | |
| 634 | |
| 635 api_name_candidate = api_name_candidate.substr(0, last_dot_index); | |
| 636 } | |
| 637 | |
| 638 *child_name = ""; | |
| 639 return ""; | |
| 640 } | |
| 641 | |
| 396 void ExtensionAPI::GetAllowedAPIs( | 642 void ExtensionAPI::GetAllowedAPIs( |
| 397 const Extension* extension, std::set<std::string>* out) { | 643 const Extension* extension, std::set<std::string>* out) { |
| 398 for (SchemaMap::const_iterator i = schemas_.begin(); i != schemas_.end(); | 644 for (SchemaMap::const_iterator i = schemas_.begin(); i != schemas_.end(); |
| 399 ++i) { | 645 ++i) { |
| 646 if (features_.find(i->first) != features_.end()) { | |
| 647 // This API is controlled by the feature system. Nothing to do here. | |
| 648 continue; | |
| 649 } | |
| 650 | |
| 400 if (extension->required_permission_set()->HasAnyAccessToAPI(i->first) || | 651 if (extension->required_permission_set()->HasAnyAccessToAPI(i->first) || |
| 401 extension->optional_permission_set()->HasAnyAccessToAPI(i->first)) { | 652 extension->optional_permission_set()->HasAnyAccessToAPI(i->first)) { |
| 402 out->insert(i->first); | 653 out->insert(i->first); |
| 403 } | 654 } |
| 404 } | 655 } |
| 405 } | 656 } |
| 406 | 657 |
| 407 void ExtensionAPI::ResolveDependencies(std::set<std::string>* out) { | 658 void ExtensionAPI::ResolveDependencies(std::set<std::string>* out) { |
| 408 std::set<std::string> missing_dependencies; | 659 std::set<std::string> missing_dependencies; |
| 409 for (std::set<std::string>::iterator i = out->begin(); i != out->end(); ++i) | 660 for (std::set<std::string>::iterator i = out->begin(); i != out->end(); ++i) |
| 410 GetMissingDependencies(*i, *out, &missing_dependencies); | 661 GetMissingDependencies(*i, *out, &missing_dependencies); |
| 411 | 662 |
| 412 while (missing_dependencies.size()) { | 663 while (missing_dependencies.size()) { |
| 413 std::string next = *missing_dependencies.begin(); | 664 std::string next = *missing_dependencies.begin(); |
| 414 missing_dependencies.erase(next); | 665 missing_dependencies.erase(next); |
| 415 out->insert(next); | 666 out->insert(next); |
| 416 GetMissingDependencies(next, *out, &missing_dependencies); | 667 GetMissingDependencies(next, *out, &missing_dependencies); |
| 417 } | 668 } |
| 418 } | 669 } |
| 419 | 670 |
| 420 void ExtensionAPI::GetMissingDependencies( | 671 void ExtensionAPI::GetMissingDependencies( |
| 421 const std::string& api_name, | 672 const std::string& api_name, |
| 422 const std::set<std::string>& excluding, | 673 const std::set<std::string>& excluding, |
| 423 std::set<std::string>* out) { | 674 std::set<std::string>* out) { |
| 424 const DictionaryValue* schema = GetSchema(api_name); | 675 std::string feature_type; |
| 425 CHECK(schema) << "Schema for " << api_name << " not found"; | 676 std::string feature_name; |
| 677 SplitDependencyName(api_name, &feature_type, &feature_name); | |
| 678 | |
| 679 // Only API features can have dependencies for now. | |
| 680 if (feature_type != "api") | |
| 681 return; | |
| 682 | |
| 683 const DictionaryValue* schema = GetSchema(feature_name); | |
| 684 CHECK(schema) << "Schema for " << feature_name << " not found"; | |
| 426 | 685 |
| 427 ListValue* dependencies = NULL; | 686 ListValue* dependencies = NULL; |
| 428 if (!schema->GetList("dependencies", &dependencies)) | 687 if (!schema->GetList("dependencies", &dependencies)) |
| 429 return; | 688 return; |
| 430 | 689 |
| 431 for (size_t i = 0; i < dependencies->GetSize(); ++i) { | 690 for (size_t i = 0; i < dependencies->GetSize(); ++i) { |
| 432 std::string api_name; | 691 std::string dependency_name; |
| 433 if (dependencies->GetString(i, &api_name) && !excluding.count(api_name)) | 692 if (dependencies->GetString(i, &dependency_name) && |
| 434 out->insert(api_name); | 693 !excluding.count(dependency_name)) { |
| 694 out->insert(dependency_name); | |
| 695 } | |
| 435 } | 696 } |
| 436 } | 697 } |
| 437 | 698 |
| 438 void ExtensionAPI::RemovePrivilegedAPIs(std::set<std::string>* apis) { | 699 void ExtensionAPI::RemovePrivilegedAPIs(std::set<std::string>* apis) { |
| 439 std::set<std::string> privileged_apis; | 700 std::set<std::string> privileged_apis; |
| 440 for (std::set<std::string>::iterator i = apis->begin(); i != apis->end(); | 701 for (std::set<std::string>::iterator i = apis->begin(); i != apis->end(); |
| 441 ++i) { | 702 ++i) { |
| 442 if (!completely_unprivileged_apis_.count(*i) && | 703 if (!completely_unprivileged_apis_.count(*i) && |
| 443 !partially_unprivileged_apis_.count(*i)) { | 704 !partially_unprivileged_apis_.count(*i)) { |
| 444 privileged_apis.insert(*i); | 705 privileged_apis.insert(*i); |
| 445 } | 706 } |
| 446 } | 707 } |
| 447 for (std::set<std::string>::iterator i = privileged_apis.begin(); | 708 for (std::set<std::string>::iterator i = privileged_apis.begin(); |
| 448 i != privileged_apis.end(); ++i) { | 709 i != privileged_apis.end(); ++i) { |
| 449 apis->erase(*i); | 710 apis->erase(*i); |
| 450 } | 711 } |
| 451 } | 712 } |
| 452 | 713 |
| 453 void ExtensionAPI::GetAPIsMatchingURL(const GURL& url, | 714 void ExtensionAPI::GetAPIsMatchingURL(const GURL& url, |
| 454 std::set<std::string>* out) { | 715 std::set<std::string>* out) { |
| 455 for (std::map<std::string, URLPatternSet>::const_iterator i = | 716 for (std::map<std::string, URLPatternSet>::const_iterator i = |
| 456 url_matching_apis_.begin(); i != url_matching_apis_.end(); ++i) { | 717 url_matching_apis_.begin(); i != url_matching_apis_.end(); ++i) { |
| 718 if (features_.find(i->first) != features_.end()) { | |
| 719 // This API is controlled by the feature system. Nothing to do. | |
| 720 continue; | |
| 721 } | |
| 722 | |
| 457 if (i->second.MatchesURL(url)) | 723 if (i->second.MatchesURL(url)) |
| 458 out->insert(i->first); | 724 out->insert(i->first); |
| 459 } | 725 } |
| 460 } | 726 } |
| 461 | 727 |
| 462 void ExtensionAPI::LoadAllSchemas() { | 728 void ExtensionAPI::LoadAllSchemas() { |
| 463 while (unloaded_schemas_.size()) { | 729 while (unloaded_schemas_.size()) { |
| 464 LoadSchema(unloaded_schemas_.begin()->second); | 730 LoadSchema(unloaded_schemas_.begin()->second); |
| 465 } | 731 } |
| 466 } | 732 } |
| 467 | 733 |
| 468 } // namespace extensions | 734 } // namespace extensions |
| OLD | NEW |