OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/extension_function_dispatcher.h" | 5 #include "chrome/browser/extensions/extension_function_dispatcher.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 | 8 |
9 #include "base/bind.h" | |
10 #include "base/json/json_string_value_serializer.h" | 9 #include "base/json/json_string_value_serializer.h" |
11 #include "base/lazy_instance.h" | 10 #include "base/lazy_instance.h" |
12 #include "base/memory/ref_counted.h" | 11 #include "base/memory/ref_counted.h" |
13 #include "base/process_util.h" | 12 #include "base/process_util.h" |
14 #include "base/values.h" | 13 #include "base/values.h" |
15 #include "build/build_config.h" | 14 #include "build/build_config.h" |
16 #include "chrome/browser/extensions/activity_log.h" | 15 #include "chrome/browser/extensions/activity_log.h" |
17 #include "chrome/browser/extensions/extension_function.h" | 16 #include "chrome/browser/extensions/extension_function.h" |
18 #include "chrome/browser/extensions/extension_function_registry.h" | 17 #include "chrome/browser/extensions/extension_function_registry.h" |
19 #include "chrome/browser/extensions/extension_service.h" | 18 #include "chrome/browser/extensions/extension_service.h" |
20 #include "chrome/browser/extensions/extension_system.h" | 19 #include "chrome/browser/extensions/extension_system.h" |
21 #include "chrome/browser/extensions/extension_web_ui.h" | 20 #include "chrome/browser/extensions/extension_web_ui.h" |
22 #include "chrome/browser/extensions/extensions_quota_service.h" | 21 #include "chrome/browser/extensions/extensions_quota_service.h" |
23 #include "chrome/browser/extensions/process_map.h" | 22 #include "chrome/browser/extensions/process_map.h" |
24 #include "chrome/browser/external_protocol/external_protocol_handler.h" | 23 #include "chrome/browser/external_protocol/external_protocol_handler.h" |
25 #include "chrome/browser/profiles/profile.h" | 24 #include "chrome/browser/profiles/profile.h" |
26 #include "chrome/browser/renderer_host/chrome_render_message_filter.h" | 25 #include "chrome/browser/renderer_host/chrome_render_message_filter.h" |
27 #include "chrome/common/extensions/api/extension_api.h" | 26 #include "chrome/common/extensions/api/extension_api.h" |
28 #include "chrome/common/extensions/extension_messages.h" | 27 #include "chrome/common/extensions/extension_messages.h" |
29 #include "chrome/common/extensions/extension_set.h" | 28 #include "chrome/common/extensions/extension_set.h" |
30 #include "chrome/common/url_constants.h" | 29 #include "chrome/common/url_constants.h" |
31 #include "content/public/browser/browser_thread.h" | |
32 #include "content/public/browser/render_process_host.h" | 30 #include "content/public/browser/render_process_host.h" |
33 #include "content/public/browser/render_view_host.h" | 31 #include "content/public/browser/render_view_host.h" |
34 #include "ipc/ipc_message.h" | 32 #include "ipc/ipc_message.h" |
35 #include "ipc/ipc_message_macros.h" | 33 #include "ipc/ipc_message_macros.h" |
36 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h" | 34 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h" |
37 #include "webkit/glue/resource_type.h" | 35 #include "webkit/glue/resource_type.h" |
38 | 36 |
39 using extensions::Extension; | 37 using extensions::Extension; |
40 using extensions::ExtensionAPI; | 38 using extensions::ExtensionAPI; |
41 using content::RenderViewHost; | 39 using content::RenderViewHost; |
42 using WebKit::WebSecurityOrigin; | 40 using WebKit::WebSecurityOrigin; |
43 | 41 |
44 namespace { | 42 namespace { |
45 | 43 |
46 const char kAccessDenied[] = "access denied"; | 44 const char kAccessDenied[] = "access denied"; |
47 const char kQuotaExceeded[] = "quota exceeded"; | 45 const char kQuotaExceeded[] = "quota exceeded"; |
48 | 46 |
49 void LogSuccess(const Extension* extension, | 47 void LogSuccess(const Extension* extension, |
50 const std::string& api_name, | 48 const ExtensionHostMsg_Request_Params& params) { |
51 scoped_ptr<ListValue> args, | 49 extensions::ActivityLog* activity_log = |
52 Profile* profile) { | 50 extensions::ActivityLog::GetInstance(); |
53 // The ActivityLog can only be accessed from the main (UI) thread. If we're | 51 if (activity_log->HasObservers(extension)) { |
54 // running on the wrong thread, re-dispatch from the main thread. | 52 std::string call_signature = params.name + "("; |
55 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | 53 ListValue::const_iterator it = params.arguments.begin(); |
56 BrowserThread::PostTask(BrowserThread::UI, | 54 for (; it != params.arguments.end(); ++it) { |
57 FROM_HERE, | 55 std::string arg; |
58 base::Bind(&LogSuccess, | 56 JSONStringValueSerializer serializer(&arg); |
59 extension, | 57 if (serializer.SerializeAndOmitBinaryValues(**it)) { |
60 api_name, | 58 if (it != params.arguments.begin()) |
61 Passed(args.Pass()), | 59 call_signature += ", "; |
62 profile)); | 60 call_signature += arg; |
63 } else { | 61 } |
64 extensions::ActivityLog* activity_log = | 62 } |
65 extensions::ActivityLog::GetInstance(profile); | 63 call_signature += ")"; |
66 if (activity_log->HasObservers(extension)) | 64 |
67 activity_log->LogAPIAction(extension, api_name, args.get(), ""); | 65 activity_log->Log(extension, |
| 66 extensions::ActivityLog::ACTIVITY_EXTENSION_API_CALL, |
| 67 call_signature); |
68 } | 68 } |
69 } | 69 } |
70 | 70 |
71 void LogFailure(const Extension* extension, | 71 void LogFailure(const Extension* extension, |
72 const std::string& api_name, | 72 const std::string& func_name, |
73 scoped_ptr<ListValue> args, | 73 const char* reason) { |
74 const char* reason, | 74 extensions::ActivityLog* activity_log = |
75 Profile* profile) { | 75 extensions::ActivityLog::GetInstance(); |
76 // The ActivityLog can only be accessed from the main (UI) thread. If we're | 76 if (activity_log->HasObservers(extension)) { |
77 // running on the wrong thread, re-dispatch from the main thread. | 77 activity_log->Log(extension, |
78 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | 78 extensions::ActivityLog::ACTIVITY_EXTENSION_API_BLOCK, |
79 BrowserThread::PostTask(BrowserThread::UI, | 79 func_name + ": " + reason); |
80 FROM_HERE, | |
81 base::Bind(&LogFailure, | |
82 extension, | |
83 api_name, | |
84 Passed(args.Pass()), | |
85 reason, | |
86 profile)); | |
87 } else { | |
88 extensions::ActivityLog* activity_log = | |
89 extensions::ActivityLog::GetInstance(profile); | |
90 if (activity_log->HasObservers(extension)) | |
91 activity_log->LogBlockedAction(extension, | |
92 api_name, | |
93 args.get(), | |
94 reason, | |
95 ""); | |
96 } | 80 } |
97 } | 81 } |
98 | 82 |
99 | |
100 // Separate copy of ExtensionAPI used for IO thread extension functions. We need | 83 // Separate copy of ExtensionAPI used for IO thread extension functions. We need |
101 // this because ExtensionAPI has mutable data. It should be possible to remove | 84 // this because ExtensionAPI has mutable data. It should be possible to remove |
102 // this once all the extension APIs are updated to the feature system. | 85 // this once all the extension APIs are updated to the feature system. |
103 struct Static { | 86 struct Static { |
104 Static() | 87 Static() |
105 : api(extensions::ExtensionAPI::CreateWithDefaultConfiguration()) { | 88 : api(extensions::ExtensionAPI::CreateWithDefaultConfiguration()) { |
106 } | 89 } |
107 scoped_ptr<extensions::ExtensionAPI> api; | 90 scoped_ptr<extensions::ExtensionAPI> api; |
108 }; | 91 }; |
109 base::LazyInstance<Static> g_global_io_data = LAZY_INSTANCE_INITIALIZER; | 92 base::LazyInstance<Static> g_global_io_data = LAZY_INSTANCE_INITIALIZER; |
(...skipping 29 matching lines...) Expand all Loading... |
139 // static | 122 // static |
140 void ExtensionFunctionDispatcher::DispatchOnIOThread( | 123 void ExtensionFunctionDispatcher::DispatchOnIOThread( |
141 ExtensionInfoMap* extension_info_map, | 124 ExtensionInfoMap* extension_info_map, |
142 void* profile, | 125 void* profile, |
143 int render_process_id, | 126 int render_process_id, |
144 base::WeakPtr<ChromeRenderMessageFilter> ipc_sender, | 127 base::WeakPtr<ChromeRenderMessageFilter> ipc_sender, |
145 int routing_id, | 128 int routing_id, |
146 const ExtensionHostMsg_Request_Params& params) { | 129 const ExtensionHostMsg_Request_Params& params) { |
147 const Extension* extension = | 130 const Extension* extension = |
148 extension_info_map->extensions().GetByID(params.extension_id); | 131 extension_info_map->extensions().GetByID(params.extension_id); |
149 Profile* profile_cast = static_cast<Profile*>(profile); | 132 |
150 scoped_refptr<ExtensionFunction> function( | 133 scoped_refptr<ExtensionFunction> function( |
151 CreateExtensionFunction(params, extension, render_process_id, | 134 CreateExtensionFunction(params, extension, render_process_id, |
152 extension_info_map->process_map(), | 135 extension_info_map->process_map(), |
153 g_global_io_data.Get().api.get(), | 136 g_global_io_data.Get().api.get(), |
154 profile, | 137 profile, |
155 ipc_sender, NULL, routing_id)); | 138 ipc_sender, NULL, routing_id)); |
156 scoped_ptr<ListValue> args(params.arguments.DeepCopy()); | |
157 | |
158 if (!function) { | 139 if (!function) { |
159 LogFailure(extension, | 140 LogFailure(extension, params.name, kAccessDenied); |
160 params.name, | |
161 args.Pass(), | |
162 kAccessDenied, | |
163 profile_cast); | |
164 return; | 141 return; |
165 } | 142 } |
166 | 143 |
167 IOThreadExtensionFunction* function_io = | 144 IOThreadExtensionFunction* function_io = |
168 function->AsIOThreadExtensionFunction(); | 145 function->AsIOThreadExtensionFunction(); |
169 if (!function_io) { | 146 if (!function_io) { |
170 NOTREACHED(); | 147 NOTREACHED(); |
171 return; | 148 return; |
172 } | 149 } |
173 function_io->set_ipc_sender(ipc_sender, routing_id); | 150 function_io->set_ipc_sender(ipc_sender, routing_id); |
174 function_io->set_extension_info_map(extension_info_map); | 151 function_io->set_extension_info_map(extension_info_map); |
175 function->set_include_incognito( | 152 function->set_include_incognito( |
176 extension_info_map->IsIncognitoEnabled(extension->id())); | 153 extension_info_map->IsIncognitoEnabled(extension->id())); |
177 | 154 |
178 if (!CheckPermissions(function, extension, params, ipc_sender, routing_id)) { | 155 if (!CheckPermissions(function, extension, params, ipc_sender, routing_id)) { |
179 LogFailure(extension, | 156 LogFailure(extension, params.name, kAccessDenied); |
180 params.name, | |
181 args.Pass(), | |
182 kAccessDenied, | |
183 profile_cast); | |
184 return; | 157 return; |
185 } | 158 } |
186 | 159 |
187 ExtensionsQuotaService* quota = extension_info_map->GetQuotaService(); | 160 ExtensionsQuotaService* quota = extension_info_map->GetQuotaService(); |
188 std::string violation_error = quota->Assess(extension->id(), | 161 std::string violation_error = quota->Assess(extension->id(), |
189 function, | 162 function, |
190 ¶ms.arguments, | 163 ¶ms.arguments, |
191 base::TimeTicks::Now()); | 164 base::TimeTicks::Now()); |
192 if (violation_error.empty()) { | 165 if (violation_error.empty()) { |
193 LogSuccess(extension, | |
194 params.name, | |
195 args.Pass(), | |
196 profile_cast); | |
197 function->Run(); | 166 function->Run(); |
| 167 LogSuccess(extension, params); |
198 } else { | 168 } else { |
199 LogFailure(extension, | |
200 params.name, | |
201 args.Pass(), | |
202 kQuotaExceeded, | |
203 profile_cast); | |
204 function->OnQuotaExceeded(violation_error); | 169 function->OnQuotaExceeded(violation_error); |
| 170 LogFailure(extension, params.name, kQuotaExceeded); |
205 } | 171 } |
206 } | 172 } |
207 | 173 |
208 ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(Profile* profile, | 174 ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(Profile* profile, |
209 Delegate* delegate) | 175 Delegate* delegate) |
210 : profile_(profile), | 176 : profile_(profile), |
211 delegate_(delegate) { | 177 delegate_(delegate) { |
212 } | 178 } |
213 | 179 |
214 ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() { | 180 ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() { |
(...skipping 16 matching lines...) Expand all Loading... |
231 WebSecurityOrigin::createFromString(params.source_origin), | 197 WebSecurityOrigin::createFromString(params.source_origin), |
232 params.source_url)); | 198 params.source_url)); |
233 | 199 |
234 scoped_refptr<ExtensionFunction> function( | 200 scoped_refptr<ExtensionFunction> function( |
235 CreateExtensionFunction(params, extension, | 201 CreateExtensionFunction(params, extension, |
236 render_view_host->GetProcess()->GetID(), | 202 render_view_host->GetProcess()->GetID(), |
237 *(service->process_map()), | 203 *(service->process_map()), |
238 extensions::ExtensionAPI::GetSharedInstance(), | 204 extensions::ExtensionAPI::GetSharedInstance(), |
239 profile(), render_view_host, render_view_host, | 205 profile(), render_view_host, render_view_host, |
240 render_view_host->GetRoutingID())); | 206 render_view_host->GetRoutingID())); |
241 scoped_ptr<ListValue> args(params.arguments.DeepCopy()); | |
242 | |
243 if (!function) { | 207 if (!function) { |
244 LogFailure(extension, | 208 LogFailure(extension, params.name, kAccessDenied); |
245 params.name, | |
246 args.Pass(), | |
247 kAccessDenied, | |
248 profile()); | |
249 return; | 209 return; |
250 } | 210 } |
251 | 211 |
252 UIThreadExtensionFunction* function_ui = | 212 UIThreadExtensionFunction* function_ui = |
253 function->AsUIThreadExtensionFunction(); | 213 function->AsUIThreadExtensionFunction(); |
254 if (!function_ui) { | 214 if (!function_ui) { |
255 NOTREACHED(); | 215 NOTREACHED(); |
256 return; | 216 return; |
257 } | 217 } |
258 function_ui->set_dispatcher(AsWeakPtr()); | 218 function_ui->set_dispatcher(AsWeakPtr()); |
259 function_ui->set_profile(profile_); | 219 function_ui->set_profile(profile_); |
260 function->set_include_incognito(service->CanCrossIncognito(extension)); | 220 function->set_include_incognito(service->CanCrossIncognito(extension)); |
261 | 221 |
262 if (!CheckPermissions(function, extension, params, render_view_host, | 222 if (!CheckPermissions(function, extension, params, render_view_host, |
263 render_view_host->GetRoutingID())) { | 223 render_view_host->GetRoutingID())) { |
264 LogFailure(extension, | 224 LogFailure(extension, params.name, kAccessDenied); |
265 params.name, | |
266 args.Pass(), | |
267 kAccessDenied, | |
268 profile()); | |
269 return; | 225 return; |
270 } | 226 } |
271 | 227 |
272 ExtensionsQuotaService* quota = service->quota_service(); | 228 ExtensionsQuotaService* quota = service->quota_service(); |
273 std::string violation_error = quota->Assess(extension->id(), | 229 std::string violation_error = quota->Assess(extension->id(), |
274 function, | 230 function, |
275 ¶ms.arguments, | 231 ¶ms.arguments, |
276 base::TimeTicks::Now()); | 232 base::TimeTicks::Now()); |
277 if (violation_error.empty()) { | 233 if (violation_error.empty()) { |
278 // See crbug.com/39178. | 234 // See crbug.com/39178. |
279 ExternalProtocolHandler::PermitLaunchUrl(); | 235 ExternalProtocolHandler::PermitLaunchUrl(); |
280 LogSuccess(extension, params.name, args.Pass(), profile()); | 236 |
281 function->Run(); | 237 function->Run(); |
| 238 LogSuccess(extension, params); |
282 } else { | 239 } else { |
283 LogFailure(extension, | |
284 params.name, | |
285 args.Pass(), | |
286 kQuotaExceeded, | |
287 profile()); | |
288 function->OnQuotaExceeded(violation_error); | 240 function->OnQuotaExceeded(violation_error); |
| 241 LogFailure(extension, params.name, kQuotaExceeded); |
289 } | 242 } |
290 | 243 |
291 // Note: do not access |this| after this point. We may have been deleted | 244 // Note: do not access |this| after this point. We may have been deleted |
292 // if function->Run() ended up closing the tab that owns us. | 245 // if function->Run() ended up closing the tab that owns us. |
293 | 246 |
294 // Check if extension was uninstalled by management.uninstall. | 247 // Check if extension was uninstalled by management.uninstall. |
295 if (!service->extensions()->GetByID(params.extension_id)) | 248 if (!service->extensions()->GetByID(params.extension_id)) |
296 return; | 249 return; |
297 | 250 |
298 // We only adjust the keepalive count for UIThreadExtensionFunction for | 251 // We only adjust the keepalive count for UIThreadExtensionFunction for |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
370 } | 323 } |
371 | 324 |
372 // static | 325 // static |
373 void ExtensionFunctionDispatcher::SendAccessDenied( | 326 void ExtensionFunctionDispatcher::SendAccessDenied( |
374 IPC::Sender* ipc_sender, int routing_id, int request_id) { | 327 IPC::Sender* ipc_sender, int routing_id, int request_id) { |
375 ListValue empty_list; | 328 ListValue empty_list; |
376 ipc_sender->Send(new ExtensionMsg_Response( | 329 ipc_sender->Send(new ExtensionMsg_Response( |
377 routing_id, request_id, false, empty_list, | 330 routing_id, request_id, false, empty_list, |
378 "Access to extension API denied.")); | 331 "Access to extension API denied.")); |
379 } | 332 } |
OLD | NEW |