| 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 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 using base::DictionaryValue; | 29 using base::DictionaryValue; |
| 30 using base::ListValue; | 30 using base::ListValue; |
| 31 using base::Value; | 31 using base::Value; |
| 32 | 32 |
| 33 namespace extensions { | 33 namespace extensions { |
| 34 | 34 |
| 35 using api::GeneratedSchemas; | 35 using api::GeneratedSchemas; |
| 36 | 36 |
| 37 namespace { | 37 namespace { |
| 38 | 38 |
| 39 const char kUnavailableMessage[] = "You do not have permission to access this " |
| 40 "API. Ensure that the required permission " |
| 41 "or manifest property is included in your " |
| 42 "manifest.json."; |
| 39 const char* kChildKinds[] = { | 43 const char* kChildKinds[] = { |
| 40 "functions", | 44 "functions", |
| 41 "events" | 45 "events" |
| 42 }; | 46 }; |
| 43 | 47 |
| 44 // Returns true if |dict| has an unprivileged "true" property. | 48 // Returns true if |dict| has an unprivileged "true" property. |
| 45 bool IsUnprivileged(const DictionaryValue* dict) { | 49 bool IsUnprivileged(const DictionaryValue* dict) { |
| 46 bool unprivileged = false; | 50 bool unprivileged = false; |
| 47 return dict->GetBoolean("unprivileged", &unprivileged) && unprivileged; | 51 return dict->GetBoolean("unprivileged", &unprivileged) && unprivileged; |
| 48 } | 52 } |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 223 // 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. |
| 224 *feature_type = "api"; | 228 *feature_type = "api"; |
| 225 *feature_name = full_name; | 229 *feature_name = full_name; |
| 226 return; | 230 return; |
| 227 } | 231 } |
| 228 | 232 |
| 229 *feature_type = full_name.substr(0, colon_index); | 233 *feature_type = full_name.substr(0, colon_index); |
| 230 *feature_name = full_name.substr(colon_index + 1); | 234 *feature_name = full_name.substr(colon_index + 1); |
| 231 } | 235 } |
| 232 | 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 |
| 233 void ExtensionAPI::LoadSchema(const std::string& name, | 242 void ExtensionAPI::LoadSchema(const std::string& name, |
| 234 const base::StringPiece& schema) { | 243 const base::StringPiece& schema) { |
| 235 scoped_ptr<ListValue> schema_list(LoadSchemaList(name, schema)); | 244 scoped_ptr<ListValue> schema_list(LoadSchemaList(name, schema)); |
| 236 std::string schema_namespace; | 245 std::string schema_namespace; |
| 237 | 246 |
| 238 while (!schema_list->empty()) { | 247 while (!schema_list->empty()) { |
| 239 DictionaryValue* schema = NULL; | 248 DictionaryValue* schema = NULL; |
| 240 { | 249 { |
| 241 Value* value = NULL; | 250 Value* value = NULL; |
| 242 schema_list->Remove(schema_list->GetSize() - 1, &value); | 251 schema_list->Remove(schema_list->GetSize() - 1, &value); |
| 243 CHECK(value->IsType(Value::TYPE_DICTIONARY)); | 252 CHECK(value->IsType(Value::TYPE_DICTIONARY)); |
| 244 schema = static_cast<DictionaryValue*>(value); | 253 schema = static_cast<DictionaryValue*>(value); |
| 245 } | 254 } |
| 246 | 255 |
| 247 CHECK(schema->GetString("namespace", &schema_namespace)); | 256 CHECK(schema->GetString("namespace", &schema_namespace)); |
| 248 PrefixWithNamespace(schema_namespace, schema); | 257 PrefixWithNamespace(schema_namespace, schema); |
| 249 schemas_[schema_namespace] = make_linked_ptr(schema); | 258 schemas_[schema_namespace] = make_linked_ptr(schema); |
| 250 CHECK_EQ(1u, unloaded_schemas_.erase(schema_namespace)); | 259 CHECK_EQ(1u, unloaded_schemas_.erase(schema_namespace)); |
| 251 | 260 |
| 252 // Populate |{completely,partially}_unprivileged_apis_|. | 261 // Populate |{completely,partially}_unprivileged_apis_|. |
| 253 // | 262 |
| 254 // For "partially", only need to look at functions/events; even though | 263 // For "partially", only need to look at functions/events; even though |
| 255 // there are unprivileged properties (e.g. in extensions), access to those | 264 // there are unprivileged properties (e.g. in extensions), access to those |
| 256 // never reaches C++ land. | 265 // never reaches C++ land. |
| 257 bool unprivileged = false; | 266 bool unprivileged = false; |
| 258 if (schema->GetBoolean("unprivileged", &unprivileged) && unprivileged) { | 267 if (schema->GetBoolean("unprivileged", &unprivileged) && unprivileged) { |
| 259 completely_unprivileged_apis_.insert(schema_namespace); | 268 completely_unprivileged_apis_.insert(schema_namespace); |
| 260 } else if (HasUnprivilegedChild(schema, "functions") || | 269 } else if (HasUnprivilegedChild(schema, "functions") || |
| 261 HasUnprivilegedChild(schema, "events") || | 270 HasUnprivilegedChild(schema, "events") || |
| 262 HasUnprivilegedChild(schema, "properties")) { | 271 HasUnprivilegedChild(schema, "properties")) { |
| 263 partially_unprivileged_apis_.insert(schema_namespace); | 272 partially_unprivileged_apis_.insert(schema_namespace); |
| 264 } | 273 } |
| 265 | 274 |
| 266 // Populate |url_matching_apis_|. | 275 bool uses_feature_system = false; |
| 267 ListValue* matches = NULL; | 276 schema->GetBoolean("uses_feature_system", &uses_feature_system); |
| 268 if (schema->GetList("matches", &matches)) { | 277 |
| 269 URLPatternSet pattern_set; | 278 if (!uses_feature_system) { |
| 270 for (size_t i = 0; i < matches->GetSize(); ++i) { | 279 // Populate |url_matching_apis_|. |
| 271 std::string pattern; | 280 ListValue* matches = NULL; |
| 272 CHECK(matches->GetString(i, &pattern)); | 281 if (schema->GetList("matches", &matches)) { |
| 273 pattern_set.AddPattern( | 282 URLPatternSet pattern_set; |
| 274 URLPattern(UserScript::kValidUserScriptSchemes, pattern)); | 283 for (size_t i = 0; i < matches->GetSize(); ++i) { |
| 284 std::string pattern; |
| 285 CHECK(matches->GetString(i, &pattern)); |
| 286 pattern_set.AddPattern( |
| 287 URLPattern(UserScript::kValidUserScriptSchemes, pattern)); |
| 288 } |
| 289 url_matching_apis_[schema_namespace] = pattern_set; |
| 275 } | 290 } |
| 276 url_matching_apis_[schema_namespace] = pattern_set; | 291 continue; |
| 277 } | 292 } |
| 278 | 293 |
| 279 // Populate feature maps. | 294 // Populate feature maps. |
| 280 // TODO(aa): Consider not storing features that can never run on the current | 295 // TODO(aa): Consider not storing features that can never run on the current |
| 281 // machine (e.g., because of platform restrictions). | 296 // machine (e.g., because of platform restrictions). |
| 282 bool uses_feature_system = false; | |
| 283 schema->GetBoolean("uses_feature_system", &uses_feature_system); | |
| 284 if (!uses_feature_system) | |
| 285 continue; | |
| 286 | |
| 287 SimpleFeature* feature = new SimpleFeature(); | 297 SimpleFeature* feature = new SimpleFeature(); |
| 288 feature->set_name(schema_namespace); | 298 feature->set_name(schema_namespace); |
| 289 feature->Parse(schema); | 299 feature->Parse(schema); |
| 290 | 300 |
| 291 FeatureMap* schema_features = new FeatureMap(); | 301 FeatureMap* schema_features = new FeatureMap(); |
| 292 CHECK(features_.insert( | 302 CHECK(features_.insert( |
| 293 std::make_pair(schema_namespace, | 303 std::make_pair(schema_namespace, |
| 294 make_linked_ptr(schema_features))).second); | 304 make_linked_ptr(schema_features))).second); |
| 295 CHECK(schema_features->insert( | 305 CHECK(schema_features->insert( |
| 296 std::make_pair("", make_linked_ptr(feature))).second); | 306 std::make_pair("", make_linked_ptr(feature))).second); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 401 void ExtensionAPI::RegisterSchema(const std::string& name, | 411 void ExtensionAPI::RegisterSchema(const std::string& name, |
| 402 const base::StringPiece& source) { | 412 const base::StringPiece& source) { |
| 403 unloaded_schemas_[name] = source; | 413 unloaded_schemas_[name] = source; |
| 404 } | 414 } |
| 405 | 415 |
| 406 void ExtensionAPI::RegisterDependencyProvider(const std::string& name, | 416 void ExtensionAPI::RegisterDependencyProvider(const std::string& name, |
| 407 FeatureProvider* provider) { | 417 FeatureProvider* provider) { |
| 408 dependency_providers_[name] = provider; | 418 dependency_providers_[name] = provider; |
| 409 } | 419 } |
| 410 | 420 |
| 411 bool ExtensionAPI::IsAvailable(const std::string& full_name, | 421 Feature::Availability ExtensionAPI::IsAvailable(const std::string& full_name, |
| 412 const Extension* extension, | 422 const Extension* extension, |
| 413 Feature::Context context) { | 423 Feature::Context context, |
| 424 const GURL& url) { |
| 414 std::set<std::string> dependency_names; | 425 std::set<std::string> dependency_names; |
| 415 dependency_names.insert(full_name); | 426 dependency_names.insert(full_name); |
| 416 ResolveDependencies(&dependency_names); | 427 ResolveDependencies(&dependency_names); |
| 417 | |
| 418 for (std::set<std::string>::iterator iter = dependency_names.begin(); | 428 for (std::set<std::string>::iterator iter = dependency_names.begin(); |
| 419 iter != dependency_names.end(); ++iter) { | 429 iter != dependency_names.end(); ++iter) { |
| 420 Feature* feature = GetFeatureDependency(full_name); | 430 //////////////////////////////////////////////////////////////////////////// |
| 431 // TODO(cduvall): Take this out once all APIs have been converted to |
| 432 // features. |
| 433 std::string feature_type; |
| 434 std::string feature_name; |
| 435 SplitDependencyName(*iter, &feature_type, &feature_name); |
| 436 if (feature_type == "api" && !UsesFeatureSystem(feature_name)) { |
| 437 if (!IsNonFeatureAvailable(feature_name, context, extension, url)) |
| 438 return Feature::CreateAvailability(Feature::INVALID_CONTEXT, |
| 439 kUnavailableMessage); |
| 440 continue; |
| 441 } |
| 442 //////////////////////////////////////////////////////////////////////////// |
| 443 Feature* feature = GetFeatureDependency(*iter); |
| 421 CHECK(feature) << *iter; | 444 CHECK(feature) << *iter; |
| 422 | 445 |
| 423 Feature::Availability availability = | 446 Feature::Availability availability = |
| 424 feature->IsAvailableToContext(extension, context); | 447 feature->IsAvailableToContext(extension, context, url); |
| 425 if (!availability.is_available()) | 448 if (!availability.is_available()) |
| 426 return false; | 449 return availability; |
| 427 } | 450 } |
| 428 | 451 |
| 429 return true; | 452 return Feature::CreateAvailability(Feature::IS_AVAILABLE, ""); |
| 430 } | 453 } |
| 431 | 454 |
| 432 bool ExtensionAPI::IsPrivileged(const std::string& full_name) { | 455 bool ExtensionAPI::IsPrivileged(const std::string& full_name) { |
| 433 std::string child_name; | 456 std::string child_name; |
| 434 std::string api_name = GetAPINameFromFullName(full_name, &child_name); | 457 std::string api_name = GetAPINameFromFullName(full_name, &child_name); |
| 435 | 458 |
| 436 // First try to use the feature system. | 459 // First try to use the feature system. |
| 437 Feature* feature(GetFeature(full_name)); | 460 Feature* feature(GetFeature(full_name)); |
| 438 if (feature) { | 461 if (feature) { |
| 439 // An API is 'privileged' if it or any of its dependencies can only be run | 462 // An API is 'privileged' if it or any of its dependencies can only be run |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 517 if (extension.is_platform_app()) { | 540 if (extension.is_platform_app()) { |
| 518 for (size_t i = 0; i < arraysize(kDisallowedPlatformAppFeatures); ++i) { | 541 for (size_t i = 0; i < arraysize(kDisallowedPlatformAppFeatures); ++i) { |
| 519 if (feature == kDisallowedPlatformAppFeatures[i]) | 542 if (feature == kDisallowedPlatformAppFeatures[i]) |
| 520 return false; | 543 return false; |
| 521 } | 544 } |
| 522 } | 545 } |
| 523 | 546 |
| 524 return true; | 547 return true; |
| 525 } | 548 } |
| 526 | 549 |
| 527 // Removes APIs from |apis| that should not be allowed for |extension|. | |
| 528 // TODO(kalman/asargent) - Make it possible to specify these rules | |
| 529 // declaratively. | |
| 530 void RemoveDisallowedAPIs(const Extension& extension, | |
| 531 std::set<std::string>* apis) { | |
| 532 CHECK(apis); | |
| 533 std::set<std::string>::iterator i = apis->begin(); | |
| 534 while (i != apis->end()) { | |
| 535 if (!IsFeatureAllowedForExtension(*i, extension)) { | |
| 536 apis->erase(i++); | |
| 537 } else { | |
| 538 ++i; | |
| 539 } | |
| 540 } | |
| 541 } | |
| 542 | |
| 543 } // namespace | 550 } // namespace |
| 544 | 551 |
| 545 std::set<std::string> ExtensionAPI::GetAPIsForContext( | 552 bool ExtensionAPI::IsNonFeatureAvailable(const std::string& name, |
| 546 Feature::Context context, const Extension* extension, const GURL& url) { | 553 Feature::Context context, |
| 547 // We're forced to load all schemas now because we need to know the metadata | 554 const Extension* extension, |
| 548 // about every API -- and the metadata is stored in the schemas themselves. | 555 const GURL& url) { |
| 549 // This is a shame. | |
| 550 // TODO(aa/kalman): store metadata in a separate file and don't load all | |
| 551 // schemas. | |
| 552 LoadAllSchemas(); | |
| 553 | |
| 554 std::set<std::string> temp_result; | |
| 555 | |
| 556 // First handle all the APIs that have been converted to the feature system. | |
| 557 if (extension) { | |
| 558 for (APIFeatureMap::iterator iter = features_.begin(); | |
| 559 iter != features_.end(); ++iter) { | |
| 560 if (IsAvailable(iter->first, extension, context)) | |
| 561 temp_result.insert(iter->first); | |
| 562 } | |
| 563 } | |
| 564 | |
| 565 // Second, fall back to the old way. | |
| 566 // TODO(aa): Remove this when all APIs have been converted. | |
| 567 switch (context) { | 556 switch (context) { |
| 568 case Feature::UNSPECIFIED_CONTEXT: | 557 case Feature::UNSPECIFIED_CONTEXT: |
| 569 break; | 558 break; |
| 570 | 559 |
| 571 case Feature::BLESSED_EXTENSION_CONTEXT: | 560 case Feature::BLESSED_EXTENSION_CONTEXT: |
| 572 if (extension) { | 561 if (extension) { |
| 573 // Availability is determined by the permissions of the extension. | 562 // Availability is determined by the permissions of the extension. |
| 574 GetAllowedAPIs(extension, &temp_result); | 563 if (!IsAPIAllowed(name, extension)) |
| 575 ResolveDependencies(&temp_result); | 564 return false; |
| 576 RemoveDisallowedAPIs(*extension, &temp_result); | 565 if (!IsFeatureAllowedForExtension(name, *extension)) |
| 566 return false; |
| 577 } | 567 } |
| 578 break; | 568 break; |
| 579 | 569 |
| 580 case Feature::UNBLESSED_EXTENSION_CONTEXT: | 570 case Feature::UNBLESSED_EXTENSION_CONTEXT: |
| 581 case Feature::CONTENT_SCRIPT_CONTEXT: | 571 case Feature::CONTENT_SCRIPT_CONTEXT: |
| 582 if (extension) { | 572 if (extension) { |
| 583 // Same as BLESSED_EXTENSION_CONTEXT, but only those APIs that are | 573 // Same as BLESSED_EXTENSION_CONTEXT, but only those APIs that are |
| 584 // unprivileged. | 574 // unprivileged. |
| 585 GetAllowedAPIs(extension, &temp_result); | 575 if (!IsAPIAllowed(name, extension)) |
| 586 // Resolving dependencies before removing unprivileged APIs means that | 576 return false; |
| 587 // some unprivileged APIs may have unrealised dependencies. Too bad! | 577 if (IsPrivilegedAPI(name)) |
| 588 ResolveDependencies(&temp_result); | 578 return false; |
| 589 RemovePrivilegedAPIs(&temp_result); | |
| 590 } | 579 } |
| 591 break; | 580 break; |
| 592 | 581 |
| 593 case Feature::WEB_PAGE_CONTEXT: | 582 case Feature::WEB_PAGE_CONTEXT: |
| 594 if (url.is_valid()) { | 583 if (url.is_valid() && url_matching_apis_.count(name)) { |
| 595 // Availablility is determined by the url. | 584 // Availablility is determined by the url. |
| 596 GetAPIsMatchingURL(url, &temp_result); | 585 return url_matching_apis_[name].MatchesURL(url); |
| 597 } | 586 } |
| 598 break; | 587 break; |
| 599 } | 588 } |
| 600 | 589 |
| 601 // Filter out all non-API features and remove the feature type part of the | 590 return true; |
| 602 // name. | |
| 603 std::set<std::string> result; | |
| 604 for (std::set<std::string>::iterator iter = temp_result.begin(); | |
| 605 iter != temp_result.end(); ++iter) { | |
| 606 std::string feature_type; | |
| 607 std::string feature_name; | |
| 608 SplitDependencyName(*iter, &feature_type, &feature_name); | |
| 609 if (feature_type == "api") | |
| 610 result.insert(feature_name); | |
| 611 } | |
| 612 | |
| 613 return result; | |
| 614 } | 591 } |
| 615 | 592 |
| 616 std::set<std::string> ExtensionAPI::GetAllAPINames() { | 593 std::set<std::string> ExtensionAPI::GetAllAPINames() { |
| 617 std::set<std::string> result; | 594 std::set<std::string> result; |
| 618 for (SchemaMap::iterator i = schemas_.begin(); i != schemas_.end(); ++i) | 595 for (SchemaMap::iterator i = schemas_.begin(); i != schemas_.end(); ++i) |
| 619 result.insert(i->first); | 596 result.insert(i->first); |
| 620 for (UnloadedSchemaMap::iterator i = unloaded_schemas_.begin(); | 597 for (UnloadedSchemaMap::iterator i = unloaded_schemas_.begin(); |
| 621 i != unloaded_schemas_.end(); ++i) { | 598 i != unloaded_schemas_.end(); ++i) { |
| 622 result.insert(i->first); | 599 result.insert(i->first); |
| 623 } | 600 } |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 692 if (last_dot_index == std::string::npos) | 669 if (last_dot_index == std::string::npos) |
| 693 break; | 670 break; |
| 694 | 671 |
| 695 api_name_candidate = api_name_candidate.substr(0, last_dot_index); | 672 api_name_candidate = api_name_candidate.substr(0, last_dot_index); |
| 696 } | 673 } |
| 697 | 674 |
| 698 *child_name = ""; | 675 *child_name = ""; |
| 699 return ""; | 676 return ""; |
| 700 } | 677 } |
| 701 | 678 |
| 702 void ExtensionAPI::GetAllowedAPIs( | 679 bool ExtensionAPI::IsAPIAllowed(const std::string& name, |
| 703 const Extension* extension, std::set<std::string>* out) { | 680 const Extension* extension) { |
| 704 for (SchemaMap::const_iterator i = schemas_.begin(); i != schemas_.end(); | 681 return extension->required_permission_set()->HasAnyAccessToAPI(name) || |
| 705 ++i) { | 682 extension->optional_permission_set()->HasAnyAccessToAPI(name); |
| 706 if (features_.find(i->first) != features_.end()) { | |
| 707 // This API is controlled by the feature system. Nothing to do here. | |
| 708 continue; | |
| 709 } | |
| 710 | |
| 711 if (extension->required_permission_set()->HasAnyAccessToAPI(i->first) || | |
| 712 extension->optional_permission_set()->HasAnyAccessToAPI(i->first)) { | |
| 713 out->insert(i->first); | |
| 714 } | |
| 715 } | |
| 716 } | 683 } |
| 717 | 684 |
| 718 void ExtensionAPI::ResolveDependencies(std::set<std::string>* out) { | 685 void ExtensionAPI::ResolveDependencies(std::set<std::string>* out) { |
| 719 std::set<std::string> missing_dependencies; | 686 std::set<std::string> missing_dependencies; |
| 720 for (std::set<std::string>::iterator i = out->begin(); i != out->end(); ++i) | 687 for (std::set<std::string>::iterator i = out->begin(); i != out->end(); ++i) |
| 721 GetMissingDependencies(*i, *out, &missing_dependencies); | 688 GetMissingDependencies(*i, *out, &missing_dependencies); |
| 722 | 689 |
| 723 while (missing_dependencies.size()) { | 690 while (missing_dependencies.size()) { |
| 724 std::string next = *missing_dependencies.begin(); | 691 std::string next = *missing_dependencies.begin(); |
| 725 missing_dependencies.erase(next); | 692 missing_dependencies.erase(next); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 749 | 716 |
| 750 for (size_t i = 0; i < dependencies->GetSize(); ++i) { | 717 for (size_t i = 0; i < dependencies->GetSize(); ++i) { |
| 751 std::string dependency_name; | 718 std::string dependency_name; |
| 752 if (dependencies->GetString(i, &dependency_name) && | 719 if (dependencies->GetString(i, &dependency_name) && |
| 753 !excluding.count(dependency_name)) { | 720 !excluding.count(dependency_name)) { |
| 754 out->insert(dependency_name); | 721 out->insert(dependency_name); |
| 755 } | 722 } |
| 756 } | 723 } |
| 757 } | 724 } |
| 758 | 725 |
| 759 void ExtensionAPI::RemovePrivilegedAPIs(std::set<std::string>* apis) { | 726 bool ExtensionAPI::IsPrivilegedAPI(const std::string& name) { |
| 760 std::set<std::string> privileged_apis; | 727 return completely_unprivileged_apis_.count(name) || |
| 761 for (std::set<std::string>::iterator i = apis->begin(); i != apis->end(); | 728 partially_unprivileged_apis_.count(name); |
| 762 ++i) { | |
| 763 if (!completely_unprivileged_apis_.count(*i) && | |
| 764 !partially_unprivileged_apis_.count(*i)) { | |
| 765 privileged_apis.insert(*i); | |
| 766 } | |
| 767 } | |
| 768 for (std::set<std::string>::iterator i = privileged_apis.begin(); | |
| 769 i != privileged_apis.end(); ++i) { | |
| 770 apis->erase(*i); | |
| 771 } | |
| 772 } | |
| 773 | |
| 774 void ExtensionAPI::GetAPIsMatchingURL(const GURL& url, | |
| 775 std::set<std::string>* out) { | |
| 776 for (std::map<std::string, URLPatternSet>::const_iterator i = | |
| 777 url_matching_apis_.begin(); i != url_matching_apis_.end(); ++i) { | |
| 778 if (features_.find(i->first) != features_.end()) { | |
| 779 // This API is controlled by the feature system. Nothing to do. | |
| 780 continue; | |
| 781 } | |
| 782 | |
| 783 if (i->second.MatchesURL(url)) | |
| 784 out->insert(i->first); | |
| 785 } | |
| 786 } | |
| 787 | |
| 788 void ExtensionAPI::LoadAllSchemas() { | |
| 789 while (unloaded_schemas_.size()) { | |
| 790 std::map<std::string, base::StringPiece>::iterator it = | |
| 791 unloaded_schemas_.begin(); | |
| 792 LoadSchema(it->first, it->second); | |
| 793 } | |
| 794 } | 729 } |
| 795 | 730 |
| 796 } // namespace extensions | 731 } // namespace extensions |
| OLD | NEW |