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