Home | History | Annotate | Download | only in automation
      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