Home | History | Annotate | Download | only in manifest_handlers
      1 // Copyright 2013 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 "extensions/common/manifest_handlers/requirements_info.h"
      6 
      7 #include "base/lazy_instance.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/strings/utf_string_conversions.h"
     10 #include "base/values.h"
     11 #include "extensions/common/error_utils.h"
     12 #include "extensions/common/manifest_constants.h"
     13 
     14 namespace extensions {
     15 
     16 namespace keys = manifest_keys;
     17 namespace errors = manifest_errors;
     18 
     19 RequirementsInfo::RequirementsInfo(const Manifest* manifest)
     20     : webgl(false),
     21       npapi(false),
     22       window_shape(false) {
     23   // Before parsing requirements from the manifest, automatically default the
     24   // NPAPI plugin requirement based on whether it includes NPAPI plugins.
     25   const base::ListValue* list_value = NULL;
     26   npapi = manifest->GetList(keys::kPlugins, &list_value) &&
     27           !list_value->empty();
     28 }
     29 
     30 RequirementsInfo::~RequirementsInfo() {
     31 }
     32 
     33 // static
     34 const RequirementsInfo& RequirementsInfo::GetRequirements(
     35     const Extension* extension) {
     36   RequirementsInfo* info = static_cast<RequirementsInfo*>(
     37       extension->GetManifestData(keys::kRequirements));
     38 
     39   // We should be guaranteed to have requirements, since they are parsed for all
     40   // extension types.
     41   CHECK(info);
     42   return *info;
     43 }
     44 
     45 RequirementsHandler::RequirementsHandler() {
     46 }
     47 
     48 RequirementsHandler::~RequirementsHandler() {
     49 }
     50 
     51 const std::vector<std::string> RequirementsHandler::PrerequisiteKeys() const {
     52   return SingleKey(keys::kPlugins);
     53 }
     54 
     55 const std::vector<std::string> RequirementsHandler::Keys() const {
     56   return SingleKey(keys::kRequirements);
     57 }
     58 
     59 bool RequirementsHandler::AlwaysParseForType(Manifest::Type type) const {
     60   return true;
     61 }
     62 
     63 bool RequirementsHandler::Parse(Extension* extension, base::string16* error) {
     64   scoped_ptr<RequirementsInfo> requirements(
     65       new RequirementsInfo(extension->manifest()));
     66 
     67   if (!extension->manifest()->HasKey(keys::kRequirements)) {
     68     extension->SetManifestData(keys::kRequirements, requirements.release());
     69     return true;
     70   }
     71 
     72   const base::DictionaryValue* requirements_value = NULL;
     73   if (!extension->manifest()->GetDictionary(keys::kRequirements,
     74                                             &requirements_value)) {
     75     *error = base::ASCIIToUTF16(errors::kInvalidRequirements);
     76     return false;
     77   }
     78 
     79   for (base::DictionaryValue::Iterator iter(*requirements_value);
     80        !iter.IsAtEnd();
     81        iter.Advance()) {
     82     const base::DictionaryValue* requirement_value;
     83     if (!iter.value().GetAsDictionary(&requirement_value)) {
     84       *error = ErrorUtils::FormatErrorMessageUTF16(
     85           errors::kInvalidRequirement, iter.key());
     86       return false;
     87     }
     88 
     89     if (iter.key() == "plugins") {
     90       for (base::DictionaryValue::Iterator plugin_iter(*requirement_value);
     91            !plugin_iter.IsAtEnd(); plugin_iter.Advance()) {
     92         bool plugin_required = false;
     93         if (!plugin_iter.value().GetAsBoolean(&plugin_required)) {
     94           *error = ErrorUtils::FormatErrorMessageUTF16(
     95               errors::kInvalidRequirement, iter.key());
     96           return false;
     97         }
     98         if (plugin_iter.key() == "npapi") {
     99           requirements->npapi = plugin_required;
    100         } else {
    101           *error = ErrorUtils::FormatErrorMessageUTF16(
    102               errors::kInvalidRequirement, iter.key());
    103           return false;
    104         }
    105       }
    106     } else if (iter.key() == "3D") {
    107       const base::ListValue* features = NULL;
    108       if (!requirement_value->GetListWithoutPathExpansion("features",
    109                                                           &features) ||
    110           !features) {
    111         *error = ErrorUtils::FormatErrorMessageUTF16(
    112             errors::kInvalidRequirement, iter.key());
    113         return false;
    114       }
    115 
    116       for (base::ListValue::const_iterator feature_iter = features->begin();
    117            feature_iter != features->end(); ++feature_iter) {
    118         std::string feature;
    119         if ((*feature_iter)->GetAsString(&feature)) {
    120           if (feature == "webgl") {
    121             requirements->webgl = true;
    122           } else if (feature == "css3d") {
    123             // css3d is always available, so no check is needed, but no error is
    124             // generated.
    125           } else {
    126             *error = ErrorUtils::FormatErrorMessageUTF16(
    127                 errors::kInvalidRequirement, iter.key());
    128             return false;
    129           }
    130         }
    131       }
    132     } else if (iter.key() == "window") {
    133       for (base::DictionaryValue::Iterator feature_iter(*requirement_value);
    134            !feature_iter.IsAtEnd(); feature_iter.Advance()) {
    135         bool feature_required = false;
    136         if (!feature_iter.value().GetAsBoolean(&feature_required)) {
    137           *error = ErrorUtils::FormatErrorMessageUTF16(
    138               errors::kInvalidRequirement, iter.key());
    139           return false;
    140         }
    141         if (feature_iter.key() == "shape") {
    142           requirements->window_shape = feature_required;
    143         } else {
    144           *error = ErrorUtils::FormatErrorMessageUTF16(
    145               errors::kInvalidRequirement, iter.key());
    146           return false;
    147         }
    148       }
    149     } else {
    150       *error = base::ASCIIToUTF16(errors::kInvalidRequirements);
    151       return false;
    152     }
    153   }
    154 
    155   extension->SetManifestData(keys::kRequirements, requirements.release());
    156   return true;
    157 }
    158 
    159 }  // namespace extensions
    160