1cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/common/manifest_handlers/file_handler_info.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
9116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/strings/stringprintf.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/values.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/common/error_utils.h"
133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "extensions/common/manifest.h"
14d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "extensions/common/manifest_constants.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace extensions {
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace keys = manifest_keys;
19d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace errors = manifest_errors;
20d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)namespace {
22f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int kMaxTypeAndExtensionHandlers = 200;
23116680a4aac90f2aa7413d9095a592090648e557Ben Murdochconst char kNotRecognized[] = "'%s' is not a recognized file handler property.";
24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)FileHandlerInfo::FileHandlerInfo() {}
27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)FileHandlerInfo::~FileHandlerInfo() {}
28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FileHandlers::FileHandlers() {}
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FileHandlers::~FileHandlers() {}
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const FileHandlersInfo* FileHandlers::GetFileHandlers(
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const Extension* extension) {
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FileHandlers* info = static_cast<FileHandlers*>(
363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      extension->GetManifestData(keys::kFileHandlers));
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return info ? &info->file_handlers : NULL;
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FileHandlersParser::FileHandlersParser() {
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FileHandlersParser::~FileHandlersParser() {
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool LoadFileHandler(const std::string& handler_id,
477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                     const base::DictionaryValue& handler_info,
48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                     FileHandlersInfo* file_handlers,
49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                     base::string16* error,
50116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                     std::vector<InstallWarning>* install_warnings) {
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(error);
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FileHandlerInfo handler;
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  handler.id = handler_id;
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  const base::ListValue* mime_types = NULL;
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (handler_info.HasKey(keys::kFileHandlerTypes) &&
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      !handler_info.GetList(keys::kFileHandlerTypes, &mime_types)) {
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *error = ErrorUtils::FormatErrorMessageUTF16(
603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        errors::kInvalidFileHandlerType, handler_id);
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  const base::ListValue* file_extensions = NULL;
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (handler_info.HasKey(keys::kFileHandlerExtensions) &&
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      !handler_info.GetList(keys::kFileHandlerExtensions, &file_extensions)) {
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    *error = ErrorUtils::FormatErrorMessageUTF16(
683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        errors::kInvalidFileHandlerExtension, handler_id);
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if ((!mime_types || mime_types->empty()) &&
73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      (!file_extensions || file_extensions->empty())) {
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    *error = ErrorUtils::FormatErrorMessageUTF16(
753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        errors::kInvalidFileHandlerNoTypeOrExtension,
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        handler_id);
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (mime_types) {
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::string type;
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for (size_t i = 0; i < mime_types->GetSize(); ++i) {
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (!mime_types->GetString(i, &type)) {
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        *error = ErrorUtils::FormatErrorMessageUTF16(
853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            errors::kInvalidFileHandlerTypeElement,
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            handler_id,
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            std::string(base::IntToString(i)));
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return false;
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      handler.types.insert(type);
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (file_extensions) {
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::string file_extension;
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for (size_t i = 0; i < file_extensions->GetSize(); ++i) {
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (!file_extensions->GetString(i, &file_extension)) {
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        *error = ErrorUtils::FormatErrorMessageUTF16(
993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            errors::kInvalidFileHandlerExtensionElement,
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            handler_id,
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            std::string(base::IntToString(i)));
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return false;
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      handler.extensions.insert(file_extension);
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  file_handlers->push_back(handler);
109116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
110116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Check for unknown keys.
111116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (base::DictionaryValue::Iterator it(handler_info); !it.IsAtEnd();
112116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       it.Advance()) {
113116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (it.key() != keys::kFileHandlerExtensions &&
114116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        it.key() != keys::kFileHandlerTypes) {
115116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      install_warnings->push_back(
116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          InstallWarning(base::StringPrintf(kNotRecognized, it.key().c_str()),
117116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                         keys::kFileHandlers,
118116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                         it.key()));
119116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
120116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
121116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool FileHandlersParser::Parse(Extension* extension, base::string16* error) {
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<FileHandlers> info(new FileHandlers);
1277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  const base::DictionaryValue* all_handlers = NULL;
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!extension->manifest()->GetDictionary(keys::kFileHandlers,
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            &all_handlers)) {
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    *error = base::ASCIIToUTF16(errors::kInvalidFileHandlers);
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
134116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::vector<InstallWarning> install_warnings;
135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (base::DictionaryValue::Iterator iter(*all_handlers);
136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)       !iter.IsAtEnd();
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       iter.Advance()) {
1387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const base::DictionaryValue* handler = NULL;
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (iter.value().GetAsDictionary(&handler)) {
140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (!LoadFileHandler(iter.key(),
141116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                           *handler,
142116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                           &info->file_handlers,
143116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                           error,
144116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                           &install_warnings))
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return false;
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      *error = base::ASCIIToUTF16(errors::kInvalidFileHandlers);
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int filter_count = 0;
153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (FileHandlersInfo::const_iterator iter = info->file_handlers.begin();
154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)       iter != info->file_handlers.end();
155f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)       iter++) {
156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    filter_count += iter->types.size();
157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    filter_count += iter->extensions.size();
158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
159f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (filter_count > kMaxTypeAndExtensionHandlers) {
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    *error = base::ASCIIToUTF16(
162f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        errors::kInvalidFileHandlersTooManyTypesAndExtensions);
163f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
164f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
165f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  extension->SetManifestData(keys::kFileHandlers, info.release());
167116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  extension->AddInstallWarnings(install_warnings);
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const std::vector<std::string> FileHandlersParser::Keys() const {
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return SingleKey(keys::kFileHandlers);
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace extensions
176