blob: 767f8dcb0a8b2668d1e95b1cf71613704ed4758b [file] [log] [blame]
[email protected]71c10c52014-01-24 01:06:401// 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
dchenge59eca1602015-12-18 17:48:007#include <utility>
8
[email protected]71c10c52014-01-24 01:06:409#include "base/lazy_instance.h"
avic9cec102015-12-23 00:39:2610#include "base/macros.h"
avi7daa16fa2016-09-20 01:52:4311#include "base/memory/ptr_util.h"
[email protected]71c10c52014-01-24 01:06:4012
13namespace extensions {
rdevlin.croninc799f9f2015-03-21 00:56:3014
[email protected]71c10c52014-01-24 01:06:4015namespace {
16
17// The maximum number of errors to be stored per extension.
18const size_t kMaxErrorsPerExtension = 100;
19
20base::LazyInstance<ErrorList> g_empty_error_list = LAZY_INSTANCE_INITIALIZER;
21
rdevlin.croninc799f9f2015-03-21 00:56:3022// 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.
24int kNextErrorId = 1;
25
[email protected]71c10c52014-01-24 01:06:4026} // namespace
27
28////////////////////////////////////////////////////////////////////////////////
rdevlin.croninc799f9f2015-03-21 00:56:3029// ErrorMap::Filter
30ErrorMap::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
vmpstr3edc9142016-02-27 01:21:5240ErrorMap::Filter::Filter(const Filter& other) = default;
41
rdevlin.croninc799f9f2015-03-21 00:56:3042ErrorMap::Filter::~Filter() {
43}
44
45ErrorMap::Filter ErrorMap::Filter::ErrorsForExtension(
46 const std::string& extension_id) {
47 return Filter(extension_id, -1, std::set<int>(), false);
48}
49
50ErrorMap::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
56ErrorMap::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
62ErrorMap::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
69ErrorMap::Filter ErrorMap::Filter::IncognitoErrors() {
70 return Filter(std::string(), -1, std::set<int>(), true);
71}
72
73bool 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]71c10c52014-01-24 01:06:4087// ErrorMap::ExtensionEntry
rdevlin.croninc799f9f2015-03-21 00:56:3088class 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.cronin20bf10b2015-04-29 16:51:4395 // Returns true if any errors were deleted.
96 bool DeleteErrors(const ErrorMap::Filter& filter);
rdevlin.croninc799f9f2015-03-21 00:56:3097 // Delete all errors in the entry.
98 void DeleteAllErrors();
99
100 // Add the error to the list, and return a weak reference.
dchengf5d241082016-04-21 03:43:11101 const ExtensionError* AddError(std::unique_ptr<ExtensionError> error);
rdevlin.croninc799f9f2015-03-21 00:56:30102
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]71c10c52014-01-24 01:06:40114ErrorMap::ExtensionEntry::ExtensionEntry() {
115}
116
117ErrorMap::ExtensionEntry::~ExtensionEntry() {
118 DeleteAllErrors();
119}
120
rdevlin.cronin20bf10b2015-04-29 16:51:43121bool ErrorMap::ExtensionEntry::DeleteErrors(const Filter& filter) {
122 bool deleted = false;
avi7daa16fa2016-09-20 01:52:43123 for (auto iter = list_.begin(); iter != list_.end();) {
124 if (filter.Matches(iter->get())) {
rdevlin.croninc799f9f2015-03-21 00:56:30125 iter = list_.erase(iter);
rdevlin.cronin20bf10b2015-04-29 16:51:43126 deleted = true;
rdevlin.croninc799f9f2015-03-21 00:56:30127 } else {
128 ++iter;
129 }
130 }
rdevlin.cronin20bf10b2015-04-29 16:51:43131 return deleted;
rdevlin.croninc799f9f2015-03-21 00:56:30132}
133
[email protected]71c10c52014-01-24 01:06:40134void ErrorMap::ExtensionEntry::DeleteAllErrors() {
[email protected]71c10c52014-01-24 01:06:40135 list_.clear();
136}
137
[email protected]71c10c52014-01-24 01:06:40138const ExtensionError* ErrorMap::ExtensionEntry::AddError(
dchengf5d241082016-04-21 03:43:11139 std::unique_ptr<ExtensionError> error) {
avi7daa16fa2016-09-20 01:52:43140 for (auto iter = list_.begin(); iter != list_.end(); ++iter) {
[email protected]71c10c52014-01-24 01:06:40141 // 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.
avi7daa16fa2016-09-20 01:52:43145 if (error->IsEqual(iter->get())) {
[email protected]71c10c52014-01-24 01:06:40146 error->set_occurrences((*iter)->occurrences() + 1);
rdevlin.croninc799f9f2015-03-21 00:56:30147 error->set_id((*iter)->id());
[email protected]71c10c52014-01-24 01:06:40148 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.
avi7daa16fa2016-09-20 01:52:43155 if (list_.size() >= kMaxErrorsPerExtension)
[email protected]71c10c52014-01-24 01:06:40156 list_.pop_front();
[email protected]71c10c52014-01-24 01:06:40157
rdevlin.croninc799f9f2015-03-21 00:56:30158 if (error->id() == 0)
159 error->set_id(kNextErrorId++);
160
avi7daa16fa2016-09-20 01:52:43161 list_.push_back(std::move(error));
162 return list_.back().get();
[email protected]71c10c52014-01-24 01:06:40163}
164
165////////////////////////////////////////////////////////////////////////////////
166// ErrorMap
167ErrorMap::ErrorMap() {
168}
169
170ErrorMap::~ErrorMap() {
171 RemoveAllErrors();
172}
173
174const ErrorList& ErrorMap::GetErrorsForExtension(
175 const std::string& extension_id) const {
avi7daa16fa2016-09-20 01:52:43176 auto iter = map_.find(extension_id);
[email protected]71c10c52014-01-24 01:06:40177 return iter != map_.end() ? *iter->second->list() : g_empty_error_list.Get();
178}
179
dchengf5d241082016-04-21 03:43:11180const ExtensionError* ErrorMap::AddError(
181 std::unique_ptr<ExtensionError> error) {
avi7daa16fa2016-09-20 01:52:43182 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]71c10c52014-01-24 01:06:40187}
188
rdevlin.cronin20bf10b2015-04-29 16:51:43189void ErrorMap::RemoveErrors(const Filter& filter,
190 std::set<std::string>* affected_ids) {
rdevlin.croninc799f9f2015-03-21 00:56:30191 if (!filter.restrict_to_extension_id.empty()) {
avi7daa16fa2016-09-20 01:52:43192 auto iter = map_.find(filter.restrict_to_extension_id);
rdevlin.cronin20bf10b2015-04-29 16:51:43193 if (iter != map_.end()) {
194 if (iter->second->DeleteErrors(filter) && affected_ids)
195 affected_ids->insert(filter.restrict_to_extension_id);
196 }
rdevlin.croninc799f9f2015-03-21 00:56:30197 } else {
rdevlin.cronin20bf10b2015-04-29 16:51:43198 for (auto& key_val : map_) {
199 if (key_val.second->DeleteErrors(filter) && affected_ids)
200 affected_ids->insert(key_val.first);
201 }
rdevlin.croninc799f9f2015-03-21 00:56:30202 }
[email protected]71c10c52014-01-24 01:06:40203}
204
205void ErrorMap::RemoveAllErrors() {
[email protected]71c10c52014-01-24 01:06:40206 map_.clear();
207}
208
209} // namespace extensions