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