automation_provider.cc revision ac1e49eb6695f711d72215fcdf9388548942a00d
1// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/automation/automation_provider.h" 6 7#include <set> 8 9#include "app/message_box_flags.h" 10#include "base/callback.h" 11#include "base/debug/trace_event.h" 12#include "base/file_path.h" 13#include "base/json/json_reader.h" 14#include "base/json/json_writer.h" 15#include "base/json/string_escape.h" 16#include "base/message_loop.h" 17#include "base/path_service.h" 18#include "base/process_util.h" 19#include "base/stl_util-inl.h" 20#include "base/string_util.h" 21#include "base/task.h" 22#include "base/thread.h" 23#include "base/string_number_conversions.h" 24#include "base/utf_string_conversions.h" 25#include "base/values.h" 26#include "base/waitable_event.h" 27#include "chrome/app/chrome_command_ids.h" 28#include "chrome/browser/app_modal_dialog.h" 29#include "chrome/browser/app_modal_dialog_queue.h" 30#include "chrome/browser/autofill/autofill_manager.h" 31#include "chrome/browser/automation/automation_autocomplete_edit_tracker.h" 32#include "chrome/browser/automation/automation_browser_tracker.h" 33#include "chrome/browser/automation/automation_extension_tracker.h" 34#include "chrome/browser/automation/automation_provider_list.h" 35#include "chrome/browser/automation/automation_provider_observers.h" 36#include "chrome/browser/automation/automation_resource_message_filter.h" 37#include "chrome/browser/automation/automation_tab_tracker.h" 38#include "chrome/browser/automation/automation_window_tracker.h" 39#include "chrome/browser/automation/extension_port_container.h" 40#include "chrome/browser/autocomplete/autocomplete_edit.h" 41#include "chrome/browser/blocked_content_container.h" 42#include "chrome/browser/bookmarks/bookmark_model.h" 43#include "chrome/browser/bookmarks/bookmark_storage.h" 44#include "chrome/browser/browser_list.h" 45#include "chrome/browser/browser_process.h" 46#include "chrome/browser/browser_thread.h" 47#include "chrome/browser/browser_window.h" 48#include "chrome/browser/browsing_data_remover.h" 49#include "chrome/browser/character_encoding.h" 50#include "chrome/browser/dom_operation_notification_details.h" 51#include "chrome/browser/debugger/devtools_manager.h" 52#include "chrome/browser/download/download_item.h" 53#include "chrome/browser/download/download_shelf.h" 54#include "chrome/browser/download/save_package.h" 55#include "chrome/browser/extensions/crx_installer.h" 56#include "chrome/browser/extensions/extension_browser_event_router.h" 57#include "chrome/browser/extensions/extension_host.h" 58#include "chrome/browser/extensions/extension_install_ui.h" 59#include "chrome/browser/extensions/extension_message_service.h" 60#include "chrome/browser/extensions/extension_tabs_module.h" 61#include "chrome/browser/extensions/extension_toolbar_model.h" 62#include "chrome/browser/extensions/extensions_service.h" 63#include "chrome/browser/extensions/user_script_master.h" 64#include "chrome/browser/find_bar.h" 65#include "chrome/browser/find_bar_controller.h" 66#include "chrome/browser/find_notification_details.h" 67#include "chrome/browser/host_content_settings_map.h" 68#include "chrome/browser/importer/importer.h" 69#include "chrome/browser/importer/importer_data_types.h" 70#include "chrome/browser/io_thread.h" 71#include "chrome/browser/location_bar.h" 72#include "chrome/browser/login_prompt.h" 73#include "chrome/browser/net/url_request_mock_util.h" 74#include "chrome/browser/platform_util.h" 75#include "chrome/browser/prefs/pref_service.h" 76#include "chrome/browser/printing/print_job.h" 77#include "chrome/browser/profile_manager.h" 78#include "chrome/browser/renderer_host/render_process_host.h" 79#include "chrome/browser/renderer_host/render_view_host.h" 80#include "chrome/browser/ssl/ssl_manager.h" 81#include "chrome/browser/ssl/ssl_blocking_page.h" 82#include "chrome/browser/tab_contents/infobar_delegate.h" 83#include "chrome/browser/tab_contents/navigation_entry.h" 84#include "chrome/browser/tab_contents/tab_contents.h" 85#include "chrome/browser/tab_contents/tab_contents_view.h" 86#include "chrome/browser/translate/translate_infobar_delegate.h" 87#include "chrome/common/automation_constants.h" 88#include "chrome/common/automation_messages.h" 89#include "chrome/common/chrome_constants.h" 90#include "chrome/common/chrome_paths.h" 91#include "chrome/common/chrome_switches.h" 92#include "chrome/common/chrome_version_info.h" 93#include "chrome/common/extensions/extension.h" 94#include "chrome/common/json_value_serializer.h" 95#include "chrome/common/net/url_request_context_getter.h" 96#include "chrome/common/notification_service.h" 97#include "chrome/common/pref_names.h" 98#include "chrome/common/url_constants.h" 99#include "chrome/test/automation/tab_proxy.h" 100#include "net/proxy/proxy_service.h" 101#include "net/proxy/proxy_config_service_fixed.h" 102#include "net/url_request/url_request_context.h" 103#include "chrome/browser/automation/ui_controls.h" 104#include "views/event.h" 105#include "webkit/glue/password_form.h" 106#include "webkit/glue/plugins/plugin_list.h" 107 108#if defined(OS_WIN) 109#include "chrome/browser/external_tab_container_win.h" 110#endif // defined(OS_WIN) 111 112using base::Time; 113 114AutomationProvider::AutomationProvider(Profile* profile) 115 : profile_(profile), 116 reply_message_(NULL), 117 is_connected_(false), 118 initial_loads_complete_(false) { 119 TRACE_EVENT_BEGIN("AutomationProvider::AutomationProvider", 0, ""); 120 121 browser_tracker_.reset(new AutomationBrowserTracker(this)); 122 extension_tracker_.reset(new AutomationExtensionTracker(this)); 123 tab_tracker_.reset(new AutomationTabTracker(this)); 124 window_tracker_.reset(new AutomationWindowTracker(this)); 125 autocomplete_edit_tracker_.reset( 126 new AutomationAutocompleteEditTracker(this)); 127 new_tab_ui_load_observer_.reset(new NewTabUILoadObserver(this)); 128 dom_operation_observer_.reset(new DomOperationMessageSender(this)); 129 metric_event_duration_observer_.reset(new MetricEventDurationObserver()); 130 extension_test_result_observer_.reset( 131 new ExtensionTestResultNotificationObserver(this)); 132 g_browser_process->AddRefModule(); 133 134 TRACE_EVENT_END("AutomationProvider::AutomationProvider", 0, ""); 135} 136 137AutomationProvider::~AutomationProvider() { 138 STLDeleteContainerPairSecondPointers(port_containers_.begin(), 139 port_containers_.end()); 140 port_containers_.clear(); 141 142 // Make sure that any outstanding NotificationObservers also get destroyed. 143 ObserverList<NotificationObserver>::Iterator it(notification_observer_list_); 144 NotificationObserver* observer; 145 while ((observer = it.GetNext()) != NULL) 146 delete observer; 147 148 if (channel_.get()) { 149 channel_->Close(); 150 } 151 g_browser_process->ReleaseModule(); 152} 153 154bool AutomationProvider::InitializeChannel(const std::string& channel_id) { 155 TRACE_EVENT_BEGIN("AutomationProvider::InitializeChannel", 0, ""); 156 157 std::string effective_channel_id = channel_id; 158 159 // If the channel_id starts with kNamedInterfacePrefix, create a named IPC 160 // server and listen on it, else connect as client to an existing IPC server 161 bool use_named_interface = 162 channel_id.find(automation::kNamedInterfacePrefix) == 0; 163 if (use_named_interface) { 164 effective_channel_id = channel_id.substr( 165 strlen(automation::kNamedInterfacePrefix)); 166 if (effective_channel_id.length() <= 0) 167 return false; 168 } 169 170 if (!automation_resource_message_filter_.get()) { 171 automation_resource_message_filter_ = new AutomationResourceMessageFilter; 172 } 173 174 channel_.reset(new IPC::SyncChannel( 175 effective_channel_id, 176 use_named_interface ? IPC::Channel::MODE_NAMED_SERVER 177 : IPC::Channel::MODE_CLIENT, 178 this, 179 automation_resource_message_filter_, 180 g_browser_process->io_thread()->message_loop(), 181 true, g_browser_process->shutdown_event())); 182 183 TRACE_EVENT_END("AutomationProvider::InitializeChannel", 0, ""); 184 185 return true; 186} 187 188std::string AutomationProvider::GetProtocolVersion() { 189 chrome::VersionInfo version_info; 190 return version_info.Version().c_str(); 191} 192 193void AutomationProvider::SetExpectedTabCount(size_t expected_tabs) { 194 if (expected_tabs == 0) 195 OnInitialLoadsComplete(); 196 else 197 initial_load_observer_.reset(new InitialLoadObserver(expected_tabs, this)); 198} 199 200void AutomationProvider::OnInitialLoadsComplete() { 201 initial_loads_complete_ = true; 202 if (is_connected_) 203 Send(new AutomationMsg_InitialLoadsComplete(0)); 204} 205 206NotificationObserver* AutomationProvider::AddNavigationStatusListener( 207 NavigationController* tab, IPC::Message* reply_message, 208 int number_of_navigations, bool include_current_navigation) { 209 NotificationObserver* observer = 210 new NavigationNotificationObserver(tab, this, reply_message, 211 number_of_navigations, 212 include_current_navigation); 213 214 notification_observer_list_.AddObserver(observer); 215 return observer; 216} 217 218void AutomationProvider::RemoveNavigationStatusListener( 219 NotificationObserver* obs) { 220 notification_observer_list_.RemoveObserver(obs); 221} 222 223NotificationObserver* AutomationProvider::AddTabStripObserver( 224 Browser* parent, 225 IPC::Message* reply_message) { 226 NotificationObserver* observer = 227 new TabAppendedNotificationObserver(parent, this, reply_message); 228 notification_observer_list_.AddObserver(observer); 229 230 return observer; 231} 232 233void AutomationProvider::RemoveTabStripObserver(NotificationObserver* obs) { 234 notification_observer_list_.RemoveObserver(obs); 235} 236 237void AutomationProvider::AddLoginHandler(NavigationController* tab, 238 LoginHandler* handler) { 239 login_handler_map_[tab] = handler; 240} 241 242void AutomationProvider::RemoveLoginHandler(NavigationController* tab) { 243 DCHECK(login_handler_map_[tab]); 244 login_handler_map_.erase(tab); 245} 246 247void AutomationProvider::AddPortContainer(ExtensionPortContainer* port) { 248 int port_id = port->port_id(); 249 DCHECK_NE(-1, port_id); 250 DCHECK(port_containers_.find(port_id) == port_containers_.end()); 251 252 port_containers_[port_id] = port; 253} 254 255void AutomationProvider::RemovePortContainer(ExtensionPortContainer* port) { 256 int port_id = port->port_id(); 257 DCHECK_NE(-1, port_id); 258 259 PortContainerMap::iterator it = port_containers_.find(port_id); 260 DCHECK(it != port_containers_.end()); 261 262 if (it != port_containers_.end()) { 263 delete it->second; 264 port_containers_.erase(it); 265 } 266} 267 268ExtensionPortContainer* AutomationProvider::GetPortContainer( 269 int port_id) const { 270 PortContainerMap::const_iterator it = port_containers_.find(port_id); 271 if (it == port_containers_.end()) 272 return NULL; 273 274 return it->second; 275} 276 277int AutomationProvider::GetIndexForNavigationController( 278 const NavigationController* controller, const Browser* parent) const { 279 DCHECK(parent); 280 return parent->GetIndexOfController(controller); 281} 282 283int AutomationProvider::AddExtension(const Extension* extension) { 284 DCHECK(extension); 285 return extension_tracker_->Add(extension); 286} 287 288// TODO(phajdan.jr): move to TestingAutomationProvider. 289DictionaryValue* AutomationProvider::GetDictionaryFromDownloadItem( 290 const DownloadItem* download) { 291 std::map<DownloadItem::DownloadState, std::string> state_to_string; 292 state_to_string[DownloadItem::IN_PROGRESS] = std::string("IN_PROGRESS"); 293 state_to_string[DownloadItem::CANCELLED] = std::string("CANCELLED"); 294 state_to_string[DownloadItem::REMOVING] = std::string("REMOVING"); 295 state_to_string[DownloadItem::COMPLETE] = std::string("COMPLETE"); 296 297 std::map<DownloadItem::SafetyState, std::string> safety_state_to_string; 298 safety_state_to_string[DownloadItem::SAFE] = std::string("SAFE"); 299 safety_state_to_string[DownloadItem::DANGEROUS] = std::string("DANGEROUS"); 300 safety_state_to_string[DownloadItem::DANGEROUS_BUT_VALIDATED] = 301 std::string("DANGEROUS_BUT_VALIDATED"); 302 303 DictionaryValue* dl_item_value = new DictionaryValue; 304 dl_item_value->SetInteger("id", static_cast<int>(download->id())); 305 dl_item_value->SetString("url", download->url().spec()); 306 dl_item_value->SetString("referrer_url", download->referrer_url().spec()); 307 dl_item_value->SetString("file_name", 308 download->GetFileNameToReportUser().value()); 309 dl_item_value->SetString("full_path", 310 download->GetTargetFilePath().value()); 311 dl_item_value->SetBoolean("is_paused", download->is_paused()); 312 dl_item_value->SetBoolean("open_when_complete", 313 download->open_when_complete()); 314 dl_item_value->SetBoolean("is_extension_install", 315 download->is_extension_install()); 316 dl_item_value->SetBoolean("is_temporary", download->is_temporary()); 317 dl_item_value->SetBoolean("is_otr", download->is_otr()); // off-the-record 318 dl_item_value->SetString("state", state_to_string[download->state()]); 319 dl_item_value->SetString("safety_state", 320 safety_state_to_string[download->safety_state()]); 321 dl_item_value->SetInteger("PercentComplete", download->PercentComplete()); 322 323 return dl_item_value; 324} 325 326const Extension* AutomationProvider::GetExtension(int extension_handle) { 327 return extension_tracker_->GetResource(extension_handle); 328} 329 330const Extension* AutomationProvider::GetEnabledExtension(int extension_handle) { 331 const Extension* extension = 332 extension_tracker_->GetResource(extension_handle); 333 ExtensionsService* service = profile_->GetExtensionsService(); 334 if (extension && service && 335 service->GetExtensionById(extension->id(), false)) 336 return extension; 337 return NULL; 338} 339 340const Extension* AutomationProvider::GetDisabledExtension( 341 int extension_handle) { 342 const Extension* extension = 343 extension_tracker_->GetResource(extension_handle); 344 ExtensionsService* service = profile_->GetExtensionsService(); 345 if (extension && service && 346 service->GetExtensionById(extension->id(), true) && 347 !service->GetExtensionById(extension->id(), false)) 348 return extension; 349 return NULL; 350} 351 352void AutomationProvider::OnChannelConnected(int pid) { 353 is_connected_ = true; 354 LOG(INFO) << "Testing channel connected, sending hello message"; 355 356 // Send a hello message with our current automation protocol version. 357 chrome::VersionInfo version_info; 358 channel_->Send(new AutomationMsg_Hello(0, version_info.Version())); 359 if (initial_loads_complete_) 360 Send(new AutomationMsg_InitialLoadsComplete(0)); 361} 362 363void AutomationProvider::OnMessageReceived(const IPC::Message& message) { 364 IPC_BEGIN_MESSAGE_MAP(AutomationProvider, message) 365#if !defined(OS_MACOSX) 366 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WindowDrag, 367 WindowSimulateDrag) 368#endif // !defined(OS_MACOSX) 369#if defined(OS_WIN) 370 IPC_MESSAGE_HANDLER(AutomationMsg_TabHWND, GetTabHWND) 371#endif // defined(OS_WIN) 372 IPC_MESSAGE_HANDLER(AutomationMsg_HandleUnused, HandleUnused) 373 IPC_MESSAGE_HANDLER(AutomationMsg_SetProxyConfig, SetProxyConfig); 374 IPC_MESSAGE_HANDLER(AutomationMsg_PrintAsync, PrintAsync) 375 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_Find, HandleFindRequest) 376 IPC_MESSAGE_HANDLER(AutomationMsg_OverrideEncoding, OverrideEncoding) 377 IPC_MESSAGE_HANDLER(AutomationMsg_SelectAll, SelectAll) 378 IPC_MESSAGE_HANDLER(AutomationMsg_Cut, Cut) 379 IPC_MESSAGE_HANDLER(AutomationMsg_Copy, Copy) 380 IPC_MESSAGE_HANDLER(AutomationMsg_Paste, Paste) 381 IPC_MESSAGE_HANDLER(AutomationMsg_ReloadAsync, ReloadAsync) 382 IPC_MESSAGE_HANDLER(AutomationMsg_StopAsync, StopAsync) 383 IPC_MESSAGE_HANDLER(AutomationMsg_SetPageFontSize, OnSetPageFontSize) 384 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_InstallExtension, 385 InstallExtension) 386 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_LoadExpandedExtension, 387 LoadExpandedExtension) 388 IPC_MESSAGE_HANDLER(AutomationMsg_GetEnabledExtensions, 389 GetEnabledExtensions) 390 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForExtensionTestResult, 391 WaitForExtensionTestResult) 392 IPC_MESSAGE_HANDLER_DELAY_REPLY( 393 AutomationMsg_InstallExtensionAndGetHandle, 394 InstallExtensionAndGetHandle) 395 IPC_MESSAGE_HANDLER(AutomationMsg_UninstallExtension, 396 UninstallExtension) 397 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_EnableExtension, 398 EnableExtension) 399 IPC_MESSAGE_HANDLER(AutomationMsg_DisableExtension, 400 DisableExtension) 401 IPC_MESSAGE_HANDLER_DELAY_REPLY( 402 AutomationMsg_ExecuteExtensionActionInActiveTabAsync, 403 ExecuteExtensionActionInActiveTabAsync) 404 IPC_MESSAGE_HANDLER(AutomationMsg_MoveExtensionBrowserAction, 405 MoveExtensionBrowserAction) 406 IPC_MESSAGE_HANDLER(AutomationMsg_GetExtensionProperty, 407 GetExtensionProperty) 408 IPC_MESSAGE_HANDLER(AutomationMsg_SaveAsAsync, SaveAsAsync) 409 IPC_MESSAGE_HANDLER(AutomationMsg_RemoveBrowsingData, RemoveBrowsingData) 410#if defined(OS_WIN) 411 // These are for use with external tabs. 412 IPC_MESSAGE_HANDLER(AutomationMsg_CreateExternalTab, CreateExternalTab) 413 IPC_MESSAGE_HANDLER(AutomationMsg_ProcessUnhandledAccelerator, 414 ProcessUnhandledAccelerator) 415 IPC_MESSAGE_HANDLER(AutomationMsg_SetInitialFocus, SetInitialFocus) 416 IPC_MESSAGE_HANDLER(AutomationMsg_TabReposition, OnTabReposition) 417 IPC_MESSAGE_HANDLER(AutomationMsg_ForwardContextMenuCommandToChrome, 418 OnForwardContextMenuCommandToChrome) 419 IPC_MESSAGE_HANDLER(AutomationMsg_NavigateInExternalTab, 420 NavigateInExternalTab) 421 IPC_MESSAGE_HANDLER(AutomationMsg_NavigateExternalTabAtIndex, 422 NavigateExternalTabAtIndex) 423 IPC_MESSAGE_HANDLER(AutomationMsg_ConnectExternalTab, ConnectExternalTab) 424 IPC_MESSAGE_HANDLER(AutomationMsg_SetEnableExtensionAutomation, 425 SetEnableExtensionAutomation) 426 IPC_MESSAGE_HANDLER(AutomationMsg_HandleMessageFromExternalHost, 427 OnMessageFromExternalHost) 428 IPC_MESSAGE_HANDLER(AutomationMsg_BrowserMove, OnBrowserMoved) 429 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_RunUnloadHandlers, 430 OnRunUnloadHandlers) 431 IPC_MESSAGE_HANDLER(AutomationMsg_SetZoomLevel, OnSetZoomLevel) 432#endif // defined(OS_WIN) 433#if defined(OS_CHROMEOS) 434 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_LoginWithUserAndPass, 435 LoginWithUserAndPass) 436#endif // defined(OS_CHROMEOS) 437 IPC_MESSAGE_UNHANDLED(OnUnhandledMessage()) 438 IPC_END_MESSAGE_MAP() 439} 440 441void AutomationProvider::OnUnhandledMessage() { 442 // We should not hang here. Print a message to indicate what's going on, 443 // and disconnect the channel to notify the caller about the error 444 // in a way it can't ignore, and make any further attempts to send 445 // messages fail fast. 446 LOG(ERROR) << "AutomationProvider received a message it can't handle. " 447 << "Please make sure that you use switches::kTestingChannelID " 448 << "for test code (TestingAutomationProvider), and " 449 << "switches::kAutomationClientChannelID for everything else " 450 << "(like ChromeFrame). Closing the automation channel."; 451 channel_->Close(); 452} 453 454// This task just adds another task to the event queue. This is useful if 455// you want to ensure that any tasks added to the event queue after this one 456// have already been processed by the time |task| is run. 457class InvokeTaskLaterTask : public Task { 458 public: 459 explicit InvokeTaskLaterTask(Task* task) : task_(task) {} 460 virtual ~InvokeTaskLaterTask() {} 461 462 virtual void Run() { 463 MessageLoop::current()->PostTask(FROM_HERE, task_); 464 } 465 466 private: 467 Task* task_; 468 469 DISALLOW_COPY_AND_ASSIGN(InvokeTaskLaterTask); 470}; 471 472void AutomationProvider::HandleUnused(const IPC::Message& message, int handle) { 473 if (window_tracker_->ContainsHandle(handle)) { 474 window_tracker_->Remove(window_tracker_->GetResource(handle)); 475 } 476} 477 478void AutomationProvider::OnChannelError() { 479 VLOG(1) << "AutomationProxy went away, shutting down app."; 480 AutomationProviderList::GetInstance()->RemoveProvider(this); 481} 482 483bool AutomationProvider::Send(IPC::Message* msg) { 484 DCHECK(channel_.get()); 485 return channel_->Send(msg); 486} 487 488Browser* AutomationProvider::FindAndActivateTab( 489 NavigationController* controller) { 490 int tab_index; 491 Browser* browser = Browser::GetBrowserForController(controller, &tab_index); 492 if (browser) 493 browser->SelectTabContentsAt(tab_index, true); 494 495 return browser; 496} 497 498void AutomationProvider::HandleFindRequest( 499 int handle, 500 const AutomationMsg_Find_Params& params, 501 IPC::Message* reply_message) { 502 if (!tab_tracker_->ContainsHandle(handle)) { 503 AutomationMsg_Find::WriteReplyParams(reply_message, -1, -1); 504 Send(reply_message); 505 return; 506 } 507 508 NavigationController* nav = tab_tracker_->GetResource(handle); 509 TabContents* tab_contents = nav->tab_contents(); 510 511 SendFindRequest(tab_contents, 512 false, 513 params.search_string, 514 params.forward, 515 params.match_case, 516 params.find_next, 517 reply_message); 518} 519 520void AutomationProvider::SendFindRequest( 521 TabContents* tab_contents, 522 bool with_json, 523 const string16& search_string, 524 bool forward, 525 bool match_case, 526 bool find_next, 527 IPC::Message* reply_message) { 528 int request_id = FindInPageNotificationObserver::kFindInPageRequestId; 529 FindInPageNotificationObserver* observer = 530 new FindInPageNotificationObserver(this, 531 tab_contents, 532 with_json, 533 reply_message); 534 if (!with_json) { 535 find_in_page_observer_.reset(observer); 536 } 537 tab_contents->set_current_find_request_id(request_id); 538 tab_contents->render_view_host()->StartFinding( 539 FindInPageNotificationObserver::kFindInPageRequestId, 540 search_string, 541 forward, 542 match_case, 543 find_next); 544} 545 546class SetProxyConfigTask : public Task { 547 public: 548 SetProxyConfigTask(URLRequestContextGetter* request_context_getter, 549 const std::string& new_proxy_config) 550 : request_context_getter_(request_context_getter), 551 proxy_config_(new_proxy_config) {} 552 virtual void Run() { 553 // First, deserialize the JSON string. If this fails, log and bail. 554 JSONStringValueSerializer deserializer(proxy_config_); 555 std::string error_msg; 556 scoped_ptr<Value> root(deserializer.Deserialize(NULL, &error_msg)); 557 if (!root.get() || root->GetType() != Value::TYPE_DICTIONARY) { 558 DLOG(WARNING) << "Received bad JSON string for ProxyConfig: " 559 << error_msg; 560 return; 561 } 562 563 scoped_ptr<DictionaryValue> dict( 564 static_cast<DictionaryValue*>(root.release())); 565 // Now put together a proxy configuration from the deserialized string. 566 net::ProxyConfig pc; 567 PopulateProxyConfig(*dict.get(), &pc); 568 569 net::ProxyService* proxy_service = 570 request_context_getter_->GetURLRequestContext()->proxy_service(); 571 DCHECK(proxy_service); 572 scoped_ptr<net::ProxyConfigService> proxy_config_service( 573 new net::ProxyConfigServiceFixed(pc)); 574 proxy_service->ResetConfigService(proxy_config_service.release()); 575 } 576 577 void PopulateProxyConfig(const DictionaryValue& dict, net::ProxyConfig* pc) { 578 DCHECK(pc); 579 bool no_proxy = false; 580 if (dict.GetBoolean(automation::kJSONProxyNoProxy, &no_proxy)) { 581 // Make no changes to the ProxyConfig. 582 return; 583 } 584 bool auto_config; 585 if (dict.GetBoolean(automation::kJSONProxyAutoconfig, &auto_config)) { 586 pc->set_auto_detect(true); 587 } 588 std::string pac_url; 589 if (dict.GetString(automation::kJSONProxyPacUrl, &pac_url)) { 590 pc->set_pac_url(GURL(pac_url)); 591 } 592 std::string proxy_bypass_list; 593 if (dict.GetString(automation::kJSONProxyBypassList, &proxy_bypass_list)) { 594 pc->proxy_rules().bypass_rules.ParseFromString(proxy_bypass_list); 595 } 596 std::string proxy_server; 597 if (dict.GetString(automation::kJSONProxyServer, &proxy_server)) { 598 pc->proxy_rules().ParseFromString(proxy_server); 599 } 600 } 601 602 private: 603 scoped_refptr<URLRequestContextGetter> request_context_getter_; 604 std::string proxy_config_; 605}; 606 607 608void AutomationProvider::SetProxyConfig(const std::string& new_proxy_config) { 609 URLRequestContextGetter* context_getter = Profile::GetDefaultRequestContext(); 610 if (!context_getter) { 611 FilePath user_data_dir; 612 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); 613 ProfileManager* profile_manager = g_browser_process->profile_manager(); 614 DCHECK(profile_manager); 615 Profile* profile = profile_manager->GetDefaultProfile(user_data_dir); 616 DCHECK(profile); 617 context_getter = profile->GetRequestContext(); 618 } 619 DCHECK(context_getter); 620 621 BrowserThread::PostTask( 622 BrowserThread::IO, FROM_HERE, 623 new SetProxyConfigTask(context_getter, new_proxy_config)); 624} 625 626TabContents* AutomationProvider::GetTabContentsForHandle( 627 int handle, NavigationController** tab) { 628 if (tab_tracker_->ContainsHandle(handle)) { 629 NavigationController* nav_controller = tab_tracker_->GetResource(handle); 630 if (tab) 631 *tab = nav_controller; 632 return nav_controller->tab_contents(); 633 } 634 return NULL; 635} 636 637// Gets the current used encoding name of the page in the specified tab. 638void AutomationProvider::OverrideEncoding(int tab_handle, 639 const std::string& encoding_name, 640 bool* success) { 641 *success = false; 642 if (tab_tracker_->ContainsHandle(tab_handle)) { 643 NavigationController* nav = tab_tracker_->GetResource(tab_handle); 644 if (!nav) 645 return; 646 Browser* browser = FindAndActivateTab(nav); 647 648 // If the browser has UI, simulate what a user would do. 649 // Activate the tab and then click the encoding menu. 650 if (browser && 651 browser->command_updater()->IsCommandEnabled(IDC_ENCODING_MENU)) { 652 int selected_encoding_id = 653 CharacterEncoding::GetCommandIdByCanonicalEncodingName(encoding_name); 654 if (selected_encoding_id) { 655 browser->OverrideEncoding(selected_encoding_id); 656 *success = true; 657 } 658 } else { 659 // There is no UI, Chrome probably runs as Chrome-Frame mode. 660 // Try to get TabContents and call its override_encoding method. 661 TabContents* contents = nav->tab_contents(); 662 if (!contents) 663 return; 664 const std::string selected_encoding = 665 CharacterEncoding::GetCanonicalEncodingNameByAliasName(encoding_name); 666 if (selected_encoding.empty()) 667 return; 668 contents->SetOverrideEncoding(selected_encoding); 669 } 670 } 671} 672 673void AutomationProvider::SelectAll(int tab_handle) { 674 RenderViewHost* view = GetViewForTab(tab_handle); 675 if (!view) { 676 NOTREACHED(); 677 return; 678 } 679 680 view->SelectAll(); 681} 682 683void AutomationProvider::Cut(int tab_handle) { 684 RenderViewHost* view = GetViewForTab(tab_handle); 685 if (!view) { 686 NOTREACHED(); 687 return; 688 } 689 690 view->Cut(); 691} 692 693void AutomationProvider::Copy(int tab_handle) { 694 RenderViewHost* view = GetViewForTab(tab_handle); 695 if (!view) { 696 NOTREACHED(); 697 return; 698 } 699 700 view->Copy(); 701} 702 703void AutomationProvider::Paste(int tab_handle) { 704 RenderViewHost* view = GetViewForTab(tab_handle); 705 if (!view) { 706 NOTREACHED(); 707 return; 708 } 709 710 view->Paste(); 711} 712 713void AutomationProvider::ReloadAsync(int tab_handle) { 714 if (tab_tracker_->ContainsHandle(tab_handle)) { 715 NavigationController* tab = tab_tracker_->GetResource(tab_handle); 716 if (!tab) { 717 NOTREACHED(); 718 return; 719 } 720 721 const bool check_for_repost = true; 722 tab->Reload(check_for_repost); 723 } 724} 725 726void AutomationProvider::StopAsync(int tab_handle) { 727 RenderViewHost* view = GetViewForTab(tab_handle); 728 if (!view) { 729 // We tolerate StopAsync being called even before a view has been created. 730 // So just log a warning instead of a NOTREACHED(). 731 DLOG(WARNING) << "StopAsync: no view for handle " << tab_handle; 732 return; 733 } 734 735 view->Stop(); 736} 737 738void AutomationProvider::OnSetPageFontSize(int tab_handle, 739 int font_size) { 740 AutomationPageFontSize automation_font_size = 741 static_cast<AutomationPageFontSize>(font_size); 742 743 if (automation_font_size < SMALLEST_FONT || 744 automation_font_size > LARGEST_FONT) { 745 DLOG(ERROR) << "Invalid font size specified : " 746 << font_size; 747 return; 748 } 749 750 if (tab_tracker_->ContainsHandle(tab_handle)) { 751 NavigationController* tab = tab_tracker_->GetResource(tab_handle); 752 DCHECK(tab != NULL); 753 if (tab && tab->tab_contents()) { 754 DCHECK(tab->tab_contents()->profile() != NULL); 755 tab->tab_contents()->profile()->GetPrefs()->SetInteger( 756 prefs::kWebKitDefaultFontSize, font_size); 757 } 758 } 759} 760 761void AutomationProvider::RemoveBrowsingData(int remove_mask) { 762 BrowsingDataRemover* remover; 763 remover = new BrowsingDataRemover(profile(), 764 BrowsingDataRemover::EVERYTHING, // All time periods. 765 base::Time()); 766 remover->Remove(remove_mask); 767 // BrowsingDataRemover deletes itself. 768} 769 770RenderViewHost* AutomationProvider::GetViewForTab(int tab_handle) { 771 if (tab_tracker_->ContainsHandle(tab_handle)) { 772 NavigationController* tab = tab_tracker_->GetResource(tab_handle); 773 if (!tab) { 774 NOTREACHED(); 775 return NULL; 776 } 777 778 TabContents* tab_contents = tab->tab_contents(); 779 if (!tab_contents) { 780 NOTREACHED(); 781 return NULL; 782 } 783 784 RenderViewHost* view_host = tab_contents->render_view_host(); 785 return view_host; 786 } 787 788 return NULL; 789} 790 791void AutomationProvider::InstallExtension(const FilePath& crx_path, 792 IPC::Message* reply_message) { 793 ExtensionsService* service = profile_->GetExtensionsService(); 794 if (service) { 795 // The observer will delete itself when done. 796 new ExtensionInstallNotificationObserver(this, 797 AutomationMsg_InstallExtension::ID, 798 reply_message); 799 800 scoped_refptr<CrxInstaller> installer( 801 new CrxInstaller(service, NULL)); // silent install, no UI 802 installer->InstallCrx(crx_path); 803 } else { 804 AutomationMsg_InstallExtension::WriteReplyParams( 805 reply_message, AUTOMATION_MSG_EXTENSION_INSTALL_FAILED); 806 Send(reply_message); 807 } 808} 809 810void AutomationProvider::LoadExpandedExtension( 811 const FilePath& extension_dir, 812 IPC::Message* reply_message) { 813 if (profile_->GetExtensionsService()) { 814 // The observer will delete itself when done. 815 new ExtensionInstallNotificationObserver( 816 this, 817 AutomationMsg_LoadExpandedExtension::ID, 818 reply_message); 819 820 profile_->GetExtensionsService()->LoadExtension(extension_dir); 821 } else { 822 AutomationMsg_LoadExpandedExtension::WriteReplyParams( 823 reply_message, AUTOMATION_MSG_EXTENSION_INSTALL_FAILED); 824 Send(reply_message); 825 } 826} 827 828void AutomationProvider::GetEnabledExtensions( 829 std::vector<FilePath>* result) { 830 ExtensionsService* service = profile_->GetExtensionsService(); 831 DCHECK(service); 832 if (service->extensions_enabled()) { 833 const ExtensionList* extensions = service->extensions(); 834 DCHECK(extensions); 835 for (size_t i = 0; i < extensions->size(); ++i) { 836 const Extension* extension = (*extensions)[i]; 837 DCHECK(extension); 838 // AutomationProvider only exposes non app internal/loaded extensions. 839 if (!extension->is_app() && 840 (extension->location() == Extension::INTERNAL || 841 extension->location() == Extension::LOAD)) { 842 result->push_back(extension->path()); 843 } 844 } 845 } 846} 847 848void AutomationProvider::WaitForExtensionTestResult( 849 IPC::Message* reply_message) { 850 DCHECK(reply_message_ == NULL); 851 reply_message_ = reply_message; 852 // Call MaybeSendResult, because the result might have come in before 853 // we were waiting on it. 854 extension_test_result_observer_->MaybeSendResult(); 855} 856 857void AutomationProvider::InstallExtensionAndGetHandle( 858 const FilePath& crx_path, bool with_ui, IPC::Message* reply_message) { 859 ExtensionsService* service = profile_->GetExtensionsService(); 860 ExtensionProcessManager* manager = profile_->GetExtensionProcessManager(); 861 if (service && manager) { 862 // The observer will delete itself when done. 863 new ExtensionReadyNotificationObserver( 864 manager, 865 this, 866 AutomationMsg_InstallExtensionAndGetHandle::ID, 867 reply_message); 868 869 ExtensionInstallUI* client = 870 (with_ui ? new ExtensionInstallUI(profile_) : NULL); 871 scoped_refptr<CrxInstaller> installer(new CrxInstaller(service, client)); 872 installer->InstallCrx(crx_path); 873 } else { 874 AutomationMsg_InstallExtensionAndGetHandle::WriteReplyParams( 875 reply_message, 0); 876 Send(reply_message); 877 } 878} 879 880void AutomationProvider::UninstallExtension(int extension_handle, 881 bool* success) { 882 *success = false; 883 const Extension* extension = GetExtension(extension_handle); 884 ExtensionsService* service = profile_->GetExtensionsService(); 885 if (extension && service) { 886 ExtensionUnloadNotificationObserver observer; 887 service->UninstallExtension(extension->id(), false); 888 // The extension unload notification should have been sent synchronously 889 // with the uninstall. Just to be safe, check that it was received. 890 *success = observer.did_receive_unload_notification(); 891 } 892} 893 894void AutomationProvider::EnableExtension(int extension_handle, 895 IPC::Message* reply_message) { 896 const Extension* extension = GetDisabledExtension(extension_handle); 897 ExtensionsService* service = profile_->GetExtensionsService(); 898 ExtensionProcessManager* manager = profile_->GetExtensionProcessManager(); 899 // Only enable if this extension is disabled. 900 if (extension && service && manager) { 901 // The observer will delete itself when done. 902 new ExtensionReadyNotificationObserver( 903 manager, 904 this, 905 AutomationMsg_EnableExtension::ID, 906 reply_message); 907 service->EnableExtension(extension->id()); 908 } else { 909 AutomationMsg_EnableExtension::WriteReplyParams(reply_message, false); 910 Send(reply_message); 911 } 912} 913 914void AutomationProvider::DisableExtension(int extension_handle, 915 bool* success) { 916 *success = false; 917 const Extension* extension = GetEnabledExtension(extension_handle); 918 ExtensionsService* service = profile_->GetExtensionsService(); 919 if (extension && service) { 920 ExtensionUnloadNotificationObserver observer; 921 service->DisableExtension(extension->id()); 922 // The extension unload notification should have been sent synchronously 923 // with the disable. Just to be safe, check that it was received. 924 *success = observer.did_receive_unload_notification(); 925 } 926} 927 928void AutomationProvider::ExecuteExtensionActionInActiveTabAsync( 929 int extension_handle, int browser_handle, 930 IPC::Message* reply_message) { 931 bool success = false; 932 const Extension* extension = GetEnabledExtension(extension_handle); 933 ExtensionsService* service = profile_->GetExtensionsService(); 934 ExtensionMessageService* message_service = 935 profile_->GetExtensionMessageService(); 936 Browser* browser = browser_tracker_->GetResource(browser_handle); 937 if (extension && service && message_service && browser) { 938 int tab_id = ExtensionTabUtil::GetTabId(browser->GetSelectedTabContents()); 939 if (extension->page_action()) { 940 ExtensionBrowserEventRouter::GetInstance()->PageActionExecuted( 941 browser->profile(), extension->id(), "action", tab_id, "", 1); 942 success = true; 943 } else if (extension->browser_action()) { 944 ExtensionBrowserEventRouter::GetInstance()->BrowserActionExecuted( 945 browser->profile(), extension->id(), browser); 946 success = true; 947 } 948 } 949 AutomationMsg_ExecuteExtensionActionInActiveTabAsync::WriteReplyParams( 950 reply_message, success); 951 Send(reply_message); 952} 953 954void AutomationProvider::MoveExtensionBrowserAction( 955 int extension_handle, int index, bool* success) { 956 *success = false; 957 const Extension* extension = GetEnabledExtension(extension_handle); 958 ExtensionsService* service = profile_->GetExtensionsService(); 959 if (extension && service) { 960 ExtensionToolbarModel* toolbar = service->toolbar_model(); 961 if (toolbar) { 962 if (index >= 0 && index < static_cast<int>(toolbar->size())) { 963 toolbar->MoveBrowserAction(extension, index); 964 *success = true; 965 } else { 966 DLOG(WARNING) << "Attempted to move browser action to invalid index."; 967 } 968 } 969 } 970} 971 972void AutomationProvider::GetExtensionProperty( 973 int extension_handle, 974 AutomationMsg_ExtensionProperty type, 975 bool* success, 976 std::string* value) { 977 *success = false; 978 const Extension* extension = GetExtension(extension_handle); 979 ExtensionsService* service = profile_->GetExtensionsService(); 980 if (extension && service) { 981 ExtensionToolbarModel* toolbar = service->toolbar_model(); 982 int found_index = -1; 983 int index = 0; 984 switch (type) { 985 case AUTOMATION_MSG_EXTENSION_ID: 986 *value = extension->id(); 987 *success = true; 988 break; 989 case AUTOMATION_MSG_EXTENSION_NAME: 990 *value = extension->name(); 991 *success = true; 992 break; 993 case AUTOMATION_MSG_EXTENSION_VERSION: 994 *value = extension->VersionString(); 995 *success = true; 996 break; 997 case AUTOMATION_MSG_EXTENSION_BROWSER_ACTION_INDEX: 998 if (toolbar) { 999 for (ExtensionList::const_iterator iter = toolbar->begin(); 1000 iter != toolbar->end(); iter++) { 1001 // Skip this extension if we are in incognito mode 1002 // and it is not incognito-enabled. 1003 if (profile_->IsOffTheRecord() && 1004 !service->IsIncognitoEnabled(*iter)) 1005 continue; 1006 if (*iter == extension) { 1007 found_index = index; 1008 break; 1009 } 1010 index++; 1011 } 1012 *value = base::IntToString(found_index); 1013 *success = true; 1014 } 1015 break; 1016 default: 1017 LOG(WARNING) << "Trying to get undefined extension property"; 1018 break; 1019 } 1020 } 1021} 1022 1023void AutomationProvider::SaveAsAsync(int tab_handle) { 1024 NavigationController* tab = NULL; 1025 TabContents* tab_contents = GetTabContentsForHandle(tab_handle, &tab); 1026 if (tab_contents) 1027 tab_contents->OnSavePage(); 1028} 1029