[email protected] | 71c10c5 | 2014-01-24 01:06:40 | [diff] [blame] | 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/browser/error_map.h" |
| 6 | |
dcheng | e59eca160 | 2015-12-18 17:48:00 | [diff] [blame] | 7 | #include <utility> |
| 8 | |
[email protected] | 71c10c5 | 2014-01-24 01:06:40 | [diff] [blame] | 9 | #include "base/lazy_instance.h" |
avi | c9cec10 | 2015-12-23 00:39:26 | [diff] [blame] | 10 | #include "base/macros.h" |
avi | 7daa16fa | 2016-09-20 01:52:43 | [diff] [blame] | 11 | #include "base/memory/ptr_util.h" |
[email protected] | 71c10c5 | 2014-01-24 01:06:40 | [diff] [blame] | 12 | |
| 13 | namespace extensions { |
rdevlin.cronin | c799f9f | 2015-03-21 00:56:30 | [diff] [blame] | 14 | |
[email protected] | 71c10c5 | 2014-01-24 01:06:40 | [diff] [blame] | 15 | namespace { |
| 16 | |
| 17 | // The maximum number of errors to be stored per extension. |
| 18 | const size_t kMaxErrorsPerExtension = 100; |
| 19 | |
| 20 | base::LazyInstance<ErrorList> g_empty_error_list = LAZY_INSTANCE_INITIALIZER; |
| 21 | |
rdevlin.cronin | c799f9f | 2015-03-21 00:56:30 | [diff] [blame] | 22 | // An incrementing counter for the next error id. Overflowing this is very |
| 23 | // unlikely, since the number of errors per extension is capped at 100. |
| 24 | int kNextErrorId = 1; |
| 25 | |
[email protected] | 71c10c5 | 2014-01-24 01:06:40 | [diff] [blame] | 26 | } // namespace |
| 27 | |
| 28 | //////////////////////////////////////////////////////////////////////////////// |
rdevlin.cronin | c799f9f | 2015-03-21 00:56:30 | [diff] [blame] | 29 | // ErrorMap::Filter |
| 30 | ErrorMap::Filter::Filter(const std::string& restrict_to_extension_id, |
| 31 | int restrict_to_type, |
| 32 | const std::set<int>& restrict_to_ids, |
| 33 | bool restrict_to_incognito) |
| 34 | : restrict_to_extension_id(restrict_to_extension_id), |
| 35 | restrict_to_type(restrict_to_type), |
| 36 | restrict_to_ids(restrict_to_ids), |
| 37 | restrict_to_incognito(restrict_to_incognito) { |
| 38 | } |
| 39 | |
vmpstr | 3edc914 | 2016-02-27 01:21:52 | [diff] [blame] | 40 | ErrorMap::Filter::Filter(const Filter& other) = default; |
| 41 | |
rdevlin.cronin | c799f9f | 2015-03-21 00:56:30 | [diff] [blame] | 42 | ErrorMap::Filter::~Filter() { |
| 43 | } |
| 44 | |
| 45 | ErrorMap::Filter ErrorMap::Filter::ErrorsForExtension( |
| 46 | const std::string& extension_id) { |
| 47 | return Filter(extension_id, -1, std::set<int>(), false); |
| 48 | } |
| 49 | |
| 50 | ErrorMap::Filter ErrorMap::Filter::ErrorsForExtensionWithType( |
| 51 | const std::string& extension_id, |
| 52 | ExtensionError::Type type) { |
| 53 | return Filter(extension_id, type, std::set<int>(), false); |
| 54 | } |
| 55 | |
| 56 | ErrorMap::Filter ErrorMap::Filter::ErrorsForExtensionWithIds( |
| 57 | const std::string& extension_id, |
| 58 | const std::set<int>& ids) { |
| 59 | return Filter(extension_id, -1, ids, false); |
| 60 | } |
| 61 | |
| 62 | ErrorMap::Filter ErrorMap::Filter::ErrorsForExtensionWithTypeAndIds( |
| 63 | const std::string& extension_id, |
| 64 | ExtensionError::Type type, |
| 65 | const std::set<int>& ids) { |
| 66 | return Filter(extension_id, type, ids, false); |
| 67 | } |
| 68 | |
| 69 | ErrorMap::Filter ErrorMap::Filter::IncognitoErrors() { |
| 70 | return Filter(std::string(), -1, std::set<int>(), true); |
| 71 | } |
| 72 | |
| 73 | bool ErrorMap::Filter::Matches(const ExtensionError* error) const { |
| 74 | if (restrict_to_type != -1 && restrict_to_type != error->type()) |
| 75 | return false; |
| 76 | if (restrict_to_incognito && !error->from_incognito()) |
| 77 | return false; |
| 78 | if (!restrict_to_extension_id.empty() && |
| 79 | error->extension_id() != restrict_to_extension_id) |
| 80 | return false; |
| 81 | if (!restrict_to_ids.empty() && restrict_to_ids.count(error->id()) == 0) |
| 82 | return false; |
| 83 | return true; |
| 84 | } |
| 85 | |
| 86 | //////////////////////////////////////////////////////////////////////////////// |
[email protected] | 71c10c5 | 2014-01-24 01:06:40 | [diff] [blame] | 87 | // ErrorMap::ExtensionEntry |
rdevlin.cronin | c799f9f | 2015-03-21 00:56:30 | [diff] [blame] | 88 | class ErrorMap::ExtensionEntry { |
| 89 | public: |
| 90 | ExtensionEntry(); |
| 91 | ~ExtensionEntry(); |
| 92 | |
| 93 | // Delete any errors in the entry that match the given ids and type, if |
| 94 | // provided. |
rdevlin.cronin | 20bf10b | 2015-04-29 16:51:43 | [diff] [blame] | 95 | // Returns true if any errors were deleted. |
| 96 | bool DeleteErrors(const ErrorMap::Filter& filter); |
rdevlin.cronin | c799f9f | 2015-03-21 00:56:30 | [diff] [blame] | 97 | // Delete all errors in the entry. |
| 98 | void DeleteAllErrors(); |
| 99 | |
| 100 | // Add the error to the list, and return a weak reference. |
dcheng | f5d24108 | 2016-04-21 03:43:11 | [diff] [blame] | 101 | const ExtensionError* AddError(std::unique_ptr<ExtensionError> error); |
rdevlin.cronin | c799f9f | 2015-03-21 00:56:30 | [diff] [blame] | 102 | |
| 103 | const ErrorList* list() const { return &list_; } |
| 104 | |
| 105 | private: |
| 106 | // The list of all errors associated with the extension. The errors are |
| 107 | // owned by the Entry (in turn owned by the ErrorMap) and are deleted upon |
| 108 | // destruction. |
| 109 | ErrorList list_; |
| 110 | |
| 111 | DISALLOW_COPY_AND_ASSIGN(ExtensionEntry); |
| 112 | }; |
| 113 | |
[email protected] | 71c10c5 | 2014-01-24 01:06:40 | [diff] [blame] | 114 | ErrorMap::ExtensionEntry::ExtensionEntry() { |
| 115 | } |
| 116 | |
| 117 | ErrorMap::ExtensionEntry::~ExtensionEntry() { |
| 118 | DeleteAllErrors(); |
| 119 | } |
| 120 | |
rdevlin.cronin | 20bf10b | 2015-04-29 16:51:43 | [diff] [blame] | 121 | bool ErrorMap::ExtensionEntry::DeleteErrors(const Filter& filter) { |
| 122 | bool deleted = false; |
avi | 7daa16fa | 2016-09-20 01:52:43 | [diff] [blame] | 123 | for (auto iter = list_.begin(); iter != list_.end();) { |
| 124 | if (filter.Matches(iter->get())) { |
rdevlin.cronin | c799f9f | 2015-03-21 00:56:30 | [diff] [blame] | 125 | iter = list_.erase(iter); |
rdevlin.cronin | 20bf10b | 2015-04-29 16:51:43 | [diff] [blame] | 126 | deleted = true; |
rdevlin.cronin | c799f9f | 2015-03-21 00:56:30 | [diff] [blame] | 127 | } else { |
| 128 | ++iter; |
| 129 | } |
| 130 | } |
rdevlin.cronin | 20bf10b | 2015-04-29 16:51:43 | [diff] [blame] | 131 | return deleted; |
rdevlin.cronin | c799f9f | 2015-03-21 00:56:30 | [diff] [blame] | 132 | } |
| 133 | |
[email protected] | 71c10c5 | 2014-01-24 01:06:40 | [diff] [blame] | 134 | void ErrorMap::ExtensionEntry::DeleteAllErrors() { |
[email protected] | 71c10c5 | 2014-01-24 01:06:40 | [diff] [blame] | 135 | list_.clear(); |
| 136 | } |
| 137 | |
[email protected] | 71c10c5 | 2014-01-24 01:06:40 | [diff] [blame] | 138 | const ExtensionError* ErrorMap::ExtensionEntry::AddError( |
dcheng | f5d24108 | 2016-04-21 03:43:11 | [diff] [blame] | 139 | std::unique_ptr<ExtensionError> error) { |
avi | 7daa16fa | 2016-09-20 01:52:43 | [diff] [blame] | 140 | for (auto iter = list_.begin(); iter != list_.end(); ++iter) { |
[email protected] | 71c10c5 | 2014-01-24 01:06:40 | [diff] [blame] | 141 | // If we find a duplicate error, remove the old error and add the new one, |
| 142 | // incrementing the occurrence count of the error. We use the new error |
| 143 | // for runtime errors, so we can link to the latest context, inspectable |
| 144 | // view, etc. |
avi | 7daa16fa | 2016-09-20 01:52:43 | [diff] [blame] | 145 | if (error->IsEqual(iter->get())) { |
[email protected] | 71c10c5 | 2014-01-24 01:06:40 | [diff] [blame] | 146 | error->set_occurrences((*iter)->occurrences() + 1); |
rdevlin.cronin | c799f9f | 2015-03-21 00:56:30 | [diff] [blame] | 147 | error->set_id((*iter)->id()); |
[email protected] | 71c10c5 | 2014-01-24 01:06:40 | [diff] [blame] | 148 | list_.erase(iter); |
| 149 | break; |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | // If there are too many errors for an extension already, limit ourselves to |
| 154 | // the most recent ones. |
avi | 7daa16fa | 2016-09-20 01:52:43 | [diff] [blame] | 155 | if (list_.size() >= kMaxErrorsPerExtension) |
[email protected] | 71c10c5 | 2014-01-24 01:06:40 | [diff] [blame] | 156 | list_.pop_front(); |
[email protected] | 71c10c5 | 2014-01-24 01:06:40 | [diff] [blame] | 157 | |
rdevlin.cronin | c799f9f | 2015-03-21 00:56:30 | [diff] [blame] | 158 | if (error->id() == 0) |
| 159 | error->set_id(kNextErrorId++); |
| 160 | |
avi | 7daa16fa | 2016-09-20 01:52:43 | [diff] [blame] | 161 | list_.push_back(std::move(error)); |
| 162 | return list_.back().get(); |
[email protected] | 71c10c5 | 2014-01-24 01:06:40 | [diff] [blame] | 163 | } |
| 164 | |
| 165 | //////////////////////////////////////////////////////////////////////////////// |
| 166 | // ErrorMap |
| 167 | ErrorMap::ErrorMap() { |
| 168 | } |
| 169 | |
| 170 | ErrorMap::~ErrorMap() { |
| 171 | RemoveAllErrors(); |
| 172 | } |
| 173 | |
| 174 | const ErrorList& ErrorMap::GetErrorsForExtension( |
| 175 | const std::string& extension_id) const { |
avi | 7daa16fa | 2016-09-20 01:52:43 | [diff] [blame] | 176 | auto iter = map_.find(extension_id); |
[email protected] | 71c10c5 | 2014-01-24 01:06:40 | [diff] [blame] | 177 | return iter != map_.end() ? *iter->second->list() : g_empty_error_list.Get(); |
| 178 | } |
| 179 | |
dcheng | f5d24108 | 2016-04-21 03:43:11 | [diff] [blame] | 180 | const ExtensionError* ErrorMap::AddError( |
| 181 | std::unique_ptr<ExtensionError> error) { |
avi | 7daa16fa | 2016-09-20 01:52:43 | [diff] [blame] | 182 | std::unique_ptr<ExtensionEntry>& entry = map_[error->extension_id()]; |
| 183 | if (!entry) |
| 184 | entry = base::MakeUnique<ExtensionEntry>(); |
| 185 | |
| 186 | return entry->AddError(std::move(error)); |
[email protected] | 71c10c5 | 2014-01-24 01:06:40 | [diff] [blame] | 187 | } |
| 188 | |
rdevlin.cronin | 20bf10b | 2015-04-29 16:51:43 | [diff] [blame] | 189 | void ErrorMap::RemoveErrors(const Filter& filter, |
| 190 | std::set<std::string>* affected_ids) { |
rdevlin.cronin | c799f9f | 2015-03-21 00:56:30 | [diff] [blame] | 191 | if (!filter.restrict_to_extension_id.empty()) { |
avi | 7daa16fa | 2016-09-20 01:52:43 | [diff] [blame] | 192 | auto iter = map_.find(filter.restrict_to_extension_id); |
rdevlin.cronin | 20bf10b | 2015-04-29 16:51:43 | [diff] [blame] | 193 | if (iter != map_.end()) { |
| 194 | if (iter->second->DeleteErrors(filter) && affected_ids) |
| 195 | affected_ids->insert(filter.restrict_to_extension_id); |
| 196 | } |
rdevlin.cronin | c799f9f | 2015-03-21 00:56:30 | [diff] [blame] | 197 | } else { |
rdevlin.cronin | 20bf10b | 2015-04-29 16:51:43 | [diff] [blame] | 198 | for (auto& key_val : map_) { |
| 199 | if (key_val.second->DeleteErrors(filter) && affected_ids) |
| 200 | affected_ids->insert(key_val.first); |
| 201 | } |
rdevlin.cronin | c799f9f | 2015-03-21 00:56:30 | [diff] [blame] | 202 | } |
[email protected] | 71c10c5 | 2014-01-24 01:06:40 | [diff] [blame] | 203 | } |
| 204 | |
| 205 | void ErrorMap::RemoveAllErrors() { |
[email protected] | 71c10c5 | 2014-01-24 01:06:40 | [diff] [blame] | 206 | map_.clear(); |
| 207 | } |
| 208 | |
| 209 | } // namespace extensions |