| 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 "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/json/json_string_value_serializer.h" | 8 #include "base/json/json_string_value_serializer.h" |
| 9 #include "base/lazy_instance.h" | 9 #include "base/lazy_instance.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 28 matching lines...) Expand all Loading... |
| 39 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h" | 39 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h" |
| 40 #include "webkit/glue/resource_type.h" | 40 #include "webkit/glue/resource_type.h" |
| 41 | 41 |
| 42 using extensions::Extension; | 42 using extensions::Extension; |
| 43 using extensions::ExtensionAPI; | 43 using extensions::ExtensionAPI; |
| 44 using content::RenderViewHost; | 44 using content::RenderViewHost; |
| 45 using WebKit::WebSecurityOrigin; | 45 using WebKit::WebSecurityOrigin; |
| 46 | 46 |
| 47 namespace { | 47 namespace { |
| 48 | 48 |
| 49 void LogSuccess(const std::string& extension_id, | 49 void LogSuccess(const Extension* extension, |
| 50 const std::string& api_name, | 50 const std::string& api_name, |
| 51 scoped_ptr<ListValue> args, | 51 scoped_ptr<ListValue> args, |
| 52 Profile* profile) { | 52 Profile* profile) { |
| 53 // The ActivityLog can only be accessed from the main (UI) thread. If we're | 53 // The ActivityLog can only be accessed from the main (UI) thread. If we're |
| 54 // running on the wrong thread, re-dispatch from the main thread. | 54 // running on the wrong thread, re-dispatch from the main thread. |
| 55 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | 55 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| 56 BrowserThread::PostTask(BrowserThread::UI, | 56 BrowserThread::PostTask(BrowserThread::UI, |
| 57 FROM_HERE, | 57 FROM_HERE, |
| 58 base::Bind(&LogSuccess, | 58 base::Bind(&LogSuccess, |
| 59 extension_id, | 59 extension, |
| 60 api_name, | 60 api_name, |
| 61 base::Passed(&args), | 61 base::Passed(&args), |
| 62 profile)); | 62 profile)); |
| 63 } else { | 63 } else { |
| 64 extensions::ActivityLog* activity_log = | 64 extensions::ActivityLog* activity_log = |
| 65 extensions::ActivityLog::GetInstance(profile); | 65 extensions::ActivityLog::GetInstance(profile); |
| 66 activity_log->LogAPIAction( | 66 activity_log->LogAPIAction(extension, api_name, args.get(), std::string()); |
| 67 extension_id, api_name, args.get(), std::string()); | |
| 68 } | 67 } |
| 69 } | 68 } |
| 70 | 69 |
| 71 void LogFailure(const std::string& extension_id, | 70 void LogFailure(const Extension* extension, |
| 72 const std::string& api_name, | 71 const std::string& api_name, |
| 73 scoped_ptr<ListValue> args, | 72 scoped_ptr<ListValue> args, |
| 74 extensions::BlockedAction::Reason reason, | 73 extensions::BlockedAction::Reason reason, |
| 75 Profile* profile) { | 74 Profile* profile) { |
| 76 // The ActivityLog can only be accessed from the main (UI) thread. If we're | 75 // The ActivityLog can only be accessed from the main (UI) thread. If we're |
| 77 // running on the wrong thread, re-dispatch from the main thread. | 76 // running on the wrong thread, re-dispatch from the main thread. |
| 78 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | 77 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| 79 BrowserThread::PostTask(BrowserThread::UI, | 78 BrowserThread::PostTask(BrowserThread::UI, |
| 80 FROM_HERE, | 79 FROM_HERE, |
| 81 base::Bind(&LogFailure, | 80 base::Bind(&LogFailure, |
| 82 extension_id, | 81 extension, |
| 83 api_name, | 82 api_name, |
| 84 base::Passed(&args), | 83 base::Passed(&args), |
| 85 reason, | 84 reason, |
| 86 profile)); | 85 profile)); |
| 87 } else { | 86 } else { |
| 88 extensions::ActivityLog* activity_log = | 87 extensions::ActivityLog* activity_log = |
| 89 extensions::ActivityLog::GetInstance(profile); | 88 extensions::ActivityLog::GetInstance(profile); |
| 90 activity_log->LogBlockedAction( | 89 activity_log->LogBlockedAction( |
| 91 extension_id, api_name, args.get(), reason, std::string()); | 90 extension, api_name, args.get(), reason, std::string()); |
| 92 } | 91 } |
| 93 } | 92 } |
| 94 | 93 |
| 95 | 94 |
| 96 // Separate copy of ExtensionAPI used for IO thread extension functions. We need | 95 // Separate copy of ExtensionAPI used for IO thread extension functions. We need |
| 97 // this because ExtensionAPI has mutable data. It should be possible to remove | 96 // this because ExtensionAPI has mutable data. It should be possible to remove |
| 98 // this once all the extension APIs are updated to the feature system. | 97 // this once all the extension APIs are updated to the feature system. |
| 99 struct Static { | 98 struct Static { |
| 100 Static() | 99 Static() |
| 101 : api(extensions::ExtensionAPI::CreateWithDefaultConfiguration()) { | 100 : api(extensions::ExtensionAPI::CreateWithDefaultConfiguration()) { |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 258 params.request_id)); | 257 params.request_id)); |
| 259 | 258 |
| 260 scoped_refptr<ExtensionFunction> function( | 259 scoped_refptr<ExtensionFunction> function( |
| 261 CreateExtensionFunction(params, extension, render_process_id, | 260 CreateExtensionFunction(params, extension, render_process_id, |
| 262 extension_info_map->process_map(), | 261 extension_info_map->process_map(), |
| 263 g_global_io_data.Get().api.get(), | 262 g_global_io_data.Get().api.get(), |
| 264 profile, callback)); | 263 profile, callback)); |
| 265 scoped_ptr<ListValue> args(params.arguments.DeepCopy()); | 264 scoped_ptr<ListValue> args(params.arguments.DeepCopy()); |
| 266 | 265 |
| 267 if (!function.get()) { | 266 if (!function.get()) { |
| 268 LogFailure(extension->id(), | 267 LogFailure(extension, |
| 269 params.name, | 268 params.name, |
| 270 args.Pass(), | 269 args.Pass(), |
| 271 extensions::BlockedAction::ACCESS_DENIED, | 270 extensions::BlockedAction::ACCESS_DENIED, |
| 272 profile_cast); | 271 profile_cast); |
| 273 return; | 272 return; |
| 274 } | 273 } |
| 275 | 274 |
| 276 IOThreadExtensionFunction* function_io = | 275 IOThreadExtensionFunction* function_io = |
| 277 function->AsIOThreadExtensionFunction(); | 276 function->AsIOThreadExtensionFunction(); |
| 278 if (!function_io) { | 277 if (!function_io) { |
| 279 NOTREACHED(); | 278 NOTREACHED(); |
| 280 return; | 279 return; |
| 281 } | 280 } |
| 282 function_io->set_ipc_sender(ipc_sender); | 281 function_io->set_ipc_sender(ipc_sender); |
| 283 function_io->set_extension_info_map(extension_info_map); | 282 function_io->set_extension_info_map(extension_info_map); |
| 284 function->set_include_incognito( | 283 function->set_include_incognito( |
| 285 extension_info_map->IsIncognitoEnabled(extension->id())); | 284 extension_info_map->IsIncognitoEnabled(extension->id())); |
| 286 | 285 |
| 287 if (!CheckPermissions(function.get(), extension, params, callback)) { | 286 if (!CheckPermissions(function.get(), extension, params, callback)) { |
| 288 LogFailure(extension->id(), | 287 LogFailure(extension, |
| 289 params.name, | 288 params.name, |
| 290 args.Pass(), | 289 args.Pass(), |
| 291 extensions::BlockedAction::ACCESS_DENIED, | 290 extensions::BlockedAction::ACCESS_DENIED, |
| 292 profile_cast); | 291 profile_cast); |
| 293 return; | 292 return; |
| 294 } | 293 } |
| 295 | 294 |
| 296 ExtensionsQuotaService* quota = extension_info_map->GetQuotaService(); | 295 ExtensionsQuotaService* quota = extension_info_map->GetQuotaService(); |
| 297 std::string violation_error = quota->Assess(extension->id(), | 296 std::string violation_error = quota->Assess(extension->id(), |
| 298 function.get(), | 297 function.get(), |
| 299 ¶ms.arguments, | 298 ¶ms.arguments, |
| 300 base::TimeTicks::Now()); | 299 base::TimeTicks::Now()); |
| 301 if (violation_error.empty()) { | 300 if (violation_error.empty()) { |
| 302 LogSuccess(extension->id(), | 301 LogSuccess(extension, |
| 303 params.name, | 302 params.name, |
| 304 args.Pass(), | 303 args.Pass(), |
| 305 profile_cast); | 304 profile_cast); |
| 306 function->Run(); | 305 function->Run(); |
| 307 } else { | 306 } else { |
| 308 LogFailure(extension->id(), | 307 LogFailure(extension, |
| 309 params.name, | 308 params.name, |
| 310 args.Pass(), | 309 args.Pass(), |
| 311 extensions::BlockedAction::QUOTA_EXCEEDED, | 310 extensions::BlockedAction::QUOTA_EXCEEDED, |
| 312 profile_cast); | 311 profile_cast); |
| 313 function->OnQuotaExceeded(violation_error); | 312 function->OnQuotaExceeded(violation_error); |
| 314 } | 313 } |
| 315 } | 314 } |
| 316 | 315 |
| 317 ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(Profile* profile, | 316 ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(Profile* profile, |
| 318 Delegate* delegate) | 317 Delegate* delegate) |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 363 | 362 |
| 364 scoped_refptr<ExtensionFunction> function( | 363 scoped_refptr<ExtensionFunction> function( |
| 365 CreateExtensionFunction(params, extension, | 364 CreateExtensionFunction(params, extension, |
| 366 render_view_host->GetProcess()->GetID(), | 365 render_view_host->GetProcess()->GetID(), |
| 367 *(service->process_map()), | 366 *(service->process_map()), |
| 368 extensions::ExtensionAPI::GetSharedInstance(), | 367 extensions::ExtensionAPI::GetSharedInstance(), |
| 369 profile(), callback)); | 368 profile(), callback)); |
| 370 scoped_ptr<ListValue> args(params.arguments.DeepCopy()); | 369 scoped_ptr<ListValue> args(params.arguments.DeepCopy()); |
| 371 | 370 |
| 372 if (!function.get()) { | 371 if (!function.get()) { |
| 373 LogFailure(extension->id(), | 372 LogFailure(extension, |
| 374 params.name, | 373 params.name, |
| 375 args.Pass(), | 374 args.Pass(), |
| 376 extensions::BlockedAction::ACCESS_DENIED, | 375 extensions::BlockedAction::ACCESS_DENIED, |
| 377 profile()); | 376 profile()); |
| 378 return; | 377 return; |
| 379 } | 378 } |
| 380 | 379 |
| 381 UIThreadExtensionFunction* function_ui = | 380 UIThreadExtensionFunction* function_ui = |
| 382 function->AsUIThreadExtensionFunction(); | 381 function->AsUIThreadExtensionFunction(); |
| 383 if (!function_ui) { | 382 if (!function_ui) { |
| 384 NOTREACHED(); | 383 NOTREACHED(); |
| 385 return; | 384 return; |
| 386 } | 385 } |
| 387 function_ui->SetRenderViewHost(render_view_host); | 386 function_ui->SetRenderViewHost(render_view_host); |
| 388 function_ui->set_dispatcher(AsWeakPtr()); | 387 function_ui->set_dispatcher(AsWeakPtr()); |
| 389 function_ui->set_profile(profile_); | 388 function_ui->set_profile(profile_); |
| 390 function->set_include_incognito(service->CanCrossIncognito(extension)); | 389 function->set_include_incognito(service->CanCrossIncognito(extension)); |
| 391 | 390 |
| 392 if (!CheckPermissions(function.get(), extension, params, callback)) { | 391 if (!CheckPermissions(function.get(), extension, params, callback)) { |
| 393 LogFailure(extension->id(), | 392 LogFailure(extension, |
| 394 params.name, | 393 params.name, |
| 395 args.Pass(), | 394 args.Pass(), |
| 396 extensions::BlockedAction::ACCESS_DENIED, | 395 extensions::BlockedAction::ACCESS_DENIED, |
| 397 profile()); | 396 profile()); |
| 398 return; | 397 return; |
| 399 } | 398 } |
| 400 | 399 |
| 401 ExtensionsQuotaService* quota = service->quota_service(); | 400 ExtensionsQuotaService* quota = service->quota_service(); |
| 402 std::string violation_error = quota->Assess(extension->id(), | 401 std::string violation_error = quota->Assess(extension->id(), |
| 403 function.get(), | 402 function.get(), |
| 404 ¶ms.arguments, | 403 ¶ms.arguments, |
| 405 base::TimeTicks::Now()); | 404 base::TimeTicks::Now()); |
| 406 if (violation_error.empty()) { | 405 if (violation_error.empty()) { |
| 407 // See crbug.com/39178. | 406 // See crbug.com/39178. |
| 408 ExternalProtocolHandler::PermitLaunchUrl(); | 407 ExternalProtocolHandler::PermitLaunchUrl(); |
| 409 LogSuccess(extension->id(), params.name, args.Pass(), profile()); | 408 LogSuccess(extension, params.name, args.Pass(), profile()); |
| 410 function->Run(); | 409 function->Run(); |
| 411 } else { | 410 } else { |
| 412 LogFailure(extension->id(), | 411 LogFailure(extension, |
| 413 params.name, | 412 params.name, |
| 414 args.Pass(), | 413 args.Pass(), |
| 415 extensions::BlockedAction::QUOTA_EXCEEDED, | 414 extensions::BlockedAction::QUOTA_EXCEEDED, |
| 416 profile()); | 415 profile()); |
| 417 function->OnQuotaExceeded(violation_error); | 416 function->OnQuotaExceeded(violation_error); |
| 418 } | 417 } |
| 419 | 418 |
| 420 // Note: do not access |this| after this point. We may have been deleted | 419 // Note: do not access |this| after this point. We may have been deleted |
| 421 // if function->Run() ended up closing the tab that owns us. | 420 // if function->Run() ended up closing the tab that owns us. |
| 422 | 421 |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 532 return function; | 531 return function; |
| 533 } | 532 } |
| 534 | 533 |
| 535 // static | 534 // static |
| 536 void ExtensionFunctionDispatcher::SendAccessDenied( | 535 void ExtensionFunctionDispatcher::SendAccessDenied( |
| 537 const ExtensionFunction::ResponseCallback& callback) { | 536 const ExtensionFunction::ResponseCallback& callback) { |
| 538 ListValue empty_list; | 537 ListValue empty_list; |
| 539 callback.Run(ExtensionFunction::FAILED, empty_list, | 538 callback.Run(ExtensionFunction::FAILED, empty_list, |
| 540 "Access to extension API denied."); | 539 "Access to extension API denied."); |
| 541 } | 540 } |
| OLD | NEW |