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