Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / extensions / activity_log / activity_actions.cc
blob05ff82fb14c636078f04592942a2bc6252aed729
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"
7 #include <string>
9 #include "base/format_macros.h"
10 #include "base/json/json_string_value_serializer.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/values.h"
15 #include "chrome/browser/extensions/activity_log/activity_action_constants.h"
16 #include "chrome/browser/extensions/activity_log/fullstream_ui_policy.h"
17 #include "extensions/common/constants.h"
18 #include "extensions/common/dom_action_types.h"
19 #include "url/gurl.h"
21 namespace constants = activity_log_constants;
22 namespace activity_log = extensions::api::activity_log_private;
24 namespace extensions {
26 namespace {
28 std::string Serialize(const base::Value* value) {
29 std::string value_as_text;
30 if (!value) {
31 value_as_text = "null";
32 } else {
33 JSONStringValueSerializer serializer(&value_as_text);
34 serializer.SerializeAndOmitBinaryValues(*value);
36 return value_as_text;
39 } // namespace
41 using api::activity_log_private::ExtensionActivity;
43 Action::Action(const std::string& extension_id,
44 const base::Time& time,
45 const ActionType action_type,
46 const std::string& api_name,
47 int64 action_id)
48 : extension_id_(extension_id),
49 time_(time),
50 action_type_(action_type),
51 api_name_(api_name),
52 page_incognito_(false),
53 arg_incognito_(false),
54 count_(0),
55 action_id_(action_id) {}
57 Action::~Action() {}
59 // TODO(mvrable): As an optimization, we might return this directly if the
60 // refcount is one. However, there are likely to be other stray references in
61 // many cases that will prevent this optimization.
62 scoped_refptr<Action> Action::Clone() const {
63 scoped_refptr<Action> clone(
64 new Action(
65 extension_id(), time(), action_type(), api_name(), action_id()));
66 if (args())
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());
73 if (other())
74 clone->set_other(make_scoped_ptr(other()->DeepCopy()));
75 return clone;
78 void Action::set_args(scoped_ptr<base::ListValue> args) {
79 args_.reset(args.release());
82 base::ListValue* Action::mutable_args() {
83 if (!args_.get()) {
84 args_.reset(new base::ListValue());
86 return args_.get();
89 void Action::set_page_url(const GURL& page_url) {
90 page_url_ = page_url;
93 void Action::set_arg_url(const GURL& arg_url) {
94 arg_url_ = arg_url;
97 void Action::set_other(scoped_ptr<base::DictionaryValue> other) {
98 other_.reset(other.release());
101 base::DictionaryValue* Action::mutable_other() {
102 if (!other_.get()) {
103 other_.reset(new base::DictionaryValue());
105 return other_.get();
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(base::StartsWith(url, constants::kIncognitoUrl,
114 base::CompareCase::SENSITIVE));
115 if (page_incognito())
116 set_page_url(GURL(url.substr(strlen(constants::kIncognitoUrl))));
117 else
118 set_page_url(GURL(url));
121 std::string Action::SerializeArgUrl() const {
122 return (arg_incognito() ? constants::kIncognitoUrl : "") + arg_url().spec();
125 void Action::ParseArgUrl(const std::string& url) {
126 set_arg_incognito(base::StartsWith(url, constants::kIncognitoUrl,
127 base::CompareCase::SENSITIVE));
128 if (arg_incognito())
129 set_arg_url(GURL(url.substr(strlen(constants::kIncognitoUrl))));
130 else
131 set_arg_url(GURL(url));
134 scoped_ptr<ExtensionActivity> Action::ConvertToExtensionActivity() {
135 scoped_ptr<ExtensionActivity> result(new ExtensionActivity);
137 // We do this translation instead of using the same enum because the database
138 // values need to be stable; this allows us to change the extension API
139 // without affecting the database.
140 switch (action_type()) {
141 case ACTION_API_CALL:
142 result->activity_type = activity_log::EXTENSION_ACTIVITY_TYPE_API_CALL;
143 break;
144 case ACTION_API_EVENT:
145 result->activity_type = activity_log::EXTENSION_ACTIVITY_TYPE_API_EVENT;
146 break;
147 case ACTION_CONTENT_SCRIPT:
148 result->activity_type =
149 activity_log::EXTENSION_ACTIVITY_TYPE_CONTENT_SCRIPT;
150 break;
151 case ACTION_DOM_ACCESS:
152 result->activity_type = activity_log::EXTENSION_ACTIVITY_TYPE_DOM_ACCESS;
153 break;
154 case ACTION_DOM_EVENT:
155 result->activity_type = activity_log::EXTENSION_ACTIVITY_TYPE_DOM_EVENT;
156 break;
157 case ACTION_WEB_REQUEST:
158 result->activity_type = activity_log::EXTENSION_ACTIVITY_TYPE_WEB_REQUEST;
159 break;
160 case UNUSED_ACTION_API_BLOCKED:
161 case ACTION_ANY:
162 default:
163 // This shouldn't be reached, but some people might have old or otherwise
164 // weird db entries. Treat it like an API call if that happens.
165 result->activity_type = activity_log::EXTENSION_ACTIVITY_TYPE_API_CALL;
166 break;
169 result->extension_id.reset(new std::string(extension_id()));
170 result->time.reset(new double(time().ToJsTime()));
171 result->count.reset(new double(count()));
172 result->api_call.reset(new std::string(api_name()));
173 result->args.reset(new std::string(Serialize(args())));
174 if (action_id() != -1)
175 result->activity_id.reset(
176 new std::string(base::StringPrintf("%" PRId64, action_id())));
177 if (page_url().is_valid()) {
178 if (!page_title().empty())
179 result->page_title.reset(new std::string(page_title()));
180 result->page_url.reset(new std::string(SerializePageUrl()));
182 if (arg_url().is_valid())
183 result->arg_url.reset(new std::string(SerializeArgUrl()));
185 if (other()) {
186 scoped_ptr<ExtensionActivity::Other> other_field(
187 new ExtensionActivity::Other);
188 bool prerender;
189 if (other()->GetBooleanWithoutPathExpansion(constants::kActionPrerender,
190 &prerender)) {
191 other_field->prerender.reset(new bool(prerender));
193 const base::DictionaryValue* web_request;
194 if (other()->GetDictionaryWithoutPathExpansion(constants::kActionWebRequest,
195 &web_request)) {
196 other_field->web_request.reset(new std::string(
197 ActivityLogPolicy::Util::Serialize(web_request)));
199 std::string extra;
200 if (other()->GetStringWithoutPathExpansion(constants::kActionExtra, &extra))
201 other_field->extra.reset(new std::string(extra));
202 int dom_verb;
203 if (other()->GetIntegerWithoutPathExpansion(constants::kActionDomVerb,
204 &dom_verb)) {
205 switch (static_cast<DomActionType::Type>(dom_verb)) {
206 case DomActionType::GETTER:
207 other_field->dom_verb =
208 activity_log::EXTENSION_ACTIVITY_DOM_VERB_GETTER;
209 break;
210 case DomActionType::SETTER:
211 other_field->dom_verb =
212 activity_log::EXTENSION_ACTIVITY_DOM_VERB_SETTER;
213 break;
214 case DomActionType::METHOD:
215 other_field->dom_verb =
216 activity_log::EXTENSION_ACTIVITY_DOM_VERB_METHOD;
217 break;
218 case DomActionType::INSERTED:
219 other_field->dom_verb =
220 activity_log::EXTENSION_ACTIVITY_DOM_VERB_INSERTED;
221 break;
222 case DomActionType::XHR:
223 other_field->dom_verb = activity_log::EXTENSION_ACTIVITY_DOM_VERB_XHR;
224 break;
225 case DomActionType::WEBREQUEST:
226 other_field->dom_verb =
227 activity_log::EXTENSION_ACTIVITY_DOM_VERB_WEBREQUEST;
228 break;
229 case DomActionType::MODIFIED:
230 other_field->dom_verb =
231 activity_log::EXTENSION_ACTIVITY_DOM_VERB_MODIFIED;
232 break;
233 default:
234 other_field->dom_verb =
235 activity_log::EXTENSION_ACTIVITY_DOM_VERB_NONE;
237 } else {
238 other_field->dom_verb = activity_log::EXTENSION_ACTIVITY_DOM_VERB_NONE;
240 result->other.reset(other_field.release());
243 return result.Pass();
246 std::string Action::PrintForDebug() const {
247 std::string result = base::StringPrintf("ACTION ID=%" PRId64, action_id());
248 result += " EXTENSION ID=" + extension_id() + " CATEGORY=";
249 switch (action_type_) {
250 case ACTION_API_CALL:
251 result += "api_call";
252 break;
253 case ACTION_API_EVENT:
254 result += "api_event_callback";
255 break;
256 case ACTION_WEB_REQUEST:
257 result += "webrequest";
258 break;
259 case ACTION_CONTENT_SCRIPT:
260 result += "content_script";
261 break;
262 case UNUSED_ACTION_API_BLOCKED:
263 // This is deprecated.
264 result += "api_blocked";
265 break;
266 case ACTION_DOM_EVENT:
267 result += "dom_event";
268 break;
269 case ACTION_DOM_ACCESS:
270 result += "dom_access";
271 break;
272 default:
273 result += base::StringPrintf("type%d", static_cast<int>(action_type_));
276 result += " API=" + api_name_;
277 if (args_.get()) {
278 result += " ARGS=" + Serialize(args_.get());
280 if (page_url_.is_valid()) {
281 if (page_incognito_)
282 result += " PAGE_URL=(incognito)" + page_url_.spec();
283 else
284 result += " PAGE_URL=" + page_url_.spec();
286 if (!page_title_.empty()) {
287 base::StringValue title(page_title_);
288 result += " PAGE_TITLE=" + Serialize(&title);
290 if (arg_url_.is_valid()) {
291 if (arg_incognito_)
292 result += " ARG_URL=(incognito)" + arg_url_.spec();
293 else
294 result += " ARG_URL=" + arg_url_.spec();
296 if (other_.get()) {
297 result += " OTHER=" + Serialize(other_.get());
300 result += base::StringPrintf(" COUNT=%d", count_);
301 return result;
304 bool ActionComparator::operator()(
305 const scoped_refptr<Action>& lhs,
306 const scoped_refptr<Action>& rhs) const {
307 if (lhs->time() != rhs->time())
308 return lhs->time() < rhs->time();
309 else if (lhs->action_id() != rhs->action_id())
310 return lhs->action_id() < rhs->action_id();
311 else
312 return ActionComparatorExcludingTimeAndActionId()(lhs, rhs);
315 bool ActionComparatorExcludingTimeAndActionId::operator()(
316 const scoped_refptr<Action>& lhs,
317 const scoped_refptr<Action>& rhs) const {
318 if (lhs->extension_id() != rhs->extension_id())
319 return lhs->extension_id() < rhs->extension_id();
320 if (lhs->action_type() != rhs->action_type())
321 return lhs->action_type() < rhs->action_type();
322 if (lhs->api_name() != rhs->api_name())
323 return lhs->api_name() < rhs->api_name();
325 // args might be null; treat a null value as less than all non-null values,
326 // including the empty string.
327 if (!lhs->args() && rhs->args())
328 return true;
329 if (lhs->args() && !rhs->args())
330 return false;
331 if (lhs->args() && rhs->args()) {
332 std::string lhs_args = ActivityLogPolicy::Util::Serialize(lhs->args());
333 std::string rhs_args = ActivityLogPolicy::Util::Serialize(rhs->args());
334 if (lhs_args != rhs_args)
335 return lhs_args < rhs_args;
338 // Compare URLs as strings, and treat the incognito flag as a separate field.
339 if (lhs->page_url().spec() != rhs->page_url().spec())
340 return lhs->page_url().spec() < rhs->page_url().spec();
341 if (lhs->page_incognito() != rhs->page_incognito())
342 return lhs->page_incognito() < rhs->page_incognito();
344 if (lhs->page_title() != rhs->page_title())
345 return lhs->page_title() < rhs->page_title();
347 if (lhs->arg_url().spec() != rhs->arg_url().spec())
348 return lhs->arg_url().spec() < rhs->arg_url().spec();
349 if (lhs->arg_incognito() != rhs->arg_incognito())
350 return lhs->arg_incognito() < rhs->arg_incognito();
352 // other is treated much like the args field.
353 if (!lhs->other() && rhs->other())
354 return true;
355 if (lhs->other() && !rhs->other())
356 return false;
357 if (lhs->other() && rhs->other()) {
358 std::string lhs_other = ActivityLogPolicy::Util::Serialize(lhs->other());
359 std::string rhs_other = ActivityLogPolicy::Util::Serialize(rhs->other());
360 if (lhs_other != rhs_other)
361 return lhs_other < rhs_other;
364 // All fields compare as equal if this point is reached.
365 return false;
368 } // namespace extensions