1 // Copyright (c) 2012 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/bind.h" 10 #include "base/callback.h" 11 #include "base/command_line.h" 12 #include "base/debug/trace_event.h" 13 #include "base/files/file_path.h" 14 #include "base/json/json_reader.h" 15 #include "base/json/json_string_value_serializer.h" 16 #include "base/json/json_writer.h" 17 #include "base/json/string_escape.h" 18 #include "base/message_loop/message_loop.h" 19 #include "base/path_service.h" 20 #include "base/prefs/pref_service.h" 21 #include "base/stl_util.h" 22 #include "base/strings/string_number_conversions.h" 23 #include "base/strings/string_util.h" 24 #include "base/strings/utf_string_conversions.h" 25 #include "base/synchronization/waitable_event.h" 26 #include "base/threading/thread.h" 27 #include "base/values.h" 28 #include "chrome/app/chrome_command_ids.h" 29 #include "chrome/browser/automation/automation_browser_tracker.h" 30 #include "chrome/browser/automation/automation_provider_list.h" 31 #include "chrome/browser/automation/automation_provider_observers.h" 32 #include "chrome/browser/automation/automation_resource_message_filter.h" 33 #include "chrome/browser/automation/automation_tab_tracker.h" 34 #include "chrome/browser/automation/automation_window_tracker.h" 35 #include "chrome/browser/browser_process.h" 36 #include "chrome/browser/browsing_data/browsing_data_helper.h" 37 #include "chrome/browser/browsing_data/browsing_data_remover.h" 38 #include "chrome/browser/character_encoding.h" 39 #include "chrome/browser/content_settings/host_content_settings_map.h" 40 #include "chrome/browser/net/url_request_mock_util.h" 41 #include "chrome/browser/printing/print_job.h" 42 #include "chrome/browser/profiles/profile_manager.h" 43 #include "chrome/browser/ssl/ssl_blocking_page.h" 44 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h" 45 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h" 46 #include "chrome/browser/ui/browser_commands.h" 47 #include "chrome/browser/ui/browser_finder.h" 48 #include "chrome/browser/ui/browser_tabstrip.h" 49 #include "chrome/browser/ui/browser_window.h" 50 #include "chrome/browser/ui/find_bar/find_bar.h" 51 #include "chrome/browser/ui/find_bar/find_bar_controller.h" 52 #include "chrome/browser/ui/find_bar/find_notification_details.h" 53 #include "chrome/browser/ui/find_bar/find_tab_helper.h" 54 #include "chrome/browser/ui/login/login_prompt.h" 55 #include "chrome/browser/ui/omnibox/location_bar.h" 56 #include "chrome/common/automation_constants.h" 57 #include "chrome/common/automation_messages.h" 58 #include "chrome/common/chrome_constants.h" 59 #include "chrome/common/chrome_paths.h" 60 #include "chrome/common/chrome_switches.h" 61 #include "chrome/common/chrome_version_info.h" 62 #include "chrome/common/pref_names.h" 63 #include "chrome/common/render_messages.h" 64 #include "chrome/common/url_constants.h" 65 #include "content/public/browser/browser_thread.h" 66 #include "content/public/browser/download_item.h" 67 #include "content/public/browser/native_web_keyboard_event.h" 68 #include "content/public/browser/render_view_host.h" 69 #include "content/public/browser/tracing_controller.h" 70 #include "content/public/browser/web_contents.h" 71 #include "content/public/browser/web_contents_view.h" 72 #include "net/proxy/proxy_config_service_fixed.h" 73 #include "net/proxy/proxy_service.h" 74 #include "net/url_request/url_request_context.h" 75 #include "net/url_request/url_request_context_getter.h" 76 #include "third_party/WebKit/public/web/WebFindOptions.h" 77 78 #if defined(OS_CHROMEOS) 79 #include "chromeos/chromeos_switches.h" 80 #include "chromeos/login/login_state.h" 81 #endif // defined(OS_CHROMEOS) 82 83 using blink::WebFindOptions; 84 using base::Time; 85 using content::BrowserThread; 86 using content::DownloadItem; 87 using content::NavigationController; 88 using content::RenderViewHost; 89 using content::TracingController; 90 using content::WebContents; 91 92 namespace { 93 94 void PopulateProxyConfig(const DictionaryValue& dict, net::ProxyConfig* pc) { 95 DCHECK(pc); 96 bool no_proxy = false; 97 if (dict.GetBoolean(automation::kJSONProxyNoProxy, &no_proxy)) { 98 // Make no changes to the ProxyConfig. 99 return; 100 } 101 bool auto_config; 102 if (dict.GetBoolean(automation::kJSONProxyAutoconfig, &auto_config)) { 103 pc->set_auto_detect(true); 104 } 105 std::string pac_url; 106 if (dict.GetString(automation::kJSONProxyPacUrl, &pac_url)) { 107 pc->set_pac_url(GURL(pac_url)); 108 } 109 bool pac_mandatory; 110 if (dict.GetBoolean(automation::kJSONProxyPacMandatory, &pac_mandatory)) { 111 pc->set_pac_mandatory(pac_mandatory); 112 } 113 std::string proxy_bypass_list; 114 if (dict.GetString(automation::kJSONProxyBypassList, &proxy_bypass_list)) { 115 pc->proxy_rules().bypass_rules.ParseFromString(proxy_bypass_list); 116 } 117 std::string proxy_server; 118 if (dict.GetString(automation::kJSONProxyServer, &proxy_server)) { 119 pc->proxy_rules().ParseFromString(proxy_server); 120 } 121 } 122 123 void SetProxyConfigCallback( 124 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter, 125 const std::string& proxy_config) { 126 // First, deserialize the JSON string. If this fails, log and bail. 127 JSONStringValueSerializer deserializer(proxy_config); 128 std::string error_msg; 129 scoped_ptr<Value> root(deserializer.Deserialize(NULL, &error_msg)); 130 if (!root.get() || root->GetType() != Value::TYPE_DICTIONARY) { 131 DLOG(WARNING) << "Received bad JSON string for ProxyConfig: " 132 << error_msg; 133 return; 134 } 135 136 scoped_ptr<DictionaryValue> dict( 137 static_cast<DictionaryValue*>(root.release())); 138 // Now put together a proxy configuration from the deserialized string. 139 net::ProxyConfig pc; 140 PopulateProxyConfig(*dict.get(), &pc); 141 142 net::ProxyService* proxy_service = 143 request_context_getter->GetURLRequestContext()->proxy_service(); 144 DCHECK(proxy_service); 145 scoped_ptr<net::ProxyConfigService> proxy_config_service( 146 new net::ProxyConfigServiceFixed(pc)); 147 proxy_service->ResetConfigService(proxy_config_service.release()); 148 } 149 150 } // namespace 151 152 AutomationProvider::AutomationProvider(Profile* profile) 153 : profile_(profile), 154 reply_message_(NULL), 155 reinitialize_on_channel_error_( 156 CommandLine::ForCurrentProcess()->HasSwitch( 157 switches::kAutomationReinitializeOnChannelError)), 158 use_initial_load_observers_(true), 159 is_connected_(false), 160 initial_tab_loads_complete_(false), 161 login_webui_ready_(true) { 162 TRACE_EVENT_BEGIN_ETW("AutomationProvider::AutomationProvider", 0, ""); 163 164 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 165 166 browser_tracker_.reset(new AutomationBrowserTracker(this)); 167 tab_tracker_.reset(new AutomationTabTracker(this)); 168 window_tracker_.reset(new AutomationWindowTracker(this)); 169 new_tab_ui_load_observer_.reset(new NewTabUILoadObserver(this, profile)); 170 metric_event_duration_observer_.reset(new MetricEventDurationObserver()); 171 172 TRACE_EVENT_END_ETW("AutomationProvider::AutomationProvider", 0, ""); 173 } 174 175 AutomationProvider::~AutomationProvider() { 176 if (channel_.get()) 177 channel_->Close(); 178 } 179 180 void AutomationProvider::set_profile(Profile* profile) { 181 profile_ = profile; 182 } 183 184 bool AutomationProvider::InitializeChannel(const std::string& channel_id) { 185 TRACE_EVENT_BEGIN_ETW("AutomationProvider::InitializeChannel", 0, ""); 186 187 channel_id_ = channel_id; 188 std::string effective_channel_id = channel_id; 189 190 // If the channel_id starts with kNamedInterfacePrefix, create a named IPC 191 // server and listen on it, else connect as client to an existing IPC server 192 bool use_named_interface = 193 channel_id.find(automation::kNamedInterfacePrefix) == 0; 194 if (use_named_interface) { 195 effective_channel_id = channel_id.substr( 196 strlen(automation::kNamedInterfacePrefix)); 197 if (effective_channel_id.length() <= 0) 198 return false; 199 200 reinitialize_on_channel_error_ = true; 201 } 202 203 if (!automation_resource_message_filter_.get()) { 204 automation_resource_message_filter_ = new AutomationResourceMessageFilter; 205 } 206 207 channel_.reset(new IPC::ChannelProxy( 208 effective_channel_id, 209 GetChannelMode(use_named_interface), 210 this, 211 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO).get())); 212 channel_->AddFilter(automation_resource_message_filter_.get()); 213 214 #if defined(OS_CHROMEOS) 215 if (use_initial_load_observers_) { 216 // Wait for webui login to be ready. 217 // Observer will delete itself. 218 if (CommandLine::ForCurrentProcess()->HasSwitch( 219 chromeos::switches::kLoginManager) && 220 !chromeos::LoginState::Get()->IsUserLoggedIn()) { 221 login_webui_ready_ = false; 222 new OOBEWebuiReadyObserver(this); 223 } 224 } 225 #endif 226 227 TRACE_EVENT_END_ETW("AutomationProvider::InitializeChannel", 0, ""); 228 229 return true; 230 } 231 232 IPC::Channel::Mode AutomationProvider::GetChannelMode( 233 bool use_named_interface) { 234 if (use_named_interface) 235 return IPC::Channel::MODE_NAMED_SERVER; 236 else 237 return IPC::Channel::MODE_CLIENT; 238 } 239 240 std::string AutomationProvider::GetProtocolVersion() { 241 chrome::VersionInfo version_info; 242 return version_info.Version().c_str(); 243 } 244 245 void AutomationProvider::SetExpectedTabCount(size_t expected_tabs) { 246 VLOG(2) << "SetExpectedTabCount:" << expected_tabs; 247 if (expected_tabs == 0) 248 OnInitialTabLoadsComplete(); 249 else 250 initial_load_observer_.reset(new InitialLoadObserver(expected_tabs, this)); 251 } 252 253 void AutomationProvider::OnInitialTabLoadsComplete() { 254 initial_tab_loads_complete_ = true; 255 VLOG(2) << "OnInitialTabLoadsComplete"; 256 SendInitialLoadMessage(); 257 } 258 259 void AutomationProvider::OnOOBEWebuiReady() { 260 login_webui_ready_ = true; 261 VLOG(2) << "OnOOBEWebuiReady"; 262 SendInitialLoadMessage(); 263 } 264 265 void AutomationProvider::SendInitialLoadMessage() { 266 if (is_connected_ && initial_tab_loads_complete_ && login_webui_ready_) { 267 VLOG(2) << "Initial loads complete; sending initial loads message."; 268 Send(new AutomationMsg_InitialLoadsComplete()); 269 } 270 } 271 272 void AutomationProvider::DisableInitialLoadObservers() { 273 use_initial_load_observers_ = false; 274 OnInitialTabLoadsComplete(); 275 OnOOBEWebuiReady(); 276 } 277 278 int AutomationProvider::GetIndexForNavigationController( 279 const NavigationController* controller, const Browser* parent) const { 280 DCHECK(parent); 281 return parent->tab_strip_model()->GetIndexOfWebContents( 282 controller->GetWebContents()); 283 } 284 285 // TODO(phajdan.jr): move to TestingAutomationProvider. 286 DictionaryValue* AutomationProvider::GetDictionaryFromDownloadItem( 287 const DownloadItem* download, bool incognito) { 288 const char *download_state_string = NULL; 289 switch (download->GetState()) { 290 case DownloadItem::IN_PROGRESS: 291 download_state_string = "IN_PROGRESS"; 292 break; 293 case DownloadItem::CANCELLED: 294 download_state_string = "CANCELLED"; 295 break; 296 case DownloadItem::INTERRUPTED: 297 download_state_string = "INTERRUPTED"; 298 break; 299 case DownloadItem::COMPLETE: 300 download_state_string = "COMPLETE"; 301 break; 302 case DownloadItem::MAX_DOWNLOAD_STATE: 303 NOTREACHED(); 304 download_state_string = "UNKNOWN"; 305 break; 306 } 307 DCHECK(download_state_string); 308 if (!download_state_string) 309 download_state_string = "UNKNOWN"; 310 311 const char* download_danger_type_string = NULL; 312 switch (download->GetDangerType()) { 313 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS: 314 download_danger_type_string = "NOT_DANGEROUS"; 315 break; 316 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: 317 download_danger_type_string = "DANGEROUS_FILE"; 318 break; 319 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: 320 download_danger_type_string = "DANGEROUS_URL"; 321 break; 322 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: 323 download_danger_type_string = "DANGEROUS_CONTENT"; 324 break; 325 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT: 326 download_danger_type_string = "MAYBE_DANGEROUS_CONTENT"; 327 break; 328 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: 329 download_danger_type_string = "UNCOMMON_CONTENT"; 330 break; 331 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED: 332 download_danger_type_string = "USER_VALIDATED"; 333 break; 334 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: 335 download_danger_type_string = "DANGEROUS_HOST"; 336 break; 337 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: 338 download_danger_type_string = "POTENTIALLY_UNWANTED"; 339 break; 340 case content::DOWNLOAD_DANGER_TYPE_MAX: 341 NOTREACHED(); 342 download_danger_type_string = "UNKNOWN"; 343 break; 344 } 345 DCHECK(download_danger_type_string); 346 if (!download_danger_type_string) 347 download_danger_type_string = "UNKNOWN"; 348 349 DictionaryValue* dl_item_value = new DictionaryValue; 350 dl_item_value->SetInteger("id", static_cast<int>(download->GetId())); 351 dl_item_value->SetString("url", download->GetURL().spec()); 352 dl_item_value->SetString("referrer_url", download->GetReferrerUrl().spec()); 353 dl_item_value->SetString("file_name", 354 download->GetFileNameToReportUser().value()); 355 dl_item_value->SetString("full_path", 356 download->GetTargetFilePath().value()); 357 dl_item_value->SetBoolean("is_paused", download->IsPaused()); 358 dl_item_value->SetBoolean("open_when_complete", 359 download->GetOpenWhenComplete()); 360 dl_item_value->SetBoolean("is_temporary", download->IsTemporary()); 361 dl_item_value->SetBoolean("is_otr", incognito); 362 dl_item_value->SetString("state", download_state_string); 363 dl_item_value->SetString("danger_type", download_danger_type_string); 364 dl_item_value->SetInteger("PercentComplete", download->PercentComplete()); 365 366 return dl_item_value; 367 } 368 369 void AutomationProvider::OnChannelConnected(int pid) { 370 is_connected_ = true; 371 372 // Send a hello message with our current automation protocol version. 373 VLOG(2) << "Testing channel connected, sending hello message"; 374 channel_->Send(new AutomationMsg_Hello(GetProtocolVersion())); 375 376 SendInitialLoadMessage(); 377 } 378 379 bool AutomationProvider::OnMessageReceived(const IPC::Message& message) { 380 bool handled = true; 381 bool deserialize_success = true; 382 IPC_BEGIN_MESSAGE_MAP_EX(AutomationProvider, message, deserialize_success) 383 IPC_MESSAGE_HANDLER(AutomationMsg_HandleUnused, HandleUnused) 384 IPC_MESSAGE_HANDLER(AutomationMsg_SetProxyConfig, SetProxyConfig) 385 IPC_MESSAGE_HANDLER(AutomationMsg_PrintAsync, PrintAsync) 386 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_Find, HandleFindRequest) 387 IPC_MESSAGE_HANDLER(AutomationMsg_OverrideEncoding, OverrideEncoding) 388 IPC_MESSAGE_HANDLER(AutomationMsg_SelectAll, SelectAll) 389 IPC_MESSAGE_HANDLER(AutomationMsg_Cut, Cut) 390 IPC_MESSAGE_HANDLER(AutomationMsg_Copy, Copy) 391 IPC_MESSAGE_HANDLER(AutomationMsg_Paste, Paste) 392 IPC_MESSAGE_HANDLER(AutomationMsg_ReloadAsync, ReloadAsync) 393 IPC_MESSAGE_HANDLER(AutomationMsg_StopAsync, StopAsync) 394 IPC_MESSAGE_HANDLER(AutomationMsg_SetPageFontSize, OnSetPageFontSize) 395 IPC_MESSAGE_HANDLER(AutomationMsg_SaveAsAsync, SaveAsAsync) 396 IPC_MESSAGE_HANDLER(AutomationMsg_RemoveBrowsingData, RemoveBrowsingData) 397 IPC_MESSAGE_HANDLER(AutomationMsg_JavaScriptStressTestControl, 398 JavaScriptStressTestControl) 399 IPC_MESSAGE_HANDLER(AutomationMsg_BeginTracing, BeginTracing) 400 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_EndTracing, EndTracing) 401 #if defined(OS_WIN) 402 // These are for use with external tabs. 403 IPC_MESSAGE_HANDLER(AutomationMsg_CreateExternalTab, CreateExternalTab) 404 IPC_MESSAGE_HANDLER(AutomationMsg_ProcessUnhandledAccelerator, 405 ProcessUnhandledAccelerator) 406 IPC_MESSAGE_HANDLER(AutomationMsg_SetInitialFocus, SetInitialFocus) 407 IPC_MESSAGE_HANDLER(AutomationMsg_TabReposition, OnTabReposition) 408 IPC_MESSAGE_HANDLER(AutomationMsg_ForwardContextMenuCommandToChrome, 409 OnForwardContextMenuCommandToChrome) 410 IPC_MESSAGE_HANDLER(AutomationMsg_NavigateInExternalTab, 411 NavigateInExternalTab) 412 IPC_MESSAGE_HANDLER(AutomationMsg_NavigateExternalTabAtIndex, 413 NavigateExternalTabAtIndex) 414 IPC_MESSAGE_HANDLER(AutomationMsg_ConnectExternalTab, ConnectExternalTab) 415 IPC_MESSAGE_HANDLER(AutomationMsg_HandleMessageFromExternalHost, 416 OnMessageFromExternalHost) 417 IPC_MESSAGE_HANDLER(AutomationMsg_BrowserMove, OnBrowserMoved) 418 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_RunUnloadHandlers, 419 OnRunUnloadHandlers) 420 IPC_MESSAGE_HANDLER(AutomationMsg_SetZoomLevel, OnSetZoomLevel) 421 #endif // defined(OS_WIN) 422 IPC_MESSAGE_UNHANDLED(handled = false) 423 IPC_END_MESSAGE_MAP_EX() 424 if (!handled) 425 OnUnhandledMessage(message); 426 if (!deserialize_success) 427 OnMessageDeserializationFailure(); 428 return handled; 429 } 430 431 void AutomationProvider::OnUnhandledMessage(const IPC::Message& message) { 432 // We should not hang here. Print a message to indicate what's going on, 433 // and disconnect the channel to notify the caller about the error 434 // in a way it can't ignore, and make any further attempts to send 435 // messages fail fast. 436 LOG(ERROR) << "AutomationProvider received a message it can't handle. " 437 << "Message type: " << message.type() 438 << ", routing ID: " << message.routing_id() << ". " 439 << "Please make sure that you use switches::kTestingChannelID " 440 << "for test code (TestingAutomationProvider), and " 441 << "switches::kAutomationClientChannelID for everything else " 442 << "(like ChromeFrame). Closing the automation channel."; 443 channel_->Close(); 444 } 445 446 void AutomationProvider::OnMessageDeserializationFailure() { 447 LOG(ERROR) << "Failed to deserialize IPC message. " 448 << "Closing the automation channel."; 449 channel_->Close(); 450 } 451 452 void AutomationProvider::HandleUnused(const IPC::Message& message, int handle) { 453 if (window_tracker_->ContainsHandle(handle)) { 454 window_tracker_->Remove(window_tracker_->GetResource(handle)); 455 } 456 } 457 458 bool AutomationProvider::ReinitializeChannel() { 459 base::ThreadRestrictions::ScopedAllowIO allow_io; 460 461 // Make sure any old channels are cleaned up before starting up a new one. 462 channel_.reset(); 463 return InitializeChannel(channel_id_); 464 } 465 466 void AutomationProvider::OnChannelError() { 467 if (reinitialize_on_channel_error_) { 468 VLOG(1) << "AutomationProxy disconnected, resetting AutomationProvider."; 469 if (ReinitializeChannel()) 470 return; 471 VLOG(1) << "Error reinitializing AutomationProvider channel."; 472 } 473 VLOG(1) << "AutomationProxy went away, shutting down app."; 474 g_browser_process->GetAutomationProviderList()->RemoveProvider(this); 475 } 476 477 bool AutomationProvider::Send(IPC::Message* msg) { 478 DCHECK(channel_.get()); 479 return channel_->Send(msg); 480 } 481 482 Browser* AutomationProvider::FindAndActivateTab( 483 NavigationController* controller) { 484 content::WebContentsDelegate* d = controller->GetWebContents()->GetDelegate(); 485 if (d) 486 d->ActivateContents(controller->GetWebContents()); 487 return chrome::FindBrowserWithWebContents(controller->GetWebContents()); 488 } 489 490 void AutomationProvider::HandleFindRequest( 491 int handle, 492 const AutomationMsg_Find_Params& params, 493 IPC::Message* reply_message) { 494 if (!tab_tracker_->ContainsHandle(handle)) { 495 AutomationMsg_Find::WriteReplyParams(reply_message, -1, -1); 496 Send(reply_message); 497 return; 498 } 499 500 NavigationController* nav = tab_tracker_->GetResource(handle); 501 WebContents* web_contents = nav->GetWebContents(); 502 503 SendFindRequest(web_contents, 504 false, 505 params.search_string, 506 params.forward, 507 params.match_case, 508 params.find_next, 509 reply_message); 510 } 511 512 void AutomationProvider::SendFindRequest( 513 WebContents* web_contents, 514 bool with_json, 515 const base::string16& search_string, 516 bool forward, 517 bool match_case, 518 bool find_next, 519 IPC::Message* reply_message) { 520 int request_id = FindInPageNotificationObserver::kFindInPageRequestId; 521 FindInPageNotificationObserver* observer = 522 new FindInPageNotificationObserver(this, 523 web_contents, 524 with_json, 525 reply_message); 526 if (!with_json) { 527 find_in_page_observer_.reset(observer); 528 } 529 FindTabHelper* find_tab_helper = FindTabHelper::FromWebContents(web_contents); 530 if (find_tab_helper) 531 find_tab_helper->set_current_find_request_id(request_id); 532 533 WebFindOptions options; 534 options.forward = forward; 535 options.matchCase = match_case; 536 options.findNext = find_next; 537 web_contents->GetRenderViewHost()->Find( 538 FindInPageNotificationObserver::kFindInPageRequestId, search_string, 539 options); 540 } 541 542 void AutomationProvider::SetProxyConfig(const std::string& new_proxy_config) { 543 net::URLRequestContextGetter* context_getter = 544 profile_->GetRequestContext(); 545 DCHECK(context_getter); 546 547 BrowserThread::PostTask( 548 BrowserThread::IO, FROM_HERE, 549 base::Bind(SetProxyConfigCallback, make_scoped_refptr(context_getter), 550 new_proxy_config)); 551 } 552 553 WebContents* AutomationProvider::GetWebContentsForHandle( 554 int handle, NavigationController** tab) { 555 if (tab_tracker_->ContainsHandle(handle)) { 556 NavigationController* nav_controller = tab_tracker_->GetResource(handle); 557 if (tab) 558 *tab = nav_controller; 559 return nav_controller->GetWebContents(); 560 } 561 return NULL; 562 } 563 564 // Gets the current used encoding name of the page in the specified tab. 565 void AutomationProvider::OverrideEncoding(int tab_handle, 566 const std::string& encoding_name, 567 bool* success) { 568 *success = false; 569 if (tab_tracker_->ContainsHandle(tab_handle)) { 570 NavigationController* nav = tab_tracker_->GetResource(tab_handle); 571 if (!nav) 572 return; 573 Browser* browser = FindAndActivateTab(nav); 574 575 // If the browser has UI, simulate what a user would do. 576 // Activate the tab and then click the encoding menu. 577 if (browser && chrome::IsCommandEnabled(browser, IDC_ENCODING_MENU)) { 578 int selected_encoding_id = 579 CharacterEncoding::GetCommandIdByCanonicalEncodingName(encoding_name); 580 if (selected_encoding_id) { 581 browser->OverrideEncoding(selected_encoding_id); 582 *success = true; 583 } 584 } else { 585 // There is no UI, Chrome probably runs as Chrome-Frame mode. 586 // Try to get WebContents and call its SetOverrideEncoding method. 587 WebContents* contents = nav->GetWebContents(); 588 if (!contents) 589 return; 590 const std::string selected_encoding = 591 CharacterEncoding::GetCanonicalEncodingNameByAliasName(encoding_name); 592 if (selected_encoding.empty()) 593 return; 594 contents->SetOverrideEncoding(selected_encoding); 595 } 596 } 597 } 598 599 void AutomationProvider::SelectAll(int tab_handle) { 600 RenderViewHost* view = GetViewForTab(tab_handle); 601 if (!view) { 602 NOTREACHED(); 603 return; 604 } 605 606 view->SelectAll(); 607 } 608 609 void AutomationProvider::Cut(int tab_handle) { 610 RenderViewHost* view = GetViewForTab(tab_handle); 611 if (!view) { 612 NOTREACHED(); 613 return; 614 } 615 616 view->Cut(); 617 } 618 619 void AutomationProvider::Copy(int tab_handle) { 620 RenderViewHost* view = GetViewForTab(tab_handle); 621 if (!view) { 622 NOTREACHED(); 623 return; 624 } 625 626 view->Copy(); 627 } 628 629 void AutomationProvider::Paste(int tab_handle) { 630 RenderViewHost* view = GetViewForTab(tab_handle); 631 if (!view) { 632 NOTREACHED(); 633 return; 634 } 635 636 view->Paste(); 637 } 638 639 void AutomationProvider::ReloadAsync(int tab_handle) { 640 if (tab_tracker_->ContainsHandle(tab_handle)) { 641 NavigationController* tab = tab_tracker_->GetResource(tab_handle); 642 if (!tab) { 643 NOTREACHED(); 644 return; 645 } 646 647 const bool check_for_repost = true; 648 tab->Reload(check_for_repost); 649 } 650 } 651 652 void AutomationProvider::StopAsync(int tab_handle) { 653 RenderViewHost* view = GetViewForTab(tab_handle); 654 if (!view) { 655 // We tolerate StopAsync being called even before a view has been created. 656 // So just log a warning instead of a NOTREACHED(). 657 DLOG(WARNING) << "StopAsync: no view for handle " << tab_handle; 658 return; 659 } 660 661 view->Stop(); 662 } 663 664 void AutomationProvider::OnSetPageFontSize(int tab_handle, 665 int font_size) { 666 AutomationPageFontSize automation_font_size = 667 static_cast<AutomationPageFontSize>(font_size); 668 669 if (automation_font_size < SMALLEST_FONT || 670 automation_font_size > LARGEST_FONT) { 671 DLOG(ERROR) << "Invalid font size specified : " 672 << font_size; 673 return; 674 } 675 676 if (tab_tracker_->ContainsHandle(tab_handle)) { 677 NavigationController* tab = tab_tracker_->GetResource(tab_handle); 678 DCHECK(tab != NULL); 679 if (tab && tab->GetWebContents()) { 680 DCHECK(tab->GetWebContents()->GetBrowserContext() != NULL); 681 Profile* profile = Profile::FromBrowserContext( 682 tab->GetWebContents()->GetBrowserContext()); 683 profile->GetPrefs()->SetInteger(prefs::kWebKitDefaultFontSize, font_size); 684 } 685 } 686 } 687 688 void AutomationProvider::RemoveBrowsingData(int remove_mask) { 689 BrowsingDataRemover* remover; 690 remover = BrowsingDataRemover::CreateForUnboundedRange(profile()); 691 remover->Remove(remove_mask, BrowsingDataHelper::UNPROTECTED_WEB); 692 // BrowsingDataRemover deletes itself. 693 } 694 695 void AutomationProvider::JavaScriptStressTestControl(int tab_handle, 696 int cmd, 697 int param) { 698 RenderViewHost* view = GetViewForTab(tab_handle); 699 if (!view) { 700 NOTREACHED(); 701 return; 702 } 703 704 view->Send(new ChromeViewMsg_JavaScriptStressTestControl( 705 view->GetRoutingID(), cmd, param)); 706 } 707 708 void AutomationProvider::BeginTracing(const std::string& category_patterns, 709 bool* success) { 710 *success = TracingController::GetInstance()->EnableRecording( 711 category_patterns, TracingController::DEFAULT_OPTIONS, 712 TracingController::EnableRecordingDoneCallback()); 713 } 714 715 void AutomationProvider::EndTracing(IPC::Message* reply_message) { 716 base::FilePath path; 717 if (!TracingController::GetInstance()->DisableRecording( 718 path, base::Bind(&AutomationProvider::OnTraceDataCollected, this, 719 reply_message))) { 720 // If failed to call EndTracingAsync, need to reply with failure now. 721 AutomationMsg_EndTracing::WriteReplyParams(reply_message, path, false); 722 Send(reply_message); 723 } 724 // Otherwise defer EndTracing reply until TraceController calls us back. 725 } 726 727 void AutomationProvider::OnTraceDataCollected(IPC::Message* reply_message, 728 const base::FilePath& path) { 729 if (reply_message) { 730 AutomationMsg_EndTracing::WriteReplyParams(reply_message, path, true); 731 Send(reply_message); 732 } 733 } 734 735 RenderViewHost* AutomationProvider::GetViewForTab(int tab_handle) { 736 if (tab_tracker_->ContainsHandle(tab_handle)) { 737 NavigationController* tab = tab_tracker_->GetResource(tab_handle); 738 if (!tab) { 739 NOTREACHED(); 740 return NULL; 741 } 742 743 WebContents* web_contents = tab->GetWebContents(); 744 if (!web_contents) { 745 NOTREACHED(); 746 return NULL; 747 } 748 749 RenderViewHost* view_host = web_contents->GetRenderViewHost(); 750 return view_host; 751 } 752 753 return NULL; 754 } 755 756 void AutomationProvider::SaveAsAsync(int tab_handle) { 757 NavigationController* tab = NULL; 758 WebContents* web_contents = GetWebContentsForHandle(tab_handle, &tab); 759 if (web_contents) 760 web_contents->OnSavePage(); 761 } 762