- add sources.
[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/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"
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     : extension_id_(extension_id),
51       time_(time),
52       action_type_(action_type),
53       api_name_(api_name),
54       page_incognito_(false),
55       arg_incognito_(false),
56       count_(0) {}
57
58 Action::~Action() {}
59
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()));
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;
76 }
77
78 void Action::set_args(scoped_ptr<ListValue> args) {
79   args_.reset(args.release());
80 }
81
82 ListValue* Action::mutable_args() {
83   if (!args_.get()) {
84     args_.reset(new ListValue());
85   }
86   return args_.get();
87 }
88
89 void Action::set_page_url(const GURL& page_url) {
90   page_url_ = page_url;
91 }
92
93 void Action::set_arg_url(const GURL& arg_url) {
94   arg_url_ = arg_url;
95 }
96
97 void Action::set_other(scoped_ptr<DictionaryValue> other) {
98   other_.reset(other.release());
99 }
100
101 DictionaryValue* Action::mutable_other() {
102   if (!other_.get()) {
103     other_.reset(new DictionaryValue());
104   }
105   return other_.get();
106 }
107
108 std::string Action::SerializePageUrl() const {
109   return (page_incognito() ? constants::kIncognitoUrl : "") + page_url().spec();
110 }
111
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))));
116   else
117     set_page_url(GURL(url));
118 }
119
120 std::string Action::SerializeArgUrl() const {
121   return (arg_incognito() ? constants::kIncognitoUrl : "") + arg_url().spec();
122 }
123
124 void Action::ParseArgUrl(const std::string& url) {
125   set_arg_incognito(StartsWithASCII(url, constants::kIncognitoUrl, true));
126   if (arg_incognito())
127     set_arg_url(GURL(url.substr(strlen(constants::kIncognitoUrl))));
128   else
129     set_arg_url(GURL(url));
130 }
131
132 scoped_ptr<ExtensionActivity> Action::ConvertToExtensionActivity() {
133   scoped_ptr<ExtensionActivity> result(new ExtensionActivity);
134
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;
141       break;
142     case ACTION_API_EVENT:
143       result->activity_type = ExtensionActivity::ACTIVITY_TYPE_API_EVENT;
144       break;
145     case ACTION_CONTENT_SCRIPT:
146       result->activity_type = ExtensionActivity::ACTIVITY_TYPE_CONTENT_SCRIPT;
147       break;
148     case ACTION_DOM_ACCESS:
149       result->activity_type = ExtensionActivity::ACTIVITY_TYPE_DOM_ACCESS;
150       break;
151     case ACTION_DOM_EVENT:
152       result->activity_type = ExtensionActivity::ACTIVITY_TYPE_DOM_EVENT;
153       break;
154     case ACTION_WEB_REQUEST:
155       result->activity_type = ExtensionActivity::ACTIVITY_TYPE_WEB_REQUEST;
156       break;
157     case UNUSED_ACTION_API_BLOCKED:
158     case ACTION_ANY:
159     default:
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;
163       break;
164   }
165
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()));
175   }
176   if (arg_url().is_valid())
177     result->arg_url.reset(new std::string(SerializeArgUrl()));
178
179   if (other()) {
180     scoped_ptr<ExtensionActivity::Other> other_field(
181         new ExtensionActivity::Other);
182     bool prerender;
183     if (other()->GetBooleanWithoutPathExpansion(constants::kActionPrerender,
184                                                 &prerender)) {
185       other_field->prerender.reset(new bool(prerender));
186     }
187     const DictionaryValue* web_request;
188     if (other()->GetDictionaryWithoutPathExpansion(constants::kActionWebRequest,
189                                                    &web_request)) {
190       other_field->web_request.reset(new std::string(
191           ActivityLogPolicy::Util::Serialize(web_request)));
192     }
193     std::string extra;
194     if (other()->GetStringWithoutPathExpansion(constants::kActionExtra, &extra))
195       other_field->extra.reset(new std::string(extra));
196     int dom_verb;
197     if (other()->GetIntegerWithoutPathExpansion(constants::kActionDomVerb,
198                                                 &dom_verb)) {
199       switch (static_cast<DomActionType::Type>(dom_verb)) {
200         case DomActionType::GETTER:
201           other_field->dom_verb = ExtensionActivity::Other::DOM_VERB_GETTER;
202           break;
203         case DomActionType::SETTER:
204           other_field->dom_verb = ExtensionActivity::Other::DOM_VERB_SETTER;
205           break;
206         case DomActionType::METHOD:
207           other_field->dom_verb = ExtensionActivity::Other::DOM_VERB_METHOD;
208           break;
209         case DomActionType::INSERTED:
210           other_field->dom_verb = ExtensionActivity::Other::DOM_VERB_INSERTED;
211           break;
212         case DomActionType::XHR:
213           other_field->dom_verb = ExtensionActivity::Other::DOM_VERB_XHR;
214           break;
215         case DomActionType::WEBREQUEST:
216           other_field->dom_verb = ExtensionActivity::Other::DOM_VERB_WEBREQUEST;
217           break;
218         case DomActionType::MODIFIED:
219           other_field->dom_verb = ExtensionActivity::Other::DOM_VERB_MODIFIED;
220           break;
221         default:
222           other_field->dom_verb = ExtensionActivity::Other::DOM_VERB_NONE;
223       }
224     } else {
225       other_field->dom_verb = ExtensionActivity::Other::DOM_VERB_NONE;
226     }
227     result->other.reset(other_field.release());
228   }
229
230   return result.Pass();
231 }
232
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";
238       break;
239     case ACTION_API_EVENT:
240       result += "api_event_callback";
241       break;
242     case ACTION_WEB_REQUEST:
243       result += "webrequest";
244       break;
245     case ACTION_CONTENT_SCRIPT:
246       result += "content_script";
247       break;
248     case UNUSED_ACTION_API_BLOCKED:
249       // This is deprecated.
250       result += "api_blocked";
251       break;
252     case ACTION_DOM_EVENT:
253       result += "dom_event";
254       break;
255     case ACTION_DOM_ACCESS:
256       result += "dom_access";
257       break;
258     default:
259       result += base::StringPrintf("type%d", static_cast<int>(action_type_));
260   }
261
262   result += " API=" + api_name_;
263   if (args_.get()) {
264     result += " ARGS=" + Serialize(args_.get());
265   }
266   if (page_url_.is_valid()) {
267     if (page_incognito_)
268       result += " PAGE_URL=(incognito)" + page_url_.spec();
269     else
270       result += " PAGE_URL=" + page_url_.spec();
271   }
272   if (!page_title_.empty()) {
273     StringValue title(page_title_);
274     result += " PAGE_TITLE=" + Serialize(&title);
275   }
276   if (arg_url_.is_valid()) {
277     if (arg_incognito_)
278       result += " ARG_URL=(incognito)" + arg_url_.spec();
279     else
280       result += " ARG_URL=" + arg_url_.spec();
281   }
282   if (other_.get()) {
283     result += " OTHER=" + Serialize(other_.get());
284   }
285
286   result += base::StringPrintf(" COUNT=%d", count_);
287   return result;
288 }
289
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();
295   else
296     return ActionComparatorExcludingTime()(lhs, rhs);
297 }
298
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();
308
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())
312     return true;
313   if (lhs->args() && !rhs->args())
314     return false;
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;
320   }
321
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();
327
328   if (lhs->page_title() != rhs->page_title())
329     return lhs->page_title() < rhs->page_title();
330
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();
335
336   // other is treated much like the args field.
337   if (!lhs->other() && rhs->other())
338     return true;
339   if (lhs->other() && !rhs->other())
340     return false;
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;
346   }
347
348   // All fields compare as equal if this point is reached.
349   return false;
350 }
351
352 }  // namespace extensions