| OLD | NEW | 
|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "chrome/browser/extensions/activity_log/fullstream_ui_policy.h" | 5 #include "chrome/browser/extensions/activity_log/fullstream_ui_policy.h" | 
| 6 | 6 | 
| 7 #include "base/callback.h" | 7 #include "base/callback.h" | 
| 8 #include "base/command_line.h" | 8 #include "base/command_line.h" | 
| 9 #include "base/files/file_path.h" | 9 #include "base/files/file_path.h" | 
| 10 #include "base/json/json_reader.h" | 10 #include "base/json/json_reader.h" | 
| (...skipping 13 matching lines...) Expand all  Loading... | 
| 24 #include "url/gurl.h" | 24 #include "url/gurl.h" | 
| 25 | 25 | 
| 26 using base::Callback; | 26 using base::Callback; | 
| 27 using base::FilePath; | 27 using base::FilePath; | 
| 28 using base::Time; | 28 using base::Time; | 
| 29 using base::Unretained; | 29 using base::Unretained; | 
| 30 using content::BrowserThread; | 30 using content::BrowserThread; | 
| 31 | 31 | 
| 32 namespace constants = activity_log_constants; | 32 namespace constants = activity_log_constants; | 
| 33 | 33 | 
| 34 namespace { |  | 
| 35 |  | 
| 36 // Key strings for passing parameters to the ProcessAction member function. |  | 
| 37 const char kKeyReason[] =         "fsuip.reason"; |  | 
| 38 const char kKeyDomainAction[] =   "fsuip.domact"; |  | 
| 39 const char kKeyURLTitle[] =       "fsuip.urltitle"; |  | 
| 40 const char kKeyDetailsString[] =  "fsuip.details"; |  | 
| 41 |  | 
| 42 // Obsolete database tables: these should be dropped from the database if |  | 
| 43 // found. |  | 
| 44 const char* kObsoleteTables[] = {"activitylog_apis", "activitylog_blocked", |  | 
| 45                                  "activitylog_urls"}; |  | 
| 46 |  | 
| 47 std::string Serialize(const base::Value* value) { |  | 
| 48   std::string value_as_text; |  | 
| 49   if (!value) { |  | 
| 50     value_as_text = "null"; |  | 
| 51   } else { |  | 
| 52     JSONStringValueSerializer serializer(&value_as_text); |  | 
| 53     serializer.SerializeAndOmitBinaryValues(*value); |  | 
| 54   } |  | 
| 55   return value_as_text; |  | 
| 56 } |  | 
| 57 |  | 
| 58 }  // namespace |  | 
| 59 |  | 
| 60 namespace extensions { | 34 namespace extensions { | 
| 61 | 35 | 
| 62 const char* FullStreamUIPolicy::kTableName = "activitylog_full"; | 36 const char* FullStreamUIPolicy::kTableName = "activitylog_full"; | 
| 63 const char* FullStreamUIPolicy::kTableContentFields[] = { | 37 const char* FullStreamUIPolicy::kTableContentFields[] = { | 
| 64   "extension_id", "time", "action_type", "api_name", "args", "page_url", | 38   "extension_id", "time", "action_type", "api_name", "args", "page_url", | 
| 65   "page_title", "arg_url", "other" | 39   "page_title", "arg_url", "other" | 
| 66 }; | 40 }; | 
| 67 const char* FullStreamUIPolicy::kTableFieldTypes[] = { | 41 const char* FullStreamUIPolicy::kTableFieldTypes[] = { | 
| 68   "LONGVARCHAR NOT NULL", "INTEGER", "INTEGER", "LONGVARCHAR", "LONGVARCHAR", | 42   "LONGVARCHAR NOT NULL", "INTEGER", "INTEGER", "LONGVARCHAR", "LONGVARCHAR", | 
| 69   "LONGVARCHAR", "LONGVARCHAR", "LONGVARCHAR", "LONGVARCHAR" | 43   "LONGVARCHAR", "LONGVARCHAR", "LONGVARCHAR", "LONGVARCHAR" | 
| 70 }; | 44 }; | 
| 71 const int FullStreamUIPolicy::kTableFieldCount = arraysize(kTableContentFields); | 45 const int FullStreamUIPolicy::kTableFieldCount = | 
|  | 46     arraysize(FullStreamUIPolicy::kTableContentFields); | 
| 72 | 47 | 
| 73 FullStreamUIPolicy::FullStreamUIPolicy(Profile* profile) | 48 FullStreamUIPolicy::FullStreamUIPolicy(Profile* profile) | 
| 74     : ActivityLogDatabasePolicy( | 49     : ActivityLogDatabasePolicy( | 
| 75           profile, | 50           profile, | 
| 76           FilePath(chrome::kExtensionActivityLogFilename)) {} | 51           FilePath(chrome::kExtensionActivityLogFilename)) {} | 
| 77 | 52 | 
| 78 FullStreamUIPolicy::~FullStreamUIPolicy() {} | 53 FullStreamUIPolicy::~FullStreamUIPolicy() {} | 
| 79 | 54 | 
| 80 bool FullStreamUIPolicy::InitDatabase(sql::Connection* db) { | 55 bool FullStreamUIPolicy::InitDatabase(sql::Connection* db) { | 
| 81   // Drop old database tables. | 56   if (!Util::DropObsoleteTables(db)) | 
| 82   for (size_t i = 0; i < arraysize(kObsoleteTables); i++) { | 57     return false; | 
| 83     const char* table_name = kObsoleteTables[i]; |  | 
| 84     if (db->DoesTableExist(table_name)) { |  | 
| 85       std::string drop_statement = |  | 
| 86           base::StringPrintf("DROP TABLE %s", table_name); |  | 
| 87       if (!db->Execute(drop_statement.c_str())) { |  | 
| 88         return false; |  | 
| 89       } |  | 
| 90     } |  | 
| 91   } |  | 
| 92 | 58 | 
| 93   // Create the unified activity log entry table. | 59   // Create the unified activity log entry table. | 
| 94   return ActivityDatabase::InitializeTable(db, | 60   return ActivityDatabase::InitializeTable(db, | 
| 95                                            kTableName, | 61                                            kTableName, | 
| 96                                            kTableContentFields, | 62                                            kTableContentFields, | 
| 97                                            kTableFieldTypes, | 63                                            kTableFieldTypes, | 
| 98                                            arraysize(kTableContentFields)); | 64                                            arraysize(kTableContentFields)); | 
| 99 } | 65 } | 
| 100 | 66 | 
| 101 bool FullStreamUIPolicy::FlushDatabase(sql::Connection* db) { | 67 bool FullStreamUIPolicy::FlushDatabase(sql::Connection* db) { | 
| 102   if (queued_actions_.empty()) | 68   if (queued_actions_.empty()) | 
| 103     return true; | 69     return true; | 
| 104 | 70 | 
| 105   sql::Transaction transaction(db); | 71   sql::Transaction transaction(db); | 
| 106   if (!transaction.Begin()) | 72   if (!transaction.Begin()) | 
| 107     return false; | 73     return false; | 
| 108 | 74 | 
| 109   std::string sql_str = | 75   std::string sql_str = | 
| 110       "INSERT INTO " + std::string(FullStreamUIPolicy::kTableName) + | 76       "INSERT INTO " + std::string(FullStreamUIPolicy::kTableName) + | 
| 111       " (extension_id, time, action_type, api_name, args, " | 77       " (extension_id, time, action_type, api_name, args, " | 
| 112       "page_url, page_title, arg_url, other) VALUES (?,?,?,?,?,?,?,?,?)"; | 78       "page_url, page_title, arg_url, other) VALUES (?,?,?,?,?,?,?,?,?)"; | 
| 113   sql::Statement statement(db->GetCachedStatement( | 79   sql::Statement statement(db->GetCachedStatement( | 
| 114       sql::StatementID(SQL_FROM_HERE), sql_str.c_str())); | 80       sql::StatementID(SQL_FROM_HERE), sql_str.c_str())); | 
| 115 | 81 | 
| 116   url_canon::Replacements<char> url_sanitizer; |  | 
| 117   if (!CommandLine::ForCurrentProcess()->HasSwitch( |  | 
| 118           switches::kEnableExtensionActivityLogTesting)) { |  | 
| 119     url_sanitizer.ClearQuery(); |  | 
| 120     url_sanitizer.ClearRef(); |  | 
| 121   } |  | 
| 122 |  | 
| 123   Action::ActionVector::size_type i; | 82   Action::ActionVector::size_type i; | 
| 124   for (i = 0; i != queued_actions_.size(); ++i) { | 83   for (i = 0; i != queued_actions_.size(); ++i) { | 
| 125     const Action& action = *queued_actions_[i]; | 84     const Action& action = *queued_actions_[i]; | 
| 126     statement.Reset(true); | 85     statement.Reset(true); | 
| 127     statement.BindString(0, action.extension_id()); | 86     statement.BindString(0, action.extension_id()); | 
| 128     statement.BindInt64(1, action.time().ToInternalValue()); | 87     statement.BindInt64(1, action.time().ToInternalValue()); | 
| 129     statement.BindInt(2, static_cast<int>(action.action_type())); | 88     statement.BindInt(2, static_cast<int>(action.action_type())); | 
| 130     statement.BindString(3, action.api_name()); | 89     statement.BindString(3, action.api_name()); | 
| 131     if (action.args()) { | 90     if (action.args()) { | 
| 132       statement.BindString(4, Serialize(action.args())); | 91       statement.BindString(4, Util::Serialize(action.args())); | 
| 133     } | 92     } | 
| 134     if (action.page_url().is_valid()) { | 93     std::string page_url_string = action.SerializePageUrl(); | 
| 135       if (action.page_incognito()) { | 94     if (!page_url_string.empty()) { | 
| 136         statement.BindString(5, constants::kIncognitoUrl); | 95       statement.BindString(5, page_url_string); | 
| 137       } else { |  | 
| 138         statement.BindString( |  | 
| 139             5, action.page_url().ReplaceComponents(url_sanitizer).spec()); |  | 
| 140       } |  | 
| 141     } | 96     } | 
| 142     if (!action.page_title().empty() && !action.page_incognito()) { | 97     if (!action.page_title().empty()) { | 
| 143       statement.BindString(6, action.page_title()); | 98       statement.BindString(6, action.page_title()); | 
| 144     } | 99     } | 
| 145     if (action.arg_url().is_valid()) { | 100     std::string arg_url_string = action.SerializePageUrl(); | 
| 146       if (action.arg_incognito()) { | 101     if (!arg_url_string.empty()) { | 
| 147         statement.BindString(7, constants::kIncognitoUrl); | 102       statement.BindString(5, arg_url_string); | 
| 148       } else { |  | 
| 149         statement.BindString( |  | 
| 150             7, action.arg_url().ReplaceComponents(url_sanitizer).spec()); |  | 
| 151       } |  | 
| 152     } | 103     } | 
| 153     if (action.other()) { | 104     if (action.other()) { | 
| 154       statement.BindString(8, Serialize(action.other())); | 105       statement.BindString(8, Util::Serialize(action.other())); | 
| 155     } | 106     } | 
| 156 | 107 | 
| 157     if (!statement.Run()) { | 108     if (!statement.Run()) { | 
| 158       LOG(ERROR) << "Activity log database I/O failed: " << sql_str; | 109       LOG(ERROR) << "Activity log database I/O failed: " << sql_str; | 
| 159       return false; | 110       return false; | 
| 160     } | 111     } | 
| 161   } | 112   } | 
| 162 | 113 | 
| 163   if (!transaction.Commit()) | 114   if (!transaction.Commit()) | 
| 164     return false; | 115     return false; | 
| 165 | 116 | 
| 166   queued_actions_.clear(); | 117   queued_actions_.clear(); | 
| 167   return true; | 118   return true; | 
| 168 } | 119 } | 
| 169 | 120 | 
| 170 scoped_ptr<Action::ActionVector> FullStreamUIPolicy::DoReadData( | 121 scoped_ptr<Action::ActionVector> FullStreamUIPolicy::DoReadData( | 
| 171     const std::string& extension_id, | 122     const std::string& extension_id, | 
| 172     const int days_ago) { | 123     const int days_ago) { | 
|  | 124   // Ensure data is flushed to the database first so that we query over all | 
|  | 125   // data. | 
|  | 126   activity_database()->AdviseFlush(ActivityDatabase::kFlushImmediately); | 
|  | 127 | 
| 173   DCHECK_GE(days_ago, 0); | 128   DCHECK_GE(days_ago, 0); | 
| 174   scoped_ptr<Action::ActionVector> actions(new Action::ActionVector()); | 129   scoped_ptr<Action::ActionVector> actions(new Action::ActionVector()); | 
| 175 | 130 | 
| 176   sql::Connection* db = GetDatabaseConnection(); | 131   sql::Connection* db = GetDatabaseConnection(); | 
| 177   if (!db) { | 132   if (!db) { | 
| 178     return actions.Pass(); | 133     return actions.Pass(); | 
| 179   } | 134   } | 
| 180 | 135 | 
| 181   // Compute the time bounds for that day. | 136   int64 early_bound; | 
| 182   base::Time morning_midnight = Now().LocalMidnight(); | 137   int64 late_bound; | 
| 183   int64 early_bound = 0; | 138   Util::ComputeDatabaseTimeBounds(Now(), days_ago, &early_bound, &late_bound); | 
| 184   int64 late_bound = 0; |  | 
| 185   if (days_ago == 0) { |  | 
| 186       early_bound = morning_midnight.ToInternalValue(); |  | 
| 187       late_bound = base::Time::Max().ToInternalValue(); |  | 
| 188   } else { |  | 
| 189       base::Time early_time = morning_midnight - |  | 
| 190           base::TimeDelta::FromDays(days_ago); |  | 
| 191       base::Time late_time = morning_midnight - |  | 
| 192           base::TimeDelta::FromDays(days_ago-1); |  | 
| 193       early_bound = early_time.ToInternalValue(); |  | 
| 194       late_bound = late_time.ToInternalValue(); |  | 
| 195   } |  | 
| 196   std::string query_str = base::StringPrintf( | 139   std::string query_str = base::StringPrintf( | 
| 197       "SELECT time, action_type, api_name, args, page_url, page_title, " | 140       "SELECT time, action_type, api_name, args, page_url, page_title, " | 
| 198       "arg_url, other " | 141       "arg_url, other " | 
| 199       "FROM %s WHERE extension_id=? AND time>? AND time<=? " | 142       "FROM %s WHERE extension_id=? AND time>? AND time<=? " | 
| 200       "ORDER BY time DESC", | 143       "ORDER BY time DESC", | 
| 201       kTableName); | 144       kTableName); | 
| 202   sql::Statement query(db->GetCachedStatement(SQL_FROM_HERE, | 145   sql::Statement query(db->GetCachedStatement(SQL_FROM_HERE, | 
| 203                                               query_str.c_str())); | 146                                               query_str.c_str())); | 
| 204   query.BindString(0, extension_id); | 147   query.BindString(0, extension_id); | 
| 205   query.BindInt64(1, early_bound); | 148   query.BindInt64(1, early_bound); | 
| (...skipping 10 matching lines...) Expand all  Loading... | 
| 216           base::JSONReader::Read(query.ColumnString(3))); | 159           base::JSONReader::Read(query.ColumnString(3))); | 
| 217       if (parsed_value && parsed_value->IsType(Value::TYPE_LIST)) { | 160       if (parsed_value && parsed_value->IsType(Value::TYPE_LIST)) { | 
| 218         action->set_args( | 161         action->set_args( | 
| 219             make_scoped_ptr(static_cast<ListValue*>(parsed_value.release()))); | 162             make_scoped_ptr(static_cast<ListValue*>(parsed_value.release()))); | 
| 220       } else { | 163       } else { | 
| 221         LOG(WARNING) << "Unable to parse args: '" << query.ColumnString(3) | 164         LOG(WARNING) << "Unable to parse args: '" << query.ColumnString(3) | 
| 222                      << "'"; | 165                      << "'"; | 
| 223       } | 166       } | 
| 224     } | 167     } | 
| 225 | 168 | 
| 226     GURL page_url(query.ColumnString(4)); | 169     action->ParsePageUrl(query.ColumnString(4)); | 
| 227     action->set_page_url(page_url); |  | 
| 228 |  | 
| 229     action->set_page_title(query.ColumnString(5)); | 170     action->set_page_title(query.ColumnString(5)); | 
| 230 | 171     action->ParseArgUrl(query.ColumnString(6)); | 
| 231     GURL arg_url(query.ColumnString(6)); |  | 
| 232     action->set_arg_url(arg_url); |  | 
| 233 | 172 | 
| 234     if (query.ColumnType(7) != sql::COLUMN_TYPE_NULL) { | 173     if (query.ColumnType(7) != sql::COLUMN_TYPE_NULL) { | 
| 235       scoped_ptr<Value> parsed_value( | 174       scoped_ptr<Value> parsed_value( | 
| 236           base::JSONReader::Read(query.ColumnString(7))); | 175           base::JSONReader::Read(query.ColumnString(7))); | 
| 237       if (parsed_value && parsed_value->IsType(Value::TYPE_DICTIONARY)) { | 176       if (parsed_value && parsed_value->IsType(Value::TYPE_DICTIONARY)) { | 
| 238         action->set_other(make_scoped_ptr( | 177         action->set_other(make_scoped_ptr( | 
| 239             static_cast<DictionaryValue*>(parsed_value.release()))); | 178             static_cast<DictionaryValue*>(parsed_value.release()))); | 
| 240       } else { | 179       } else { | 
| 241         LOG(WARNING) << "Unable to parse other: '" << query.ColumnString(7) | 180         LOG(WARNING) << "Unable to parse other: '" << query.ColumnString(7) | 
| 242                      << "'"; | 181                      << "'"; | 
| (...skipping 27 matching lines...) Expand all  Loading... | 
| 270   BrowserThread::PostTaskAndReplyWithResult( | 209   BrowserThread::PostTaskAndReplyWithResult( | 
| 271       BrowserThread::DB, | 210       BrowserThread::DB, | 
| 272       FROM_HERE, | 211       FROM_HERE, | 
| 273       base::Bind(&FullStreamUIPolicy::DoReadData, | 212       base::Bind(&FullStreamUIPolicy::DoReadData, | 
| 274                  base::Unretained(this), | 213                  base::Unretained(this), | 
| 275                  extension_id, | 214                  extension_id, | 
| 276                  day), | 215                  day), | 
| 277       callback); | 216       callback); | 
| 278 } | 217 } | 
| 279 | 218 | 
| 280 std::string FullStreamUIPolicy::GetKey(ActivityLogPolicy::KeyType key_ty) const |  | 
| 281 { |  | 
| 282   switch (key_ty) { |  | 
| 283     case PARAM_KEY_REASON: |  | 
| 284       return std::string(kKeyReason); |  | 
| 285     case PARAM_KEY_DOM_ACTION: |  | 
| 286       return std::string(kKeyDomainAction); |  | 
| 287     case PARAM_KEY_URL_TITLE: |  | 
| 288       return std::string(kKeyURLTitle); |  | 
| 289     case PARAM_KEY_DETAILS_STRING: |  | 
| 290       return std::string(kKeyDetailsString); |  | 
| 291     default: |  | 
| 292       return std::string(); |  | 
| 293   } |  | 
| 294 } |  | 
| 295 |  | 
| 296 scoped_refptr<Action> FullStreamUIPolicy::ProcessArguments( | 219 scoped_refptr<Action> FullStreamUIPolicy::ProcessArguments( | 
| 297     scoped_refptr<Action> action) const { | 220     scoped_refptr<Action> action) const { | 
| 298   return action; | 221   return action; | 
| 299 } | 222 } | 
| 300 | 223 | 
| 301 void FullStreamUIPolicy::ProcessAction(scoped_refptr<Action> action) { | 224 void FullStreamUIPolicy::ProcessAction(scoped_refptr<Action> action) { | 
| 302   // TODO(mvrable): Right now this argument stripping updates the Action object | 225   // TODO(mvrable): Right now this argument stripping updates the Action object | 
| 303   // in place, which isn't good if there are other users of the object.  When | 226   // in place, which isn't good if there are other users of the object.  When | 
| 304   // database writing is moved to policy class, the modifications should be | 227   // database writing is moved to policy class, the modifications should be | 
| 305   // made locally. | 228   // made locally. | 
| 306   action = ProcessArguments(action); | 229   action = ProcessArguments(action); | 
| 307   ScheduleAndForget(this, &FullStreamUIPolicy::QueueAction, action); | 230   ScheduleAndForget(this, &FullStreamUIPolicy::QueueAction, action); | 
| 308 } | 231 } | 
| 309 | 232 | 
| 310 void FullStreamUIPolicy::QueueAction(scoped_refptr<Action> action) { | 233 void FullStreamUIPolicy::QueueAction(scoped_refptr<Action> action) { | 
| 311   if (activity_database()->is_db_valid()) { | 234   if (activity_database()->is_db_valid()) { | 
| 312     queued_actions_.push_back(action); | 235     queued_actions_.push_back(action); | 
| 313     activity_database()->NotifyAction(); | 236     activity_database()->AdviseFlush(queued_actions_.size()); | 
| 314   } | 237   } | 
| 315 } | 238 } | 
| 316 | 239 | 
| 317 }  // namespace extensions | 240 }  // namespace extensions | 
| OLD | NEW | 
|---|