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