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
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/activity_log/activity_actions.h"
9 #include "base/command_line.h"
10 #include "base/json/json_string_value_serializer.h"
11 #include "base/logging.h"
12 #include "base/memory/singleton.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/stringprintf.h"
16 #include "chrome/browser/extensions/activity_log/activity_action_constants.h"
17 #include "chrome/browser/extensions/activity_log/fullstream_ui_policy.h"
18 #include "chrome/browser/ui/browser.h"
19 #include "chrome/common/chrome_switches.h"
20 #include "chrome/common/extensions/dom_action_types.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/web_contents.h"
23 #include "sql/statement.h"
25 namespace constants
= activity_log_constants
;
29 std::string
Serialize(const base::Value
* value
) {
30 std::string value_as_text
;
32 value_as_text
= "null";
34 JSONStringValueSerializer
serializer(&value_as_text
);
35 serializer
.SerializeAndOmitBinaryValues(*value
);
42 namespace extensions
{
44 using api::activity_log_private::ExtensionActivity
;
46 Action::Action(const std::string
& extension_id
,
47 const base::Time
& time
,
48 const ActionType action_type
,
49 const std::string
& api_name
)
50 : extension_id_(extension_id
),
52 action_type_(action_type
),
54 page_incognito_(false),
55 arg_incognito_(false),
60 // TODO(mvrable): As an optimization, we might return this directly if the
61 // refcount is one. However, there are likely to be other stray references in
62 // many cases that will prevent this optimization.
63 scoped_refptr
<Action
> Action::Clone() const {
64 scoped_refptr
<Action
> clone(
65 new Action(extension_id(), time(), action_type(), api_name()));
67 clone
->set_args(make_scoped_ptr(args()->DeepCopy()));
68 clone
->set_page_url(page_url());
69 clone
->set_page_title(page_title());
70 clone
->set_page_incognito(page_incognito());
71 clone
->set_arg_url(arg_url());
72 clone
->set_arg_incognito(arg_incognito());
74 clone
->set_other(make_scoped_ptr(other()->DeepCopy()));
78 void Action::set_args(scoped_ptr
<ListValue
> args
) {
79 args_
.reset(args
.release());
82 ListValue
* Action::mutable_args() {
84 args_
.reset(new ListValue());
89 void Action::set_page_url(const GURL
& page_url
) {
93 void Action::set_arg_url(const GURL
& arg_url
) {
97 void Action::set_other(scoped_ptr
<DictionaryValue
> other
) {
98 other_
.reset(other
.release());
101 DictionaryValue
* Action::mutable_other() {
103 other_
.reset(new DictionaryValue());
108 std::string
Action::SerializePageUrl() const {
109 return (page_incognito() ? constants::kIncognitoUrl
: "") + page_url().spec();
112 void Action::ParsePageUrl(const std::string
& url
) {
113 set_page_incognito(StartsWithASCII(url
, constants::kIncognitoUrl
, true));
114 if (page_incognito())
115 set_page_url(GURL(url
.substr(strlen(constants::kIncognitoUrl
))));
117 set_page_url(GURL(url
));
120 std::string
Action::SerializeArgUrl() const {
121 return (arg_incognito() ? constants::kIncognitoUrl
: "") + arg_url().spec();
124 void Action::ParseArgUrl(const std::string
& url
) {
125 set_arg_incognito(StartsWithASCII(url
, constants::kIncognitoUrl
, true));
127 set_arg_url(GURL(url
.substr(strlen(constants::kIncognitoUrl
))));
129 set_arg_url(GURL(url
));
132 scoped_ptr
<ExtensionActivity
> Action::ConvertToExtensionActivity() {
133 scoped_ptr
<ExtensionActivity
> result(new ExtensionActivity
);
135 // We do this translation instead of using the same enum because the database
136 // values need to be stable; this allows us to change the extension API
137 // without affecting the database.
138 switch (action_type()) {
139 case ACTION_API_CALL
:
140 result
->activity_type
= ExtensionActivity::ACTIVITY_TYPE_API_CALL
;
142 case ACTION_API_EVENT
:
143 result
->activity_type
= ExtensionActivity::ACTIVITY_TYPE_API_EVENT
;
145 case ACTION_CONTENT_SCRIPT
:
146 result
->activity_type
= ExtensionActivity::ACTIVITY_TYPE_CONTENT_SCRIPT
;
148 case ACTION_DOM_ACCESS
:
149 result
->activity_type
= ExtensionActivity::ACTIVITY_TYPE_DOM_ACCESS
;
151 case ACTION_DOM_EVENT
:
152 result
->activity_type
= ExtensionActivity::ACTIVITY_TYPE_DOM_EVENT
;
154 case ACTION_WEB_REQUEST
:
155 result
->activity_type
= ExtensionActivity::ACTIVITY_TYPE_WEB_REQUEST
;
157 case UNUSED_ACTION_API_BLOCKED
:
160 // This shouldn't be reached, but some people might have old or otherwise
161 // weird db entries. Treat it like an API call if that happens.
162 result
->activity_type
= ExtensionActivity::ACTIVITY_TYPE_API_CALL
;
166 result
->extension_id
.reset(new std::string(extension_id()));
167 result
->time
.reset(new double(time().ToJsTime()));
168 result
->count
.reset(new double(count()));
169 result
->api_call
.reset(new std::string(api_name()));
170 result
->args
.reset(new std::string(Serialize(args())));
171 if (page_url().is_valid()) {
172 if (!page_title().empty())
173 result
->page_title
.reset(new std::string(page_title()));
174 result
->page_url
.reset(new std::string(SerializePageUrl()));
176 if (arg_url().is_valid())
177 result
->arg_url
.reset(new std::string(SerializeArgUrl()));
180 scoped_ptr
<ExtensionActivity::Other
> other_field(
181 new ExtensionActivity::Other
);
183 if (other()->GetBooleanWithoutPathExpansion(constants::kActionPrerender
,
185 other_field
->prerender
.reset(new bool(prerender
));
187 const DictionaryValue
* web_request
;
188 if (other()->GetDictionaryWithoutPathExpansion(constants::kActionWebRequest
,
190 other_field
->web_request
.reset(new std::string(
191 ActivityLogPolicy::Util::Serialize(web_request
)));
194 if (other()->GetStringWithoutPathExpansion(constants::kActionExtra
, &extra
))
195 other_field
->extra
.reset(new std::string(extra
));
197 if (other()->GetIntegerWithoutPathExpansion(constants::kActionDomVerb
,
199 switch (static_cast<DomActionType::Type
>(dom_verb
)) {
200 case DomActionType::GETTER
:
201 other_field
->dom_verb
= ExtensionActivity::Other::DOM_VERB_GETTER
;
203 case DomActionType::SETTER
:
204 other_field
->dom_verb
= ExtensionActivity::Other::DOM_VERB_SETTER
;
206 case DomActionType::METHOD
:
207 other_field
->dom_verb
= ExtensionActivity::Other::DOM_VERB_METHOD
;
209 case DomActionType::INSERTED
:
210 other_field
->dom_verb
= ExtensionActivity::Other::DOM_VERB_INSERTED
;
212 case DomActionType::XHR
:
213 other_field
->dom_verb
= ExtensionActivity::Other::DOM_VERB_XHR
;
215 case DomActionType::WEBREQUEST
:
216 other_field
->dom_verb
= ExtensionActivity::Other::DOM_VERB_WEBREQUEST
;
218 case DomActionType::MODIFIED
:
219 other_field
->dom_verb
= ExtensionActivity::Other::DOM_VERB_MODIFIED
;
222 other_field
->dom_verb
= ExtensionActivity::Other::DOM_VERB_NONE
;
225 other_field
->dom_verb
= ExtensionActivity::Other::DOM_VERB_NONE
;
227 result
->other
.reset(other_field
.release());
230 return result
.Pass();
233 std::string
Action::PrintForDebug() const {
234 std::string result
= "ID=" + extension_id() + " CATEGORY=";
235 switch (action_type_
) {
236 case ACTION_API_CALL
:
237 result
+= "api_call";
239 case ACTION_API_EVENT
:
240 result
+= "api_event_callback";
242 case ACTION_WEB_REQUEST
:
243 result
+= "webrequest";
245 case ACTION_CONTENT_SCRIPT
:
246 result
+= "content_script";
248 case UNUSED_ACTION_API_BLOCKED
:
249 // This is deprecated.
250 result
+= "api_blocked";
252 case ACTION_DOM_EVENT
:
253 result
+= "dom_event";
255 case ACTION_DOM_ACCESS
:
256 result
+= "dom_access";
259 result
+= base::StringPrintf("type%d", static_cast<int>(action_type_
));
262 result
+= " API=" + api_name_
;
264 result
+= " ARGS=" + Serialize(args_
.get());
266 if (page_url_
.is_valid()) {
268 result
+= " PAGE_URL=(incognito)" + page_url_
.spec();
270 result
+= " PAGE_URL=" + page_url_
.spec();
272 if (!page_title_
.empty()) {
273 StringValue
title(page_title_
);
274 result
+= " PAGE_TITLE=" + Serialize(&title
);
276 if (arg_url_
.is_valid()) {
278 result
+= " ARG_URL=(incognito)" + arg_url_
.spec();
280 result
+= " ARG_URL=" + arg_url_
.spec();
283 result
+= " OTHER=" + Serialize(other_
.get());
286 result
+= base::StringPrintf(" COUNT=%d", count_
);
290 bool ActionComparator::operator()(
291 const scoped_refptr
<Action
>& lhs
,
292 const scoped_refptr
<Action
>& rhs
) const {
293 if (lhs
->time() != rhs
->time())
294 return lhs
->time() < rhs
->time();
296 return ActionComparatorExcludingTime()(lhs
, rhs
);
299 bool ActionComparatorExcludingTime::operator()(
300 const scoped_refptr
<Action
>& lhs
,
301 const scoped_refptr
<Action
>& rhs
) const {
302 if (lhs
->extension_id() != rhs
->extension_id())
303 return lhs
->extension_id() < rhs
->extension_id();
304 if (lhs
->action_type() != rhs
->action_type())
305 return lhs
->action_type() < rhs
->action_type();
306 if (lhs
->api_name() != rhs
->api_name())
307 return lhs
->api_name() < rhs
->api_name();
309 // args might be null; treat a null value as less than all non-null values,
310 // including the empty string.
311 if (!lhs
->args() && rhs
->args())
313 if (lhs
->args() && !rhs
->args())
315 if (lhs
->args() && rhs
->args()) {
316 std::string lhs_args
= ActivityLogPolicy::Util::Serialize(lhs
->args());
317 std::string rhs_args
= ActivityLogPolicy::Util::Serialize(rhs
->args());
318 if (lhs_args
!= rhs_args
)
319 return lhs_args
< rhs_args
;
322 // Compare URLs as strings, and treat the incognito flag as a separate field.
323 if (lhs
->page_url().spec() != rhs
->page_url().spec())
324 return lhs
->page_url().spec() < rhs
->page_url().spec();
325 if (lhs
->page_incognito() != rhs
->page_incognito())
326 return lhs
->page_incognito() < rhs
->page_incognito();
328 if (lhs
->page_title() != rhs
->page_title())
329 return lhs
->page_title() < rhs
->page_title();
331 if (lhs
->arg_url().spec() != rhs
->arg_url().spec())
332 return lhs
->arg_url().spec() < rhs
->arg_url().spec();
333 if (lhs
->arg_incognito() != rhs
->arg_incognito())
334 return lhs
->arg_incognito() < rhs
->arg_incognito();
336 // other is treated much like the args field.
337 if (!lhs
->other() && rhs
->other())
339 if (lhs
->other() && !rhs
->other())
341 if (lhs
->other() && rhs
->other()) {
342 std::string lhs_other
= ActivityLogPolicy::Util::Serialize(lhs
->other());
343 std::string rhs_other
= ActivityLogPolicy::Util::Serialize(rhs
->other());
344 if (lhs_other
!= rhs_other
)
345 return lhs_other
< rhs_other
;
348 // All fields compare as equal if this point is reached.
352 } // namespace extensions