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/test/automation/tab_proxy.h" 6 7 #include <algorithm> 8 9 #include "base/json/json_string_value_serializer.h" 10 #include "base/logging.h" 11 #include "base/strings/string16.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "base/threading/platform_thread.h" 14 #include "chrome/common/automation_constants.h" 15 #include "chrome/common/automation_messages.h" 16 #include "chrome/test/automation/automation_proxy.h" 17 #include "chrome/test/automation/browser_proxy.h" 18 #include "url/gurl.h" 19 20 TabProxy::TabProxy(AutomationMessageSender* sender, 21 AutomationHandleTracker* tracker, 22 int handle) 23 : AutomationResourceProxy(tracker, sender, handle) { 24 } 25 26 bool TabProxy::GetTabTitle(std::wstring* title) const { 27 if (!is_valid()) 28 return false; 29 30 if (!title) { 31 NOTREACHED(); 32 return false; 33 } 34 35 int tab_title_size_response = 0; 36 37 bool succeeded = sender_->Send( 38 new AutomationMsg_TabTitle(handle_, &tab_title_size_response, title)); 39 return succeeded; 40 } 41 42 bool TabProxy::GetTabIndex(int* index) const { 43 if (!is_valid()) 44 return false; 45 46 if (!index) { 47 NOTREACHED(); 48 return false; 49 } 50 51 return sender_->Send(new AutomationMsg_TabIndex(handle_, index)); 52 } 53 54 int TabProxy::FindInPage(const std::wstring& search_string, 55 FindInPageDirection forward, 56 FindInPageCase match_case, 57 bool find_next, 58 int* ordinal) { 59 if (!is_valid()) 60 return -1; 61 62 AutomationMsg_Find_Params params; 63 params.search_string = WideToUTF16Hack(search_string); 64 params.find_next = find_next; 65 params.match_case = (match_case == CASE_SENSITIVE); 66 params.forward = (forward == FWD); 67 68 int matches = 0; 69 int ordinal2 = 0; 70 bool succeeded = sender_->Send(new AutomationMsg_Find(handle_, 71 params, 72 &ordinal2, 73 &matches)); 74 if (!succeeded) 75 return -1; 76 if (ordinal) 77 *ordinal = ordinal2; 78 return matches; 79 } 80 81 AutomationMsg_NavigationResponseValues TabProxy::NavigateToURL( 82 const GURL& url) { 83 return NavigateToURLBlockUntilNavigationsComplete(url, 1); 84 } 85 86 AutomationMsg_NavigationResponseValues 87 TabProxy::NavigateToURLBlockUntilNavigationsComplete( 88 const GURL& url, int number_of_navigations) { 89 if (!is_valid()) 90 return AUTOMATION_MSG_NAVIGATION_ERROR; 91 92 AutomationMsg_NavigationResponseValues navigate_response = 93 AUTOMATION_MSG_NAVIGATION_ERROR; 94 95 sender_->Send(new AutomationMsg_NavigateToURLBlockUntilNavigationsComplete( 96 handle_, url, number_of_navigations, &navigate_response)); 97 98 return navigate_response; 99 } 100 101 AutomationMsg_NavigationResponseValues TabProxy::GoBack() { 102 return GoBackBlockUntilNavigationsComplete(1); 103 } 104 105 AutomationMsg_NavigationResponseValues 106 TabProxy::GoBackBlockUntilNavigationsComplete(int number_of_navigations) { 107 if (!is_valid()) 108 return AUTOMATION_MSG_NAVIGATION_ERROR; 109 110 AutomationMsg_NavigationResponseValues navigate_response = 111 AUTOMATION_MSG_NAVIGATION_ERROR; 112 sender_->Send(new AutomationMsg_GoBackBlockUntilNavigationsComplete( 113 handle_, number_of_navigations, &navigate_response)); 114 return navigate_response; 115 } 116 117 AutomationMsg_NavigationResponseValues TabProxy::GoForward() { 118 return GoForwardBlockUntilNavigationsComplete(1); 119 } 120 121 AutomationMsg_NavigationResponseValues 122 TabProxy::GoForwardBlockUntilNavigationsComplete( 123 int number_of_navigations) { 124 if (!is_valid()) 125 return AUTOMATION_MSG_NAVIGATION_ERROR; 126 127 AutomationMsg_NavigationResponseValues navigate_response = 128 AUTOMATION_MSG_NAVIGATION_ERROR; 129 sender_->Send(new AutomationMsg_GoForwardBlockUntilNavigationsComplete( 130 handle_, number_of_navigations, &navigate_response)); 131 return navigate_response; 132 } 133 134 AutomationMsg_NavigationResponseValues TabProxy::Reload() { 135 if (!is_valid()) 136 return AUTOMATION_MSG_NAVIGATION_ERROR; 137 138 AutomationMsg_NavigationResponseValues navigate_response = 139 AUTOMATION_MSG_NAVIGATION_ERROR; 140 sender_->Send(new AutomationMsg_Reload(handle_, &navigate_response)); 141 return navigate_response; 142 } 143 144 bool TabProxy::GetCurrentURL(GURL* url) const { 145 if (!is_valid()) 146 return false; 147 148 if (!url) { 149 NOTREACHED(); 150 return false; 151 } 152 153 bool succeeded = false; 154 sender_->Send(new AutomationMsg_TabURL(handle_, &succeeded, url)); 155 return succeeded; 156 } 157 158 bool TabProxy::NavigateToURLAsync(const GURL& url) { 159 if (!is_valid()) 160 return false; 161 162 bool status = false; 163 sender_->Send(new AutomationMsg_NavigationAsync(handle_, 164 url, 165 &status)); 166 return status; 167 } 168 169 bool TabProxy::ExecuteAndExtractString(const std::wstring& frame_xpath, 170 const std::wstring& jscript, 171 std::wstring* string_value) { 172 scoped_ptr<Value> root(ExecuteAndExtractValue(frame_xpath, jscript)); 173 if (root == NULL) 174 return false; 175 176 DCHECK(root->IsType(Value::TYPE_LIST)); 177 Value* value = NULL; 178 bool succeeded = static_cast<ListValue*>(root.get())->Get(0, &value); 179 if (succeeded) { 180 string16 read_value; 181 succeeded = value->GetAsString(&read_value); 182 if (succeeded) { 183 // TODO(viettrungluu): remove conversion. (But should |jscript| be UTF-8?) 184 *string_value = UTF16ToWideHack(read_value); 185 } 186 } 187 return succeeded; 188 } 189 190 bool TabProxy::ExecuteAndExtractBool(const std::wstring& frame_xpath, 191 const std::wstring& jscript, 192 bool* bool_value) { 193 scoped_ptr<Value> root(ExecuteAndExtractValue(frame_xpath, jscript)); 194 if (root == NULL) 195 return false; 196 197 bool read_value = false; 198 DCHECK(root->IsType(Value::TYPE_LIST)); 199 Value* value = NULL; 200 bool succeeded = static_cast<ListValue*>(root.get())->Get(0, &value); 201 if (succeeded) { 202 succeeded = value->GetAsBoolean(&read_value); 203 if (succeeded) { 204 *bool_value = read_value; 205 } 206 } 207 return succeeded; 208 } 209 210 bool TabProxy::ExecuteAndExtractInt(const std::wstring& frame_xpath, 211 const std::wstring& jscript, 212 int* int_value) { 213 scoped_ptr<Value> root(ExecuteAndExtractValue(frame_xpath, jscript)); 214 if (root == NULL) 215 return false; 216 217 int read_value = 0; 218 DCHECK(root->IsType(Value::TYPE_LIST)); 219 Value* value = NULL; 220 bool succeeded = static_cast<ListValue*>(root.get())->Get(0, &value); 221 if (succeeded) { 222 succeeded = value->GetAsInteger(&read_value); 223 if (succeeded) { 224 *int_value = read_value; 225 } 226 } 227 return succeeded; 228 } 229 230 Value* TabProxy::ExecuteAndExtractValue(const std::wstring& frame_xpath, 231 const std::wstring& jscript) { 232 if (!is_valid()) 233 return NULL; 234 235 std::string json; 236 if (!sender_->Send(new AutomationMsg_DomOperation(handle_, frame_xpath, 237 jscript, &json))) { 238 return NULL; 239 } 240 // Wrap |json| in an array before deserializing because valid JSON has an 241 // array or an object as the root. 242 json.insert(0, "["); 243 json.append("]"); 244 245 JSONStringValueSerializer deserializer(json); 246 return deserializer.Deserialize(NULL, NULL); 247 } 248 249 bool TabProxy::GetCookies(const GURL& url, std::string* cookies) { 250 if (!is_valid()) 251 return false; 252 253 int size = 0; 254 return sender_->Send(new AutomationMsg_GetCookies(url, handle_, &size, 255 cookies)); 256 } 257 258 bool TabProxy::GetCookieByName(const GURL& url, 259 const std::string& name, 260 std::string* cookie) { 261 std::string cookies; 262 if (!GetCookies(url, &cookies)) 263 return false; 264 265 std::string namestr = name + "="; 266 std::string::size_type idx = cookies.find(namestr); 267 if (idx != std::string::npos) { 268 cookies.erase(0, idx + namestr.length()); 269 *cookie = cookies.substr(0, cookies.find(";")); 270 } else { 271 cookie->clear(); 272 } 273 274 return true; 275 } 276 277 bool TabProxy::Close() { 278 return Close(false); 279 } 280 281 bool TabProxy::Close(bool wait_until_closed) { 282 if (!is_valid()) 283 return false; 284 285 bool succeeded = false; 286 sender_->Send(new AutomationMsg_CloseTab(handle_, wait_until_closed, 287 &succeeded)); 288 return succeeded; 289 } 290 291 #if defined(OS_WIN) 292 bool TabProxy::ProcessUnhandledAccelerator(const MSG& msg) { 293 if (!is_valid()) 294 return false; 295 296 return sender_->Send( 297 new AutomationMsg_ProcessUnhandledAccelerator(handle_, msg)); 298 // This message expects no response 299 } 300 301 bool TabProxy::SetInitialFocus(bool reverse, bool restore_focus_to_view) { 302 if (!is_valid()) 303 return false; 304 305 return sender_->Send( 306 new AutomationMsg_SetInitialFocus(handle_, reverse, 307 restore_focus_to_view)); 308 // This message expects no response 309 } 310 311 AutomationMsg_NavigationResponseValues TabProxy::NavigateInExternalTab( 312 const GURL& url, const GURL& referrer) { 313 if (!is_valid()) 314 return AUTOMATION_MSG_NAVIGATION_ERROR; 315 316 AutomationMsg_NavigationResponseValues rv = AUTOMATION_MSG_NAVIGATION_ERROR; 317 sender_->Send(new AutomationMsg_NavigateInExternalTab(handle_, url, 318 referrer, &rv)); 319 return rv; 320 } 321 322 AutomationMsg_NavigationResponseValues TabProxy::NavigateExternalTabAtIndex( 323 int index) { 324 if (!is_valid()) 325 return AUTOMATION_MSG_NAVIGATION_ERROR; 326 327 AutomationMsg_NavigationResponseValues rv = AUTOMATION_MSG_NAVIGATION_ERROR; 328 sender_->Send(new AutomationMsg_NavigateExternalTabAtIndex(handle_, index, 329 &rv)); 330 return rv; 331 } 332 333 void TabProxy::HandleMessageFromExternalHost(const std::string& message, 334 const std::string& origin, 335 const std::string& target) { 336 if (!is_valid()) 337 return; 338 339 sender_->Send( 340 new AutomationMsg_HandleMessageFromExternalHost( 341 handle_, message, origin, target)); 342 } 343 #endif // defined(OS_WIN) 344 345 bool TabProxy::PrintAsync() { 346 if (!is_valid()) 347 return false; 348 349 return sender_->Send(new AutomationMsg_PrintAsync(handle_)); 350 } 351 352 bool TabProxy::WaitForInfoBarCount(size_t target_count) { 353 if (!is_valid()) 354 return false; 355 356 bool success = false; 357 return sender_->Send(new AutomationMsg_WaitForInfoBarCount( 358 handle_, target_count, &success)) && success; 359 } 360 361 bool TabProxy::OverrideEncoding(const std::string& encoding) { 362 if (!is_valid()) 363 return false; 364 365 bool succeeded = false; 366 sender_->Send(new AutomationMsg_OverrideEncoding(handle_, encoding, 367 &succeeded)); 368 return succeeded; 369 } 370 371 #if defined(OS_WIN) 372 void TabProxy::Reposition(HWND window, HWND window_insert_after, int left, 373 int top, int width, int height, int flags, 374 HWND parent_window) { 375 Reposition_Params params; 376 params.window = window; 377 params.window_insert_after = window_insert_after; 378 params.left = left; 379 params.top = top; 380 params.width = width; 381 params.height = height; 382 params.flags = flags; 383 params.set_parent = (::IsWindow(parent_window) ? true : false); 384 params.parent_window = parent_window; 385 sender_->Send(new AutomationMsg_TabReposition(handle_, params)); 386 } 387 388 void TabProxy::SendContextMenuCommand(int selected_command) { 389 sender_->Send(new AutomationMsg_ForwardContextMenuCommandToChrome( 390 handle_, selected_command)); 391 } 392 393 void TabProxy::OnHostMoved() { 394 sender_->Send(new AutomationMsg_BrowserMove(handle_)); 395 } 396 #endif // defined(OS_WIN) 397 398 void TabProxy::SelectAll() { 399 sender_->Send(new AutomationMsg_SelectAll(handle_)); 400 } 401 402 void TabProxy::Cut() { 403 sender_->Send(new AutomationMsg_Cut(handle_)); 404 } 405 406 void TabProxy::Copy() { 407 sender_->Send(new AutomationMsg_Copy(handle_)); 408 } 409 410 void TabProxy::Paste() { 411 sender_->Send(new AutomationMsg_Paste(handle_)); 412 } 413 414 void TabProxy::ReloadAsync() { 415 sender_->Send(new AutomationMsg_ReloadAsync(handle_)); 416 } 417 418 void TabProxy::StopAsync() { 419 sender_->Send(new AutomationMsg_StopAsync(handle_)); 420 } 421 422 void TabProxy::SaveAsAsync() { 423 sender_->Send(new AutomationMsg_SaveAsAsync(handle_)); 424 } 425 426 void TabProxy::JavaScriptStressTestControl(int cmd, int param) { 427 if (!is_valid()) 428 return; 429 430 sender_->Send(new AutomationMsg_JavaScriptStressTestControl( 431 handle_, cmd, param)); 432 } 433 434 void TabProxy::AddObserver(TabProxyDelegate* observer) { 435 base::AutoLock lock(list_lock_); 436 observers_list_.AddObserver(observer); 437 } 438 439 void TabProxy::RemoveObserver(TabProxyDelegate* observer) { 440 base::AutoLock lock(list_lock_); 441 observers_list_.RemoveObserver(observer); 442 } 443 444 // Called on Channel background thread, if TabMessages filter is installed. 445 bool TabProxy::OnMessageReceived(const IPC::Message& message) { 446 base::AutoLock lock(list_lock_); 447 FOR_EACH_OBSERVER(TabProxyDelegate, observers_list_, 448 OnMessageReceived(this, message)); 449 return true; 450 } 451 452 void TabProxy::OnChannelError() { 453 base::AutoLock lock(list_lock_); 454 FOR_EACH_OBSERVER(TabProxyDelegate, observers_list_, OnChannelError(this)); 455 } 456 457 TabProxy::~TabProxy() {} 458 459 void TabProxy::FirstObjectAdded() { 460 AddRef(); 461 } 462 463 void TabProxy::LastObjectRemoved() { 464 Release(); 465 } 466