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.
5 #include "extensions/browser/error_map.h"
7 #include "base/lazy_instance.h"
8 #include "base/stl_util.h"
10 namespace extensions
{
14 // The maximum number of errors to be stored per extension.
15 const size_t kMaxErrorsPerExtension
= 100;
17 base::LazyInstance
<ErrorList
> g_empty_error_list
= LAZY_INSTANCE_INITIALIZER
;
19 // An incrementing counter for the next error id. Overflowing this is very
20 // unlikely, since the number of errors per extension is capped at 100.
25 ////////////////////////////////////////////////////////////////////////////////
27 ErrorMap::Filter::Filter(const std::string
& restrict_to_extension_id
,
29 const std::set
<int>& restrict_to_ids
,
30 bool restrict_to_incognito
)
31 : restrict_to_extension_id(restrict_to_extension_id
),
32 restrict_to_type(restrict_to_type
),
33 restrict_to_ids(restrict_to_ids
),
34 restrict_to_incognito(restrict_to_incognito
) {
37 ErrorMap::Filter::~Filter() {
40 ErrorMap::Filter
ErrorMap::Filter::ErrorsForExtension(
41 const std::string
& extension_id
) {
42 return Filter(extension_id
, -1, std::set
<int>(), false);
45 ErrorMap::Filter
ErrorMap::Filter::ErrorsForExtensionWithType(
46 const std::string
& extension_id
,
47 ExtensionError::Type type
) {
48 return Filter(extension_id
, type
, std::set
<int>(), false);
51 ErrorMap::Filter
ErrorMap::Filter::ErrorsForExtensionWithIds(
52 const std::string
& extension_id
,
53 const std::set
<int>& ids
) {
54 return Filter(extension_id
, -1, ids
, false);
57 ErrorMap::Filter
ErrorMap::Filter::ErrorsForExtensionWithTypeAndIds(
58 const std::string
& extension_id
,
59 ExtensionError::Type type
,
60 const std::set
<int>& ids
) {
61 return Filter(extension_id
, type
, ids
, false);
64 ErrorMap::Filter
ErrorMap::Filter::IncognitoErrors() {
65 return Filter(std::string(), -1, std::set
<int>(), true);
68 bool ErrorMap::Filter::Matches(const ExtensionError
* error
) const {
69 if (restrict_to_type
!= -1 && restrict_to_type
!= error
->type())
71 if (restrict_to_incognito
&& !error
->from_incognito())
73 if (!restrict_to_extension_id
.empty() &&
74 error
->extension_id() != restrict_to_extension_id
)
76 if (!restrict_to_ids
.empty() && restrict_to_ids
.count(error
->id()) == 0)
81 ////////////////////////////////////////////////////////////////////////////////
82 // ErrorMap::ExtensionEntry
83 class ErrorMap::ExtensionEntry
{
88 // Delete any errors in the entry that match the given ids and type, if
90 // Returns true if any errors were deleted.
91 bool DeleteErrors(const ErrorMap::Filter
& filter
);
92 // Delete all errors in the entry.
93 void DeleteAllErrors();
95 // Add the error to the list, and return a weak reference.
96 const ExtensionError
* AddError(scoped_ptr
<ExtensionError
> error
);
98 const ErrorList
* list() const { return &list_
; }
101 // The list of all errors associated with the extension. The errors are
102 // owned by the Entry (in turn owned by the ErrorMap) and are deleted upon
106 DISALLOW_COPY_AND_ASSIGN(ExtensionEntry
);
109 ErrorMap::ExtensionEntry::ExtensionEntry() {
112 ErrorMap::ExtensionEntry::~ExtensionEntry() {
116 bool ErrorMap::ExtensionEntry::DeleteErrors(const Filter
& filter
) {
117 bool deleted
= false;
118 for (ErrorList::iterator iter
= list_
.begin(); iter
!= list_
.end();) {
119 if (filter
.Matches(*iter
)) {
121 iter
= list_
.erase(iter
);
130 void ErrorMap::ExtensionEntry::DeleteAllErrors() {
131 STLDeleteContainerPointers(list_
.begin(), list_
.end());
135 const ExtensionError
* ErrorMap::ExtensionEntry::AddError(
136 scoped_ptr
<ExtensionError
> error
) {
137 for (ErrorList::iterator iter
= list_
.begin(); iter
!= list_
.end(); ++iter
) {
138 // If we find a duplicate error, remove the old error and add the new one,
139 // incrementing the occurrence count of the error. We use the new error
140 // for runtime errors, so we can link to the latest context, inspectable
142 if (error
->IsEqual(*iter
)) {
143 error
->set_occurrences((*iter
)->occurrences() + 1);
144 error
->set_id((*iter
)->id());
151 // If there are too many errors for an extension already, limit ourselves to
152 // the most recent ones.
153 if (list_
.size() >= kMaxErrorsPerExtension
) {
154 delete list_
.front();
158 if (error
->id() == 0)
159 error
->set_id(kNextErrorId
++);
161 list_
.push_back(error
.release());
165 ////////////////////////////////////////////////////////////////////////////////
167 ErrorMap::ErrorMap() {
170 ErrorMap::~ErrorMap() {
174 const ErrorList
& ErrorMap::GetErrorsForExtension(
175 const std::string
& extension_id
) const {
176 EntryMap::const_iterator iter
= map_
.find(extension_id
);
177 return iter
!= map_
.end() ? *iter
->second
->list() : g_empty_error_list
.Get();
180 const ExtensionError
* ErrorMap::AddError(scoped_ptr
<ExtensionError
> error
) {
181 EntryMap::iterator iter
= map_
.find(error
->extension_id());
182 if (iter
== map_
.end()) {
183 iter
= map_
.insert(std::pair
<std::string
, ExtensionEntry
*>(
184 error
->extension_id(), new ExtensionEntry
)).first
;
186 return iter
->second
->AddError(error
.Pass());
189 void ErrorMap::RemoveErrors(const Filter
& filter
,
190 std::set
<std::string
>* affected_ids
) {
191 if (!filter
.restrict_to_extension_id
.empty()) {
192 EntryMap::iterator iter
= map_
.find(filter
.restrict_to_extension_id
);
193 if (iter
!= map_
.end()) {
194 if (iter
->second
->DeleteErrors(filter
) && affected_ids
)
195 affected_ids
->insert(filter
.restrict_to_extension_id
);
198 for (auto& key_val
: map_
) {
199 if (key_val
.second
->DeleteErrors(filter
) && affected_ids
)
200 affected_ids
->insert(key_val
.first
);
205 void ErrorMap::RemoveAllErrors() {
206 for (EntryMap::iterator iter
= map_
.begin(); iter
!= map_
.end(); ++iter
)
211 } // namespace extensions