1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/automation/automation_provider.h"
6
7 #include <set>
8
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/command_line.h"
12 #include "base/debug/trace_event.h"
13 #include "base/files/file_path.h"
14 #include "base/json/json_reader.h"
15 #include "base/json/json_string_value_serializer.h"
16 #include "base/json/json_writer.h"
17 #include "base/json/string_escape.h"
18 #include "base/message_loop/message_loop.h"
19 #include "base/path_service.h"
20 #include "base/prefs/pref_service.h"
21 #include "base/stl_util.h"
22 #include "base/strings/string_number_conversions.h"
23 #include "base/strings/string_util.h"
24 #include "base/strings/utf_string_conversions.h"
25 #include "base/synchronization/waitable_event.h"
26 #include "base/threading/thread.h"
27 #include "base/values.h"
28 #include "chrome/app/chrome_command_ids.h"
29 #include "chrome/browser/automation/automation_browser_tracker.h"
30 #include "chrome/browser/automation/automation_provider_list.h"
31 #include "chrome/browser/automation/automation_provider_observers.h"
32 #include "chrome/browser/automation/automation_resource_message_filter.h"
33 #include "chrome/browser/automation/automation_tab_tracker.h"
34 #include "chrome/browser/automation/automation_window_tracker.h"
35 #include "chrome/browser/browser_process.h"
36 #include "chrome/browser/browsing_data/browsing_data_helper.h"
37 #include "chrome/browser/browsing_data/browsing_data_remover.h"
38 #include "chrome/browser/character_encoding.h"
39 #include "chrome/browser/content_settings/host_content_settings_map.h"
40 #include "chrome/browser/net/url_request_mock_util.h"
41 #include "chrome/browser/printing/print_job.h"
42 #include "chrome/browser/profiles/profile_manager.h"
43 #include "chrome/browser/ssl/ssl_blocking_page.h"
44 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
45 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
46 #include "chrome/browser/ui/browser_commands.h"
47 #include "chrome/browser/ui/browser_finder.h"
48 #include "chrome/browser/ui/browser_tabstrip.h"
49 #include "chrome/browser/ui/browser_window.h"
50 #include "chrome/browser/ui/find_bar/find_bar.h"
51 #include "chrome/browser/ui/find_bar/find_bar_controller.h"
52 #include "chrome/browser/ui/find_bar/find_notification_details.h"
53 #include "chrome/browser/ui/find_bar/find_tab_helper.h"
54 #include "chrome/browser/ui/login/login_prompt.h"
55 #include "chrome/browser/ui/omnibox/location_bar.h"
56 #include "chrome/common/automation_constants.h"
57 #include "chrome/common/automation_messages.h"
58 #include "chrome/common/chrome_constants.h"
59 #include "chrome/common/chrome_paths.h"
60 #include "chrome/common/chrome_switches.h"
61 #include "chrome/common/chrome_version_info.h"
62 #include "chrome/common/pref_names.h"
63 #include "chrome/common/render_messages.h"
64 #include "chrome/common/url_constants.h"
65 #include "content/public/browser/browser_thread.h"
66 #include "content/public/browser/download_item.h"
67 #include "content/public/browser/native_web_keyboard_event.h"
68 #include "content/public/browser/render_view_host.h"
69 #include "content/public/browser/tracing_controller.h"
70 #include "content/public/browser/web_contents.h"
71 #include "content/public/browser/web_contents_view.h"
72 #include "net/proxy/proxy_config_service_fixed.h"
73 #include "net/proxy/proxy_service.h"
74 #include "net/url_request/url_request_context.h"
75 #include "net/url_request/url_request_context_getter.h"
76 #include "third_party/WebKit/public/web/WebFindOptions.h"
77
78 #if defined(OS_CHROMEOS)
79 #include "chromeos/chromeos_switches.h"
80 #include "chromeos/login/login_state.h"
81 #endif // defined(OS_CHROMEOS)
82
83 using blink::WebFindOptions;
84 using base::Time;
85 using content::BrowserThread;
86 using content::DownloadItem;
87 using content::NavigationController;
88 using content::RenderViewHost;
89 using content::TracingController;
90 using content::WebContents;
91
92 namespace {
93
PopulateProxyConfig(const DictionaryValue & dict,net::ProxyConfig * pc)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
SetProxyConfigCallback(const scoped_refptr<net::URLRequestContextGetter> & request_context_getter,const std::string & proxy_config)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
AutomationProvider(Profile * profile)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
~AutomationProvider()175 AutomationProvider::~AutomationProvider() {
176 if (channel_.get())
177 channel_->Close();
178 }
179
set_profile(Profile * profile)180 void AutomationProvider::set_profile(Profile* profile) {
181 profile_ = profile;
182 }
183
InitializeChannel(const std::string & channel_id)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
GetChannelMode(bool use_named_interface)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
GetProtocolVersion()240 std::string AutomationProvider::GetProtocolVersion() {
241 chrome::VersionInfo version_info;
242 return version_info.Version().c_str();
243 }
244
SetExpectedTabCount(size_t expected_tabs)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
OnInitialTabLoadsComplete()253 void AutomationProvider::OnInitialTabLoadsComplete() {
254 initial_tab_loads_complete_ = true;
255 VLOG(2) << "OnInitialTabLoadsComplete";
256 SendInitialLoadMessage();
257 }
258
OnOOBEWebuiReady()259 void AutomationProvider::OnOOBEWebuiReady() {
260 login_webui_ready_ = true;
261 VLOG(2) << "OnOOBEWebuiReady";
262 SendInitialLoadMessage();
263 }
264
SendInitialLoadMessage()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
DisableInitialLoadObservers()272 void AutomationProvider::DisableInitialLoadObservers() {
273 use_initial_load_observers_ = false;
274 OnInitialTabLoadsComplete();
275 OnOOBEWebuiReady();
276 }
277
GetIndexForNavigationController(const NavigationController * controller,const Browser * parent) const278 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.
GetDictionaryFromDownloadItem(const DownloadItem * download,bool incognito)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
OnChannelConnected(int pid)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
OnMessageReceived(const IPC::Message & message)379 bool AutomationProvider::OnMessageReceived(const IPC::Message& message) {
380 bool handled = true;
381 bool deserialize_success = true;
382 IPC_BEGIN_MESSAGE_MAP_EX(AutomationProvider, message, deserialize_success)
383 IPC_MESSAGE_HANDLER(AutomationMsg_HandleUnused, HandleUnused)
384 IPC_MESSAGE_HANDLER(AutomationMsg_SetProxyConfig, SetProxyConfig)
385 IPC_MESSAGE_HANDLER(AutomationMsg_PrintAsync, PrintAsync)
386 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_Find, HandleFindRequest)
387 IPC_MESSAGE_HANDLER(AutomationMsg_OverrideEncoding, OverrideEncoding)
388 IPC_MESSAGE_HANDLER(AutomationMsg_SelectAll, SelectAll)
389 IPC_MESSAGE_HANDLER(AutomationMsg_Cut, Cut)
390 IPC_MESSAGE_HANDLER(AutomationMsg_Copy, Copy)
391 IPC_MESSAGE_HANDLER(AutomationMsg_Paste, Paste)
392 IPC_MESSAGE_HANDLER(AutomationMsg_ReloadAsync, ReloadAsync)
393 IPC_MESSAGE_HANDLER(AutomationMsg_StopAsync, StopAsync)
394 IPC_MESSAGE_HANDLER(AutomationMsg_SetPageFontSize, OnSetPageFontSize)
395 IPC_MESSAGE_HANDLER(AutomationMsg_SaveAsAsync, SaveAsAsync)
396 IPC_MESSAGE_HANDLER(AutomationMsg_RemoveBrowsingData, RemoveBrowsingData)
397 IPC_MESSAGE_HANDLER(AutomationMsg_JavaScriptStressTestControl,
398 JavaScriptStressTestControl)
399 IPC_MESSAGE_HANDLER(AutomationMsg_BeginTracing, BeginTracing)
400 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_EndTracing, EndTracing)
401 #if defined(OS_WIN)
402 // These are for use with external tabs.
403 IPC_MESSAGE_HANDLER(AutomationMsg_CreateExternalTab, CreateExternalTab)
404 IPC_MESSAGE_HANDLER(AutomationMsg_ProcessUnhandledAccelerator,
405 ProcessUnhandledAccelerator)
406 IPC_MESSAGE_HANDLER(AutomationMsg_SetInitialFocus, SetInitialFocus)
407 IPC_MESSAGE_HANDLER(AutomationMsg_TabReposition, OnTabReposition)
408 IPC_MESSAGE_HANDLER(AutomationMsg_ForwardContextMenuCommandToChrome,
409 OnForwardContextMenuCommandToChrome)
410 IPC_MESSAGE_HANDLER(AutomationMsg_NavigateInExternalTab,
411 NavigateInExternalTab)
412 IPC_MESSAGE_HANDLER(AutomationMsg_NavigateExternalTabAtIndex,
413 NavigateExternalTabAtIndex)
414 IPC_MESSAGE_HANDLER(AutomationMsg_ConnectExternalTab, ConnectExternalTab)
415 IPC_MESSAGE_HANDLER(AutomationMsg_HandleMessageFromExternalHost,
416 OnMessageFromExternalHost)
417 IPC_MESSAGE_HANDLER(AutomationMsg_BrowserMove, OnBrowserMoved)
418 IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_RunUnloadHandlers,
419 OnRunUnloadHandlers)
420 IPC_MESSAGE_HANDLER(AutomationMsg_SetZoomLevel, OnSetZoomLevel)
421 #endif // defined(OS_WIN)
422 IPC_MESSAGE_UNHANDLED(handled = false)
423 IPC_END_MESSAGE_MAP_EX()
424 if (!handled)
425 OnUnhandledMessage(message);
426 if (!deserialize_success)
427 OnMessageDeserializationFailure();
428 return handled;
429 }
430
OnUnhandledMessage(const IPC::Message & message)431 void AutomationProvider::OnUnhandledMessage(const IPC::Message& message) {
432 // We should not hang here. Print a message to indicate what's going on,
433 // and disconnect the channel to notify the caller about the error
434 // in a way it can't ignore, and make any further attempts to send
435 // messages fail fast.
436 LOG(ERROR) << "AutomationProvider received a message it can't handle. "
437 << "Message type: " << message.type()
438 << ", routing ID: " << message.routing_id() << ". "
439 << "Please make sure that you use switches::kTestingChannelID "
440 << "for test code (TestingAutomationProvider), and "
441 << "switches::kAutomationClientChannelID for everything else "
442 << "(like ChromeFrame). Closing the automation channel.";
443 channel_->Close();
444 }
445
OnMessageDeserializationFailure()446 void AutomationProvider::OnMessageDeserializationFailure() {
447 LOG(ERROR) << "Failed to deserialize IPC message. "
448 << "Closing the automation channel.";
449 channel_->Close();
450 }
451
HandleUnused(const IPC::Message & message,int handle)452 void AutomationProvider::HandleUnused(const IPC::Message& message, int handle) {
453 if (window_tracker_->ContainsHandle(handle)) {
454 window_tracker_->Remove(window_tracker_->GetResource(handle));
455 }
456 }
457
ReinitializeChannel()458 bool AutomationProvider::ReinitializeChannel() {
459 base::ThreadRestrictions::ScopedAllowIO allow_io;
460
461 // Make sure any old channels are cleaned up before starting up a new one.
462 channel_.reset();
463 return InitializeChannel(channel_id_);
464 }
465
OnChannelError()466 void AutomationProvider::OnChannelError() {
467 if (reinitialize_on_channel_error_) {
468 VLOG(1) << "AutomationProxy disconnected, resetting AutomationProvider.";
469 if (ReinitializeChannel())
470 return;
471 VLOG(1) << "Error reinitializing AutomationProvider channel.";
472 }
473 VLOG(1) << "AutomationProxy went away, shutting down app.";
474 g_browser_process->GetAutomationProviderList()->RemoveProvider(this);
475 }
476
Send(IPC::Message * msg)477 bool AutomationProvider::Send(IPC::Message* msg) {
478 DCHECK(channel_.get());
479 return channel_->Send(msg);
480 }
481
FindAndActivateTab(NavigationController * controller)482 Browser* AutomationProvider::FindAndActivateTab(
483 NavigationController* controller) {
484 content::WebContentsDelegate* d = controller->GetWebContents()->GetDelegate();
485 if (d)
486 d->ActivateContents(controller->GetWebContents());
487 return chrome::FindBrowserWithWebContents(controller->GetWebContents());
488 }
489
HandleFindRequest(int handle,const AutomationMsg_Find_Params & params,IPC::Message * reply_message)490 void AutomationProvider::HandleFindRequest(
491 int handle,
492 const AutomationMsg_Find_Params& params,
493 IPC::Message* reply_message) {
494 if (!tab_tracker_->ContainsHandle(handle)) {
495 AutomationMsg_Find::WriteReplyParams(reply_message, -1, -1);
496 Send(reply_message);
497 return;
498 }
499
500 NavigationController* nav = tab_tracker_->GetResource(handle);
501 WebContents* web_contents = nav->GetWebContents();
502
503 SendFindRequest(web_contents,
504 false,
505 params.search_string,
506 params.forward,
507 params.match_case,
508 params.find_next,
509 reply_message);
510 }
511
SendFindRequest(WebContents * web_contents,bool with_json,const base::string16 & search_string,bool forward,bool match_case,bool find_next,IPC::Message * reply_message)512 void AutomationProvider::SendFindRequest(
513 WebContents* web_contents,
514 bool with_json,
515 const base::string16& search_string,
516 bool forward,
517 bool match_case,
518 bool find_next,
519 IPC::Message* reply_message) {
520 int request_id = FindInPageNotificationObserver::kFindInPageRequestId;
521 FindInPageNotificationObserver* observer =
522 new FindInPageNotificationObserver(this,
523 web_contents,
524 with_json,
525 reply_message);
526 if (!with_json) {
527 find_in_page_observer_.reset(observer);
528 }
529 FindTabHelper* find_tab_helper = FindTabHelper::FromWebContents(web_contents);
530 if (find_tab_helper)
531 find_tab_helper->set_current_find_request_id(request_id);
532
533 WebFindOptions options;
534 options.forward = forward;
535 options.matchCase = match_case;
536 options.findNext = find_next;
537 web_contents->GetRenderViewHost()->Find(
538 FindInPageNotificationObserver::kFindInPageRequestId, search_string,
539 options);
540 }
541
SetProxyConfig(const std::string & new_proxy_config)542 void AutomationProvider::SetProxyConfig(const std::string& new_proxy_config) {
543 net::URLRequestContextGetter* context_getter =
544 profile_->GetRequestContext();
545 DCHECK(context_getter);
546
547 BrowserThread::PostTask(
548 BrowserThread::IO, FROM_HERE,
549 base::Bind(SetProxyConfigCallback, make_scoped_refptr(context_getter),
550 new_proxy_config));
551 }
552
GetWebContentsForHandle(int handle,NavigationController ** tab)553 WebContents* AutomationProvider::GetWebContentsForHandle(
554 int handle, NavigationController** tab) {
555 if (tab_tracker_->ContainsHandle(handle)) {
556 NavigationController* nav_controller = tab_tracker_->GetResource(handle);
557 if (tab)
558 *tab = nav_controller;
559 return nav_controller->GetWebContents();
560 }
561 return NULL;
562 }
563
564 // Gets the current used encoding name of the page in the specified tab.
OverrideEncoding(int tab_handle,const std::string & encoding_name,bool * success)565 void AutomationProvider::OverrideEncoding(int tab_handle,
566 const std::string& encoding_name,
567 bool* success) {
568 *success = false;
569 if (tab_tracker_->ContainsHandle(tab_handle)) {
570 NavigationController* nav = tab_tracker_->GetResource(tab_handle);
571 if (!nav)
572 return;
573 Browser* browser = FindAndActivateTab(nav);
574
575 // If the browser has UI, simulate what a user would do.
576 // Activate the tab and then click the encoding menu.
577 if (browser && chrome::IsCommandEnabled(browser, IDC_ENCODING_MENU)) {
578 int selected_encoding_id =
579 CharacterEncoding::GetCommandIdByCanonicalEncodingName(encoding_name);
580 if (selected_encoding_id) {
581 browser->OverrideEncoding(selected_encoding_id);
582 *success = true;
583 }
584 } else {
585 // There is no UI, Chrome probably runs as Chrome-Frame mode.
586 // Try to get WebContents and call its SetOverrideEncoding method.
587 WebContents* contents = nav->GetWebContents();
588 if (!contents)
589 return;
590 const std::string selected_encoding =
591 CharacterEncoding::GetCanonicalEncodingNameByAliasName(encoding_name);
592 if (selected_encoding.empty())
593 return;
594 contents->SetOverrideEncoding(selected_encoding);
595 }
596 }
597 }
598
SelectAll(int tab_handle)599 void AutomationProvider::SelectAll(int tab_handle) {
600 RenderViewHost* view = GetViewForTab(tab_handle);
601 if (!view) {
602 NOTREACHED();
603 return;
604 }
605
606 view->SelectAll();
607 }
608
Cut(int tab_handle)609 void AutomationProvider::Cut(int tab_handle) {
610 RenderViewHost* view = GetViewForTab(tab_handle);
611 if (!view) {
612 NOTREACHED();
613 return;
614 }
615
616 view->Cut();
617 }
618
Copy(int tab_handle)619 void AutomationProvider::Copy(int tab_handle) {
620 RenderViewHost* view = GetViewForTab(tab_handle);
621 if (!view) {
622 NOTREACHED();
623 return;
624 }
625
626 view->Copy();
627 }
628
Paste(int tab_handle)629 void AutomationProvider::Paste(int tab_handle) {
630 RenderViewHost* view = GetViewForTab(tab_handle);
631 if (!view) {
632 NOTREACHED();
633 return;
634 }
635
636 view->Paste();
637 }
638
ReloadAsync(int tab_handle)639 void AutomationProvider::ReloadAsync(int tab_handle) {
640 if (tab_tracker_->ContainsHandle(tab_handle)) {
641 NavigationController* tab = tab_tracker_->GetResource(tab_handle);
642 if (!tab) {
643 NOTREACHED();
644 return;
645 }
646
647 const bool check_for_repost = true;
648 tab->Reload(check_for_repost);
649 }
650 }
651
StopAsync(int tab_handle)652 void AutomationProvider::StopAsync(int tab_handle) {
653 RenderViewHost* view = GetViewForTab(tab_handle);
654 if (!view) {
655 // We tolerate StopAsync being called even before a view has been created.
656 // So just log a warning instead of a NOTREACHED().
657 DLOG(WARNING) << "StopAsync: no view for handle " << tab_handle;
658 return;
659 }
660
661 view->Stop();
662 }
663
OnSetPageFontSize(int tab_handle,int font_size)664 void AutomationProvider::OnSetPageFontSize(int tab_handle,
665 int font_size) {
666 AutomationPageFontSize automation_font_size =
667 static_cast<AutomationPageFontSize>(font_size);
668
669 if (automation_font_size < SMALLEST_FONT ||
670 automation_font_size > LARGEST_FONT) {
671 DLOG(ERROR) << "Invalid font size specified : "
672 << font_size;
673 return;
674 }
675
676 if (tab_tracker_->ContainsHandle(tab_handle)) {
677 NavigationController* tab = tab_tracker_->GetResource(tab_handle);
678 DCHECK(tab != NULL);
679 if (tab && tab->GetWebContents()) {
680 DCHECK(tab->GetWebContents()->GetBrowserContext() != NULL);
681 Profile* profile = Profile::FromBrowserContext(
682 tab->GetWebContents()->GetBrowserContext());
683 profile->GetPrefs()->SetInteger(prefs::kWebKitDefaultFontSize, font_size);
684 }
685 }
686 }
687
RemoveBrowsingData(int remove_mask)688 void AutomationProvider::RemoveBrowsingData(int remove_mask) {
689 BrowsingDataRemover* remover;
690 remover = BrowsingDataRemover::CreateForUnboundedRange(profile());
691 remover->Remove(remove_mask, BrowsingDataHelper::UNPROTECTED_WEB);
692 // BrowsingDataRemover deletes itself.
693 }
694
JavaScriptStressTestControl(int tab_handle,int cmd,int param)695 void AutomationProvider::JavaScriptStressTestControl(int tab_handle,
696 int cmd,
697 int param) {
698 RenderViewHost* view = GetViewForTab(tab_handle);
699 if (!view) {
700 NOTREACHED();
701 return;
702 }
703
704 view->Send(new ChromeViewMsg_JavaScriptStressTestControl(
705 view->GetRoutingID(), cmd, param));
706 }
707
BeginTracing(const std::string & category_patterns,bool * success)708 void AutomationProvider::BeginTracing(const std::string& category_patterns,
709 bool* success) {
710 *success = TracingController::GetInstance()->EnableRecording(
711 category_patterns, TracingController::DEFAULT_OPTIONS,
712 TracingController::EnableRecordingDoneCallback());
713 }
714
EndTracing(IPC::Message * reply_message)715 void AutomationProvider::EndTracing(IPC::Message* reply_message) {
716 base::FilePath path;
717 if (!TracingController::GetInstance()->DisableRecording(
718 path, base::Bind(&AutomationProvider::OnTraceDataCollected, this,
719 reply_message))) {
720 // If failed to call EndTracingAsync, need to reply with failure now.
721 AutomationMsg_EndTracing::WriteReplyParams(reply_message, path, false);
722 Send(reply_message);
723 }
724 // Otherwise defer EndTracing reply until TraceController calls us back.
725 }
726
OnTraceDataCollected(IPC::Message * reply_message,const base::FilePath & path)727 void AutomationProvider::OnTraceDataCollected(IPC::Message* reply_message,
728 const base::FilePath& path) {
729 if (reply_message) {
730 AutomationMsg_EndTracing::WriteReplyParams(reply_message, path, true);
731 Send(reply_message);
732 }
733 }
734
GetViewForTab(int tab_handle)735 RenderViewHost* AutomationProvider::GetViewForTab(int tab_handle) {
736 if (tab_tracker_->ContainsHandle(tab_handle)) {
737 NavigationController* tab = tab_tracker_->GetResource(tab_handle);
738 if (!tab) {
739 NOTREACHED();
740 return NULL;
741 }
742
743 WebContents* web_contents = tab->GetWebContents();
744 if (!web_contents) {
745 NOTREACHED();
746 return NULL;
747 }
748
749 RenderViewHost* view_host = web_contents->GetRenderViewHost();
750 return view_host;
751 }
752
753 return NULL;
754 }
755
SaveAsAsync(int tab_handle)756 void AutomationProvider::SaveAsAsync(int tab_handle) {
757 NavigationController* tab = NULL;
758 WebContents* web_contents = GetWebContentsForHandle(tab_handle, &tab);
759 if (web_contents)
760 web_contents->OnSavePage();
761 }
762