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

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: fixed memory leak Created 7 years, 8 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 can only be run in a blessed context.
459 // in a blessed context. 459 return feature->GetContexts()->size() ==
460 std::set<std::string> resolved_dependencies; 460 feature->GetContexts()->count(Feature::BLESSED_EXTENSION_CONTEXT);
461 resolved_dependencies.insert(full_name);
462 ResolveDependencies(&resolved_dependencies);
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 }
473 return true;
474 } 461 }
475 462
463 // Get the schema now to populate |completely_unprivileged_apis_|.
464 const DictionaryValue* schema = GetSchema(api_name);
476 // If this API hasn't been converted yet, fall back to the old system. 465 // If this API hasn't been converted yet, fall back to the old system.
477 if (completely_unprivileged_apis_.count(api_name)) 466 if (completely_unprivileged_apis_.count(api_name))
478 return false; 467 return false;
479 468
480 const DictionaryValue* schema = GetSchema(api_name);
481 if (partially_unprivileged_apis_.count(api_name)) 469 if (partially_unprivileged_apis_.count(api_name))
482 return IsChildNamePrivileged(schema, child_name); 470 return IsChildNamePrivileged(schema, child_name);
483 471
484 return true; 472 return true;
485 } 473 }
486 474
487 bool ExtensionAPI::IsChildNamePrivileged(const DictionaryValue* name_space_node, 475 bool ExtensionAPI::IsChildNamePrivileged(const DictionaryValue* name_space_node,
488 const std::string& child_name) { 476 const std::string& child_name) {
489 bool unprivileged = false; 477 bool unprivileged = false;
490 const DictionaryValue* child = GetSchemaChild(name_space_node, child_name); 478 const DictionaryValue* child = GetSchemaChild(name_space_node, child_name);
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
542 530
543 return true; 531 return true;
544 } 532 }
545 533
546 } // namespace 534 } // namespace
547 535
548 bool ExtensionAPI::IsNonFeatureAPIAvailable(const std::string& name, 536 bool ExtensionAPI::IsNonFeatureAPIAvailable(const std::string& name,
549 Feature::Context context, 537 Feature::Context context,
550 const Extension* extension, 538 const Extension* extension,
551 const GURL& url) { 539 const GURL& url) {
540 // Make sure schema is loaded.
541 GetSchema(name);
552 switch (context) { 542 switch (context) {
553 case Feature::UNSPECIFIED_CONTEXT: 543 case Feature::UNSPECIFIED_CONTEXT:
554 break; 544 break;
555 545
556 case Feature::BLESSED_EXTENSION_CONTEXT: 546 case Feature::BLESSED_EXTENSION_CONTEXT:
557 if (extension) { 547 if (extension) {
558 // Availability is determined by the permissions of the extension. 548 // Availability is determined by the permissions of the extension.
559 if (!IsAPIAllowed(name, extension)) 549 if (!IsAPIAllowed(name, extension))
560 return false; 550 return false;
561 if (!IsFeatureAllowedForExtension(name, *extension)) 551 if (!IsFeatureAllowedForExtension(name, *extension))
(...skipping 28 matching lines...) Expand all
590 std::set<std::string> result; 580 std::set<std::string> result;
591 for (SchemaMap::iterator i = schemas_.begin(); i != schemas_.end(); ++i) 581 for (SchemaMap::iterator i = schemas_.begin(); i != schemas_.end(); ++i)
592 result.insert(i->first); 582 result.insert(i->first);
593 for (UnloadedSchemaMap::iterator i = unloaded_schemas_.begin(); 583 for (UnloadedSchemaMap::iterator i = unloaded_schemas_.begin();
594 i != unloaded_schemas_.end(); ++i) { 584 i != unloaded_schemas_.end(); ++i) {
595 result.insert(i->first); 585 result.insert(i->first);
596 } 586 }
597 return result; 587 return result;
598 } 588 }
599 589
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) { 590 Feature* ExtensionAPI::GetFeatureDependency(const std::string& full_name) {
631 std::string feature_type; 591 std::string feature_type;
632 std::string feature_name; 592 std::string feature_name;
633 SplitDependencyName(full_name, &feature_type, &feature_name); 593 SplitDependencyName(full_name, &feature_type, &feature_name);
634 594
635 FeatureProviderMap::iterator provider = 595 FeatureProviderMap::iterator provider =
636 dependency_providers_.find(feature_type); 596 dependency_providers_.find(feature_type);
637 CHECK(provider != dependency_providers_.end()) << full_name; 597 if (provider == dependency_providers_.end())
598 return NULL;
638 599
639 Feature* feature = provider->second->GetFeature(feature_name); 600 Feature* feature = provider->second->GetFeature(feature_name);
640 CHECK(feature) << full_name; 601 // Try getting the feature for the parent API, if this was a child.
641 602 if (!feature) {
603 std::string child_name;
604 feature = provider->second->GetFeature(
605 GetAPINameFromFullName(feature_name, &child_name));
606 }
642 return feature; 607 return feature;
643 } 608 }
644 609
645 std::string ExtensionAPI::GetAPINameFromFullName(const std::string& full_name, 610 std::string ExtensionAPI::GetAPINameFromFullName(const std::string& full_name,
646 std::string* child_name) { 611 std::string* child_name) {
647 std::string api_name_candidate = full_name; 612 std::string api_name_candidate = full_name;
648 while (true) { 613 while (true) {
649 if (features_.find(api_name_candidate) != features_.end() || 614 if (features_.find(api_name_candidate) != features_.end() ||
650 schemas_.find(api_name_candidate) != schemas_.end() || 615 schemas_.find(api_name_candidate) != schemas_.end() ||
651 unloaded_schemas_.find(api_name_candidate) != unloaded_schemas_.end()) { 616 unloaded_schemas_.find(api_name_candidate) != unloaded_schemas_.end()) {
(...skipping 19 matching lines...) Expand all
671 *child_name = ""; 636 *child_name = "";
672 return ""; 637 return "";
673 } 638 }
674 639
675 bool ExtensionAPI::IsAPIAllowed(const std::string& name, 640 bool ExtensionAPI::IsAPIAllowed(const std::string& name,
676 const Extension* extension) { 641 const Extension* extension) {
677 return extension->required_permission_set()->HasAnyAccessToAPI(name) || 642 return extension->required_permission_set()->HasAnyAccessToAPI(name) ||
678 extension->optional_permission_set()->HasAnyAccessToAPI(name); 643 extension->optional_permission_set()->HasAnyAccessToAPI(name);
679 } 644 }
680 645
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) { 646 bool ExtensionAPI::IsPrivilegedAPI(const std::string& name) {
723 return completely_unprivileged_apis_.count(name) || 647 return completely_unprivileged_apis_.count(name) ||
724 partially_unprivileged_apis_.count(name); 648 partially_unprivileged_apis_.count(name);
725 } 649 }
726 650
727 } // namespace extensions 651 } // namespace extensions
OLDNEW
« no previous file with comments | « chrome/common/extensions/api/extension_api.h ('k') | chrome/common/extensions/api/extension_api_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698