#include <map>
#include <vector>
+#include "base/bind.h"
#include "base/command_line.h"
#include "base/debug/alias.h"
#include "base/lazy_instance.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
+#include "extensions/common/extension_api.h"
+#include "extensions/common/features/feature_provider.h"
#include "extensions/common/switches.h"
namespace extensions {
namespace {
+Feature::Availability IsAvailableToManifestForBind(
+ const std::string& extension_id,
+ Manifest::Type type,
+ Manifest::Location location,
+ int manifest_version,
+ Feature::Platform platform,
+ const Feature* feature) {
+ return feature->IsAvailableToManifest(
+ extension_id, type, location, manifest_version, platform);
+}
+
+Feature::Availability IsAvailableToContextForBind(const Extension* extension,
+ Feature::Context context,
+ const GURL& url,
+ Feature::Platform platform,
+ const Feature* feature) {
+ return feature->IsAvailableToContext(extension, context, url, platform);
+}
+
struct Mappings {
Mappings() {
extension_types["extension"] = Manifest::TYPE_EXTENSION;
contexts["content_script"] = Feature::CONTENT_SCRIPT_CONTEXT;
contexts["web_page"] = Feature::WEB_PAGE_CONTEXT;
contexts["blessed_web_page"] = Feature::BLESSED_WEB_PAGE_CONTEXT;
+ contexts["webui"] = Feature::WEBUI_CONTEXT;
locations["component"] = SimpleFeature::COMPONENT_LOCATION;
locations["policy"] = SimpleFeature::POLICY_LOCATION;
return "web page";
case Feature::BLESSED_WEB_PAGE_CONTEXT:
return "hosted app";
+ case Feature::WEBUI_CONTEXT:
+ return "webui";
}
NOTREACHED();
return "";
SimpleFeature::~SimpleFeature() {}
+bool SimpleFeature::HasDependencies() {
+ return !dependencies_.empty();
+}
+
void SimpleFeature::AddFilter(scoped_ptr<SimpleFeatureFilter> filter) {
filters_.push_back(make_linked_ptr(filter.release()));
}
value->GetBoolean("component_extensions_auto_granted",
&component_extensions_auto_granted_);
- if (matches_.is_empty() && contexts_.count(WEB_PAGE_CONTEXT) != 0) {
- return name() + ": Allowing web_page contexts requires supplying a value " +
- "for matches.";
- }
+ // NOTE: ideally we'd sanity check that "matches" can be specified if and
+ // only if there's a "web_page" or "webui" context, but without
+ // (Simple)Features being aware of their own heirarchy this is impossible.
+ //
+ // For example, we might have feature "foo" available to "web_page" context
+ // and "matches" google.com/*. Then a sub-feature "foo.bar" might override
+ // "matches" to be chromium.org/*. That sub-feature doesn't need to specify
+ // "web_page" context because it's inherited, but we don't know that here.
for (FilterList::iterator filter_iter = filters_.begin();
filter_iter != filters_.end();
return availability;
}
- return CreateAvailability(IS_AVAILABLE, type);
+ return CheckDependencies(base::Bind(&IsAvailableToManifestForBind,
+ extension_id,
+ type,
+ location,
+ manifest_version,
+ platform));
}
Feature::Availability SimpleFeature::IsAvailableToContext(
if (!contexts_.empty() && contexts_.find(context) == contexts_.end())
return CreateAvailability(INVALID_CONTEXT, context);
- if (!matches_.is_empty() && !matches_.MatchesURL(url))
+ // TODO(kalman): Consider checking |matches_| regardless of context type.
+ // Fewer surprises, and if the feature configuration wants to isolate
+ // "matches" from say "blessed_extension" then they can use complex features.
+ if ((context == WEB_PAGE_CONTEXT || context == WEBUI_CONTEXT) &&
+ !matches_.MatchesURL(url)) {
return CreateAvailability(INVALID_URL, url);
+ }
for (FilterList::const_iterator filter_iter = filters_.begin();
filter_iter != filters_.end();
return availability;
}
- return CreateAvailability(IS_AVAILABLE);
+ // TODO(kalman): Assert that if the context was a webpage or WebUI context
+ // then at some point a "matches" restriction was checked.
+ return CheckDependencies(base::Bind(
+ &IsAvailableToContextForBind, extension, context, url, platform));
}
std::string SimpleFeature::GetAvailabilityMessage(
context));
}
-std::set<Feature::Context>* SimpleFeature::GetContexts() {
- return &contexts_;
-}
-
bool SimpleFeature::IsInternal() const {
return false;
}
-bool SimpleFeature::IsBlockedInServiceWorker() const { return false; }
-
bool SimpleFeature::IsIdInBlacklist(const std::string& extension_id) const {
return IsIdInList(extension_id, blacklist_);
}
return false;
}
+Feature::Availability SimpleFeature::CheckDependencies(
+ const base::Callback<Availability(const Feature*)>& checker) const {
+ for (std::set<std::string>::const_iterator it = dependencies_.begin();
+ it != dependencies_.end();
+ ++it) {
+ Feature* dependency =
+ ExtensionAPI::GetSharedInstance()->GetFeatureDependency(*it);
+ if (!dependency)
+ return CreateAvailability(NOT_PRESENT);
+ Availability dependency_availability = checker.Run(dependency);
+ if (!dependency_availability.is_available())
+ return dependency_availability;
+ }
+ return CreateAvailability(IS_AVAILABLE);
+}
+
} // namespace extensions