Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / extensions / common / features / simple_feature.cc
index 21d4e22..e623bcf 100644 (file)
@@ -7,6 +7,7 @@
 #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;
@@ -34,6 +56,7 @@ struct Mappings {
     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;
@@ -190,6 +213,8 @@ std::string GetDisplayName(Feature::Context context) {
       return "web page";
     case Feature::BLESSED_WEB_PAGE_CONTEXT:
       return "hosted app";
+    case Feature::WEBUI_CONTEXT:
+      return "webui";
   }
   NOTREACHED();
   return "";
@@ -234,6 +259,10 @@ SimpleFeature::SimpleFeature()
 
 SimpleFeature::~SimpleFeature() {}
 
+bool SimpleFeature::HasDependencies() {
+  return !dependencies_.empty();
+}
+
 void SimpleFeature::AddFilter(scoped_ptr<SimpleFeatureFilter> filter) {
   filters_.push_back(make_linked_ptr(filter.release()));
 }
@@ -261,10 +290,14 @@ std::string SimpleFeature::Parse(const base::DictionaryValue* value) {
   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();
@@ -343,7 +376,12 @@ Feature::Availability SimpleFeature::IsAvailableToManifest(
       return availability;
   }
 
-  return CreateAvailability(IS_AVAILABLE, type);
+  return CheckDependencies(base::Bind(&IsAvailableToManifestForBind,
+                                      extension_id,
+                                      type,
+                                      location,
+                                      manifest_version,
+                                      platform));
 }
 
 Feature::Availability SimpleFeature::IsAvailableToContext(
@@ -364,8 +402,13 @@ 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();
@@ -376,7 +419,10 @@ Feature::Availability SimpleFeature::IsAvailableToContext(
       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(
@@ -470,16 +516,10 @@ Feature::Availability SimpleFeature::CreateAvailability(
                                      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_);
 }
@@ -522,4 +562,20 @@ bool SimpleFeature::MatchesManifestLocation(
   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