Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(116)

Side by Side Diff: chrome/browser/extensions/activity_log/activity_log.cc

Issue 23545012: [Activity log] Rework extraction of URLs from argument lists (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Fixes Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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/activity_log.h" 5 #include "chrome/browser/extensions/activity_log/activity_log.h"
6 6
7 #include <set> 7 #include <set>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/command_line.h" 10 #include "base/command_line.h"
(...skipping 22 matching lines...) Expand all
33 #include "chrome/common/pref_names.h" 33 #include "chrome/common/pref_names.h"
34 #include "components/browser_context_keyed_service/browser_context_dependency_ma nager.h" 34 #include "components/browser_context_keyed_service/browser_context_dependency_ma nager.h"
35 #include "content/public/browser/web_contents.h" 35 #include "content/public/browser/web_contents.h"
36 #include "third_party/re2/re2/re2.h" 36 #include "third_party/re2/re2/re2.h"
37 #include "url/gurl.h" 37 #include "url/gurl.h"
38 38
39 namespace constants = activity_log_constants; 39 namespace constants = activity_log_constants;
40 40
41 namespace { 41 namespace {
42 42
43 // Concatenate arguments. 43 using extensions::Action;
44 std::string MakeArgList(const base::ListValue* args) { 44 using constants::kArgUrlPlaceholder;
45 std::string call_signature; 45
46 base::ListValue::const_iterator it = args->begin(); 46 // Information about specific Chrome and DOM APIs, such as which contain
47 for (; it != args->end(); ++it) { 47 // arguments that should be extracted into the arg_url field of an Action.
48 std::string arg; 48 struct ApiInfo {
49 JSONStringValueSerializer serializer(&arg); 49 // The lookup key consists of the action_type and api_name in the Action
50 if (serializer.SerializeAndOmitBinaryValues(**it)) { 50 // object.
51 if (it != args->begin()) 51 Action::ActionType action_type;
52 call_signature += ", "; 52 const char* api_name;
53 call_signature += arg; 53
54 // If non-negative, an index into args might contain a URL to be extracted
55 // into arg_url.
56 int arg_url_index;
57
58 // An optional transformation to apply to the data found at index
59 // arg_url_index in the argument list.
60 //
61 // If NULL, the data is expected to be a string which is treated as a URL.
62 //
63 // If the special value kArgUrlLookupTabId, the data is either an integer
64 // which is treated as a tab ID and translated (in the context of a provided
65 // Profile), or a list of tab IDs which are translated.
66 //
67 // Otherwise, the data is expected to be a dictionary, and arg_url_lookup is
68 // a path (list of keys delimited by ".") where a URL string is to be found.
69 const char* arg_url_lookup;
not at google - send to devlin 2013/09/06 17:36:15 this is kind of roundabout and looking at the code
mvrable 2013/09/06 21:27:42 That is a little more verbose but I don't mind cha
70 };
71
72 // Note: Comparisons against kArgUrlLookupTabId are done by address only; the
73 // contents of the string aren't relevant.
74 const char kArgUrlLookupTabId[] = "<lookupTabId>";
75
76 static const ApiInfo kApiInfoTable[] = {
77 // Tabs APIs that require tab ID translation
78 {Action::ACTION_API_CALL, "tabs.connect", 0, kArgUrlLookupTabId},
79 {Action::ACTION_API_CALL, "tabs.detectLanguage", 0, kArgUrlLookupTabId},
80 {Action::ACTION_API_CALL, "tabs.duplicate", 0, kArgUrlLookupTabId},
81 {Action::ACTION_API_CALL, "tabs.executeScript", 0, kArgUrlLookupTabId},
82 {Action::ACTION_API_CALL, "tabs.get", 0, kArgUrlLookupTabId},
83 {Action::ACTION_API_CALL, "tabs.insertCSS", 0, kArgUrlLookupTabId},
84 {Action::ACTION_API_CALL, "tabs.move", 0, kArgUrlLookupTabId},
85 {Action::ACTION_API_CALL, "tabs.reload", 0, kArgUrlLookupTabId},
86 {Action::ACTION_API_CALL, "tabs.remove", 0, kArgUrlLookupTabId},
87 {Action::ACTION_API_CALL, "tabs.sendMessage", 0, kArgUrlLookupTabId},
88 {Action::ACTION_API_CALL, "tabs.update", 0, kArgUrlLookupTabId},
89
90 {Action::ACTION_API_EVENT, "tabs.onUpdated", 0, kArgUrlLookupTabId},
91 {Action::ACTION_API_EVENT, "tabs.onMoved", 0, kArgUrlLookupTabId},
92 {Action::ACTION_API_EVENT, "tabs.onDetached", 0, kArgUrlLookupTabId},
93 {Action::ACTION_API_EVENT, "tabs.onAttached", 0, kArgUrlLookupTabId},
94 {Action::ACTION_API_EVENT, "tabs.onRemoved", 0, kArgUrlLookupTabId},
95 {Action::ACTION_API_EVENT, "tabs.onReplaced", 0, kArgUrlLookupTabId},
96
97 // Other APIs that accept URLs as strings
98 {Action::ACTION_API_CALL, "windows.create", 0, "url"},
not at google - send to devlin 2013/09/06 17:36:15 Generally speaking - and this would be a much larg
mvrable 2013/09/06 21:27:42 Agreed, it would be much more sustainable if we ha
not at google - send to devlin 2013/09/06 22:05:05 Totally fine to have this for now. It would be nic
99
100 {Action::ACTION_DOM_ACCESS, "Location.assign", 0, NULL},
101 {Action::ACTION_DOM_ACCESS, "Location.replace", 0, NULL},
102 {Action::ACTION_DOM_ACCESS, "XMLHttpRequest.open", 1, NULL},
103 };
104
105 // A singleton class which provides lookups into the kApiInfoTable data
106 // structure. It inserts all data into a map on first lookup.
107 class ApiInfoDatabase {
108 public:
109 static ApiInfoDatabase* GetInstance() {
110 return Singleton<ApiInfoDatabase>::get();
111 }
112
113 // Retrieves an ApiInfo record for the given Action type. Returns either a
114 // pointer to the record, or NULL if no such record was found.
115 const ApiInfo* Lookup(Action::ActionType action_type,
116 const std::string& api_name) const {
117 std::map<std::string, const ApiInfo*>::const_iterator i =
118 api_database_.find(api_name);
119 if (i == api_database_.end())
120 return NULL;
121 if (i->second->action_type != action_type)
not at google - send to devlin 2013/09/06 17:36:15 Can this ever be false? I think the comment on ap
mvrable 2013/09/06 21:27:42 Yes, this could potentially be false since we coul
122 return NULL;
123 return i->second;
124 }
125
126 private:
127 ApiInfoDatabase() {
128 for (size_t i = 0; i < arraysize(kApiInfoTable); i++) {
129 const ApiInfo* info = &kApiInfoTable[i];
130 api_database_[info->api_name] = info;
54 } 131 }
55 } 132 }
56 return call_signature; 133 virtual ~ApiInfoDatabase() {}
57 }
58 134
59 // Gets the URL for a given tab ID. Helper method for LookupTabId. Returns 135 // The map is keyed by API name only, since API names aren't be repeated
136 // across multiple action types in kApiInfoTable. However, the action type
137 // should still be checked before returning a positive match.
138 std::map<std::string, const ApiInfo*> api_database_;
139
140 friend struct DefaultSingletonTraits<ApiInfoDatabase>;
141 DISALLOW_COPY_AND_ASSIGN(ApiInfoDatabase);
142 };
143
144 // Gets the URL for a given tab ID. Helper method for ExtractUrls. Returns
60 // true if able to perform the lookup. The URL is stored to *url, and 145 // true if able to perform the lookup. The URL is stored to *url, and
61 // *is_incognito is set to indicate whether the URL is for an incognito tab. 146 // *is_incognito is set to indicate whether the URL is for an incognito tab.
62 bool GetUrlForTabId(int tab_id, 147 bool GetUrlForTabId(int tab_id,
63 Profile* profile, 148 Profile* profile,
64 GURL* url, 149 GURL* url,
65 bool* is_incognito) { 150 bool* is_incognito) {
66 content::WebContents* contents = NULL; 151 content::WebContents* contents = NULL;
67 Browser* browser = NULL; 152 Browser* browser = NULL;
68 bool found = ExtensionTabUtil::GetTabById(tab_id, 153 bool found = ExtensionTabUtil::GetTabById(tab_id,
69 profile, 154 profile,
70 true, // search incognito tabs too 155 true, // search incognito tabs too
71 &browser, 156 &browser,
72 NULL, 157 NULL,
73 &contents, 158 &contents,
74 NULL); 159 NULL);
75 if (found) { 160 if (found) {
76 *url = contents->GetURL(); 161 *url = contents->GetURL();
77 *is_incognito = browser->profile()->IsOffTheRecord(); 162 *is_incognito = browser->profile()->IsOffTheRecord();
78 return true; 163 return true;
79 } else { 164 } else {
80 return false; 165 return false;
81 } 166 }
82 } 167 }
83 168
84 // Translate tab IDs to URLs in tabs API calls. Mutates the Action object in 169 // Performs processing of the Action object to extract URLs from the argument
85 // place. There is a small chance that the URL translation could be wrong, if 170 // list and translate tab IDs to URLs, according to the API call metadata in
86 // the tab has already been navigated by the time of invocation. 171 // kApiInfoTable. Mutates the Action object in place. There is a small chance
172 // that the tab id->URL translation could be wrong, if the tab has already been
173 // navigated by the time of invocation.
87 // 174 //
88 // If a single tab ID is translated to a URL, the URL is stored into arg_url 175 // Any extracted URL is stored into the arg_url field of the action, and the
89 // where it can more easily be searched for in the database. For APIs that 176 // URL in the argument list is replaced with the marker value "<arg_url>". For
90 // take a list of tab IDs, replace each tab ID with the URL in the argument 177 // APIs that take a list of tab IDs, extracts the first valid URL into arg_url
91 // list; we can only extract a single URL into arg_url so arbitrarily pull out 178 // and overwrites the other tab IDs in the argument list with the translated
92 // the first one. 179 // URL.
93 void LookupTabIds(scoped_refptr<extensions::Action> action, Profile* profile) { 180 void ExtractUrls(scoped_refptr<Action> action, Profile* profile) {
94 const std::string& api_call = action->api_name(); 181 const ApiInfo* api_info = ApiInfoDatabase::GetInstance()->Lookup(
95 if (api_call == "tabs.get" || // api calls, ID as int 182 action->action_type(), action->api_name());
96 api_call == "tabs.connect" || 183 if (api_info == NULL)
97 api_call == "tabs.sendMessage" || 184 return;
98 api_call == "tabs.duplicate" || 185
99 api_call == "tabs.update" || 186 int url_index = api_info->arg_url_index;
100 api_call == "tabs.reload" || 187
101 api_call == "tabs.detectLanguage" || 188 if (!action->args() || url_index < 0 ||
102 api_call == "tabs.executeScript" || 189 static_cast<size_t>(url_index) >= action->args()->GetSize())
103 api_call == "tabs.insertCSS" || 190 return;
104 api_call == "tabs.move" || // api calls, IDs in array 191
105 api_call == "tabs.remove" || 192 // Do not overwrite an existing arg_url value in the Action, so that callers
106 api_call == "tabs.onUpdated" || // events, ID as int 193 // have the option of doing custom arg_url extraction.
107 api_call == "tabs.onMoved" || 194 if (action->arg_url().is_valid())
108 api_call == "tabs.onDetached" || 195 return;
109 api_call == "tabs.onAttached" || 196
110 api_call == "tabs.onRemoved" || 197 GURL arg_url;
111 api_call == "tabs.onReplaced") { 198 bool arg_incognito = action->page_incognito();
199
200 if (api_info->arg_url_lookup == kArgUrlLookupTabId) {
201 // Translation of tab IDs to URLs has been requested. There are two cases
202 // to consider: either a single integer or a list of integers (when
203 // multiple tabs are manipulated).
112 int tab_id; 204 int tab_id;
113 base::ListValue* id_list; 205 base::ListValue* tab_list;
not at google - send to devlin 2013/09/06 17:36:15 = NULL
mvrable 2013/09/06 21:27:42 Done.
114 base::ListValue* args = action->mutable_args(); 206 if (action->args()->GetInteger(url_index, &tab_id)) {
115 if (args->GetInteger(0, &tab_id)) {
116 // Single tab ID to translate. 207 // Single tab ID to translate.
117 GURL url; 208 GetUrlForTabId(tab_id, profile, &arg_url, &arg_incognito);
118 bool is_incognito; 209 if (arg_url.is_valid()) {
119 if (GetUrlForTabId(tab_id, profile, &url, &is_incognito)) { 210 action->mutable_args()->Set(url_index,
120 action->set_arg_url(url); 211 new StringValue(kArgUrlPlaceholder));
121 action->set_arg_incognito(is_incognito);
122 } 212 }
123 } else if ((api_call == "tabs.move" || api_call == "tabs.remove") && 213 } else if (action->mutable_args()->GetList(url_index, &tab_list)) {
124 args->GetList(0, &id_list)) { 214 // A list of possible IDs to translate. Work through in reverse order
125 // Array of tab IDs to translate. 215 // so the last one translated is left in arg_url.
126 for (int i = 0; i < static_cast<int>(id_list->GetSize()); ++i) { 216 int extracted_index = -1; // Which item in the list is stored to arg_url?
127 if (id_list->GetInteger(i, &tab_id)) { 217 for (int i = tab_list->GetSize(); i >= 0; i--) {
not at google - send to devlin 2013/09/06 17:36:15 --i not i--. and shouldn't this be tab_list->GetS
mvrable 2013/09/06 21:27:42 Done.
128 GURL url; 218 if (tab_list->GetInteger(i, &tab_id) &&
129 bool is_incognito; 219 GetUrlForTabId(tab_id, profile, &arg_url, &arg_incognito)) {
130 if (GetUrlForTabId(tab_id, profile, &url, &is_incognito) && 220 if (!arg_incognito)
131 !is_incognito) { 221 tab_list->Set(i, new base::StringValue(arg_url.spec()));
132 id_list->Set(i, new base::StringValue(url.spec())); 222 extracted_index = i;
133 if (i == 0) {
134 action->set_arg_url(url);
135 action->set_arg_incognito(is_incognito);
136 }
137 }
138 } else {
139 LOG(ERROR) << "The tab ID array is malformed at index " << i;
140 } 223 }
141 } 224 }
225 if (extracted_index >= 0)
226 tab_list->Set(extracted_index, new StringValue(kArgUrlPlaceholder));
142 } 227 }
228 } else {
229 // No translation needed; just extract the URL directly from a raw string
230 // or from a dictionary.
231 DictionaryValue* dict;
not at google - send to devlin 2013/09/06 17:36:15 = NULL
mvrable 2013/09/06 21:27:42 Done.
232 std::string url_string;
233
234 if (api_info->arg_url_lookup) {
235 if (action->mutable_args()->GetDictionary(url_index, &dict) &&
236 dict->GetString(api_info->arg_url_lookup, &url_string)) {
237 arg_url = GURL(url_string);
238 if (arg_url.is_valid())
239 dict->SetString(api_info->arg_url_lookup, kArgUrlPlaceholder);
240 }
241 } else if (action->args()->GetString(url_index, &url_string)) {
242 arg_url = GURL(url_string);
243 if (arg_url.is_valid()) {
244 action->mutable_args()->Set(url_index,
245 new StringValue(kArgUrlPlaceholder));
246 }
247 }
248 }
249
250 if (arg_url.is_valid()) {
251 action->set_arg_incognito(arg_incognito);
252 action->set_arg_url(arg_url);
143 } 253 }
144 } 254 }
145 255
146 } // namespace 256 } // namespace
147 257
148 namespace extensions { 258 namespace extensions {
149 259
150 // ActivityLogFactory 260 // ActivityLogFactory
151 261
152 ActivityLogFactory* ActivityLogFactory::GetInstance() { 262 ActivityLogFactory* ActivityLogFactory::GetInstance() {
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 } 445 }
336 446
337 // LOG ACTIONS. ---------------------------------------------------------------- 447 // LOG ACTIONS. ----------------------------------------------------------------
338 448
339 void ActivityLog::LogAction(scoped_refptr<Action> action) { 449 void ActivityLog::LogAction(scoped_refptr<Action> action) {
340 if (ActivityLogAPI::IsExtensionWhitelisted(action->extension_id())) 450 if (ActivityLogAPI::IsExtensionWhitelisted(action->extension_id()))
341 return; 451 return;
342 452
343 // Perform some preprocessing of the Action data: convert tab IDs to URLs and 453 // Perform some preprocessing of the Action data: convert tab IDs to URLs and
344 // mask out incognito URLs if appropriate. 454 // mask out incognito URLs if appropriate.
345 if ((action->action_type() == Action::ACTION_API_CALL || 455 ExtractUrls(action, profile_);
346 action->action_type() == Action::ACTION_API_EVENT) &&
347 StartsWithASCII(action->api_name(), "tabs.", true)) {
348 LookupTabIds(action, profile_);
349 }
350 456
351 if (IsDatabaseEnabled() && policy_) 457 if (IsDatabaseEnabled() && policy_)
352 policy_->ProcessAction(action); 458 policy_->ProcessAction(action);
353 if (IsWatchdogAppActive()) 459 if (IsWatchdogAppActive())
354 observers_->Notify(&Observer::OnExtensionActivity, action); 460 observers_->Notify(&Observer::OnExtensionActivity, action);
355 if (testing_mode_) 461 if (testing_mode_)
356 LOG(INFO) << action->PrintForDebug(); 462 LOG(INFO) << action->PrintForDebug();
357 } 463 }
358 464
359 void ActivityLog::OnScriptsExecuted( 465 void ActivityLog::OnScriptsExecuted(
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
450 556
451 void ActivityLog::RemoveURL(const GURL& url) { 557 void ActivityLog::RemoveURL(const GURL& url) {
452 if (url.is_empty()) 558 if (url.is_empty())
453 return; 559 return;
454 std::vector<GURL> urls; 560 std::vector<GURL> urls;
455 urls.push_back(url); 561 urls.push_back(url);
456 RemoveURLs(urls); 562 RemoveURLs(urls);
457 } 563 }
458 564
459 } // namespace extensions 565 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698