1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/automation/automation_provider.h" 6 7 #include <set> 8 9 #include "base/callback.h" 10 #include "base/debug/trace_event.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_number_conversions.h" 20 #include "base/string_util.h" 21 #include "base/synchronization/waitable_event.h" 22 #include "base/task.h" 23 #include "base/threading/thread.h" 24 #include "base/utf_string_conversions.h" 25 #include "base/values.h" 26 #include "chrome/app/chrome_command_ids.h" 27 #include "chrome/browser/autocomplete/autocomplete_edit.h" 28 #include "chrome/browser/autofill/autofill_manager.h" 29 #include "chrome/browser/automation/automation_autocomplete_edit_tracker.h" 30 #include "chrome/browser/automation/automation_browser_tracker.h" 31 #include "chrome/browser/automation/automation_extension_tracker.h" 32 #include "chrome/browser/automation/automation_provider_list.h" 33 #include "chrome/browser/automation/automation_provider_observers.h" 34 #include "chrome/browser/automation/automation_resource_message_filter.h" 35 #include "chrome/browser/automation/automation_tab_tracker.h" 36 #include "chrome/browser/automation/automation_window_tracker.h" 37 #include "chrome/browser/automation/ui_controls.h" 38 #include "chrome/browser/blocked_content_container.h" 39 #include "chrome/browser/bookmarks/bookmark_model.h" 40 #include "chrome/browser/bookmarks/bookmark_storage.h" 41 #include "chrome/browser/browser_process.h" 42 #include "chrome/browser/browsing_data_remover.h" 43 #include "chrome/browser/character_encoding.h" 44 #include "chrome/browser/content_settings/host_content_settings_map.h" 45 #include "chrome/browser/debugger/devtools_manager.h" 46 #include "chrome/browser/dom_operation_notification_details.h" 47 #include "chrome/browser/download/download_item.h" 48 #include "chrome/browser/download/download_shelf.h" 49 #include "chrome/browser/download/save_package.h" 50 #include "chrome/browser/extensions/crx_installer.h" 51 #include "chrome/browser/extensions/extension_browser_event_router.h" 52 #include "chrome/browser/extensions/extension_host.h" 53 #include "chrome/browser/extensions/extension_install_ui.h" 54 #include "chrome/browser/extensions/extension_message_service.h" 55 #include "chrome/browser/extensions/extension_service.h" 56 #include "chrome/browser/extensions/extension_tabs_module.h" 57 #include "chrome/browser/extensions/extension_toolbar_model.h" 58 #include "chrome/browser/extensions/user_script_master.h" 59 #include "chrome/browser/io_thread.h" 60 #include "chrome/browser/net/url_request_mock_util.h" 61 #include "chrome/browser/platform_util.h" 62 #include "chrome/browser/prefs/pref_service.h" 63 #include "chrome/browser/printing/print_job.h" 64 #include "chrome/browser/profiles/profile_manager.h" 65 #include "chrome/browser/ssl/ssl_blocking_page.h" 66 #include "chrome/browser/ssl/ssl_manager.h" 67 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h" 68 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h" 69 #include "chrome/browser/ui/browser_list.h" 70 #include "chrome/browser/ui/browser_window.h" 71 #include "chrome/browser/ui/download/download_tab_helper.h" 72 #include "chrome/browser/ui/find_bar/find_bar.h" 73 #include "chrome/browser/ui/find_bar/find_bar_controller.h" 74 #include "chrome/browser/ui/find_bar/find_notification_details.h" 75 #include "chrome/browser/ui/find_bar/find_tab_helper.h" 76 #include "chrome/browser/ui/login/login_prompt.h" 77 #include "chrome/browser/ui/omnibox/location_bar.h" 78 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 79 #include "chrome/common/automation_constants.h" 80 #include "chrome/common/automation_messages.h" 81 #include "chrome/common/chrome_constants.h" 82 #include "chrome/common/chrome_paths.h" 83 #include "chrome/common/chrome_switches.h" 84 #include "chrome/common/chrome_version_info.h" 85 #include "chrome/common/extensions/extension.h" 86 #include "chrome/common/pref_names.h" 87 #include "chrome/common/url_constants.h" 88 #include "chrome/test/automation/tab_proxy.h" 89 #include "content/browser/browser_thread.h" 90 #include "content/browser/renderer_host/render_process_host.h" 91 #include "content/browser/renderer_host/render_view_host.h" 92 #include "content/browser/tab_contents/navigation_entry.h" 93 #include "content/browser/tab_contents/tab_contents.h" 94 #include "content/browser/tab_contents/tab_contents_view.h" 95 #include "content/common/json_value_serializer.h" 96 #include "net/proxy/proxy_config_service_fixed.h" 97 #include "net/proxy/proxy_service.h" 98 #include "net/url_request/url_request_context.h" 99 #include "net/url_request/url_request_context_getter.h" 100 #include "webkit/glue/password_form.h" 101 102 #if defined(OS_WIN) 103 #include "chrome/browser/external_tab_container_win.h" 104 #endif // defined(OS_WIN) 105 106 using base::Time; 107 108 AutomationProvider::AutomationProvider(Profile* profile) 109 : profile_(profile), 110 reply_message_(NULL), 111 reinitialize_on_channel_error_(false), 112 is_connected_(false), 113 initial_tab_loads_complete_(false), 114 network_library_initialized_(true) { 115 TRACE_EVENT_BEGIN("AutomationProvider::AutomationProvider", 0, ""); 116 117 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 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 metric_event_duration_observer_.reset(new MetricEventDurationObserver()); 127 extension_test_result_observer_.reset( 128 new ExtensionTestResultNotificationObserver(this)); 129 g_browser_process->AddRefModule(); 130 131 TRACE_EVENT_END("AutomationProvider::AutomationProvider", 0, ""); 132 } 133 134 AutomationProvider::~AutomationProvider() { 135 if (channel_.get()) 136 channel_->Close(); 137 138 g_browser_process->ReleaseModule(); 139 } 140 141 bool AutomationProvider::InitializeChannel(const std::string& channel_id) { 142 TRACE_EVENT_BEGIN("AutomationProvider::InitializeChannel", 0, ""); 143 144 channel_id_ = channel_id; 145 std::string effective_channel_id = channel_id; 146 147 // If the channel_id starts with kNamedInterfacePrefix, create a named IPC 148 // server and listen on it, else connect as client to an existing IPC server 149 bool use_named_interface = 150 channel_id.find(automation::kNamedInterfacePrefix) == 0; 151 if (use_named_interface) { 152 effective_channel_id = channel_id.substr( 153 strlen(automation::kNamedInterfacePrefix)); 154 if (effective_channel_id.length() <= 0) 155 return false; 156 157 reinitialize_on_channel_error_ = true; 158 } 159 160 if (!automation_resource_message_filter_.get()) { 161 automation_resource_message_filter_ = new AutomationResourceMessageFilter; 162 } 163 164 channel_.reset(new IPC::SyncChannel( 165 effective_channel_id, 166 use_named_interface ? IPC::Channel::MODE_NAMED_SERVER 167 : IPC::Channel::MODE_CLIENT, 168 this, 169 g_browser_process->io_thread()->message_loop(), 170 true, g_browser_process->shutdown_event())); 171 channel_->AddFilter(automation_resource_message_filter_); 172 173 #if defined(OS_CHROMEOS) 174 // Wait for the network manager to initialize. 175 // The observer will delete itself when done. 176 network_library_initialized_ = false; 177 NetworkManagerInitObserver* observer = new NetworkManagerInitObserver(this); 178 if (!observer->Init()) 179 delete observer; 180 #endif 181 182 TRACE_EVENT_END("AutomationProvider::InitializeChannel", 0, ""); 183 184 return true; 185 } 186 187 std::string AutomationProvider::GetProtocolVersion() { 188 chrome::VersionInfo version_info; 189 return version_info.Version().c_str(); 190 } 191 192 void AutomationProvider::SetExpectedTabCount(size_t expected_tabs) { 193 if (expected_tabs == 0) 194 OnInitialTabLoadsComplete(); 195 else 196 initial_load_observer_.reset(new InitialLoadObserver(expected_tabs, this)); 197 } 198 199 void AutomationProvider::OnInitialTabLoadsComplete() { 200 initial_tab_loads_complete_ = true; 201 if (is_connected_ && network_library_initialized_) 202 Send(new AutomationMsg_InitialLoadsComplete()); 203 } 204 205 void AutomationProvider::OnNetworkLibraryInit() { 206 network_library_initialized_ = true; 207 if (is_connected_ && initial_tab_loads_complete_) 208 Send(new AutomationMsg_InitialLoadsComplete()); 209 } 210 211 void AutomationProvider::AddLoginHandler(NavigationController* tab, 212 LoginHandler* handler) { 213 login_handler_map_[tab] = handler; 214 } 215 216 void AutomationProvider::RemoveLoginHandler(NavigationController* tab) { 217 DCHECK(login_handler_map_[tab]); 218 login_handler_map_.erase(tab); 219 } 220 221 int AutomationProvider::GetIndexForNavigationController( 222 const NavigationController* controller, const Browser* parent) const { 223 DCHECK(parent); 224 return parent->GetIndexOfController(controller); 225 } 226 227 int AutomationProvider::AddExtension(const Extension* extension) { 228 DCHECK(extension); 229 return extension_tracker_->Add(extension); 230 } 231 232 // TODO(phajdan.jr): move to TestingAutomationProvider. 233 DictionaryValue* AutomationProvider::GetDictionaryFromDownloadItem( 234 const DownloadItem* download) { 235 std::map<DownloadItem::DownloadState, std::string> state_to_string; 236 state_to_string[DownloadItem::IN_PROGRESS] = std::string("IN_PROGRESS"); 237 state_to_string[DownloadItem::CANCELLED] = std::string("CANCELLED"); 238 state_to_string[DownloadItem::REMOVING] = std::string("REMOVING"); 239 state_to_string[DownloadItem::INTERRUPTED] = std::string("INTERRUPTED"); 240 state_to_string[DownloadItem::COMPLETE] = std::string("COMPLETE"); 241 242 std::map<DownloadItem::SafetyState, std::string> safety_state_to_string; 243 safety_state_to_string[DownloadItem::SAFE] = std::string("SAFE"); 244 safety_state_to_string[DownloadItem::DANGEROUS] = std::string("DANGEROUS"); 245 safety_state_to_string[DownloadItem::DANGEROUS_BUT_VALIDATED] = 246 std::string("DANGEROUS_BUT_VALIDATED"); 247 248 DictionaryValue* dl_item_value = new DictionaryValue; 249 dl_item_value->SetInteger("id", static_cast<int>(download->id())); 250 dl_item_value->SetString("url", download->url().spec()); 251 dl_item_value->SetString("referrer_url", download->referrer_url().spec()); 252 dl_item_value->SetString("file_name", 253 download->GetFileNameToReportUser().value()); 254 dl_item_value->SetString("full_path", 255 download->GetTargetFilePath().value()); 256 dl_item_value->SetBoolean("is_paused", download->is_paused()); 257 dl_item_value->SetBoolean("open_when_complete", 258 download->open_when_complete()); 259 dl_item_value->SetBoolean("is_extension_install", 260 download->is_extension_install()); 261 dl_item_value->SetBoolean("is_temporary", download->is_temporary()); 262 dl_item_value->SetBoolean("is_otr", download->is_otr()); // incognito 263 dl_item_value->SetString("state", state_to_string[download->state()]); 264 dl_item_value->SetString("safety_state", 265 safety_state_to_string[download->safety_state()]); 266 dl_item_value->SetInteger("PercentComplete", download->PercentComplete()); 267 268 return dl_item_value; 269 } 270 271 const Extension* AutomationProvider::GetExtension(int extension_handle) { 272 return extension_tracker_->GetResource(extension_handle); 273 } 274 275 const Extension* AutomationProvider::GetEnabledExtension(int extension_handle) { 276 const Extension* extension = 277 extension_tracker_->GetResource(extension_handle); 278 ExtensionService* service = profile_->GetExtensionService(); 279 if (extension && service && 280 service->GetExtensionById(extension->id(), false)) 281 return extension; 282 return NULL; 283 } 284 285 const Extension* AutomationProvider::GetDisabledExtension( 286 int extension_handle) { 287 const Extension* extension = 288 extension_tracker_->GetResource(extension_handle); 289 ExtensionService* service = profile_->GetExtensionService(); 290 if (extension && service && 291 service->GetExtensionById(extension->id(), true) && 292 !service->GetExtensionById(extension->id(), false)) 293 return extension; 294 return NULL; 295 } 296 297 void AutomationProvider::OnChannelConnected(int pid) { 298 is_connected_ = true; 299 LOG(INFO) << "Testing channel connected, sending hello message"; 300 301 // Send a hello message with our current automation protocol version. 302 channel_->Send(new AutomationMsg_Hello(GetProtocolVersion())); 303 if (initial_tab_loads_complete_ && network_library_initialized_) 304 Send(new AutomationMsg_InitialLoadsComplete()); 305 } 306 307 bool AutomationProvider::OnMessageReceived(const IPC::Message& message) { 308 bool handled = true; 309 bool deserialize_success = true; 310 IPC_BEGIN_MESSAGE_MAP_EX(AutomationProvider, message, deserialize_success) 311 #if !defined(OS_MACOSX) 312 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WindowDrag, 313 WindowSimulateDrag) 314 #endif // !defined(OS_MACOSX) 315 IPC_MESSAGE_HANDLER(AutomationMsg_HandleUnused, HandleUnused) 316 IPC_MESSAGE_HANDLER(AutomationMsg_SetProxyConfig, SetProxyConfig) 317 IPC_MESSAGE_HANDLER(AutomationMsg_PrintAsync, PrintAsync) 318 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_Find, HandleFindRequest) 319 IPC_MESSAGE_HANDLER(AutomationMsg_OverrideEncoding, OverrideEncoding) 320 IPC_MESSAGE_HANDLER(AutomationMsg_SelectAll, SelectAll) 321 IPC_MESSAGE_HANDLER(AutomationMsg_Cut, Cut) 322 IPC_MESSAGE_HANDLER(AutomationMsg_Copy, Copy) 323 IPC_MESSAGE_HANDLER(AutomationMsg_Paste, Paste) 324 IPC_MESSAGE_HANDLER(AutomationMsg_ReloadAsync, ReloadAsync) 325 IPC_MESSAGE_HANDLER(AutomationMsg_StopAsync, StopAsync) 326 IPC_MESSAGE_HANDLER(AutomationMsg_SetPageFontSize, OnSetPageFontSize) 327 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_InstallExtension, 328 InstallExtension) 329 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForExtensionTestResult, 330 WaitForExtensionTestResult) 331 IPC_MESSAGE_HANDLER_DELAY_REPLY( 332 AutomationMsg_InstallExtensionAndGetHandle, 333 InstallExtensionAndGetHandle) 334 IPC_MESSAGE_HANDLER(AutomationMsg_UninstallExtension, 335 UninstallExtension) 336 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_EnableExtension, 337 EnableExtension) 338 IPC_MESSAGE_HANDLER(AutomationMsg_DisableExtension, 339 DisableExtension) 340 IPC_MESSAGE_HANDLER_DELAY_REPLY( 341 AutomationMsg_ExecuteExtensionActionInActiveTabAsync, 342 ExecuteExtensionActionInActiveTabAsync) 343 IPC_MESSAGE_HANDLER(AutomationMsg_MoveExtensionBrowserAction, 344 MoveExtensionBrowserAction) 345 IPC_MESSAGE_HANDLER(AutomationMsg_GetExtensionProperty, 346 GetExtensionProperty) 347 IPC_MESSAGE_HANDLER(AutomationMsg_SaveAsAsync, SaveAsAsync) 348 IPC_MESSAGE_HANDLER(AutomationMsg_RemoveBrowsingData, RemoveBrowsingData) 349 IPC_MESSAGE_HANDLER(AutomationMsg_JavaScriptStressTestControl, 350 JavaScriptStressTestControl) 351 #if defined(OS_WIN) 352 // These are for use with external tabs. 353 IPC_MESSAGE_HANDLER(AutomationMsg_CreateExternalTab, CreateExternalTab) 354 IPC_MESSAGE_HANDLER(AutomationMsg_ProcessUnhandledAccelerator, 355 ProcessUnhandledAccelerator) 356 IPC_MESSAGE_HANDLER(AutomationMsg_SetInitialFocus, SetInitialFocus) 357 IPC_MESSAGE_HANDLER(AutomationMsg_TabReposition, OnTabReposition) 358 IPC_MESSAGE_HANDLER(AutomationMsg_ForwardContextMenuCommandToChrome, 359 OnForwardContextMenuCommandToChrome) 360 IPC_MESSAGE_HANDLER(AutomationMsg_NavigateInExternalTab, 361 NavigateInExternalTab) 362 IPC_MESSAGE_HANDLER(AutomationMsg_NavigateExternalTabAtIndex, 363 NavigateExternalTabAtIndex) 364 IPC_MESSAGE_HANDLER(AutomationMsg_ConnectExternalTab, ConnectExternalTab) 365 IPC_MESSAGE_HANDLER(AutomationMsg_HandleMessageFromExternalHost, 366 OnMessageFromExternalHost) 367 IPC_MESSAGE_HANDLER(AutomationMsg_BrowserMove, OnBrowserMoved) 368 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_RunUnloadHandlers, 369 OnRunUnloadHandlers) 370 IPC_MESSAGE_HANDLER(AutomationMsg_SetZoomLevel, OnSetZoomLevel) 371 #endif // defined(OS_WIN) 372 IPC_MESSAGE_UNHANDLED(handled = false; OnUnhandledMessage()) 373 IPC_END_MESSAGE_MAP_EX() 374 if (!deserialize_success) 375 OnMessageDeserializationFailure(); 376 return handled; 377 } 378 379 void AutomationProvider::OnUnhandledMessage() { 380 // We should not hang here. Print a message to indicate what's going on, 381 // and disconnect the channel to notify the caller about the error 382 // in a way it can't ignore, and make any further attempts to send 383 // messages fail fast. 384 LOG(ERROR) << "AutomationProvider received a message it can't handle. " 385 << "Please make sure that you use switches::kTestingChannelID " 386 << "for test code (TestingAutomationProvider), and " 387 << "switches::kAutomationClientChannelID for everything else " 388 << "(like ChromeFrame). Closing the automation channel."; 389 channel_->Close(); 390 } 391 392 void AutomationProvider::OnMessageDeserializationFailure() { 393 LOG(ERROR) << "Failed to deserialize IPC message. " 394 << "Closing the automation channel."; 395 channel_->Close(); 396 } 397 398 // This task just adds another task to the event queue. This is useful if 399 // you want to ensure that any tasks added to the event queue after this one 400 // have already been processed by the time |task| is run. 401 class InvokeTaskLaterTask : public Task { 402 public: 403 explicit InvokeTaskLaterTask(Task* task) : task_(task) {} 404 virtual ~InvokeTaskLaterTask() {} 405 406 virtual void Run() { 407 MessageLoop::current()->PostTask(FROM_HERE, task_); 408 } 409 410 private: 411 Task* task_; 412 413 DISALLOW_COPY_AND_ASSIGN(InvokeTaskLaterTask); 414 }; 415 416 void AutomationProvider::HandleUnused(const IPC::Message& message, int handle) { 417 if (window_tracker_->ContainsHandle(handle)) { 418 window_tracker_->Remove(window_tracker_->GetResource(handle)); 419 } 420 } 421 422 bool AutomationProvider::ReinitializeChannel() { 423 base::ThreadRestrictions::ScopedAllowIO allow_io; 424 425 // Make sure any old channels are cleaned up before starting up a new one. 426 channel_.reset(); 427 return InitializeChannel(channel_id_); 428 } 429 430 void AutomationProvider::OnChannelError() { 431 if (reinitialize_on_channel_error_) { 432 VLOG(1) << "AutomationProxy disconnected, resetting AutomationProvider."; 433 if (ReinitializeChannel()) 434 return; 435 VLOG(1) << "Error reinitializing AutomationProvider channel."; 436 } 437 VLOG(1) << "AutomationProxy went away, shutting down app."; 438 AutomationProviderList::GetInstance()->RemoveProvider(this); 439 } 440 441 bool AutomationProvider::Send(IPC::Message* msg) { 442 DCHECK(channel_.get()); 443 return channel_->Send(msg); 444 } 445 446 Browser* AutomationProvider::FindAndActivateTab( 447 NavigationController* controller) { 448 int tab_index; 449 Browser* browser = Browser::GetBrowserForController(controller, &tab_index); 450 if (browser) 451 browser->ActivateTabAt(tab_index, true); 452 453 return browser; 454 } 455 456 void AutomationProvider::HandleFindRequest( 457 int handle, 458 const AutomationMsg_Find_Params& params, 459 IPC::Message* reply_message) { 460 if (!tab_tracker_->ContainsHandle(handle)) { 461 AutomationMsg_Find::WriteReplyParams(reply_message, -1, -1); 462 Send(reply_message); 463 return; 464 } 465 466 NavigationController* nav = tab_tracker_->GetResource(handle); 467 TabContents* tab_contents = nav->tab_contents(); 468 469 SendFindRequest(tab_contents, 470 false, 471 params.search_string, 472 params.forward, 473 params.match_case, 474 params.find_next, 475 reply_message); 476 } 477 478 void AutomationProvider::SendFindRequest( 479 TabContents* tab_contents, 480 bool with_json, 481 const string16& search_string, 482 bool forward, 483 bool match_case, 484 bool find_next, 485 IPC::Message* reply_message) { 486 int request_id = FindInPageNotificationObserver::kFindInPageRequestId; 487 FindInPageNotificationObserver* observer = 488 new FindInPageNotificationObserver(this, 489 tab_contents, 490 with_json, 491 reply_message); 492 if (!with_json) { 493 find_in_page_observer_.reset(observer); 494 } 495 TabContentsWrapper* wrapper = 496 TabContentsWrapper::GetCurrentWrapperForContents(tab_contents); 497 if (wrapper) 498 wrapper->find_tab_helper()->set_current_find_request_id(request_id); 499 500 tab_contents->render_view_host()->StartFinding( 501 FindInPageNotificationObserver::kFindInPageRequestId, 502 search_string, 503 forward, 504 match_case, 505 find_next); 506 } 507 508 class SetProxyConfigTask : public Task { 509 public: 510 SetProxyConfigTask(net::URLRequestContextGetter* request_context_getter, 511 const std::string& new_proxy_config) 512 : request_context_getter_(request_context_getter), 513 proxy_config_(new_proxy_config) {} 514 virtual void Run() { 515 // First, deserialize the JSON string. If this fails, log and bail. 516 JSONStringValueSerializer deserializer(proxy_config_); 517 std::string error_msg; 518 scoped_ptr<Value> root(deserializer.Deserialize(NULL, &error_msg)); 519 if (!root.get() || root->GetType() != Value::TYPE_DICTIONARY) { 520 DLOG(WARNING) << "Received bad JSON string for ProxyConfig: " 521 << error_msg; 522 return; 523 } 524 525 scoped_ptr<DictionaryValue> dict( 526 static_cast<DictionaryValue*>(root.release())); 527 // Now put together a proxy configuration from the deserialized string. 528 net::ProxyConfig pc; 529 PopulateProxyConfig(*dict.get(), &pc); 530 531 net::ProxyService* proxy_service = 532 request_context_getter_->GetURLRequestContext()->proxy_service(); 533 DCHECK(proxy_service); 534 scoped_ptr<net::ProxyConfigService> proxy_config_service( 535 new net::ProxyConfigServiceFixed(pc)); 536 proxy_service->ResetConfigService(proxy_config_service.release()); 537 } 538 539 void PopulateProxyConfig(const DictionaryValue& dict, net::ProxyConfig* pc) { 540 DCHECK(pc); 541 bool no_proxy = false; 542 if (dict.GetBoolean(automation::kJSONProxyNoProxy, &no_proxy)) { 543 // Make no changes to the ProxyConfig. 544 return; 545 } 546 bool auto_config; 547 if (dict.GetBoolean(automation::kJSONProxyAutoconfig, &auto_config)) { 548 pc->set_auto_detect(true); 549 } 550 std::string pac_url; 551 if (dict.GetString(automation::kJSONProxyPacUrl, &pac_url)) { 552 pc->set_pac_url(GURL(pac_url)); 553 } 554 std::string proxy_bypass_list; 555 if (dict.GetString(automation::kJSONProxyBypassList, &proxy_bypass_list)) { 556 pc->proxy_rules().bypass_rules.ParseFromString(proxy_bypass_list); 557 } 558 std::string proxy_server; 559 if (dict.GetString(automation::kJSONProxyServer, &proxy_server)) { 560 pc->proxy_rules().ParseFromString(proxy_server); 561 } 562 } 563 564 private: 565 scoped_refptr<net::URLRequestContextGetter> request_context_getter_; 566 std::string proxy_config_; 567 }; 568 569 570 void AutomationProvider::SetProxyConfig(const std::string& new_proxy_config) { 571 net::URLRequestContextGetter* context_getter = 572 Profile::GetDefaultRequestContext(); 573 if (!context_getter) { 574 FilePath user_data_dir; 575 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); 576 ProfileManager* profile_manager = g_browser_process->profile_manager(); 577 DCHECK(profile_manager); 578 Profile* profile = profile_manager->GetDefaultProfile(user_data_dir); 579 DCHECK(profile); 580 context_getter = profile->GetRequestContext(); 581 } 582 DCHECK(context_getter); 583 584 BrowserThread::PostTask( 585 BrowserThread::IO, FROM_HERE, 586 new SetProxyConfigTask(context_getter, new_proxy_config)); 587 } 588 589 TabContents* AutomationProvider::GetTabContentsForHandle( 590 int handle, NavigationController** tab) { 591 if (tab_tracker_->ContainsHandle(handle)) { 592 NavigationController* nav_controller = tab_tracker_->GetResource(handle); 593 if (tab) 594 *tab = nav_controller; 595 return nav_controller->tab_contents(); 596 } 597 return NULL; 598 } 599 600 // Gets the current used encoding name of the page in the specified tab. 601 void AutomationProvider::OverrideEncoding(int tab_handle, 602 const std::string& encoding_name, 603 bool* success) { 604 *success = false; 605 if (tab_tracker_->ContainsHandle(tab_handle)) { 606 NavigationController* nav = tab_tracker_->GetResource(tab_handle); 607 if (!nav) 608 return; 609 Browser* browser = FindAndActivateTab(nav); 610 611 // If the browser has UI, simulate what a user would do. 612 // Activate the tab and then click the encoding menu. 613 if (browser && 614 browser->command_updater()->IsCommandEnabled(IDC_ENCODING_MENU)) { 615 int selected_encoding_id = 616 CharacterEncoding::GetCommandIdByCanonicalEncodingName(encoding_name); 617 if (selected_encoding_id) { 618 browser->OverrideEncoding(selected_encoding_id); 619 *success = true; 620 } 621 } else { 622 // There is no UI, Chrome probably runs as Chrome-Frame mode. 623 // Try to get TabContents and call its override_encoding method. 624 TabContents* contents = nav->tab_contents(); 625 if (!contents) 626 return; 627 const std::string selected_encoding = 628 CharacterEncoding::GetCanonicalEncodingNameByAliasName(encoding_name); 629 if (selected_encoding.empty()) 630 return; 631 contents->SetOverrideEncoding(selected_encoding); 632 } 633 } 634 } 635 636 void AutomationProvider::SelectAll(int tab_handle) { 637 RenderViewHost* view = GetViewForTab(tab_handle); 638 if (!view) { 639 NOTREACHED(); 640 return; 641 } 642 643 view->SelectAll(); 644 } 645 646 void AutomationProvider::Cut(int tab_handle) { 647 RenderViewHost* view = GetViewForTab(tab_handle); 648 if (!view) { 649 NOTREACHED(); 650 return; 651 } 652 653 view->Cut(); 654 } 655 656 void AutomationProvider::Copy(int tab_handle) { 657 RenderViewHost* view = GetViewForTab(tab_handle); 658 if (!view) { 659 NOTREACHED(); 660 return; 661 } 662 663 view->Copy(); 664 } 665 666 void AutomationProvider::Paste(int tab_handle) { 667 RenderViewHost* view = GetViewForTab(tab_handle); 668 if (!view) { 669 NOTREACHED(); 670 return; 671 } 672 673 view->Paste(); 674 } 675 676 void AutomationProvider::ReloadAsync(int tab_handle) { 677 if (tab_tracker_->ContainsHandle(tab_handle)) { 678 NavigationController* tab = tab_tracker_->GetResource(tab_handle); 679 if (!tab) { 680 NOTREACHED(); 681 return; 682 } 683 684 const bool check_for_repost = true; 685 tab->Reload(check_for_repost); 686 } 687 } 688 689 void AutomationProvider::StopAsync(int tab_handle) { 690 RenderViewHost* view = GetViewForTab(tab_handle); 691 if (!view) { 692 // We tolerate StopAsync being called even before a view has been created. 693 // So just log a warning instead of a NOTREACHED(). 694 DLOG(WARNING) << "StopAsync: no view for handle " << tab_handle; 695 return; 696 } 697 698 view->Stop(); 699 } 700 701 void AutomationProvider::OnSetPageFontSize(int tab_handle, 702 int font_size) { 703 AutomationPageFontSize automation_font_size = 704 static_cast<AutomationPageFontSize>(font_size); 705 706 if (automation_font_size < SMALLEST_FONT || 707 automation_font_size > LARGEST_FONT) { 708 DLOG(ERROR) << "Invalid font size specified : " 709 << font_size; 710 return; 711 } 712 713 if (tab_tracker_->ContainsHandle(tab_handle)) { 714 NavigationController* tab = tab_tracker_->GetResource(tab_handle); 715 DCHECK(tab != NULL); 716 if (tab && tab->tab_contents()) { 717 DCHECK(tab->tab_contents()->profile() != NULL); 718 tab->tab_contents()->profile()->GetPrefs()->SetInteger( 719 prefs::kWebKitDefaultFontSize, font_size); 720 } 721 } 722 } 723 724 void AutomationProvider::RemoveBrowsingData(int remove_mask) { 725 BrowsingDataRemover* remover; 726 remover = new BrowsingDataRemover(profile(), 727 BrowsingDataRemover::EVERYTHING, // All time periods. 728 base::Time()); 729 remover->Remove(remove_mask); 730 // BrowsingDataRemover deletes itself. 731 } 732 733 void AutomationProvider::JavaScriptStressTestControl(int tab_handle, 734 int cmd, 735 int param) { 736 RenderViewHost* view = GetViewForTab(tab_handle); 737 if (!view) { 738 NOTREACHED(); 739 return; 740 } 741 742 view->JavaScriptStressTestControl(cmd, param); 743 } 744 745 RenderViewHost* AutomationProvider::GetViewForTab(int tab_handle) { 746 if (tab_tracker_->ContainsHandle(tab_handle)) { 747 NavigationController* tab = tab_tracker_->GetResource(tab_handle); 748 if (!tab) { 749 NOTREACHED(); 750 return NULL; 751 } 752 753 TabContents* tab_contents = tab->tab_contents(); 754 if (!tab_contents) { 755 NOTREACHED(); 756 return NULL; 757 } 758 759 RenderViewHost* view_host = tab_contents->render_view_host(); 760 return view_host; 761 } 762 763 return NULL; 764 } 765 766 void AutomationProvider::InstallExtension(const FilePath& crx_path, 767 IPC::Message* reply_message) { 768 ExtensionService* service = profile_->GetExtensionService(); 769 if (service) { 770 // The observer will delete itself when done. 771 new ExtensionInstallNotificationObserver(this, 772 AutomationMsg_InstallExtension::ID, 773 reply_message); 774 775 scoped_refptr<CrxInstaller> installer( 776 new CrxInstaller(service, NULL)); // silent install, no UI 777 installer->InstallCrx(crx_path); 778 } else { 779 AutomationMsg_InstallExtension::WriteReplyParams( 780 reply_message, AUTOMATION_MSG_EXTENSION_INSTALL_FAILED); 781 Send(reply_message); 782 } 783 } 784 785 void AutomationProvider::WaitForExtensionTestResult( 786 IPC::Message* reply_message) { 787 DCHECK(!reply_message_); 788 reply_message_ = reply_message; 789 // Call MaybeSendResult, because the result might have come in before 790 // we were waiting on it. 791 extension_test_result_observer_->MaybeSendResult(); 792 } 793 794 void AutomationProvider::InstallExtensionAndGetHandle( 795 const FilePath& crx_path, bool with_ui, IPC::Message* reply_message) { 796 ExtensionService* service = profile_->GetExtensionService(); 797 ExtensionProcessManager* manager = profile_->GetExtensionProcessManager(); 798 if (service && manager) { 799 // The observer will delete itself when done. 800 new ExtensionReadyNotificationObserver( 801 manager, 802 this, 803 AutomationMsg_InstallExtensionAndGetHandle::ID, 804 reply_message); 805 806 ExtensionInstallUI* client = 807 (with_ui ? new ExtensionInstallUI(profile_) : NULL); 808 scoped_refptr<CrxInstaller> installer(new CrxInstaller(service, client)); 809 installer->InstallCrx(crx_path); 810 } else { 811 AutomationMsg_InstallExtensionAndGetHandle::WriteReplyParams( 812 reply_message, 0); 813 Send(reply_message); 814 } 815 } 816 817 void AutomationProvider::UninstallExtension(int extension_handle, 818 bool* success) { 819 *success = false; 820 const Extension* extension = GetExtension(extension_handle); 821 ExtensionService* service = profile_->GetExtensionService(); 822 if (extension && service) { 823 ExtensionUnloadNotificationObserver observer; 824 service->UninstallExtension(extension->id(), false, NULL); 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 831 void AutomationProvider::EnableExtension(int extension_handle, 832 IPC::Message* reply_message) { 833 const Extension* extension = GetDisabledExtension(extension_handle); 834 ExtensionService* service = profile_->GetExtensionService(); 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 851 void AutomationProvider::DisableExtension(int extension_handle, 852 bool* success) { 853 *success = false; 854 const Extension* extension = GetEnabledExtension(extension_handle); 855 ExtensionService* service = profile_->GetExtensionService(); 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 865 void AutomationProvider::ExecuteExtensionActionInActiveTabAsync( 866 int extension_handle, int browser_handle, 867 IPC::Message* reply_message) { 868 bool success = false; 869 const Extension* extension = GetEnabledExtension(extension_handle); 870 ExtensionService* service = profile_->GetExtensionService(); 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 service->browser_event_router()->PageActionExecuted( 878 browser->profile(), extension->id(), "action", tab_id, "", 1); 879 success = true; 880 } else if (extension->browser_action()) { 881 service->browser_event_router()->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 891 void AutomationProvider::MoveExtensionBrowserAction( 892 int extension_handle, int index, bool* success) { 893 *success = false; 894 const Extension* extension = GetEnabledExtension(extension_handle); 895 ExtensionService* service = profile_->GetExtensionService(); 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 909 void AutomationProvider::GetExtensionProperty( 910 int extension_handle, 911 AutomationMsg_ExtensionProperty type, 912 bool* success, 913 std::string* value) { 914 *success = false; 915 const Extension* extension = GetExtension(extension_handle); 916 ExtensionService* service = profile_->GetExtensionService(); 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)->id())) 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 960 void AutomationProvider::SaveAsAsync(int tab_handle) { 961 NavigationController* tab = NULL; 962 TabContents* tab_contents = GetTabContentsForHandle(tab_handle, &tab); 963 if (tab_contents) { 964 TabContentsWrapper* wrapper = 965 TabContentsWrapper::GetCurrentWrapperForContents(tab_contents); 966 wrapper->download_tab_helper()->OnSavePage(); 967 } 968 } 969