1 // Copyright (c) 2013 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/chromedriver/window_commands.h" 6 7 #include <list> 8 #include <string> 9 10 #include "base/callback.h" 11 #include "base/strings/string_number_conversions.h" 12 #include "base/strings/stringprintf.h" 13 #include "base/threading/platform_thread.h" 14 #include "base/time/time.h" 15 #include "base/values.h" 16 #include "chrome/test/chromedriver/basic_types.h" 17 #include "chrome/test/chromedriver/chrome/automation_extension.h" 18 #include "chrome/test/chromedriver/chrome/chrome.h" 19 #include "chrome/test/chromedriver/chrome/chrome_desktop_impl.h" 20 #include "chrome/test/chromedriver/chrome/devtools_client.h" 21 #include "chrome/test/chromedriver/chrome/geoposition.h" 22 #include "chrome/test/chromedriver/chrome/javascript_dialog_manager.h" 23 #include "chrome/test/chromedriver/chrome/js.h" 24 #include "chrome/test/chromedriver/chrome/status.h" 25 #include "chrome/test/chromedriver/chrome/ui_events.h" 26 #include "chrome/test/chromedriver/chrome/web_view.h" 27 #include "chrome/test/chromedriver/element_util.h" 28 #include "chrome/test/chromedriver/session.h" 29 #include "chrome/test/chromedriver/util.h" 30 31 namespace { 32 33 Status GetMouseButton(const base::DictionaryValue& params, 34 MouseButton* button) { 35 int button_num; 36 if (!params.GetInteger("button", &button_num)) { 37 button_num = 0; // Default to left mouse button. 38 } else if (button_num < 0 || button_num > 2) { 39 return Status(kUnknownError, 40 base::StringPrintf("invalid button: %d", button_num)); 41 } 42 *button = static_cast<MouseButton>(button_num); 43 return Status(kOk); 44 } 45 46 Status GetUrl(WebView* web_view, const std::string& frame, std::string* url) { 47 scoped_ptr<base::Value> value; 48 base::ListValue args; 49 Status status = web_view->CallFunction( 50 frame, "function() { return document.URL; }", args, &value); 51 if (status.IsError()) 52 return status; 53 if (!value->GetAsString(url)) 54 return Status(kUnknownError, "javascript failed to return the url"); 55 return Status(kOk); 56 } 57 58 struct Cookie { 59 Cookie(const std::string& name, 60 const std::string& value, 61 const std::string& domain, 62 const std::string& path, 63 double expiry, 64 bool secure, 65 bool session) 66 : name(name), value(value), domain(domain), path(path), expiry(expiry), 67 secure(secure), session(session) {} 68 69 std::string name; 70 std::string value; 71 std::string domain; 72 std::string path; 73 double expiry; 74 bool secure; 75 bool session; 76 }; 77 78 base::DictionaryValue* CreateDictionaryFrom(const Cookie& cookie) { 79 base::DictionaryValue* dict = new base::DictionaryValue(); 80 dict->SetString("name", cookie.name); 81 dict->SetString("value", cookie.value); 82 if (!cookie.domain.empty()) 83 dict->SetString("domain", cookie.domain); 84 if (!cookie.path.empty()) 85 dict->SetString("path", cookie.path); 86 if (!cookie.session) 87 dict->SetDouble("expiry", cookie.expiry); 88 dict->SetBoolean("secure", cookie.secure); 89 return dict; 90 } 91 92 Status GetVisibleCookies(WebView* web_view, 93 std::list<Cookie>* cookies) { 94 scoped_ptr<base::ListValue> internal_cookies; 95 Status status = web_view->GetCookies(&internal_cookies); 96 if (status.IsError()) 97 return status; 98 std::list<Cookie> cookies_tmp; 99 for (size_t i = 0; i < internal_cookies->GetSize(); ++i) { 100 base::DictionaryValue* cookie_dict; 101 if (!internal_cookies->GetDictionary(i, &cookie_dict)) 102 return Status(kUnknownError, "DevTools returns a non-dictionary cookie"); 103 104 std::string name; 105 cookie_dict->GetString("name", &name); 106 std::string value; 107 cookie_dict->GetString("value", &value); 108 std::string domain; 109 cookie_dict->GetString("domain", &domain); 110 std::string path; 111 cookie_dict->GetString("path", &path); 112 double expiry = 0; 113 cookie_dict->GetDouble("expires", &expiry); 114 expiry /= 1000; // Convert from millisecond to second. 115 bool session = false; 116 cookie_dict->GetBoolean("session", &session); 117 bool secure = false; 118 cookie_dict->GetBoolean("secure", &secure); 119 120 cookies_tmp.push_back( 121 Cookie(name, value, domain, path, expiry, secure, session)); 122 } 123 cookies->swap(cookies_tmp); 124 return Status(kOk); 125 } 126 127 Status ScrollCoordinateInToView( 128 Session* session, WebView* web_view, int x, int y, int* offset_x, 129 int* offset_y) { 130 scoped_ptr<base::Value> value; 131 base::ListValue args; 132 args.AppendInteger(x); 133 args.AppendInteger(y); 134 Status status = web_view->CallFunction( 135 std::string(), 136 "function(x, y) {" 137 " if (x < window.pageXOffset ||" 138 " x >= window.pageXOffset + window.innerWidth ||" 139 " y < window.pageYOffset ||" 140 " y >= window.pageYOffset + window.innerHeight) {" 141 " window.scrollTo(x - window.innerWidth/2, y - window.innerHeight/2);" 142 " }" 143 " return {" 144 " view_x: Math.floor(window.pageXOffset)," 145 " view_y: Math.floor(window.pageYOffset)," 146 " view_width: Math.floor(window.innerWidth)," 147 " view_height: Math.floor(window.innerHeight)};" 148 "}", 149 args, 150 &value); 151 if (!status.IsOk()) 152 return status; 153 base::DictionaryValue* view_attrib; 154 value->GetAsDictionary(&view_attrib); 155 int view_x, view_y, view_width, view_height; 156 view_attrib->GetInteger("view_x", &view_x); 157 view_attrib->GetInteger("view_y", &view_y); 158 view_attrib->GetInteger("view_width", &view_width); 159 view_attrib->GetInteger("view_height", &view_height); 160 *offset_x = x - view_x; 161 *offset_y = y - view_y; 162 if (*offset_x < 0 || *offset_x >= view_width || *offset_y < 0 || 163 *offset_y >= view_height) 164 return Status(kUnknownError, "Failed to scroll coordinate into view"); 165 return Status(kOk); 166 } 167 168 Status ExecuteTouchEvent( 169 Session* session, WebView* web_view, TouchEventType type, 170 const base::DictionaryValue& params) { 171 int x, y; 172 if (!params.GetInteger("x", &x)) 173 return Status(kUnknownError, "'x' must be an integer"); 174 if (!params.GetInteger("y", &y)) 175 return Status(kUnknownError, "'y' must be an integer"); 176 int relative_x = x; 177 int relative_y = y; 178 Status status = ScrollCoordinateInToView( 179 session, web_view, x, y, &relative_x, &relative_y); 180 if (!status.IsOk()) 181 return status; 182 std::list<TouchEvent> events; 183 events.push_back( 184 TouchEvent(type, relative_x, relative_y)); 185 return web_view->DispatchTouchEvents(events); 186 } 187 188 } // namespace 189 190 Status ExecuteWindowCommand( 191 const WindowCommand& command, 192 Session* session, 193 const base::DictionaryValue& params, 194 scoped_ptr<base::Value>* value) { 195 WebView* web_view = NULL; 196 Status status = session->GetTargetWindow(&web_view); 197 if (status.IsError()) 198 return status; 199 200 status = web_view->ConnectIfNecessary(); 201 if (status.IsError()) 202 return status; 203 204 status = web_view->HandleReceivedEvents(); 205 if (status.IsError()) 206 return status; 207 208 if (web_view->GetJavaScriptDialogManager()->IsDialogOpen()) 209 return Status(kUnexpectedAlertOpen); 210 211 Status nav_status(kOk); 212 for (int attempt = 0; attempt < 2; attempt++) { 213 if (attempt == 1) { 214 if (status.code() == kNoSuchExecutionContext) 215 // Switch to main frame and retry command if subframe no longer exists. 216 session->SwitchToTopFrame(); 217 else 218 break; 219 } 220 nav_status = web_view->WaitForPendingNavigations( 221 session->GetCurrentFrameId(), session->page_load_timeout, true); 222 if (nav_status.IsError()) 223 return nav_status; 224 225 status = command.Run(session, web_view, params, value); 226 } 227 228 nav_status = web_view->WaitForPendingNavigations( 229 session->GetCurrentFrameId(), session->page_load_timeout, true); 230 231 if (status.IsOk() && nav_status.IsError() && 232 nav_status.code() != kUnexpectedAlertOpen) 233 return nav_status; 234 if (status.code() == kUnexpectedAlertOpen) 235 return Status(kOk); 236 return status; 237 } 238 239 Status ExecuteGet( 240 Session* session, 241 WebView* web_view, 242 const base::DictionaryValue& params, 243 scoped_ptr<base::Value>* value) { 244 std::string url; 245 if (!params.GetString("url", &url)) 246 return Status(kUnknownError, "'url' must be a string"); 247 return web_view->Load(url); 248 } 249 250 Status ExecuteExecuteScript( 251 Session* session, 252 WebView* web_view, 253 const base::DictionaryValue& params, 254 scoped_ptr<base::Value>* value) { 255 std::string script; 256 if (!params.GetString("script", &script)) 257 return Status(kUnknownError, "'script' must be a string"); 258 if (script == ":takeHeapSnapshot") { 259 return web_view->TakeHeapSnapshot(value); 260 } else { 261 const base::ListValue* args; 262 if (!params.GetList("args", &args)) 263 return Status(kUnknownError, "'args' must be a list"); 264 265 return web_view->CallFunction(session->GetCurrentFrameId(), 266 "function(){" + script + "}", *args, value); 267 } 268 } 269 270 Status ExecuteExecuteAsyncScript( 271 Session* session, 272 WebView* web_view, 273 const base::DictionaryValue& params, 274 scoped_ptr<base::Value>* value) { 275 std::string script; 276 if (!params.GetString("script", &script)) 277 return Status(kUnknownError, "'script' must be a string"); 278 const base::ListValue* args; 279 if (!params.GetList("args", &args)) 280 return Status(kUnknownError, "'args' must be a list"); 281 282 return web_view->CallUserAsyncFunction( 283 session->GetCurrentFrameId(), "function(){" + script + "}", *args, 284 session->script_timeout, value); 285 } 286 287 Status ExecuteSwitchToFrame( 288 Session* session, 289 WebView* web_view, 290 const base::DictionaryValue& params, 291 scoped_ptr<base::Value>* value) { 292 const base::Value* id; 293 if (!params.Get("id", &id)) 294 return Status(kUnknownError, "missing 'id'"); 295 296 if (id->IsType(base::Value::TYPE_NULL)) { 297 session->SwitchToTopFrame(); 298 return Status(kOk); 299 } 300 301 std::string script; 302 base::ListValue args; 303 const base::DictionaryValue* id_dict; 304 if (id->GetAsDictionary(&id_dict)) { 305 script = "function(elem) { return elem; }"; 306 args.Append(id_dict->DeepCopy()); 307 } else { 308 script = 309 "function(xpath) {" 310 " return document.evaluate(xpath, document, null, " 311 " XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;" 312 "}"; 313 std::string xpath = "(/html/body//iframe|/html/frameset/frame)"; 314 std::string id_string; 315 int id_int; 316 if (id->GetAsString(&id_string)) { 317 xpath += base::StringPrintf( 318 "[@name=\"%s\" or @id=\"%s\"]", id_string.c_str(), id_string.c_str()); 319 } else if (id->GetAsInteger(&id_int)) { 320 xpath += base::StringPrintf("[%d]", id_int + 1); 321 } else { 322 return Status(kUnknownError, "invalid 'id'"); 323 } 324 args.Append(new base::StringValue(xpath)); 325 } 326 std::string frame; 327 Status status = web_view->GetFrameByFunction( 328 session->GetCurrentFrameId(), script, args, &frame); 329 if (status.IsError()) 330 return status; 331 332 scoped_ptr<base::Value> result; 333 status = web_view->CallFunction( 334 session->GetCurrentFrameId(), script, args, &result); 335 if (status.IsError()) 336 return status; 337 const base::DictionaryValue* element; 338 if (!result->GetAsDictionary(&element)) 339 return Status(kUnknownError, "fail to locate the sub frame element"); 340 341 std::string chrome_driver_id = GenerateId(); 342 const char* kSetFrameIdentifier = 343 "function(frame, id) {" 344 " frame.setAttribute('cd_frame_id_', id);" 345 "}"; 346 base::ListValue new_args; 347 new_args.Append(element->DeepCopy()); 348 new_args.AppendString(chrome_driver_id); 349 result.reset(NULL); 350 status = web_view->CallFunction( 351 session->GetCurrentFrameId(), kSetFrameIdentifier, new_args, &result); 352 if (status.IsError()) 353 return status; 354 session->SwitchToSubFrame(frame, chrome_driver_id); 355 return Status(kOk); 356 } 357 358 Status ExecuteGetTitle( 359 Session* session, 360 WebView* web_view, 361 const base::DictionaryValue& params, 362 scoped_ptr<base::Value>* value) { 363 const char* kGetTitleScript = 364 "function() {" 365 " if (document.title)" 366 " return document.title;" 367 " else" 368 " return document.URL;" 369 "}"; 370 base::ListValue args; 371 return web_view->CallFunction(std::string(), kGetTitleScript, args, value); 372 } 373 374 Status ExecuteGetPageSource( 375 Session* session, 376 WebView* web_view, 377 const base::DictionaryValue& params, 378 scoped_ptr<base::Value>* value) { 379 const char* kGetPageSource = 380 "function() {" 381 " return new XMLSerializer().serializeToString(document);" 382 "}"; 383 base::ListValue args; 384 return web_view->CallFunction( 385 session->GetCurrentFrameId(), kGetPageSource, args, value); 386 } 387 388 Status ExecuteFindElement( 389 int interval_ms, 390 Session* session, 391 WebView* web_view, 392 const base::DictionaryValue& params, 393 scoped_ptr<base::Value>* value) { 394 return FindElement(interval_ms, true, NULL, session, web_view, params, value); 395 } 396 397 Status ExecuteFindElements( 398 int interval_ms, 399 Session* session, 400 WebView* web_view, 401 const base::DictionaryValue& params, 402 scoped_ptr<base::Value>* value) { 403 return FindElement( 404 interval_ms, false, NULL, session, web_view, params, value); 405 } 406 407 Status ExecuteGetCurrentUrl( 408 Session* session, 409 WebView* web_view, 410 const base::DictionaryValue& params, 411 scoped_ptr<base::Value>* value) { 412 std::string url; 413 Status status = GetUrl(web_view, session->GetCurrentFrameId(), &url); 414 if (status.IsError()) 415 return status; 416 value->reset(new base::StringValue(url)); 417 return Status(kOk); 418 } 419 420 Status ExecuteGoBack( 421 Session* session, 422 WebView* web_view, 423 const base::DictionaryValue& params, 424 scoped_ptr<base::Value>* value) { 425 return web_view->EvaluateScript( 426 std::string(), "window.history.back();", value); 427 } 428 429 Status ExecuteGoForward( 430 Session* session, 431 WebView* web_view, 432 const base::DictionaryValue& params, 433 scoped_ptr<base::Value>* value) { 434 return web_view->EvaluateScript( 435 std::string(), "window.history.forward();", value); 436 } 437 438 Status ExecuteRefresh( 439 Session* session, 440 WebView* web_view, 441 const base::DictionaryValue& params, 442 scoped_ptr<base::Value>* value) { 443 return web_view->Reload(); 444 } 445 446 Status ExecuteMouseMoveTo( 447 Session* session, 448 WebView* web_view, 449 const base::DictionaryValue& params, 450 scoped_ptr<base::Value>* value) { 451 std::string element_id; 452 bool has_element = params.GetString("element", &element_id); 453 int x_offset = 0; 454 int y_offset = 0; 455 bool has_offset = params.GetInteger("xoffset", &x_offset) && 456 params.GetInteger("yoffset", &y_offset); 457 if (!has_element && !has_offset) 458 return Status(kUnknownError, "at least an element or offset should be set"); 459 460 WebPoint location; 461 if (has_element) { 462 Status status = ScrollElementIntoView( 463 session, web_view, element_id, &location); 464 if (status.IsError()) 465 return status; 466 } else { 467 location = session->mouse_position; 468 } 469 470 if (has_offset) { 471 location.Offset(x_offset, y_offset); 472 } else { 473 WebSize size; 474 Status status = GetElementSize(session, web_view, element_id, &size); 475 if (status.IsError()) 476 return status; 477 location.Offset(size.width / 2, size.height / 2); 478 } 479 480 std::list<MouseEvent> events; 481 events.push_back( 482 MouseEvent(kMovedMouseEventType, kNoneMouseButton, 483 location.x, location.y, session->sticky_modifiers, 0)); 484 Status status = 485 web_view->DispatchMouseEvents(events, session->GetCurrentFrameId()); 486 if (status.IsOk()) 487 session->mouse_position = location; 488 return status; 489 } 490 491 Status ExecuteMouseClick( 492 Session* session, 493 WebView* web_view, 494 const base::DictionaryValue& params, 495 scoped_ptr<base::Value>* value) { 496 MouseButton button; 497 Status status = GetMouseButton(params, &button); 498 if (status.IsError()) 499 return status; 500 std::list<MouseEvent> events; 501 events.push_back( 502 MouseEvent(kPressedMouseEventType, button, 503 session->mouse_position.x, session->mouse_position.y, 504 session->sticky_modifiers, 1)); 505 events.push_back( 506 MouseEvent(kReleasedMouseEventType, button, 507 session->mouse_position.x, session->mouse_position.y, 508 session->sticky_modifiers, 1)); 509 return web_view->DispatchMouseEvents(events, session->GetCurrentFrameId()); 510 } 511 512 Status ExecuteMouseButtonDown( 513 Session* session, 514 WebView* web_view, 515 const base::DictionaryValue& params, 516 scoped_ptr<base::Value>* value) { 517 MouseButton button; 518 Status status = GetMouseButton(params, &button); 519 if (status.IsError()) 520 return status; 521 std::list<MouseEvent> events; 522 events.push_back( 523 MouseEvent(kPressedMouseEventType, button, 524 session->mouse_position.x, session->mouse_position.y, 525 session->sticky_modifiers, 1)); 526 return web_view->DispatchMouseEvents(events, session->GetCurrentFrameId()); 527 } 528 529 Status ExecuteMouseButtonUp( 530 Session* session, 531 WebView* web_view, 532 const base::DictionaryValue& params, 533 scoped_ptr<base::Value>* value) { 534 MouseButton button; 535 Status status = GetMouseButton(params, &button); 536 if (status.IsError()) 537 return status; 538 std::list<MouseEvent> events; 539 events.push_back( 540 MouseEvent(kReleasedMouseEventType, button, 541 session->mouse_position.x, session->mouse_position.y, 542 session->sticky_modifiers, 1)); 543 return web_view->DispatchMouseEvents(events, session->GetCurrentFrameId()); 544 } 545 546 Status ExecuteMouseDoubleClick( 547 Session* session, 548 WebView* web_view, 549 const base::DictionaryValue& params, 550 scoped_ptr<base::Value>* value) { 551 MouseButton button; 552 Status status = GetMouseButton(params, &button); 553 if (status.IsError()) 554 return status; 555 std::list<MouseEvent> events; 556 events.push_back( 557 MouseEvent(kPressedMouseEventType, button, 558 session->mouse_position.x, session->mouse_position.y, 559 session->sticky_modifiers, 2)); 560 events.push_back( 561 MouseEvent(kReleasedMouseEventType, button, 562 session->mouse_position.x, session->mouse_position.y, 563 session->sticky_modifiers, 2)); 564 return web_view->DispatchMouseEvents(events, session->GetCurrentFrameId()); 565 } 566 567 Status ExecuteTouchDown( 568 Session* session, 569 WebView* web_view, 570 const base::DictionaryValue& params, 571 scoped_ptr<base::Value>* value) { 572 return ExecuteTouchEvent(session, web_view, kTouchStart, params); 573 } 574 575 Status ExecuteTouchUp( 576 Session* session, 577 WebView* web_view, 578 const base::DictionaryValue& params, 579 scoped_ptr<base::Value>* value) { 580 return ExecuteTouchEvent(session, web_view, kTouchEnd, params); 581 } 582 583 Status ExecuteTouchMove( 584 Session* session, 585 WebView* web_view, 586 const base::DictionaryValue& params, 587 scoped_ptr<base::Value>* value) { 588 return ExecuteTouchEvent(session, web_view, kTouchMove, params); 589 } 590 591 Status ExecuteGetActiveElement( 592 Session* session, 593 WebView* web_view, 594 const base::DictionaryValue& params, 595 scoped_ptr<base::Value>* value) { 596 return GetActiveElement(session, web_view, value); 597 } 598 599 Status ExecuteSendKeysToActiveElement( 600 Session* session, 601 WebView* web_view, 602 const base::DictionaryValue& params, 603 scoped_ptr<base::Value>* value) { 604 const base::ListValue* key_list; 605 if (!params.GetList("value", &key_list)) 606 return Status(kUnknownError, "'value' must be a list"); 607 return SendKeysOnWindow( 608 web_view, key_list, false, &session->sticky_modifiers); 609 } 610 611 Status ExecuteGetAppCacheStatus( 612 Session* session, 613 WebView* web_view, 614 const base::DictionaryValue& params, 615 scoped_ptr<base::Value>* value) { 616 return web_view->EvaluateScript( 617 session->GetCurrentFrameId(), 618 "applicationCache.status", 619 value); 620 } 621 622 Status ExecuteIsBrowserOnline( 623 Session* session, 624 WebView* web_view, 625 const base::DictionaryValue& params, 626 scoped_ptr<base::Value>* value) { 627 return web_view->EvaluateScript( 628 session->GetCurrentFrameId(), 629 "navigator.onLine", 630 value); 631 } 632 633 Status ExecuteGetStorageItem( 634 const char* storage, 635 Session* session, 636 WebView* web_view, 637 const base::DictionaryValue& params, 638 scoped_ptr<base::Value>* value) { 639 std::string key; 640 if (!params.GetString("key", &key)) 641 return Status(kUnknownError, "'key' must be a string"); 642 base::ListValue args; 643 args.Append(new base::StringValue(key)); 644 return web_view->CallFunction( 645 session->GetCurrentFrameId(), 646 base::StringPrintf("function(key) { return %s[key]; }", storage), 647 args, 648 value); 649 } 650 651 Status ExecuteGetStorageKeys( 652 const char* storage, 653 Session* session, 654 WebView* web_view, 655 const base::DictionaryValue& params, 656 scoped_ptr<base::Value>* value) { 657 const char script[] = 658 "var keys = [];" 659 "for (var key in %s) {" 660 " keys.push(key);" 661 "}" 662 "keys"; 663 return web_view->EvaluateScript( 664 session->GetCurrentFrameId(), 665 base::StringPrintf(script, storage), 666 value); 667 } 668 669 Status ExecuteSetStorageItem( 670 const char* storage, 671 Session* session, 672 WebView* web_view, 673 const base::DictionaryValue& params, 674 scoped_ptr<base::Value>* value) { 675 std::string key; 676 if (!params.GetString("key", &key)) 677 return Status(kUnknownError, "'key' must be a string"); 678 std::string storage_value; 679 if (!params.GetString("value", &storage_value)) 680 return Status(kUnknownError, "'value' must be a string"); 681 base::ListValue args; 682 args.Append(new base::StringValue(key)); 683 args.Append(new base::StringValue(storage_value)); 684 return web_view->CallFunction( 685 session->GetCurrentFrameId(), 686 base::StringPrintf("function(key, value) { %s[key] = value; }", storage), 687 args, 688 value); 689 } 690 691 Status ExecuteRemoveStorageItem( 692 const char* storage, 693 Session* session, 694 WebView* web_view, 695 const base::DictionaryValue& params, 696 scoped_ptr<base::Value>* value) { 697 std::string key; 698 if (!params.GetString("key", &key)) 699 return Status(kUnknownError, "'key' must be a string"); 700 base::ListValue args; 701 args.Append(new base::StringValue(key)); 702 return web_view->CallFunction( 703 session->GetCurrentFrameId(), 704 base::StringPrintf("function(key) { %s.removeItem(key) }", storage), 705 args, 706 value); 707 } 708 709 Status ExecuteClearStorage( 710 const char* storage, 711 Session* session, 712 WebView* web_view, 713 const base::DictionaryValue& params, 714 scoped_ptr<base::Value>* value) { 715 return web_view->EvaluateScript( 716 session->GetCurrentFrameId(), 717 base::StringPrintf("%s.clear()", storage), 718 value); 719 } 720 721 Status ExecuteGetStorageSize( 722 const char* storage, 723 Session* session, 724 WebView* web_view, 725 const base::DictionaryValue& params, 726 scoped_ptr<base::Value>* value) { 727 return web_view->EvaluateScript( 728 session->GetCurrentFrameId(), 729 base::StringPrintf("%s.length", storage), 730 value); 731 } 732 733 Status ExecuteScreenshot( 734 Session* session, 735 WebView* web_view, 736 const base::DictionaryValue& params, 737 scoped_ptr<base::Value>* value) { 738 Status status = session->chrome->ActivateWebView(web_view->GetId()); 739 if (status.IsError()) 740 return status; 741 742 std::string screenshot; 743 if (session->chrome->GetAsDesktop() && !session->force_devtools_screenshot) { 744 AutomationExtension* extension = NULL; 745 status = 746 session->chrome->GetAsDesktop()->GetAutomationExtension(&extension); 747 if (status.IsError()) 748 return status; 749 status = extension->CaptureScreenshot(&screenshot); 750 // If the screenshot was forbidden, fallback to DevTools. 751 if (status.code() == kForbidden) 752 status = web_view->CaptureScreenshot(&screenshot); 753 } else { 754 status = web_view->CaptureScreenshot(&screenshot); 755 } 756 if (status.IsError()) 757 return status; 758 759 value->reset(new base::StringValue(screenshot)); 760 return Status(kOk); 761 } 762 763 Status ExecuteGetCookies( 764 Session* session, 765 WebView* web_view, 766 const base::DictionaryValue& params, 767 scoped_ptr<base::Value>* value) { 768 std::list<Cookie> cookies; 769 Status status = GetVisibleCookies(web_view, &cookies); 770 if (status.IsError()) 771 return status; 772 scoped_ptr<base::ListValue> cookie_list(new base::ListValue()); 773 for (std::list<Cookie>::const_iterator it = cookies.begin(); 774 it != cookies.end(); ++it) { 775 cookie_list->Append(CreateDictionaryFrom(*it)); 776 } 777 value->reset(cookie_list.release()); 778 return Status(kOk); 779 } 780 781 Status ExecuteAddCookie( 782 Session* session, 783 WebView* web_view, 784 const base::DictionaryValue& params, 785 scoped_ptr<base::Value>* value) { 786 const base::DictionaryValue* cookie; 787 if (!params.GetDictionary("cookie", &cookie)) 788 return Status(kUnknownError, "missing 'cookie'"); 789 base::ListValue args; 790 args.Append(cookie->DeepCopy()); 791 scoped_ptr<base::Value> result; 792 return web_view->CallFunction( 793 session->GetCurrentFrameId(), kAddCookieScript, args, &result); 794 } 795 796 Status ExecuteDeleteCookie( 797 Session* session, 798 WebView* web_view, 799 const base::DictionaryValue& params, 800 scoped_ptr<base::Value>* value) { 801 std::string name; 802 if (!params.GetString("name", &name)) 803 return Status(kUnknownError, "missing 'name'"); 804 base::DictionaryValue params_url; 805 scoped_ptr<base::Value> value_url; 806 std::string url; 807 Status status = GetUrl(web_view, session->GetCurrentFrameId(), &url); 808 if (status.IsError()) 809 return status; 810 return web_view->DeleteCookie(name, url); 811 } 812 813 Status ExecuteDeleteAllCookies( 814 Session* session, 815 WebView* web_view, 816 const base::DictionaryValue& params, 817 scoped_ptr<base::Value>* value) { 818 std::list<Cookie> cookies; 819 Status status = GetVisibleCookies(web_view, &cookies); 820 if (status.IsError()) 821 return status; 822 823 if (!cookies.empty()) { 824 base::DictionaryValue params_url; 825 scoped_ptr<base::Value> value_url; 826 std::string url; 827 status = GetUrl(web_view, session->GetCurrentFrameId(), &url); 828 if (status.IsError()) 829 return status; 830 for (std::list<Cookie>::const_iterator it = cookies.begin(); 831 it != cookies.end(); ++it) { 832 status = web_view->DeleteCookie(it->name, url); 833 if (status.IsError()) 834 return status; 835 } 836 } 837 838 return Status(kOk); 839 } 840 841 Status ExecuteSetLocation( 842 Session* session, 843 WebView* web_view, 844 const base::DictionaryValue& params, 845 scoped_ptr<base::Value>* value) { 846 const base::DictionaryValue* location = NULL; 847 Geoposition geoposition; 848 if (!params.GetDictionary("location", &location) || 849 !location->GetDouble("latitude", &geoposition.latitude) || 850 !location->GetDouble("longitude", &geoposition.longitude)) 851 return Status(kUnknownError, "missing or invalid 'location'"); 852 if (location->HasKey("accuracy") && 853 !location->GetDouble("accuracy", &geoposition.accuracy)) { 854 return Status(kUnknownError, "invalid 'accuracy'"); 855 } else { 856 // |accuracy| is not part of the WebDriver spec yet, so if it is not given 857 // default to 100 meters accuracy. 858 geoposition.accuracy = 100; 859 } 860 861 Status status = web_view->OverrideGeolocation(geoposition); 862 if (status.IsOk()) 863 session->overridden_geoposition.reset(new Geoposition(geoposition)); 864 return status; 865 } 866 867 Status ExecuteTakeHeapSnapshot( 868 Session* session, 869 WebView* web_view, 870 const base::DictionaryValue& params, 871 scoped_ptr<base::Value>* value) { 872 return web_view->TakeHeapSnapshot(value); 873 } 874