OLD | NEW |
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/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/memory/ref_counted.h" | 9 #include "base/memory/ref_counted.h" |
10 #include "base/memory/singleton.h" | 10 #include "base/memory/singleton.h" |
(...skipping 28 matching lines...) Expand all Loading... |
39 #include "chrome/browser/extensions/extension_tabs_module.h" | 39 #include "chrome/browser/extensions/extension_tabs_module.h" |
40 #include "chrome/browser/extensions/extension_test_api.h" | 40 #include "chrome/browser/extensions/extension_test_api.h" |
41 #include "chrome/browser/extensions/extension_tts_api.h" | 41 #include "chrome/browser/extensions/extension_tts_api.h" |
42 #include "chrome/browser/extensions/extension_web_socket_proxy_private_api.h" | 42 #include "chrome/browser/extensions/extension_web_socket_proxy_private_api.h" |
43 #include "chrome/browser/extensions/extension_web_ui.h" | 43 #include "chrome/browser/extensions/extension_web_ui.h" |
44 #include "chrome/browser/extensions/extension_webrequest_api.h" | 44 #include "chrome/browser/extensions/extension_webrequest_api.h" |
45 #include "chrome/browser/extensions/extension_webstore_private_api.h" | 45 #include "chrome/browser/extensions/extension_webstore_private_api.h" |
46 #include "chrome/browser/extensions/extensions_quota_service.h" | 46 #include "chrome/browser/extensions/extensions_quota_service.h" |
47 #include "chrome/browser/external_protocol/external_protocol_handler.h" | 47 #include "chrome/browser/external_protocol/external_protocol_handler.h" |
48 #include "chrome/browser/profiles/profile.h" | 48 #include "chrome/browser/profiles/profile.h" |
| 49 #include "chrome/browser/renderer_host/chrome_render_message_filter.h" |
49 #include "chrome/browser/ui/browser_list.h" | 50 #include "chrome/browser/ui/browser_list.h" |
50 #include "chrome/browser/ui/browser_window.h" | 51 #include "chrome/browser/ui/browser_window.h" |
51 #include "chrome/common/extensions/extension_messages.h" | 52 #include "chrome/common/extensions/extension_messages.h" |
52 #include "chrome/common/url_constants.h" | 53 #include "chrome/common/url_constants.h" |
53 #include "content/browser/child_process_security_policy.h" | 54 #include "content/browser/child_process_security_policy.h" |
54 #include "content/browser/renderer_host/render_process_host.h" | 55 #include "content/browser/renderer_host/render_process_host.h" |
55 #include "content/browser/renderer_host/render_view_host.h" | 56 #include "content/browser/renderer_host/render_view_host.h" |
56 #include "ipc/ipc_message.h" | 57 #include "ipc/ipc_message.h" |
57 #include "ipc/ipc_message_macros.h" | 58 #include "ipc/ipc_message_macros.h" |
58 #include "third_party/skia/include/core/SkBitmap.h" | 59 #include "third_party/skia/include/core/SkBitmap.h" |
(...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
404 | 405 |
405 bool ExtensionFunctionDispatcher::OverrideFunction( | 406 bool ExtensionFunctionDispatcher::OverrideFunction( |
406 const std::string& name, ExtensionFunctionFactory factory) { | 407 const std::string& name, ExtensionFunctionFactory factory) { |
407 return FactoryRegistry::GetInstance()->OverrideFunction(name, factory); | 408 return FactoryRegistry::GetInstance()->OverrideFunction(name, factory); |
408 } | 409 } |
409 | 410 |
410 void ExtensionFunctionDispatcher::ResetFunctions() { | 411 void ExtensionFunctionDispatcher::ResetFunctions() { |
411 FactoryRegistry::GetInstance()->ResetFunctions(); | 412 FactoryRegistry::GetInstance()->ResetFunctions(); |
412 } | 413 } |
413 | 414 |
| 415 // static |
| 416 void ExtensionFunctionDispatcher::DispatchOnIOThread( |
| 417 const ExtensionInfoMap* extension_info_map, |
| 418 ProfileId profile_id, |
| 419 int render_process_id, |
| 420 base::WeakPtr<ChromeRenderMessageFilter> ipc_sender, |
| 421 int routing_id, |
| 422 const ExtensionHostMsg_Request_Params& params) { |
| 423 const Extension* extension = |
| 424 extension_info_map->extensions().GetByURL(params.source_url); |
| 425 |
| 426 scoped_refptr<ExtensionFunction> function( |
| 427 CreateExtensionFunction(params, extension, profile_id, render_process_id, |
| 428 ipc_sender, routing_id)); |
| 429 if (!function) |
| 430 return; |
| 431 |
| 432 IOThreadExtensionFunction* function_io = |
| 433 function->AsIOThreadExtensionFunction(); |
| 434 if (!function_io) { |
| 435 NOTREACHED(); |
| 436 return; |
| 437 } |
| 438 function_io->set_ipc_sender(ipc_sender, routing_id); |
| 439 function_io->set_extension_info_map(extension_info_map); |
| 440 function->set_include_incognito( |
| 441 extension_info_map->IsIncognitoEnabled(extension->id())); |
| 442 function->Run(); |
| 443 } |
| 444 |
414 ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(Profile* profile, | 445 ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(Profile* profile, |
415 Delegate* delegate) | 446 Delegate* delegate) |
416 : profile_(profile), | 447 : profile_(profile), |
417 delegate_(delegate) { | 448 delegate_(delegate) { |
418 } | 449 } |
419 | 450 |
420 ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() { | 451 ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() { |
421 } | 452 } |
422 | 453 |
423 Browser* ExtensionFunctionDispatcher::GetCurrentBrowser( | 454 Browser* ExtensionFunctionDispatcher::GetCurrentBrowser( |
(...skipping 17 matching lines...) Expand all Loading... |
441 // before the browser is sufficiently initialized to return here. | 472 // before the browser is sufficiently initialized to return here. |
442 // A similar situation may arise during shutdown. | 473 // A similar situation may arise during shutdown. |
443 // TODO(rafaelw): Delay creation of background_page until the browser | 474 // TODO(rafaelw): Delay creation of background_page until the browser |
444 // is available. http://code.google.com/p/chromium/issues/detail?id=13284 | 475 // is available. http://code.google.com/p/chromium/issues/detail?id=13284 |
445 return browser; | 476 return browser; |
446 } | 477 } |
447 | 478 |
448 void ExtensionFunctionDispatcher::Dispatch( | 479 void ExtensionFunctionDispatcher::Dispatch( |
449 const ExtensionHostMsg_Request_Params& params, | 480 const ExtensionHostMsg_Request_Params& params, |
450 RenderViewHost* render_view_host) { | 481 RenderViewHost* render_view_host) { |
451 // TODO(aa): It would be cool to use ExtensionProcessManager to track which | |
452 // processes are extension processes rather than ChildProcessSecurityPolicy. | |
453 // EPM has richer information: it not only knows which processes contain | |
454 // at least one extension, but it knows which extensions are inside and what | |
455 // permissions the have. So we would be able to enforce permissions more | |
456 // granularly. | |
457 if (!ChildProcessSecurityPolicy::GetInstance()->HasExtensionBindings( | |
458 render_view_host->process()->id())) { | |
459 // TODO(aa): Allow content scripts access to low-threat extension APIs. | |
460 // See: crbug.com/80308. | |
461 LOG(ERROR) << "Extension API called from non-extension process."; | |
462 SendAccessDenied(render_view_host, params.request_id); | |
463 return; | |
464 } | |
465 | |
466 ExtensionService* service = profile()->GetExtensionService(); | 482 ExtensionService* service = profile()->GetExtensionService(); |
467 if (!service) | 483 if (!service) |
468 return; | 484 return; |
469 | 485 |
470 if (!service->ExtensionBindingsAllowed(params.source_url)) { | 486 if (!service->ExtensionBindingsAllowed(params.source_url)) { |
471 LOG(ERROR) << "Extension bindings not allowed for URL: " | 487 LOG(ERROR) << "Extension bindings not allowed for URL: " |
472 << params.source_url.spec(); | 488 << params.source_url.spec(); |
473 SendAccessDenied(render_view_host, params.request_id); | 489 SendAccessDenied(render_view_host, render_view_host->routing_id(), |
| 490 params.request_id); |
474 return; | 491 return; |
475 } | 492 } |
476 | 493 |
477 // TODO(aa): When we allow content scripts to call extension APIs, we will | 494 // TODO(aa): When we allow content scripts to call extension APIs, we will |
478 // have to pass the extension ID explicitly here, not use the source URL. | 495 // have to pass the extension ID explicitly here, not use the source URL. |
479 const Extension* extension = service->GetExtensionByURL(params.source_url); | 496 const Extension* extension = service->GetExtensionByURL(params.source_url); |
480 if (!extension) | 497 if (!extension) |
481 extension = service->GetExtensionByWebExtent(params.source_url); | 498 extension = service->GetExtensionByWebExtent(params.source_url); |
482 if (!extension) { | 499 |
483 LOG(ERROR) << "Extension does not exist for URL: " | 500 scoped_refptr<ExtensionFunction> function(CreateExtensionFunction( |
484 << params.source_url.spec(); | 501 params, extension, profile_->GetRuntimeId(), |
485 SendAccessDenied(render_view_host, params.request_id); | 502 render_view_host->process()->id(), |
| 503 render_view_host, render_view_host->routing_id())); |
| 504 if (!function) |
486 return; | 505 return; |
487 } | |
488 | 506 |
489 if (!extension->HasApiPermission(params.name)) { | |
490 LOG(ERROR) << "Extension " << extension->id() << " does not have " | |
491 << "permission to function: " << params.name; | |
492 SendAccessDenied(render_view_host, params.request_id); | |
493 return; | |
494 } | |
495 | |
496 scoped_refptr<ExtensionFunction> function( | |
497 FactoryRegistry::GetInstance()->NewFunction(params.name)); | |
498 UIThreadExtensionFunction* function_ui = | 507 UIThreadExtensionFunction* function_ui = |
499 function->AsUIThreadExtensionFunction(); | 508 function->AsUIThreadExtensionFunction(); |
500 if (!function_ui) { | 509 if (!function_ui) { |
501 NOTREACHED(); | 510 NOTREACHED(); |
502 return; | 511 return; |
503 } | 512 } |
504 function_ui->SetRenderViewHost(render_view_host); | 513 function_ui->SetRenderViewHost(render_view_host); |
505 function_ui->set_dispatcher(AsWeakPtr()); | 514 function_ui->set_dispatcher(AsWeakPtr()); |
506 function_ui->set_profile(profile_); | 515 function_ui->set_profile(profile_); |
507 | |
508 function->set_profile_id(profile_->GetRuntimeId()); | |
509 function->set_extension(extension); | |
510 function->SetArgs(¶ms.arguments); | |
511 function->set_source_url(params.source_url); | |
512 function->set_request_id(params.request_id); | |
513 function->set_has_callback(params.has_callback); | |
514 function->set_user_gesture(params.user_gesture); | |
515 function->set_include_incognito(service->CanCrossIncognito(extension)); | 516 function->set_include_incognito(service->CanCrossIncognito(extension)); |
516 | 517 |
517 ExtensionsQuotaService* quota = service->quota_service(); | 518 ExtensionsQuotaService* quota = service->quota_service(); |
518 if (quota->Assess(extension->id(), function, ¶ms.arguments, | 519 if (quota->Assess(extension->id(), function, ¶ms.arguments, |
519 base::TimeTicks::Now())) { | 520 base::TimeTicks::Now())) { |
520 // See crbug.com/39178. | 521 // See crbug.com/39178. |
521 ExternalProtocolHandler::PermitLaunchUrl(); | 522 ExternalProtocolHandler::PermitLaunchUrl(); |
522 | 523 |
523 function->Run(); | 524 function->Run(); |
524 } else { | 525 } else { |
525 render_view_host->Send(new ExtensionMsg_Response( | 526 render_view_host->Send(new ExtensionMsg_Response( |
526 render_view_host->routing_id(), function->request_id(), false, | 527 render_view_host->routing_id(), function->request_id(), false, |
527 std::string(), QuotaLimitHeuristic::kGenericOverQuotaError)); | 528 std::string(), QuotaLimitHeuristic::kGenericOverQuotaError)); |
528 } | 529 } |
529 } | 530 } |
530 | 531 |
| 532 // static |
| 533 ExtensionFunction* ExtensionFunctionDispatcher::CreateExtensionFunction( |
| 534 const ExtensionHostMsg_Request_Params& params, |
| 535 const Extension* extension, |
| 536 ProfileId profile_id, |
| 537 int render_process_id, |
| 538 IPC::Message::Sender* ipc_sender, |
| 539 int routing_id) { |
| 540 // TODO(aa): It would be cool to use ExtensionProcessManager to track which |
| 541 // processes are extension processes rather than ChildProcessSecurityPolicy. |
| 542 // EPM has richer information: it not only knows which processes contain |
| 543 // at least one extension, but it knows which extensions are inside and what |
| 544 // permissions the have. So we would be able to enforce permissions more |
| 545 // granularly. |
| 546 if (!ChildProcessSecurityPolicy::GetInstance()->HasExtensionBindings( |
| 547 render_process_id)) { |
| 548 // TODO(aa): Allow content scripts access to low-threat extension APIs. |
| 549 // See: crbug.com/80308. |
| 550 LOG(ERROR) << "Extension API called from non-extension process."; |
| 551 SendAccessDenied(ipc_sender, routing_id, params.request_id); |
| 552 return NULL; |
| 553 } |
| 554 |
| 555 if (!extension) { |
| 556 LOG(ERROR) << "Extension does not exist for URL: " |
| 557 << params.source_url.spec(); |
| 558 SendAccessDenied(ipc_sender, routing_id, params.request_id); |
| 559 return NULL; |
| 560 } |
| 561 |
| 562 if (!extension->HasApiPermission(params.name)) { |
| 563 LOG(ERROR) << "Extension " << extension->id() << " does not have " |
| 564 << "permission to function: " << params.name; |
| 565 SendAccessDenied(ipc_sender, routing_id, params.request_id); |
| 566 return NULL; |
| 567 } |
| 568 |
| 569 ExtensionFunction* function = |
| 570 FactoryRegistry::GetInstance()->NewFunction(params.name); |
| 571 function->SetArgs(¶ms.arguments); |
| 572 function->set_source_url(params.source_url); |
| 573 function->set_request_id(params.request_id); |
| 574 function->set_has_callback(params.has_callback); |
| 575 function->set_user_gesture(params.user_gesture); |
| 576 function->set_extension(extension); |
| 577 function->set_profile_id(profile_id); |
| 578 return function; |
| 579 } |
| 580 |
| 581 // static |
531 void ExtensionFunctionDispatcher::SendAccessDenied( | 582 void ExtensionFunctionDispatcher::SendAccessDenied( |
532 RenderViewHost* render_view_host, int request_id) { | 583 IPC::Message::Sender* ipc_sender, int routing_id, int request_id) { |
533 render_view_host->Send(new ExtensionMsg_Response( | 584 ipc_sender->Send(new ExtensionMsg_Response( |
534 render_view_host->routing_id(), request_id, false, std::string(), | 585 routing_id, request_id, false, std::string(), |
535 "Access to extension API denied.")); | 586 "Access to extension API denied.")); |
536 } | 587 } |
OLD | NEW |