Home | History | Annotate | Download | only in features
      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
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/common/extensions/features/base_feature_provider.h"
      6 
      7 #include <stack>
      8 
      9 #include "base/json/json_reader.h"
     10 #include "base/lazy_instance.h"
     11 #include "base/strings/string_split.h"
     12 #include "base/strings/string_util.h"
     13 #include "chrome/common/extensions/features/api_feature.h"
     14 #include "chrome/common/extensions/features/complex_feature.h"
     15 #include "chrome/common/extensions/features/manifest_feature.h"
     16 #include "chrome/common/extensions/features/permission_feature.h"
     17 #include "grit/common_resources.h"
     18 #include "ui/base/resource/resource_bundle.h"
     19 
     20 namespace extensions {
     21 
     22 namespace {
     23 
     24 template<class FeatureClass>
     25 SimpleFeature* CreateFeature() {
     26   return new FeatureClass();
     27 }
     28 
     29 class LazyFeatureProvider : public FeatureProvider {
     30  public:
     31   LazyFeatureProvider(const std::string& name,
     32                       BaseFeatureProvider::FeatureFactory factory,
     33                       int resource_id)
     34       : name_(name),
     35         factory_(factory),
     36         resource_id_(resource_id) {
     37   }
     38 
     39   virtual Feature* GetFeature(const std::string& name) OVERRIDE {
     40     return GetBaseFeatureProvider()->GetFeature(name);
     41   }
     42 
     43   virtual Feature* GetParent(Feature* feature) OVERRIDE {
     44     return GetBaseFeatureProvider()->GetParent(feature);
     45   }
     46 
     47   virtual const std::vector<std::string>& GetAllFeatureNames() OVERRIDE {
     48     return GetBaseFeatureProvider()->GetAllFeatureNames();
     49   }
     50 
     51  private:
     52   BaseFeatureProvider* GetBaseFeatureProvider() {
     53     if (!features_)
     54       features_ = LoadProvider();
     55     return features_.get();
     56   }
     57 
     58   scoped_ptr<BaseFeatureProvider> LoadProvider() {
     59     const std::string& features_file =
     60         ResourceBundle::GetSharedInstance().GetRawDataResource(
     61             resource_id_).as_string();
     62     int error_code = 0;
     63     std::string error_message;
     64     scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError(
     65         features_file, base::JSON_PARSE_RFC,
     66         &error_code, &error_message));
     67     DCHECK(value) << "Could not load features: " << name_ << " "
     68         << error_message;
     69     scoped_ptr<base::DictionaryValue> value_as_dict;
     70     if (value) {
     71       CHECK(value->IsType(base::Value::TYPE_DICTIONARY)) << name_;
     72       value_as_dict.reset(static_cast<base::DictionaryValue*>(value.release()));
     73     } else {
     74       // http://crbug.com/176381
     75       value_as_dict.reset(new base::DictionaryValue());
     76     }
     77     return make_scoped_ptr(new BaseFeatureProvider(*value_as_dict, factory_));
     78   }
     79 
     80   std::string name_;
     81   BaseFeatureProvider::FeatureFactory factory_;
     82   int resource_id_;
     83   scoped_ptr<BaseFeatureProvider> features_;
     84 };
     85 
     86 struct Static {
     87   Static() {
     88     lazy_feature_providers["api"] = make_linked_ptr(
     89         new LazyFeatureProvider("api",
     90                                 &CreateFeature<APIFeature>,
     91                                 IDR_EXTENSION_API_FEATURES));
     92     lazy_feature_providers["permission"] = make_linked_ptr(
     93         new LazyFeatureProvider("permission",
     94                                 &CreateFeature<PermissionFeature>,
     95                                 IDR_EXTENSION_PERMISSION_FEATURES));
     96     lazy_feature_providers["manifest"] = make_linked_ptr(
     97         new LazyFeatureProvider("manifest",
     98                                 &CreateFeature<ManifestFeature>,
     99                                 IDR_EXTENSION_MANIFEST_FEATURES));
    100   }
    101 
    102   typedef std::map<std::string, linked_ptr<LazyFeatureProvider> >
    103       LazyFeatureProviderMap;
    104 
    105   LazyFeatureProvider* LazyGetFeatures(const std::string& name) {
    106     LazyFeatureProviderMap::iterator it = lazy_feature_providers.find(name);
    107     CHECK(it != lazy_feature_providers.end());
    108     return it->second.get();
    109   }
    110 
    111   LazyFeatureProviderMap lazy_feature_providers;
    112 };
    113 
    114 base::LazyInstance<Static> g_static = LAZY_INSTANCE_INITIALIZER;
    115 
    116 bool ParseFeature(const base::DictionaryValue* value,
    117                   const std::string& name,
    118                   SimpleFeature* feature) {
    119   feature->set_name(name);
    120   std::string error = feature->Parse(value);
    121   if (!error.empty())
    122     LOG(ERROR) << error;
    123   return error.empty();
    124 }
    125 
    126 }  // namespace
    127 
    128 BaseFeatureProvider::BaseFeatureProvider(const base::DictionaryValue& root,
    129                                          FeatureFactory factory)
    130     : factory_(factory ? factory :
    131                static_cast<FeatureFactory>(&CreateFeature<SimpleFeature>)) {
    132   for (base::DictionaryValue::Iterator iter(root); !iter.IsAtEnd();
    133        iter.Advance()) {
    134     if (iter.value().GetType() == base::Value::TYPE_DICTIONARY) {
    135       linked_ptr<SimpleFeature> feature((*factory_)());
    136 
    137       std::vector<std::string> split;
    138       base::SplitString(iter.key(), '.', &split);
    139 
    140       // Push parent features on the stack, starting with the current feature.
    141       // If one of the features has "noparent" set, stop pushing features on
    142       // the stack. The features will then be parsed in order, starting with
    143       // the farthest parent that is either top level or has "noparent" set.
    144       std::stack<std::pair<std::string, const base::DictionaryValue*> >
    145           parse_stack;
    146       while (!split.empty()) {
    147         std::string parent_name = JoinString(split, '.');
    148         split.pop_back();
    149         if (root.HasKey(parent_name)) {
    150           const base::DictionaryValue* parent = NULL;
    151           CHECK(root.GetDictionaryWithoutPathExpansion(parent_name, &parent));
    152           parse_stack.push(std::make_pair(parent_name, parent));
    153           bool no_parent = false;
    154           parent->GetBoolean("noparent", &no_parent);
    155           if (no_parent)
    156             break;
    157         }
    158       }
    159 
    160       CHECK(!parse_stack.empty());
    161       // Parse all parent features.
    162       bool parse_error = false;
    163       while (!parse_stack.empty()) {
    164         if (!ParseFeature(parse_stack.top().second,
    165                           parse_stack.top().first,
    166                           feature.get())) {
    167           parse_error = true;
    168           break;
    169         }
    170         parse_stack.pop();
    171       }
    172 
    173       if (parse_error)
    174         continue;
    175 
    176       features_[iter.key()] = feature;
    177     } else if (iter.value().GetType() == base::Value::TYPE_LIST) {
    178       // This is a complex feature.
    179       const base::ListValue* list =
    180           static_cast<const base::ListValue*>(&iter.value());
    181       CHECK_GT(list->GetSize(), 0UL);
    182 
    183       scoped_ptr<ComplexFeature::FeatureList> features(
    184           new ComplexFeature::FeatureList());
    185 
    186       // Parse and add all SimpleFeatures from the list.
    187       for (base::ListValue::const_iterator list_iter = list->begin();
    188            list_iter != list->end(); ++list_iter) {
    189         if ((*list_iter)->GetType() != base::Value::TYPE_DICTIONARY) {
    190           LOG(ERROR) << iter.key() << ": Feature rules must be dictionaries.";
    191           continue;
    192         }
    193 
    194         scoped_ptr<SimpleFeature> feature((*factory_)());
    195         if (!ParseFeature(static_cast<const base::DictionaryValue*>(*list_iter),
    196                           iter.key(),
    197                           feature.get()))
    198           continue;
    199 
    200         features->push_back(feature.release());
    201       }
    202 
    203       linked_ptr<ComplexFeature> feature(new ComplexFeature(features.Pass()));
    204       feature->set_name(iter.key());
    205 
    206       features_[iter.key()] = feature;
    207     } else {
    208       LOG(ERROR) << iter.key() << ": Feature description must be dictionary or"
    209                  << " list of dictionaries.";
    210     }
    211   }
    212 }
    213 
    214 BaseFeatureProvider::~BaseFeatureProvider() {
    215 }
    216 
    217 // static
    218 FeatureProvider* BaseFeatureProvider::GetByName(
    219     const std::string& name) {
    220   return g_static.Get().LazyGetFeatures(name);
    221 }
    222 
    223 const std::vector<std::string>& BaseFeatureProvider::GetAllFeatureNames() {
    224   if (feature_names_.empty()) {
    225     for (FeatureMap::const_iterator iter = features_.begin();
    226          iter != features_.end(); ++iter) {
    227       feature_names_.push_back(iter->first);
    228     }
    229   }
    230   return feature_names_;
    231 }
    232 
    233 Feature* BaseFeatureProvider::GetFeature(const std::string& name) {
    234   FeatureMap::iterator iter = features_.find(name);
    235   if (iter != features_.end())
    236     return iter->second.get();
    237   else
    238     return NULL;
    239 }
    240 
    241 Feature* BaseFeatureProvider::GetParent(Feature* feature) {
    242   CHECK(feature);
    243   if (feature->no_parent())
    244     return NULL;
    245 
    246   std::vector<std::string> split;
    247   base::SplitString(feature->name(), '.', &split);
    248   if (split.size() < 2)
    249     return NULL;
    250   split.pop_back();
    251   return GetFeature(JoinString(split, '.'));
    252 }
    253 
    254 } // namespace extensions
    255