Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / activity_log / activity_actions.cc
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.
4
5 #include "chrome/browser/extensions/activity_log/activity_actions.h"
6
7 #include <string>
8
9 #include "base/command_line.h"
10 #include "base/format_macros.h"
11 #include "base/json/json_string_value_serializer.h"
12 #include "base/logging.h"
13 #include "base/memory/singleton.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "chrome/browser/extensions/activity_log/activity_action_constants.h"
18 #include "chrome/browser/extensions/activity_log/fullstream_ui_policy.h"
19 #include "chrome/browser/ui/browser.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chrome/common/extensions/dom_action_types.h"
22 #include "content/public/browser/web_contents.h"
23 #include "sql/statement.h"
24
25 namespace constants = activity_log_constants;
26
27 namespace {
28
29 std::string Serialize(const base::Value* value) {
30   std::string value_as_text;
31   if (!value) {
32     value_as_text = "null";
33   } else {
34     JSONStringValueSerializer serializer(&value_as_text);
35     serializer.SerializeAndOmitBinaryValues(*value);
36   }
37   return value_as_text;
38 }
39
40 }  // namespace
41
42 namespace extensions {
43
44 using api::activity_log_private::ExtensionActivity;
45
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                int64 action_id)
51     : extension_id_(extension_id),
52       time_(time),
53       action_type_(action_type),
54       api_name_(api_name),
55       page_incognito_(false),
56       arg_incognito_(false),
57       count_(0),
58       action_id_(action_id) {}
59
60 Action::~Action() {}
61
62 // TODO(mvrable): As an optimization, we might return this directly if the
63 // refcount is one.  However, there are likely to be other stray references in
64 // many cases that will prevent this optimization.
65 scoped_refptr<Action> Action::Clone() const {
66   scoped_refptr<Action> clone(
67       new Action(
68           extension_id(), time(), action_type(), api_name(), action_id()));
69   if (args())
70     clone->set_args(make_scoped_ptr(args()->DeepCopy()));
71   clone->set_page_url(page_url());
72   clone->set_page_title(page_title());
73   clone->set_page_incognito(page_incognito());
74   clone->set_arg_url(arg_url());
75   clone->set_arg_incognito(arg_incognito());
76   if (other())
77     clone->set_other(make_scoped_ptr(other()->DeepCopy()));
78   return clone;
79 }
80
81 void Action::set_args(scoped_ptr<base::ListValue> args) {
82   args_.reset(args.release());
83 }
84
85 base::ListValue* Action::mutable_args() {
86   if (!args_.get()) {
87     args_.reset(new base::ListValue());
88   }
89   return args_.get();
90 }
91
92 void Action::set_page_url(const GURL& page_url) {
93   page_url_ = page_url;
94 }
95
96 void Action::set_arg_url(const GURL& arg_url) {
97   arg_url_ = arg_url;
98 }
99
100 void Action::set_other(scoped_ptr<base::DictionaryValue> other) {
101   other_.reset(other.release());
102 }
103
104 base::DictionaryValue* Action::mutable_other() {
105   if (!other_.get()) {
106     other_.reset(new base::DictionaryValue());
107   }
108   return other_.get();
109 }
110
111 std::string Action::SerializePageUrl() const {
112   return (page_incognito() ? constants::kIncognitoUrl : "") + page_url().spec();
113 }
114
115 void Action::ParsePageUrl(const std::string& url) {
116   set_page_incognito(StartsWithASCII(url, constants::kIncognitoUrl, true));
117   if (page_incognito())
118     set_page_url(GURL(url.substr(strlen(constants::kIncognitoUrl))));
119   else
120     set_page_url(GURL(url));
121 }
122
123 std::string Action::SerializeArgUrl() const {
124   return (arg_incognito() ? constants::kIncognitoUrl : "") + arg_url().spec();
125 }
126
127 void Action::ParseArgUrl(const std::string& url) {
128   set_arg_incognito(StartsWithASCII(url, constants::kIncognitoUrl, true));
129   if (arg_incognito())
130     set_arg_url(GURL(url.substr(strlen(constants::kIncognitoUrl))));
131   else
132     set_arg_url(GURL(url));
133 }
134
135 scoped_ptr<ExtensionActivity> Action::ConvertToExtensionActivity() {
136   scoped_ptr<ExtensionActivity> result(new ExtensionActivity);
137
138   // We do this translation instead of using the same enum because the database
139   // values need to be stable; this allows us to change the extension API
140   // without affecting the database.
141   switch (action_type()) {
142     case ACTION_API_CALL:
143       result->activity_type = ExtensionActivity::ACTIVITY_TYPE_API_CALL;
144       break;
145     case ACTION_API_EVENT:
146       result->activity_type = ExtensionActivity::ACTIVITY_TYPE_API_EVENT;
147       break;
148     case ACTION_CONTENT_SCRIPT:
149       result->activity_type = ExtensionActivity::ACTIVITY_TYPE_CONTENT_SCRIPT;
150       break;
151     case ACTION_DOM_ACCESS:
152       result->activity_type = ExtensionActivity::ACTIVITY_TYPE_DOM_ACCESS;
153       break;
154     case ACTION_DOM_EVENT:
155       result->activity_type = ExtensionActivity::ACTIVITY_TYPE_DOM_EVENT;
156       break;
157     case ACTION_WEB_REQUEST:
158       result->activity_type = ExtensionActivity::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 = ExtensionActivity::ACTIVITY_TYPE_API_CALL;
166       break;
167   }
168
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()));
181   }
182   if (arg_url().is_valid())
183     result->arg_url.reset(new std::string(SerializeArgUrl()));
184
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));
192     }
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)));
198     }
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 = ExtensionActivity::Other::DOM_VERB_GETTER;
208           break;
209         case DomActionType::SETTER:
210           other_field->dom_verb = ExtensionActivity::Other::DOM_VERB_SETTER;
211           break;
212         case DomActionType::METHOD:
213           other_field->dom_verb = ExtensionActivity::Other::DOM_VERB_METHOD;
214           break;
215         case DomActionType::INSERTED:
216           other_field->dom_verb = ExtensionActivity::Other::DOM_VERB_INSERTED;
217           break;
218         case DomActionType::XHR:
219           other_field->dom_verb = ExtensionActivity::Other::DOM_VERB_XHR;
220           break;
221         case DomActionType::WEBREQUEST:
222           other_field->dom_verb = ExtensionActivity::Other::DOM_VERB_WEBREQUEST;
223           break;
224         case DomActionType::MODIFIED:
225           other_field->dom_verb = ExtensionActivity::Other::DOM_VERB_MODIFIED;
226           break;
227         default:
228           other_field->dom_verb = ExtensionActivity::Other::DOM_VERB_NONE;
229       }
230     } else {
231       other_field->dom_verb = ExtensionActivity::Other::DOM_VERB_NONE;
232     }
233     result->other.reset(other_field.release());
234   }
235
236   return result.Pass();
237 }
238
239 std::string Action::PrintForDebug() const {
240   std::string result = base::StringPrintf("ACTION ID=%" PRId64, action_id());
241   result += " EXTENSION ID=" + extension_id() + " CATEGORY=";
242   switch (action_type_) {
243     case ACTION_API_CALL:
244       result += "api_call";
245       break;
246     case ACTION_API_EVENT:
247       result += "api_event_callback";
248       break;
249     case ACTION_WEB_REQUEST:
250       result += "webrequest";
251       break;
252     case ACTION_CONTENT_SCRIPT:
253       result += "content_script";
254       break;
255     case UNUSED_ACTION_API_BLOCKED:
256       // This is deprecated.
257       result += "api_blocked";
258       break;
259     case ACTION_DOM_EVENT:
260       result += "dom_event";
261       break;
262     case ACTION_DOM_ACCESS:
263       result += "dom_access";
264       break;
265     default:
266       result += base::StringPrintf("type%d", static_cast<int>(action_type_));
267   }
268
269   result += " API=" + api_name_;
270   if (args_.get()) {
271     result += " ARGS=" + Serialize(args_.get());
272   }
273   if (page_url_.is_valid()) {
274     if (page_incognito_)
275       result += " PAGE_URL=(incognito)" + page_url_.spec();
276     else
277       result += " PAGE_URL=" + page_url_.spec();
278   }
279   if (!page_title_.empty()) {
280     base::StringValue title(page_title_);
281     result += " PAGE_TITLE=" + Serialize(&title);
282   }
283   if (arg_url_.is_valid()) {
284     if (arg_incognito_)
285       result += " ARG_URL=(incognito)" + arg_url_.spec();
286     else
287       result += " ARG_URL=" + arg_url_.spec();
288   }
289   if (other_.get()) {
290     result += " OTHER=" + Serialize(other_.get());
291   }
292
293   result += base::StringPrintf(" COUNT=%d", count_);
294   return result;
295 }
296
297 bool ActionComparator::operator()(
298     const scoped_refptr<Action>& lhs,
299     const scoped_refptr<Action>& rhs) const {
300   if (lhs->time() != rhs->time())
301     return lhs->time() < rhs->time();
302   else if (lhs->action_id() != rhs->action_id())
303     return lhs->action_id() < rhs->action_id();
304   else
305     return ActionComparatorExcludingTimeAndActionId()(lhs, rhs);
306 }
307
308 bool ActionComparatorExcludingTimeAndActionId::operator()(
309     const scoped_refptr<Action>& lhs,
310     const scoped_refptr<Action>& rhs) const {
311   if (lhs->extension_id() != rhs->extension_id())
312     return lhs->extension_id() < rhs->extension_id();
313   if (lhs->action_type() != rhs->action_type())
314     return lhs->action_type() < rhs->action_type();
315   if (lhs->api_name() != rhs->api_name())
316     return lhs->api_name() < rhs->api_name();
317
318   // args might be null; treat a null value as less than all non-null values,
319   // including the empty string.
320   if (!lhs->args() && rhs->args())
321     return true;
322   if (lhs->args() && !rhs->args())
323     return false;
324   if (lhs->args() && rhs->args()) {
325     std::string lhs_args = ActivityLogPolicy::Util::Serialize(lhs->args());
326     std::string rhs_args = ActivityLogPolicy::Util::Serialize(rhs->args());
327     if (lhs_args != rhs_args)
328       return lhs_args < rhs_args;
329   }
330
331   // Compare URLs as strings, and treat the incognito flag as a separate field.
332   if (lhs->page_url().spec() != rhs->page_url().spec())
333     return lhs->page_url().spec() < rhs->page_url().spec();
334   if (lhs->page_incognito() != rhs->page_incognito())
335     return lhs->page_incognito() < rhs->page_incognito();
336
337   if (lhs->page_title() != rhs->page_title())
338     return lhs->page_title() < rhs->page_title();
339
340   if (lhs->arg_url().spec() != rhs->arg_url().spec())
341     return lhs->arg_url().spec() < rhs->arg_url().spec();
342   if (lhs->arg_incognito() != rhs->arg_incognito())
343     return lhs->arg_incognito() < rhs->arg_incognito();
344
345   // other is treated much like the args field.
346   if (!lhs->other() && rhs->other())
347     return true;
348   if (lhs->other() && !rhs->other())
349     return false;
350   if (lhs->other() && rhs->other()) {
351     std::string lhs_other = ActivityLogPolicy::Util::Serialize(lhs->other());
352     std::string rhs_other = ActivityLogPolicy::Util::Serialize(rhs->other());
353     if (lhs_other != rhs_other)
354       return lhs_other < rhs_other;
355   }
356
357   // All fields compare as equal if this point is reached.
358   return false;
359 }
360
361 }  // namespace extensions