Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(104)

Side by Side Diff: chrome/common/extensions/manifest_handler.cc

Issue 12091115: Allow manifest handlers to declare keys they depend on that must be parsed before them. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: keys Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/common/extensions/manifest_handler.h" 5 #include "chrome/common/extensions/manifest_handler.h"
6 6
7 #include <map> 7 #include <map>
8 8
9 #include "base/lazy_instance.h" 9 #include "base/lazy_instance.h"
10 #include "base/memory/linked_ptr.h" 10 #include "base/stl_util.h"
11 #include "chrome/common/extensions/manifest.h" 11 #include "chrome/common/extensions/manifest.h"
12 12
13 namespace extensions { 13 namespace extensions {
14 14
15 namespace { 15 namespace {
16 16
17 class ManifestHandlerRegistry { 17 class ManifestHandlerRegistry {
18 public: 18 public:
19 ManifestHandlerRegistry() : is_sorted_(false) {
20 }
21
19 void RegisterManifestHandler(const std::string& key, 22 void RegisterManifestHandler(const std::string& key,
20 ManifestHandler* handler); 23 linked_ptr<ManifestHandler> handler);
21 bool ParseExtension(Extension* extension, string16* error); 24 bool ParseExtension(Extension* extension, string16* error);
25 void ClearForTesting();
22 26
23 private: 27 private:
24 friend struct base::DefaultLazyInstanceTraits<ManifestHandlerRegistry>; 28 friend struct base::DefaultLazyInstanceTraits<ManifestHandlerRegistry>;
25 typedef std::map<std::string, linked_ptr<ManifestHandler> > 29 typedef std::map<std::string, linked_ptr<ManifestHandler> >
26 ManifestHandlerMap; 30 ManifestHandlerMap;
31 typedef std::map<ManifestHandler*, int> ManifestHandlerPriorityMap;
27 32
33 // Puts the manifest handlers in order such that each handler comes after
34 // any handlers for their PrerequisiteKeys. If there is no handler for
35 // a prerequisite key, that dependency is simply ignored.
36 // Manifest handlers with circular dependencies are unregistered.
37 void SortManifestHandlers();
38
39 // All registered manifest handlers.
28 ManifestHandlerMap handlers_; 40 ManifestHandlerMap handlers_;
41
42 // The priority for each manifest handler. Handlers with lower priority
43 // values are evaluated first.
44 ManifestHandlerPriorityMap priority_map_;
45 bool is_sorted_;
29 }; 46 };
30 47
31 void ManifestHandlerRegistry::RegisterManifestHandler( 48 void ManifestHandlerRegistry::RegisterManifestHandler(
32 const std::string& key, ManifestHandler* handler) { 49 const std::string& key, linked_ptr<ManifestHandler> handler) {
33 handlers_[key] = make_linked_ptr(handler); 50 handlers_[key] = handler;
51 is_sorted_ = false;
34 } 52 }
35 53
36 bool ManifestHandlerRegistry::ParseExtension(Extension* extension, 54 bool ManifestHandlerRegistry::ParseExtension(Extension* extension,
37 string16* error) { 55 string16* error) {
38 std::set<ManifestHandler*> handler_set; 56 SortManifestHandlers();
57 std::map<int, ManifestHandler*> handlers_by_priority;
39 for (ManifestHandlerMap::iterator iter = handlers_.begin(); 58 for (ManifestHandlerMap::iterator iter = handlers_.begin();
40 iter != handlers_.end(); ++iter) { 59 iter != handlers_.end(); ++iter) {
41 ManifestHandler* handler = iter->second.get(); 60 ManifestHandler* handler = iter->second.get();
42 if (extension->manifest()->HasPath(iter->first) || 61 if (extension->manifest()->HasPath(iter->first) ||
43 handler->AlwaysParseForType(extension->GetType())) 62 handler->AlwaysParseForType(extension->GetType())) {
44 handler_set.insert(handler); 63 handlers_by_priority[priority_map_[handler]] = handler;
64 }
45 } 65 }
46 66 for (std::map<int, ManifestHandler*>::iterator iter =
47 // TODO(yoz): Some handlers may depend on other handlers having already 67 handlers_by_priority.begin();
48 // parsed their keys. Reorder the handlers so that handlers needed earlier 68 iter != handlers_by_priority.end(); ++iter) {
49 // come first in the returned container. 69 if (!(iter->second)->Parse(extension, error))
50 for (std::set<ManifestHandler*>::iterator iter = handler_set.begin();
51 iter != handler_set.end(); ++iter) {
52 if (!(*iter)->Parse(extension, error))
53 return false; 70 return false;
54 } 71 }
55 return true; 72 return true;
56 } 73 }
57 74
75 void ManifestHandlerRegistry::ClearForTesting() {
76 priority_map_.clear();
77 handlers_.clear();
78 is_sorted_ = false;
79 }
80
81 void ManifestHandlerRegistry::SortManifestHandlers() {
82 if (is_sorted_)
83 return;
84
85 // Forget our existing sort order.
86 priority_map_.clear();
87 std::set<ManifestHandler*> unsorted_handlers;
88 for (ManifestHandlerMap::const_iterator iter = handlers_.begin();
89 iter != handlers_.end(); ++iter) {
90 unsorted_handlers.insert(iter->second.get());
91 }
92
93 int priority = 0;
94 while (true) {
95 std::set<ManifestHandler*> next_unsorted_handlers;
96 for (std::set<ManifestHandler*>::const_iterator iter =
97 unsorted_handlers.begin();
98 iter != unsorted_handlers.end(); ++iter) {
99 ManifestHandler* handler = *iter;
100 const std::vector<std::string>& prerequisites =
101 handler->PrerequisiteKeys();
102 int unsatisfied = prerequisites.size();
103 for (size_t i = 0; i < prerequisites.size(); ++i) {
104 ManifestHandlerMap::const_iterator prereq_iter =
105 handlers_.find(prerequisites[i]);
106 if (prereq_iter == handlers_.end()) {
107 // Nonexistent prerequisite; ignore it.
Matt Perry 2013/02/02 00:58:58 Shouldn't this be an error?
Yoyo Zhou 2013/02/02 02:26:45 A fatal error? That's probably okay. My concern is
108 unsatisfied--;
109 } else if (ContainsKey(priority_map_,
110 prereq_iter->second.get())) {
111 // Prerequisite is in our map.
112 unsatisfied--;
113 }
114 }
115 if (unsatisfied == 0) {
116 priority_map_[handler] = priority;
117 priority++;
118 } else {
119 // Put in the list for next time.
120 next_unsorted_handlers.insert(handler);
121 }
122 }
123 if (next_unsorted_handlers.size() == unsorted_handlers.size())
124 break;
125 unsorted_handlers.swap(next_unsorted_handlers);
126 }
127
128 // If there are any leftover unsorted handlers, they must have had
129 // circular dependencies. Drop them, and log a warning.
130 if (unsorted_handlers.size() > 0) {
131 LOG(WARNING) << "Ignoring extension manifest handlers with "
132 << "circular dependencies:";
Matt Perry 2013/02/02 00:58:58 This should be a fatal error, no?
Yoyo Zhou 2013/02/02 02:26:45 Sure. I deleted the circular dependencies unit te
Matt Perry 2013/02/02 02:29:03 I thought there was some way to make unit tests tr
Yoyo Zhou 2013/02/02 02:38:39 I found this: https://code.google.com/p/chromium/i
133 for (ManifestHandlerMap::iterator iter = handlers_.begin();
134 iter != handlers_.end();) {
135 ManifestHandlerMap::iterator current = iter++;
136 if (ContainsKey(unsorted_handlers, current->second.get())) {
137 LOG(WARNING) << "key: " << current->first;
138 handlers_.erase(current);
139 }
140 }
141 }
142
143 is_sorted_ = true;
144 }
145
58 static base::LazyInstance<ManifestHandlerRegistry> g_registry = 146 static base::LazyInstance<ManifestHandlerRegistry> g_registry =
59 LAZY_INSTANCE_INITIALIZER; 147 LAZY_INSTANCE_INITIALIZER;
60 148
149 static base::LazyInstance<std::vector<std::string> > g_empty_string_vector =
150 LAZY_INSTANCE_INITIALIZER;
151
61 } // namespace 152 } // namespace
62 153
63 ManifestHandler::ManifestHandler() { 154 ManifestHandler::ManifestHandler() {
64 } 155 }
65 156
66 ManifestHandler::~ManifestHandler() { 157 ManifestHandler::~ManifestHandler() {
67 } 158 }
68 159
69 bool ManifestHandler::AlwaysParseForType(Manifest::Type type) { 160 bool ManifestHandler::AlwaysParseForType(Manifest::Type type) {
70 return false; 161 return false;
71 } 162 }
72 163
164 const std::vector<std::string>& ManifestHandler::PrerequisiteKeys() {
165 return g_empty_string_vector.Get();
166 }
167
73 // static 168 // static
74 void ManifestHandler::Register(const std::string& key, 169 void ManifestHandler::Register(const std::string& key,
75 ManifestHandler* handler) { 170 linked_ptr<ManifestHandler> handler) {
76 g_registry.Get().RegisterManifestHandler(key, handler); 171 g_registry.Get().RegisterManifestHandler(key, handler);
77 } 172 }
78 173
79 // static 174 // static
80 bool ManifestHandler::ParseExtension(Extension* extension, string16* error) { 175 bool ManifestHandler::ParseExtension(Extension* extension, string16* error) {
81 return g_registry.Get().ParseExtension(extension, error); 176 return g_registry.Get().ParseExtension(extension, error);
82 } 177 }
83 178
179 // static
180 void ManifestHandler::ClearRegistryForTesting() {
181 g_registry.Get().ClearForTesting();
182 }
183
84 } // namespace extensions 184 } // namespace extensions
OLDNEW
« no previous file with comments | « chrome/common/extensions/manifest_handler.h ('k') | chrome/common/extensions/manifest_handler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698