Home | History | Annotate | Download | only in activity_log
      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 "content/public/browser/browser_thread.h"
     21 #include "content/public/browser/web_contents.h"
     22 #include "sql/statement.h"
     23 
     24 namespace constants = activity_log_constants;
     25 
     26 namespace {
     27 
     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);
     35   }
     36   return value_as_text;
     37 }
     38 
     39 }  // namespace
     40 
     41 namespace extensions {
     42 
     43 using api::activity_log_private::BlockedChromeActivityDetail;
     44 using api::activity_log_private::ChromeActivityDetail;
     45 using api::activity_log_private::DomActivityDetail;
     46 using api::activity_log_private::ExtensionActivity;
     47 
     48 Action::Action(const std::string& extension_id,
     49                const base::Time& time,
     50                const ActionType action_type,
     51                const std::string& api_name)
     52     : extension_id_(extension_id),
     53       time_(time),
     54       action_type_(action_type),
     55       api_name_(api_name),
     56       page_incognito_(false),
     57       arg_incognito_(false) {}
     58 
     59 Action::~Action() {}
     60 
     61 // TODO(mvrable): As an optimization, we might return this directly if the
     62 // refcount is one.  However, there are likely to be other stray references in
     63 // many cases that will prevent this optimization.
     64 scoped_refptr<Action> Action::Clone() const {
     65   scoped_refptr<Action> clone(
     66       new Action(extension_id(), time(), action_type(), api_name()));
     67   if (args())
     68     clone->set_args(make_scoped_ptr(args()->DeepCopy()));
     69   clone->set_page_url(page_url());
     70   clone->set_page_title(page_title());
     71   clone->set_page_incognito(page_incognito());
     72   clone->set_arg_url(arg_url());
     73   clone->set_arg_incognito(arg_incognito());
     74   if (other())
     75     clone->set_other(make_scoped_ptr(other()->DeepCopy()));
     76   return clone;
     77 }
     78 
     79 void Action::set_args(scoped_ptr<ListValue> args) {
     80   args_.reset(args.release());
     81 }
     82 
     83 ListValue* Action::mutable_args() {
     84   if (!args_.get()) {
     85     args_.reset(new ListValue());
     86   }
     87   return args_.get();
     88 }
     89 
     90 void Action::set_page_url(const GURL& page_url) {
     91   page_url_ = page_url;
     92 }
     93 
     94 void Action::set_arg_url(const GURL& arg_url) {
     95   arg_url_ = arg_url;
     96 }
     97 
     98 void Action::set_other(scoped_ptr<DictionaryValue> other) {
     99   other_.reset(other.release());
    100 }
    101 
    102 DictionaryValue* Action::mutable_other() {
    103   if (!other_.get()) {
    104     other_.reset(new DictionaryValue());
    105   }
    106   return other_.get();
    107 }
    108 
    109 std::string Action::SerializePageUrl() const {
    110   return (page_incognito() ? constants::kIncognitoUrl : "") + page_url().spec();
    111 }
    112 
    113 void Action::ParsePageUrl(const std::string& url) {
    114   set_page_incognito(StartsWithASCII(url, constants::kIncognitoUrl, true));
    115   if (page_incognito())
    116     set_page_url(GURL(url.substr(strlen(constants::kIncognitoUrl))));
    117   else
    118     set_page_url(GURL(url));
    119 }
    120 
    121 std::string Action::SerializeArgUrl() const {
    122   return (arg_incognito() ? constants::kIncognitoUrl : "") + arg_url().spec();
    123 }
    124 
    125 void Action::ParseArgUrl(const std::string& url) {
    126   set_arg_incognito(StartsWithASCII(url, constants::kIncognitoUrl, true));
    127   if (arg_incognito())
    128     set_arg_url(GURL(url.substr(strlen(constants::kIncognitoUrl))));
    129   else
    130     set_arg_url(GURL(url));
    131 }
    132 
    133 scoped_ptr<ExtensionActivity> Action::ConvertToExtensionActivity() {
    134   scoped_ptr<ExtensionActivity> result(new ExtensionActivity);
    135 
    136   result->extension_id.reset(new std::string(extension_id()));
    137   result->time.reset(new double(time().ToJsTime()));
    138 
    139   switch (action_type()) {
    140     case ACTION_API_CALL:
    141     case ACTION_API_EVENT: {
    142       ChromeActivityDetail* details = new ChromeActivityDetail;
    143       if (action_type() == ACTION_API_CALL) {
    144         details->api_activity_type =
    145             ChromeActivityDetail::API_ACTIVITY_TYPE_CALL;
    146       } else {
    147         details->api_activity_type =
    148             ChromeActivityDetail::API_ACTIVITY_TYPE_EVENT_CALLBACK;
    149       }
    150       details->api_call.reset(new std::string(api_name()));
    151       details->args.reset(new std::string(Serialize(args())));
    152       details->extra.reset(new std::string(Serialize(other())));
    153 
    154       result->activity_type = ExtensionActivity::ACTIVITY_TYPE_CHROME;
    155       result->chrome_activity_detail.reset(details);
    156       break;
    157     }
    158 
    159     case ACTION_API_BLOCKED: {
    160       BlockedChromeActivityDetail* details = new BlockedChromeActivityDetail;
    161       details->api_call.reset(new std::string(api_name()));
    162       details->args.reset(new std::string(Serialize(args())));
    163       details->extra.reset(new std::string(Serialize(other())));
    164       // TODO(mvrable): details->reason isn't filled in; fix this after
    165       // converting logging to using the types from
    166       // BlockedChromeActivityDetail::Reason.
    167       details->reason = BlockedChromeActivityDetail::REASON_NONE;
    168 
    169       result->activity_type = ExtensionActivity::ACTIVITY_TYPE_BLOCKED_CHROME;
    170       result->blocked_chrome_activity_detail.reset(details);
    171       break;
    172     }
    173 
    174     case ACTION_DOM_EVENT:
    175     case ACTION_DOM_ACCESS:
    176     case ACTION_CONTENT_SCRIPT:
    177     case ACTION_WEB_REQUEST: {
    178       DomActivityDetail* details = new DomActivityDetail;
    179 
    180       if (action_type() == ACTION_WEB_REQUEST) {
    181         details->dom_activity_type =
    182             DomActivityDetail::DOM_ACTIVITY_TYPE_WEBREQUEST;
    183       } else if (action_type() == ACTION_CONTENT_SCRIPT) {
    184         details->dom_activity_type =
    185             DomActivityDetail::DOM_ACTIVITY_TYPE_INSERTED;
    186       } else {
    187         // TODO(mvrable): This ought to be filled in properly, but since the
    188         // API will change soon don't worry about it now.
    189         details->dom_activity_type =
    190             DomActivityDetail::DOM_ACTIVITY_TYPE_NONE;
    191       }
    192       details->api_call.reset(new std::string(api_name()));
    193       details->args.reset(new std::string(Serialize(args())));
    194       details->extra.reset(new std::string(Serialize(other())));
    195       if (page_incognito()) {
    196         details->url.reset(new std::string(constants::kIncognitoUrl));
    197       } else {
    198         details->url.reset(new std::string(page_url().spec()));
    199         if (!page_title().empty())
    200           details->url_title.reset(new std::string(page_title()));
    201       }
    202 
    203       result->activity_type = ExtensionActivity::ACTIVITY_TYPE_DOM;
    204       result->dom_activity_detail.reset(details);
    205       break;
    206     }
    207 
    208     default:
    209       LOG(WARNING) << "Bad activity log entry read from database (type="
    210                    << action_type_ << ")!";
    211   }
    212 
    213   return result.Pass();
    214 }
    215 
    216 std::string Action::PrintForDebug() const {
    217   std::string result = "ID=" + extension_id() + " CATEGORY=";
    218   switch (action_type_) {
    219     case ACTION_API_CALL:
    220       result += "api_call";
    221       break;
    222     case ACTION_API_EVENT:
    223       result += "api_event_callback";
    224       break;
    225     case ACTION_WEB_REQUEST:
    226       result += "webrequest";
    227       break;
    228     case ACTION_CONTENT_SCRIPT:
    229       result += "content_script";
    230       break;
    231     case ACTION_API_BLOCKED:
    232       result += "api_blocked";
    233       break;
    234     case ACTION_DOM_EVENT:
    235       result += "dom_event";
    236       break;
    237     case ACTION_DOM_ACCESS:
    238       result += "dom_access";
    239       break;
    240     default:
    241       result += base::StringPrintf("type%d", static_cast<int>(action_type_));
    242   }
    243 
    244   result += " API=" + api_name_;
    245   if (args_.get()) {
    246     result += " ARGS=" + Serialize(args_.get());
    247   }
    248   if (page_url_.is_valid()) {
    249     if (page_incognito_)
    250       result += " PAGE_URL=(incognito)" + page_url_.spec();
    251     else
    252       result += " PAGE_URL=" + page_url_.spec();
    253   }
    254   if (!page_title_.empty()) {
    255     StringValue title(page_title_);
    256     result += " PAGE_TITLE=" + Serialize(&title);
    257   }
    258   if (arg_url_.is_valid()) {
    259     if (arg_incognito_)
    260       result += " ARG_URL=(incognito)" + arg_url_.spec();
    261     else
    262       result += " ARG_URL=" + arg_url_.spec();
    263   }
    264   if (other_.get()) {
    265     result += " OTHER=" + Serialize(other_.get());
    266   }
    267 
    268   return result;
    269 }
    270 
    271 }  // namespace extensions
    272