Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(550)

Side by Side Diff: chrome/common/extensions/api/extension_api.cc

Issue 12846011: Implement API features for the Extension API feature system (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: tests and comments Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after
227 // TODO(aa): Remove this code when all API descriptions have been updated. 227 // TODO(aa): Remove this code when all API descriptions have been updated.
228 *feature_type = "api"; 228 *feature_type = "api";
229 *feature_name = full_name; 229 *feature_name = full_name;
230 return; 230 return;
231 } 231 }
232 232
233 *feature_type = full_name.substr(0, colon_index); 233 *feature_type = full_name.substr(0, colon_index);
234 *feature_name = full_name.substr(colon_index + 1); 234 *feature_name = full_name.substr(colon_index + 1);
235 } 235 }
236 236
237 bool ExtensionAPI::UsesFeatureSystem(const std::string& full_name) {
238 std::string api_name = GetAPINameFromFullName(full_name, NULL);
239 return features_.find(api_name) != features_.end();
240 }
241
242 void ExtensionAPI::LoadSchema(const std::string& name, 237 void ExtensionAPI::LoadSchema(const std::string& name,
243 const base::StringPiece& schema) { 238 const base::StringPiece& schema) {
244 scoped_ptr<ListValue> schema_list(LoadSchemaList(name, schema)); 239 scoped_ptr<ListValue> schema_list(LoadSchemaList(name, schema));
245 std::string schema_namespace; 240 std::string schema_namespace;
246 241
247 while (!schema_list->empty()) { 242 while (!schema_list->empty()) {
248 DictionaryValue* schema = NULL; 243 DictionaryValue* schema = NULL;
249 { 244 {
250 Value* value = NULL; 245 Value* value = NULL;
251 schema_list->Remove(schema_list->GetSize() - 1, &value); 246 schema_list->Remove(schema_list->GetSize() - 1, &value);
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
325 child_feature->set_name(schema_namespace + "." + child_name); 320 child_feature->set_name(schema_namespace + "." + child_name);
326 CHECK(schema_features->insert( 321 CHECK(schema_features->insert(
327 std::make_pair(child_name, 322 std::make_pair(child_name,
328 make_linked_ptr(child_feature.release()))).second); 323 make_linked_ptr(child_feature.release()))).second);
329 } 324 }
330 } 325 }
331 } 326 }
332 } 327 }
333 328
334 ExtensionAPI::ExtensionAPI() { 329 ExtensionAPI::ExtensionAPI() {
335 RegisterDependencyProvider("api", this);
336
337 // TODO(aa): Can remove this when all JSON files are converted.
338 RegisterDependencyProvider("", this);
339 } 330 }
340 331
341 ExtensionAPI::~ExtensionAPI() { 332 ExtensionAPI::~ExtensionAPI() {
342 } 333 }
343 334
344 void ExtensionAPI::InitDefaultConfiguration() { 335 void ExtensionAPI::InitDefaultConfiguration() {
345 RegisterDependencyProvider( 336 RegisterDependencyProvider(
337 "api", BaseFeatureProvider::GetApiFeatures());
338 RegisterDependencyProvider(
346 "manifest", BaseFeatureProvider::GetManifestFeatures()); 339 "manifest", BaseFeatureProvider::GetManifestFeatures());
347 RegisterDependencyProvider( 340 RegisterDependencyProvider(
348 "permission", BaseFeatureProvider::GetPermissionFeatures()); 341 "permission", BaseFeatureProvider::GetPermissionFeatures());
349 342
350 // Schemas to be loaded from resources. 343 // Schemas to be loaded from resources.
351 CHECK(unloaded_schemas_.empty()); 344 CHECK(unloaded_schemas_.empty());
352 RegisterSchema("app", ReadFromResource( 345 RegisterSchema("app", ReadFromResource(
353 IDR_EXTENSION_API_JSON_APP)); 346 IDR_EXTENSION_API_JSON_APP));
354 RegisterSchema("browserAction", ReadFromResource( 347 RegisterSchema("browserAction", ReadFromResource(
355 IDR_EXTENSION_API_JSON_BROWSERACTION)); 348 IDR_EXTENSION_API_JSON_BROWSERACTION));
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
415 408
416 void ExtensionAPI::RegisterDependencyProvider(const std::string& name, 409 void ExtensionAPI::RegisterDependencyProvider(const std::string& name,
417 FeatureProvider* provider) { 410 FeatureProvider* provider) {
418 dependency_providers_[name] = provider; 411 dependency_providers_[name] = provider;
419 } 412 }
420 413
421 Feature::Availability ExtensionAPI::IsAvailable(const std::string& full_name, 414 Feature::Availability ExtensionAPI::IsAvailable(const std::string& full_name,
422 const Extension* extension, 415 const Extension* extension,
423 Feature::Context context, 416 Feature::Context context,
424 const GURL& url) { 417 const GURL& url) {
425 std::set<std::string> dependency_names; 418 std::string feature_type;
426 dependency_names.insert(full_name); 419 std::string feature_name;
427 ResolveDependencies(&dependency_names); 420 SplitDependencyName(full_name, &feature_type, &feature_name);
421
422 std::string child_name;
423 std::string api_name = GetAPINameFromFullName(feature_name, &child_name);
424
425 Feature* feature = GetFeatureDependency(full_name);
428 426
429 // Check APIs not using the feature system first. 427 // Check APIs not using the feature system first.
430 if (!UsesFeatureSystem(full_name)) { 428 if (!feature) {
431 return IsNonFeatureAPIAvailable(full_name, context, extension, url) ? 429 return IsNonFeatureAPIAvailable(api_name, context, extension, url) ?
432 Feature::CreateAvailability(Feature::IS_AVAILABLE, "") : 430 Feature::CreateAvailability(Feature::IS_AVAILABLE, "") :
433 Feature::CreateAvailability(Feature::INVALID_CONTEXT, 431 Feature::CreateAvailability(Feature::INVALID_CONTEXT,
434 kUnavailableMessage); 432 kUnavailableMessage);
435 } 433 }
436 434
437 for (std::set<std::string>::iterator iter = dependency_names.begin(); 435 Feature::Availability availability =
438 iter != dependency_names.end(); ++iter) { 436 feature->IsAvailableToContext(extension, context, url);
439 Feature* feature = GetFeatureDependency(*iter); 437 if (!availability.is_available())
440 CHECK(feature) << *iter; 438 return availability;
441 439
442 Feature::Availability availability = 440 for (std::set<std::string>::iterator iter = feature->dependencies().begin();
443 feature->IsAvailableToContext(extension, context, url); 441 iter != feature->dependencies().end(); ++iter) {
444 if (!availability.is_available()) 442 Feature::Availability dependency_availability =
445 return availability; 443 IsAvailable(*iter, extension, context, url);
444 if (!dependency_availability.is_available())
445 return dependency_availability;
446 } 446 }
447 447
448 return Feature::CreateAvailability(Feature::IS_AVAILABLE, ""); 448 return Feature::CreateAvailability(Feature::IS_AVAILABLE, "");
449 } 449 }
450 450
451 bool ExtensionAPI::IsPrivileged(const std::string& full_name) { 451 bool ExtensionAPI::IsPrivileged(const std::string& full_name) {
452 std::string child_name; 452 std::string child_name;
453 std::string api_name = GetAPINameFromFullName(full_name, &child_name); 453 std::string api_name = GetAPINameFromFullName(full_name, &child_name);
454 Feature* feature = GetFeatureDependency(full_name);
454 455
455 // First try to use the feature system. 456 // First try to use the feature system.
456 Feature* feature(GetFeature(full_name));
457 if (feature) { 457 if (feature) {
458 // An API is 'privileged' if it or any of its dependencies can only be run 458 // An API is 'privileged' if it or any of its dependencies can only be run
459 // in a blessed context. 459 // in a blessed context.
460 std::set<std::string> resolved_dependencies; 460 if (feature->GetContexts()->size() !=
461 resolved_dependencies.insert(full_name); 461 feature->GetContexts()->count(Feature::BLESSED_EXTENSION_CONTEXT)) {
462 ResolveDependencies(&resolved_dependencies); 462 return false;
463 for (std::set<std::string>::iterator iter = resolved_dependencies.begin();
464 iter != resolved_dependencies.end(); ++iter) {
465 Feature* dependency = GetFeatureDependency(*iter);
466 for (std::set<Feature::Context>::iterator context =
467 dependency->GetContexts()->begin();
468 context != dependency->GetContexts()->end(); ++context) {
469 if (*context != Feature::BLESSED_EXTENSION_CONTEXT)
470 return false;
471 }
472 } 463 }
473 return true; 464 std::set<std::string> dependencies = feature->dependencies();
465 for (std::set<std::string>::iterator iter = dependencies.begin();
466 iter != dependencies.end(); ++iter) {
467 if (!IsPrivileged(*iter))
468 return false;
469 }
474 } 470 }
475 471
472 // Get the schema now to populate |completely_unprivileged_apis_|.
473 const DictionaryValue* schema = GetSchema(api_name);
476 // If this API hasn't been converted yet, fall back to the old system. 474 // If this API hasn't been converted yet, fall back to the old system.
477 if (completely_unprivileged_apis_.count(api_name)) 475 if (completely_unprivileged_apis_.count(api_name))
478 return false; 476 return false;
479 477
480 const DictionaryValue* schema = GetSchema(api_name);
481 if (partially_unprivileged_apis_.count(api_name)) 478 if (partially_unprivileged_apis_.count(api_name))
482 return IsChildNamePrivileged(schema, child_name); 479 return IsChildNamePrivileged(schema, child_name);
483 480
484 return true; 481 return true;
485 } 482 }
486 483
487 bool ExtensionAPI::IsChildNamePrivileged(const DictionaryValue* name_space_node, 484 bool ExtensionAPI::IsChildNamePrivileged(const DictionaryValue* name_space_node,
488 const std::string& child_name) { 485 const std::string& child_name) {
489 bool unprivileged = false; 486 bool unprivileged = false;
490 const DictionaryValue* child = GetSchemaChild(name_space_node, child_name); 487 const DictionaryValue* child = GetSchemaChild(name_space_node, child_name);
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
542 539
543 return true; 540 return true;
544 } 541 }
545 542
546 } // namespace 543 } // namespace
547 544
548 bool ExtensionAPI::IsNonFeatureAPIAvailable(const std::string& name, 545 bool ExtensionAPI::IsNonFeatureAPIAvailable(const std::string& name,
549 Feature::Context context, 546 Feature::Context context,
550 const Extension* extension, 547 const Extension* extension,
551 const GURL& url) { 548 const GURL& url) {
549 // Make sure schema is loaded.
550 GetSchema(name);
552 switch (context) { 551 switch (context) {
553 case Feature::UNSPECIFIED_CONTEXT: 552 case Feature::UNSPECIFIED_CONTEXT:
554 break; 553 break;
555 554
556 case Feature::BLESSED_EXTENSION_CONTEXT: 555 case Feature::BLESSED_EXTENSION_CONTEXT:
557 if (extension) { 556 if (extension) {
558 // Availability is determined by the permissions of the extension. 557 // Availability is determined by the permissions of the extension.
559 if (!IsAPIAllowed(name, extension)) 558 if (!IsAPIAllowed(name, extension))
560 return false; 559 return false;
561 if (!IsFeatureAllowedForExtension(name, *extension)) 560 if (!IsFeatureAllowedForExtension(name, *extension))
(...skipping 28 matching lines...) Expand all
590 std::set<std::string> result; 589 std::set<std::string> result;
591 for (SchemaMap::iterator i = schemas_.begin(); i != schemas_.end(); ++i) 590 for (SchemaMap::iterator i = schemas_.begin(); i != schemas_.end(); ++i)
592 result.insert(i->first); 591 result.insert(i->first);
593 for (UnloadedSchemaMap::iterator i = unloaded_schemas_.begin(); 592 for (UnloadedSchemaMap::iterator i = unloaded_schemas_.begin();
594 i != unloaded_schemas_.end(); ++i) { 593 i != unloaded_schemas_.end(); ++i) {
595 result.insert(i->first); 594 result.insert(i->first);
596 } 595 }
597 return result; 596 return result;
598 } 597 }
599 598
600 Feature* ExtensionAPI::GetFeature(const std::string& full_name) {
601 // Ensure it's loaded.
602 GetSchema(full_name);
603
604 std::string child_name;
605 std::string api_namespace = GetAPINameFromFullName(full_name, &child_name);
606
607 APIFeatureMap::iterator feature_map = features_.find(api_namespace);
608 if (feature_map == features_.end())
609 return NULL;
610
611 Feature* result = NULL;
612 FeatureMap::iterator child_feature = feature_map->second->find(child_name);
613 if (child_feature != feature_map->second->end()) {
614 result = child_feature->second.get();
615 } else {
616 FeatureMap::iterator parent_feature = feature_map->second->find("");
617 CHECK(parent_feature != feature_map->second->end());
618 result = parent_feature->second.get();
619 }
620
621 if (result->GetContexts()->empty()) {
622 LOG(ERROR) << "API feature '" << full_name
623 << "' must specify at least one context.";
624 return NULL;
625 }
626
627 return result;
628 }
629
630 Feature* ExtensionAPI::GetFeatureDependency(const std::string& full_name) { 599 Feature* ExtensionAPI::GetFeatureDependency(const std::string& full_name) {
631 std::string feature_type; 600 std::string feature_type;
632 std::string feature_name; 601 std::string feature_name;
633 SplitDependencyName(full_name, &feature_type, &feature_name); 602 SplitDependencyName(full_name, &feature_type, &feature_name);
634 603
635 FeatureProviderMap::iterator provider = 604 FeatureProviderMap::iterator provider =
636 dependency_providers_.find(feature_type); 605 dependency_providers_.find(feature_type);
637 CHECK(provider != dependency_providers_.end()) << full_name; 606 if (provider == dependency_providers_.end())
607 return NULL;
638 608
639 Feature* feature = provider->second->GetFeature(feature_name); 609 Feature* feature = provider->second->GetFeature(feature_name);
640 CHECK(feature) << full_name; 610 // Try getting the feature for the parent API, if this was a child.
641 611 if (!feature) {
612 std::string child_name;
613 feature = provider->second->GetFeature(
614 GetAPINameFromFullName(feature_name, &child_name));
615 }
642 return feature; 616 return feature;
643 } 617 }
644 618
645 std::string ExtensionAPI::GetAPINameFromFullName(const std::string& full_name, 619 std::string ExtensionAPI::GetAPINameFromFullName(const std::string& full_name,
646 std::string* child_name) { 620 std::string* child_name) {
647 std::string api_name_candidate = full_name; 621 std::string api_name_candidate = full_name;
648 while (true) { 622 while (true) {
649 if (features_.find(api_name_candidate) != features_.end() || 623 if (features_.find(api_name_candidate) != features_.end() ||
650 schemas_.find(api_name_candidate) != schemas_.end() || 624 schemas_.find(api_name_candidate) != schemas_.end() ||
651 unloaded_schemas_.find(api_name_candidate) != unloaded_schemas_.end()) { 625 unloaded_schemas_.find(api_name_candidate) != unloaded_schemas_.end()) {
(...skipping 19 matching lines...) Expand all
671 *child_name = ""; 645 *child_name = "";
672 return ""; 646 return "";
673 } 647 }
674 648
675 bool ExtensionAPI::IsAPIAllowed(const std::string& name, 649 bool ExtensionAPI::IsAPIAllowed(const std::string& name,
676 const Extension* extension) { 650 const Extension* extension) {
677 return extension->required_permission_set()->HasAnyAccessToAPI(name) || 651 return extension->required_permission_set()->HasAnyAccessToAPI(name) ||
678 extension->optional_permission_set()->HasAnyAccessToAPI(name); 652 extension->optional_permission_set()->HasAnyAccessToAPI(name);
679 } 653 }
680 654
681 void ExtensionAPI::ResolveDependencies(std::set<std::string>* out) {
682 std::set<std::string> missing_dependencies;
683 for (std::set<std::string>::iterator i = out->begin(); i != out->end(); ++i)
684 GetMissingDependencies(*i, *out, &missing_dependencies);
685
686 while (missing_dependencies.size()) {
687 std::string next = *missing_dependencies.begin();
688 missing_dependencies.erase(next);
689 out->insert(next);
690 GetMissingDependencies(next, *out, &missing_dependencies);
691 }
692 }
693
694 void ExtensionAPI::GetMissingDependencies(
695 const std::string& api_name,
696 const std::set<std::string>& excluding,
697 std::set<std::string>* out) {
698 std::string feature_type;
699 std::string feature_name;
700 SplitDependencyName(api_name, &feature_type, &feature_name);
701
702 // Only API features can have dependencies for now.
703 if (feature_type != "api")
704 return;
705
706 const DictionaryValue* schema = GetSchema(feature_name);
707 CHECK(schema) << "Schema for " << feature_name << " not found";
708
709 const ListValue* dependencies = NULL;
710 if (!schema->GetList("dependencies", &dependencies))
711 return;
712
713 for (size_t i = 0; i < dependencies->GetSize(); ++i) {
714 std::string dependency_name;
715 if (dependencies->GetString(i, &dependency_name) &&
716 !excluding.count(dependency_name)) {
717 out->insert(dependency_name);
718 }
719 }
720 }
721
722 bool ExtensionAPI::IsPrivilegedAPI(const std::string& name) { 655 bool ExtensionAPI::IsPrivilegedAPI(const std::string& name) {
723 return completely_unprivileged_apis_.count(name) || 656 return completely_unprivileged_apis_.count(name) ||
724 partially_unprivileged_apis_.count(name); 657 partially_unprivileged_apis_.count(name);
725 } 658 }
726 659
727 } // namespace extensions 660 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698