1 // Copyright 2014 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/file_handler_info.h"
6
7 #include "base/memory/scoped_ptr.h"
8 #include "base/strings/string_number_conversions.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.h"
13 #include "extensions/common/manifest_constants.h"
14
15 namespace extensions {
16
17 namespace keys = manifest_keys;
18 namespace errors = manifest_errors;
19
20 namespace {
21 const int kMaxTypeAndExtensionHandlers = 200;
22 }
23
FileHandlerInfo()24 FileHandlerInfo::FileHandlerInfo() {}
~FileHandlerInfo()25 FileHandlerInfo::~FileHandlerInfo() {}
26
FileHandlers()27 FileHandlers::FileHandlers() {}
~FileHandlers()28 FileHandlers::~FileHandlers() {}
29
30 // static
GetFileHandlers(const Extension * extension)31 const FileHandlersInfo* FileHandlers::GetFileHandlers(
32 const Extension* extension) {
33 FileHandlers* info = static_cast<FileHandlers*>(
34 extension->GetManifestData(keys::kFileHandlers));
35 return info ? &info->file_handlers : NULL;
36 }
37
FileHandlersParser()38 FileHandlersParser::FileHandlersParser() {
39 }
40
~FileHandlersParser()41 FileHandlersParser::~FileHandlersParser() {
42 }
43
LoadFileHandler(const std::string & handler_id,const base::DictionaryValue & handler_info,FileHandlersInfo * file_handlers,base::string16 * error)44 bool LoadFileHandler(const std::string& handler_id,
45 const base::DictionaryValue& handler_info,
46 FileHandlersInfo* file_handlers,
47 base::string16* error) {
48 DCHECK(error);
49 FileHandlerInfo handler;
50
51 handler.id = handler_id;
52
53 const base::ListValue* mime_types = NULL;
54 if (handler_info.HasKey(keys::kFileHandlerTypes) &&
55 !handler_info.GetList(keys::kFileHandlerTypes, &mime_types)) {
56 *error = ErrorUtils::FormatErrorMessageUTF16(
57 errors::kInvalidFileHandlerType, handler_id);
58 return false;
59 }
60
61 const base::ListValue* file_extensions = NULL;
62 if (handler_info.HasKey(keys::kFileHandlerExtensions) &&
63 !handler_info.GetList(keys::kFileHandlerExtensions, &file_extensions)) {
64 *error = ErrorUtils::FormatErrorMessageUTF16(
65 errors::kInvalidFileHandlerExtension, handler_id);
66 return false;
67 }
68
69 if ((!mime_types || mime_types->empty()) &&
70 (!file_extensions || file_extensions->empty())) {
71 *error = ErrorUtils::FormatErrorMessageUTF16(
72 errors::kInvalidFileHandlerNoTypeOrExtension,
73 handler_id);
74 return false;
75 }
76
77 if (handler_info.HasKey(keys::kFileHandlerTitle) &&
78 !handler_info.GetString(keys::kFileHandlerTitle, &handler.title)) {
79 *error = base::ASCIIToUTF16(errors::kInvalidFileHandlerTitle);
80 return false;
81 }
82
83 if (mime_types) {
84 std::string type;
85 for (size_t i = 0; i < mime_types->GetSize(); ++i) {
86 if (!mime_types->GetString(i, &type)) {
87 *error = ErrorUtils::FormatErrorMessageUTF16(
88 errors::kInvalidFileHandlerTypeElement,
89 handler_id,
90 std::string(base::IntToString(i)));
91 return false;
92 }
93 handler.types.insert(type);
94 }
95 }
96
97 if (file_extensions) {
98 std::string file_extension;
99 for (size_t i = 0; i < file_extensions->GetSize(); ++i) {
100 if (!file_extensions->GetString(i, &file_extension)) {
101 *error = ErrorUtils::FormatErrorMessageUTF16(
102 errors::kInvalidFileHandlerExtensionElement,
103 handler_id,
104 std::string(base::IntToString(i)));
105 return false;
106 }
107 handler.extensions.insert(file_extension);
108 }
109 }
110
111 file_handlers->push_back(handler);
112 return true;
113 }
114
Parse(Extension * extension,base::string16 * error)115 bool FileHandlersParser::Parse(Extension* extension, base::string16* error) {
116 scoped_ptr<FileHandlers> info(new FileHandlers);
117 const base::DictionaryValue* all_handlers = NULL;
118 if (!extension->manifest()->GetDictionary(keys::kFileHandlers,
119 &all_handlers)) {
120 *error = base::ASCIIToUTF16(errors::kInvalidFileHandlers);
121 return false;
122 }
123
124 for (base::DictionaryValue::Iterator iter(*all_handlers);
125 !iter.IsAtEnd();
126 iter.Advance()) {
127 // A file handler entry is a title and a list of MIME types to handle.
128 const base::DictionaryValue* handler = NULL;
129 if (iter.value().GetAsDictionary(&handler)) {
130 if (!LoadFileHandler(iter.key(), *handler, &info->file_handlers, error))
131 return false;
132 } else {
133 *error = base::ASCIIToUTF16(errors::kInvalidFileHandlers);
134 return false;
135 }
136 }
137
138 int filter_count = 0;
139 for (FileHandlersInfo::const_iterator iter = info->file_handlers.begin();
140 iter != info->file_handlers.end();
141 iter++) {
142 filter_count += iter->types.size();
143 filter_count += iter->extensions.size();
144 }
145
146 if (filter_count > kMaxTypeAndExtensionHandlers) {
147 *error = base::ASCIIToUTF16(
148 errors::kInvalidFileHandlersTooManyTypesAndExtensions);
149 return false;
150 }
151
152 extension->SetManifestData(keys::kFileHandlers, info.release());
153 return true;
154 }
155
Keys() const156 const std::vector<std::string> FileHandlersParser::Keys() const {
157 return SingleKey(keys::kFileHandlers);
158 }
159
160 } // namespace extensions
161