- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / automation / automation_provider.cc
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/trace_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 WebKit::WebFindOptions;
84 using base::Time;
85 using content::BrowserThread;
86 using content::DownloadItem;
87 using content::NavigationController;
88 using content::RenderViewHost;
89 using content::TraceController;
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 void AutomationProvider::OnEndTracingComplete() {
380   IPC::Message* reply_message = tracing_data_.reply_message.release();
381   if (reply_message) {
382     AutomationMsg_EndTracing::WriteReplyParams(
383         reply_message, tracing_data_.trace_output.size(), true);
384     Send(reply_message);
385   }
386 }
387
388 void AutomationProvider::OnTraceDataCollected(
389     const scoped_refptr<base::RefCountedString>& trace_fragment) {
390   tracing_data_.trace_output.push_back(trace_fragment->data());
391 }
392
393 bool AutomationProvider::OnMessageReceived(const IPC::Message& message) {
394   bool handled = true;
395   bool deserialize_success = true;
396   IPC_BEGIN_MESSAGE_MAP_EX(AutomationProvider, message, deserialize_success)
397     IPC_MESSAGE_HANDLER(AutomationMsg_HandleUnused, HandleUnused)
398     IPC_MESSAGE_HANDLER(AutomationMsg_SetProxyConfig, SetProxyConfig)
399     IPC_MESSAGE_HANDLER(AutomationMsg_PrintAsync, PrintAsync)
400     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_Find, HandleFindRequest)
401     IPC_MESSAGE_HANDLER(AutomationMsg_OverrideEncoding, OverrideEncoding)
402     IPC_MESSAGE_HANDLER(AutomationMsg_SelectAll, SelectAll)
403     IPC_MESSAGE_HANDLER(AutomationMsg_Cut, Cut)
404     IPC_MESSAGE_HANDLER(AutomationMsg_Copy, Copy)
405     IPC_MESSAGE_HANDLER(AutomationMsg_Paste, Paste)
406     IPC_MESSAGE_HANDLER(AutomationMsg_ReloadAsync, ReloadAsync)
407     IPC_MESSAGE_HANDLER(AutomationMsg_StopAsync, StopAsync)
408     IPC_MESSAGE_HANDLER(AutomationMsg_SetPageFontSize, OnSetPageFontSize)
409     IPC_MESSAGE_HANDLER(AutomationMsg_SaveAsAsync, SaveAsAsync)
410     IPC_MESSAGE_HANDLER(AutomationMsg_RemoveBrowsingData, RemoveBrowsingData)
411     IPC_MESSAGE_HANDLER(AutomationMsg_JavaScriptStressTestControl,
412                         JavaScriptStressTestControl)
413     IPC_MESSAGE_HANDLER(AutomationMsg_BeginTracing, BeginTracing)
414     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_EndTracing, EndTracing)
415     IPC_MESSAGE_HANDLER(AutomationMsg_GetTracingOutput, GetTracingOutput)
416 #if defined(OS_WIN)
417     // These are for use with external tabs.
418     IPC_MESSAGE_HANDLER(AutomationMsg_CreateExternalTab, CreateExternalTab)
419     IPC_MESSAGE_HANDLER(AutomationMsg_ProcessUnhandledAccelerator,
420                         ProcessUnhandledAccelerator)
421     IPC_MESSAGE_HANDLER(AutomationMsg_SetInitialFocus, SetInitialFocus)
422     IPC_MESSAGE_HANDLER(AutomationMsg_TabReposition, OnTabReposition)
423     IPC_MESSAGE_HANDLER(AutomationMsg_ForwardContextMenuCommandToChrome,
424                         OnForwardContextMenuCommandToChrome)
425     IPC_MESSAGE_HANDLER(AutomationMsg_NavigateInExternalTab,
426                         NavigateInExternalTab)
427     IPC_MESSAGE_HANDLER(AutomationMsg_NavigateExternalTabAtIndex,
428                         NavigateExternalTabAtIndex)
429     IPC_MESSAGE_HANDLER(AutomationMsg_ConnectExternalTab, ConnectExternalTab)
430     IPC_MESSAGE_HANDLER(AutomationMsg_HandleMessageFromExternalHost,
431                         OnMessageFromExternalHost)
432     IPC_MESSAGE_HANDLER(AutomationMsg_BrowserMove, OnBrowserMoved)
433     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_RunUnloadHandlers,
434                                     OnRunUnloadHandlers)
435     IPC_MESSAGE_HANDLER(AutomationMsg_SetZoomLevel, OnSetZoomLevel)
436 #endif  // defined(OS_WIN)
437     IPC_MESSAGE_UNHANDLED(handled = false)
438   IPC_END_MESSAGE_MAP_EX()
439   if (!handled)
440     OnUnhandledMessage(message);
441   if (!deserialize_success)
442     OnMessageDeserializationFailure();
443   return handled;
444 }
445
446 void AutomationProvider::OnUnhandledMessage(const IPC::Message& message) {
447   // We should not hang here. Print a message to indicate what's going on,
448   // and disconnect the channel to notify the caller about the error
449   // in a way it can't ignore, and make any further attempts to send
450   // messages fail fast.
451   LOG(ERROR) << "AutomationProvider received a message it can't handle. "
452              << "Message type: " << message.type()
453              << ", routing ID: " << message.routing_id() << ". "
454              << "Please make sure that you use switches::kTestingChannelID "
455              << "for test code (TestingAutomationProvider), and "
456              << "switches::kAutomationClientChannelID for everything else "
457              << "(like ChromeFrame). Closing the automation channel.";
458   channel_->Close();
459 }
460
461 void AutomationProvider::OnMessageDeserializationFailure() {
462   LOG(ERROR) << "Failed to deserialize IPC message. "
463              << "Closing the automation channel.";
464   channel_->Close();
465 }
466
467 void AutomationProvider::HandleUnused(const IPC::Message& message, int handle) {
468   if (window_tracker_->ContainsHandle(handle)) {
469     window_tracker_->Remove(window_tracker_->GetResource(handle));
470   }
471 }
472
473 bool AutomationProvider::ReinitializeChannel() {
474   base::ThreadRestrictions::ScopedAllowIO allow_io;
475
476   // Make sure any old channels are cleaned up before starting up a new one.
477   channel_.reset();
478   return InitializeChannel(channel_id_);
479 }
480
481 void AutomationProvider::OnChannelError() {
482   if (reinitialize_on_channel_error_) {
483     VLOG(1) << "AutomationProxy disconnected, resetting AutomationProvider.";
484     if (ReinitializeChannel())
485       return;
486     VLOG(1) << "Error reinitializing AutomationProvider channel.";
487   }
488   VLOG(1) << "AutomationProxy went away, shutting down app.";
489   g_browser_process->GetAutomationProviderList()->RemoveProvider(this);
490 }
491
492 bool AutomationProvider::Send(IPC::Message* msg) {
493   DCHECK(channel_.get());
494   return channel_->Send(msg);
495 }
496
497 Browser* AutomationProvider::FindAndActivateTab(
498     NavigationController* controller) {
499   content::WebContentsDelegate* d = controller->GetWebContents()->GetDelegate();
500   if (d)
501     d->ActivateContents(controller->GetWebContents());
502   return chrome::FindBrowserWithWebContents(controller->GetWebContents());
503 }
504
505 void AutomationProvider::HandleFindRequest(
506     int handle,
507     const AutomationMsg_Find_Params& params,
508     IPC::Message* reply_message) {
509   if (!tab_tracker_->ContainsHandle(handle)) {
510     AutomationMsg_Find::WriteReplyParams(reply_message, -1, -1);
511     Send(reply_message);
512     return;
513   }
514
515   NavigationController* nav = tab_tracker_->GetResource(handle);
516   WebContents* web_contents = nav->GetWebContents();
517
518   SendFindRequest(web_contents,
519                   false,
520                   params.search_string,
521                   params.forward,
522                   params.match_case,
523                   params.find_next,
524                   reply_message);
525 }
526
527 void AutomationProvider::SendFindRequest(
528     WebContents* web_contents,
529     bool with_json,
530     const string16& search_string,
531     bool forward,
532     bool match_case,
533     bool find_next,
534     IPC::Message* reply_message) {
535   int request_id = FindInPageNotificationObserver::kFindInPageRequestId;
536   FindInPageNotificationObserver* observer =
537       new FindInPageNotificationObserver(this,
538                                          web_contents,
539                                          with_json,
540                                          reply_message);
541   if (!with_json) {
542     find_in_page_observer_.reset(observer);
543   }
544   FindTabHelper* find_tab_helper = FindTabHelper::FromWebContents(web_contents);
545   if (find_tab_helper)
546     find_tab_helper->set_current_find_request_id(request_id);
547
548   WebFindOptions options;
549   options.forward = forward;
550   options.matchCase = match_case;
551   options.findNext = find_next;
552   web_contents->GetRenderViewHost()->Find(
553       FindInPageNotificationObserver::kFindInPageRequestId, search_string,
554       options);
555 }
556
557 void AutomationProvider::SetProxyConfig(const std::string& new_proxy_config) {
558   net::URLRequestContextGetter* context_getter =
559       profile_->GetRequestContext();
560   DCHECK(context_getter);
561
562   BrowserThread::PostTask(
563       BrowserThread::IO, FROM_HERE,
564       base::Bind(SetProxyConfigCallback, make_scoped_refptr(context_getter),
565                  new_proxy_config));
566 }
567
568 WebContents* AutomationProvider::GetWebContentsForHandle(
569     int handle, NavigationController** tab) {
570   if (tab_tracker_->ContainsHandle(handle)) {
571     NavigationController* nav_controller = tab_tracker_->GetResource(handle);
572     if (tab)
573       *tab = nav_controller;
574     return nav_controller->GetWebContents();
575   }
576   return NULL;
577 }
578
579 // Gets the current used encoding name of the page in the specified tab.
580 void AutomationProvider::OverrideEncoding(int tab_handle,
581                                           const std::string& encoding_name,
582                                           bool* success) {
583   *success = false;
584   if (tab_tracker_->ContainsHandle(tab_handle)) {
585     NavigationController* nav = tab_tracker_->GetResource(tab_handle);
586     if (!nav)
587       return;
588     Browser* browser = FindAndActivateTab(nav);
589
590     // If the browser has UI, simulate what a user would do.
591     // Activate the tab and then click the encoding menu.
592     if (browser && chrome::IsCommandEnabled(browser, IDC_ENCODING_MENU)) {
593       int selected_encoding_id =
594           CharacterEncoding::GetCommandIdByCanonicalEncodingName(encoding_name);
595       if (selected_encoding_id) {
596         browser->OverrideEncoding(selected_encoding_id);
597         *success = true;
598       }
599     } else {
600       // There is no UI, Chrome probably runs as Chrome-Frame mode.
601       // Try to get WebContents and call its SetOverrideEncoding method.
602       WebContents* contents = nav->GetWebContents();
603       if (!contents)
604         return;
605       const std::string selected_encoding =
606           CharacterEncoding::GetCanonicalEncodingNameByAliasName(encoding_name);
607       if (selected_encoding.empty())
608         return;
609       contents->SetOverrideEncoding(selected_encoding);
610     }
611   }
612 }
613
614 void AutomationProvider::SelectAll(int tab_handle) {
615   RenderViewHost* view = GetViewForTab(tab_handle);
616   if (!view) {
617     NOTREACHED();
618     return;
619   }
620
621   view->SelectAll();
622 }
623
624 void AutomationProvider::Cut(int tab_handle) {
625   RenderViewHost* view = GetViewForTab(tab_handle);
626   if (!view) {
627     NOTREACHED();
628     return;
629   }
630
631   view->Cut();
632 }
633
634 void AutomationProvider::Copy(int tab_handle) {
635   RenderViewHost* view = GetViewForTab(tab_handle);
636   if (!view) {
637     NOTREACHED();
638     return;
639   }
640
641   view->Copy();
642 }
643
644 void AutomationProvider::Paste(int tab_handle) {
645   RenderViewHost* view = GetViewForTab(tab_handle);
646   if (!view) {
647     NOTREACHED();
648     return;
649   }
650
651   view->Paste();
652 }
653
654 void AutomationProvider::ReloadAsync(int tab_handle) {
655   if (tab_tracker_->ContainsHandle(tab_handle)) {
656     NavigationController* tab = tab_tracker_->GetResource(tab_handle);
657     if (!tab) {
658       NOTREACHED();
659       return;
660     }
661
662     const bool check_for_repost = true;
663     tab->Reload(check_for_repost);
664   }
665 }
666
667 void AutomationProvider::StopAsync(int tab_handle) {
668   RenderViewHost* view = GetViewForTab(tab_handle);
669   if (!view) {
670     // We tolerate StopAsync being called even before a view has been created.
671     // So just log a warning instead of a NOTREACHED().
672     DLOG(WARNING) << "StopAsync: no view for handle " << tab_handle;
673     return;
674   }
675
676   view->Stop();
677 }
678
679 void AutomationProvider::OnSetPageFontSize(int tab_handle,
680                                            int font_size) {
681   AutomationPageFontSize automation_font_size =
682       static_cast<AutomationPageFontSize>(font_size);
683
684   if (automation_font_size < SMALLEST_FONT ||
685       automation_font_size > LARGEST_FONT) {
686       DLOG(ERROR) << "Invalid font size specified : "
687                   << font_size;
688       return;
689   }
690
691   if (tab_tracker_->ContainsHandle(tab_handle)) {
692     NavigationController* tab = tab_tracker_->GetResource(tab_handle);
693     DCHECK(tab != NULL);
694     if (tab && tab->GetWebContents()) {
695       DCHECK(tab->GetWebContents()->GetBrowserContext() != NULL);
696       Profile* profile = Profile::FromBrowserContext(
697           tab->GetWebContents()->GetBrowserContext());
698       profile->GetPrefs()->SetInteger(prefs::kWebKitDefaultFontSize, font_size);
699     }
700   }
701 }
702
703 void AutomationProvider::RemoveBrowsingData(int remove_mask) {
704   BrowsingDataRemover* remover;
705   remover = BrowsingDataRemover::CreateForUnboundedRange(profile());
706   remover->Remove(remove_mask, BrowsingDataHelper::UNPROTECTED_WEB);
707   // BrowsingDataRemover deletes itself.
708 }
709
710 void AutomationProvider::JavaScriptStressTestControl(int tab_handle,
711                                                      int cmd,
712                                                      int param) {
713   RenderViewHost* view = GetViewForTab(tab_handle);
714   if (!view) {
715     NOTREACHED();
716     return;
717   }
718
719   view->Send(new ChromeViewMsg_JavaScriptStressTestControl(
720       view->GetRoutingID(), cmd, param));
721 }
722
723 void AutomationProvider::BeginTracing(const std::string& category_patterns,
724                                       bool* success) {
725   tracing_data_.trace_output.clear();
726   *success = TraceController::GetInstance()->BeginTracing(
727       this,
728       category_patterns,
729       base::debug::TraceLog::RECORD_UNTIL_FULL);
730 }
731
732 void AutomationProvider::EndTracing(IPC::Message* reply_message) {
733   bool success = false;
734   if (!tracing_data_.reply_message.get())
735     success = TraceController::GetInstance()->EndTracingAsync(this);
736   if (success) {
737     // Defer EndTracing reply until TraceController calls us back with all the
738     // events.
739     tracing_data_.reply_message.reset(reply_message);
740   } else {
741     // If failed to call EndTracingAsync, need to reply with failure now.
742     AutomationMsg_EndTracing::WriteReplyParams(reply_message, size_t(0), false);
743     Send(reply_message);
744   }
745 }
746
747 void AutomationProvider::GetTracingOutput(std::string* chunk,
748                                           bool* success) {
749   // The JSON data is sent back to the test in chunks, because IPC sends will
750   // fail if they are too large.
751   if (tracing_data_.trace_output.empty()) {
752     *chunk = "";
753     *success = false;
754   } else {
755     *chunk = tracing_data_.trace_output.front();
756     tracing_data_.trace_output.pop_front();
757     *success = true;
758   }
759 }
760
761 RenderViewHost* AutomationProvider::GetViewForTab(int tab_handle) {
762   if (tab_tracker_->ContainsHandle(tab_handle)) {
763     NavigationController* tab = tab_tracker_->GetResource(tab_handle);
764     if (!tab) {
765       NOTREACHED();
766       return NULL;
767     }
768
769     WebContents* web_contents = tab->GetWebContents();
770     if (!web_contents) {
771       NOTREACHED();
772       return NULL;
773     }
774
775     RenderViewHost* view_host = web_contents->GetRenderViewHost();
776     return view_host;
777   }
778
779   return NULL;
780 }
781
782 void AutomationProvider::SaveAsAsync(int tab_handle) {
783   NavigationController* tab = NULL;
784   WebContents* web_contents = GetWebContentsForHandle(tab_handle, &tab);
785   if (web_contents)
786     web_contents->OnSavePage();
787 }