Home | History | Annotate | Download | only in automation
      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