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