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