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.
5 #include "chrome/test/chromedriver/window_commands.h"
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/network_conditions.h"
25 #include "chrome/test/chromedriver/chrome/status.h"
26 #include "chrome/test/chromedriver/chrome/ui_events.h"
27 #include "chrome/test/chromedriver/chrome/web_view.h"
28 #include "chrome/test/chromedriver/element_util.h"
29 #include "chrome/test/chromedriver/session.h"
30 #include "chrome/test/chromedriver/util.h"
34 Status
GetMouseButton(const base::DictionaryValue
& params
,
35 MouseButton
* button
) {
37 if (!params
.GetInteger("button", &button_num
)) {
38 button_num
= 0; // Default to left mouse button.
39 } else if (button_num
< 0 || button_num
> 2) {
40 return Status(kUnknownError
,
41 base::StringPrintf("invalid button: %d", button_num
));
43 *button
= static_cast<MouseButton
>(button_num
);
47 Status
GetUrl(WebView
* web_view
, const std::string
& frame
, std::string
* url
) {
48 scoped_ptr
<base::Value
> value
;
50 Status status
= web_view
->CallFunction(
51 frame
, "function() { return document.URL; }", args
, &value
);
54 if (!value
->GetAsString(url
))
55 return Status(kUnknownError
, "javascript failed to return the url");
60 Cookie(const std::string
& name
,
61 const std::string
& value
,
62 const std::string
& domain
,
63 const std::string
& path
,
67 : name(name
), value(value
), domain(domain
), path(path
), expiry(expiry
),
68 secure(secure
), session(session
) {}
79 base::DictionaryValue
* CreateDictionaryFrom(const Cookie
& cookie
) {
80 base::DictionaryValue
* dict
= new base::DictionaryValue();
81 dict
->SetString("name", cookie
.name
);
82 dict
->SetString("value", cookie
.value
);
83 if (!cookie
.domain
.empty())
84 dict
->SetString("domain", cookie
.domain
);
85 if (!cookie
.path
.empty())
86 dict
->SetString("path", cookie
.path
);
88 dict
->SetDouble("expiry", cookie
.expiry
);
89 dict
->SetBoolean("secure", cookie
.secure
);
93 Status
GetVisibleCookies(WebView
* web_view
,
94 std::list
<Cookie
>* cookies
) {
95 scoped_ptr
<base::ListValue
> internal_cookies
;
96 Status status
= web_view
->GetCookies(&internal_cookies
);
99 std::list
<Cookie
> cookies_tmp
;
100 for (size_t i
= 0; i
< internal_cookies
->GetSize(); ++i
) {
101 base::DictionaryValue
* cookie_dict
;
102 if (!internal_cookies
->GetDictionary(i
, &cookie_dict
))
103 return Status(kUnknownError
, "DevTools returns a non-dictionary cookie");
106 cookie_dict
->GetString("name", &name
);
108 cookie_dict
->GetString("value", &value
);
110 cookie_dict
->GetString("domain", &domain
);
112 cookie_dict
->GetString("path", &path
);
114 cookie_dict
->GetDouble("expires", &expiry
);
115 expiry
/= 1000; // Convert from millisecond to second.
116 bool session
= false;
117 cookie_dict
->GetBoolean("session", &session
);
119 cookie_dict
->GetBoolean("secure", &secure
);
121 cookies_tmp
.push_back(
122 Cookie(name
, value
, domain
, path
, expiry
, secure
, session
));
124 cookies
->swap(cookies_tmp
);
128 Status
ScrollCoordinateInToView(
129 Session
* session
, WebView
* web_view
, int x
, int y
, int* offset_x
,
131 scoped_ptr
<base::Value
> value
;
132 base::ListValue args
;
133 args
.AppendInteger(x
);
134 args
.AppendInteger(y
);
135 Status status
= web_view
->CallFunction(
138 " if (x < window.pageXOffset ||"
139 " x >= window.pageXOffset + window.innerWidth ||"
140 " y < window.pageYOffset ||"
141 " y >= window.pageYOffset + window.innerHeight) {"
142 " window.scrollTo(x - window.innerWidth/2, y - window.innerHeight/2);"
145 " view_x: Math.floor(window.pageXOffset),"
146 " view_y: Math.floor(window.pageYOffset),"
147 " view_width: Math.floor(window.innerWidth),"
148 " view_height: Math.floor(window.innerHeight)};"
154 base::DictionaryValue
* view_attrib
;
155 value
->GetAsDictionary(&view_attrib
);
156 int view_x
, view_y
, view_width
, view_height
;
157 view_attrib
->GetInteger("view_x", &view_x
);
158 view_attrib
->GetInteger("view_y", &view_y
);
159 view_attrib
->GetInteger("view_width", &view_width
);
160 view_attrib
->GetInteger("view_height", &view_height
);
161 *offset_x
= x
- view_x
;
162 *offset_y
= y
- view_y
;
163 if (*offset_x
< 0 || *offset_x
>= view_width
|| *offset_y
< 0 ||
164 *offset_y
>= view_height
)
165 return Status(kUnknownError
, "Failed to scroll coordinate into view");
169 Status
ExecuteTouchEvent(
170 Session
* session
, WebView
* web_view
, TouchEventType type
,
171 const base::DictionaryValue
& params
) {
173 if (!params
.GetInteger("x", &x
))
174 return Status(kUnknownError
, "'x' must be an integer");
175 if (!params
.GetInteger("y", &y
))
176 return Status(kUnknownError
, "'y' must be an integer");
179 Status status
= ScrollCoordinateInToView(
180 session
, web_view
, x
, y
, &relative_x
, &relative_y
);
183 std::list
<TouchEvent
> events
;
185 TouchEvent(type
, relative_x
, relative_y
));
186 return web_view
->DispatchTouchEvents(events
);
191 Status
ExecuteWindowCommand(
192 const WindowCommand
& command
,
194 const base::DictionaryValue
& params
,
195 scoped_ptr
<base::Value
>* value
) {
196 WebView
* web_view
= NULL
;
197 Status status
= session
->GetTargetWindow(&web_view
);
198 if (status
.IsError())
201 status
= web_view
->ConnectIfNecessary();
202 if (status
.IsError())
205 status
= web_view
->HandleReceivedEvents();
206 if (status
.IsError())
209 if (web_view
->GetJavaScriptDialogManager()->IsDialogOpen())
210 return Status(kUnexpectedAlertOpen
);
212 Status
nav_status(kOk
);
213 for (int attempt
= 0; attempt
< 2; attempt
++) {
215 if (status
.code() == kNoSuchExecutionContext
)
216 // Switch to main frame and retry command if subframe no longer exists.
217 session
->SwitchToTopFrame();
221 nav_status
= web_view
->WaitForPendingNavigations(
222 session
->GetCurrentFrameId(), session
->page_load_timeout
, true);
223 if (nav_status
.IsError())
226 status
= command
.Run(session
, web_view
, params
, value
);
229 nav_status
= web_view
->WaitForPendingNavigations(
230 session
->GetCurrentFrameId(), session
->page_load_timeout
, true);
232 if (status
.IsOk() && nav_status
.IsError() &&
233 nav_status
.code() != kUnexpectedAlertOpen
)
235 if (status
.code() == kUnexpectedAlertOpen
)
243 const base::DictionaryValue
& params
,
244 scoped_ptr
<base::Value
>* value
) {
246 if (!params
.GetString("url", &url
))
247 return Status(kUnknownError
, "'url' must be a string");
248 return web_view
->Load(url
);
251 Status
ExecuteExecuteScript(
254 const base::DictionaryValue
& params
,
255 scoped_ptr
<base::Value
>* value
) {
257 if (!params
.GetString("script", &script
))
258 return Status(kUnknownError
, "'script' must be a string");
259 if (script
== ":takeHeapSnapshot") {
260 return web_view
->TakeHeapSnapshot(value
);
261 } else if (script
== ":startProfile") {
262 return web_view
->StartProfile();
263 } else if (script
== ":endProfile") {
264 return web_view
->EndProfile(value
);
266 const base::ListValue
* args
;
267 if (!params
.GetList("args", &args
))
268 return Status(kUnknownError
, "'args' must be a list");
270 return web_view
->CallFunction(session
->GetCurrentFrameId(),
271 "function(){" + script
+ "}", *args
, value
);
275 Status
ExecuteExecuteAsyncScript(
278 const base::DictionaryValue
& params
,
279 scoped_ptr
<base::Value
>* value
) {
281 if (!params
.GetString("script", &script
))
282 return Status(kUnknownError
, "'script' must be a string");
283 const base::ListValue
* args
;
284 if (!params
.GetList("args", &args
))
285 return Status(kUnknownError
, "'args' must be a list");
287 return web_view
->CallUserAsyncFunction(
288 session
->GetCurrentFrameId(), "function(){" + script
+ "}", *args
,
289 session
->script_timeout
, value
);
292 Status
ExecuteSwitchToFrame(
295 const base::DictionaryValue
& params
,
296 scoped_ptr
<base::Value
>* value
) {
297 const base::Value
* id
;
298 if (!params
.Get("id", &id
))
299 return Status(kUnknownError
, "missing 'id'");
301 if (id
->IsType(base::Value::TYPE_NULL
)) {
302 session
->SwitchToTopFrame();
307 base::ListValue args
;
308 const base::DictionaryValue
* id_dict
;
309 if (id
->GetAsDictionary(&id_dict
)) {
310 script
= "function(elem) { return elem; }";
311 args
.Append(id_dict
->DeepCopy());
315 " return document.evaluate(xpath, document, null, "
316 " XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;"
318 std::string xpath
= "(/html/body//iframe|/html/frameset/frame)";
319 std::string id_string
;
321 if (id
->GetAsString(&id_string
)) {
322 xpath
+= base::StringPrintf(
323 "[@name=\"%s\" or @id=\"%s\"]", id_string
.c_str(), id_string
.c_str());
324 } else if (id
->GetAsInteger(&id_int
)) {
325 xpath
+= base::StringPrintf("[%d]", id_int
+ 1);
327 return Status(kUnknownError
, "invalid 'id'");
329 args
.Append(new base::StringValue(xpath
));
332 Status status
= web_view
->GetFrameByFunction(
333 session
->GetCurrentFrameId(), script
, args
, &frame
);
334 if (status
.IsError())
337 scoped_ptr
<base::Value
> result
;
338 status
= web_view
->CallFunction(
339 session
->GetCurrentFrameId(), script
, args
, &result
);
340 if (status
.IsError())
342 const base::DictionaryValue
* element
;
343 if (!result
->GetAsDictionary(&element
))
344 return Status(kUnknownError
, "fail to locate the sub frame element");
346 std::string chrome_driver_id
= GenerateId();
347 const char kSetFrameIdentifier
[] =
348 "function(frame, id) {"
349 " frame.setAttribute('cd_frame_id_', id);"
351 base::ListValue new_args
;
352 new_args
.Append(element
->DeepCopy());
353 new_args
.AppendString(chrome_driver_id
);
355 status
= web_view
->CallFunction(
356 session
->GetCurrentFrameId(), kSetFrameIdentifier
, new_args
, &result
);
357 if (status
.IsError())
359 session
->SwitchToSubFrame(frame
, chrome_driver_id
);
363 Status
ExecuteSwitchToParentFrame(
366 const base::DictionaryValue
& params
,
367 scoped_ptr
<base::Value
>* value
) {
368 session
->SwitchToParentFrame();
372 Status
ExecuteGetTitle(
375 const base::DictionaryValue
& params
,
376 scoped_ptr
<base::Value
>* value
) {
377 const char kGetTitleScript
[] =
379 " if (document.title)"
380 " return document.title;"
382 " return document.URL;"
384 base::ListValue args
;
385 return web_view
->CallFunction(std::string(), kGetTitleScript
, args
, value
);
388 Status
ExecuteGetPageSource(
391 const base::DictionaryValue
& params
,
392 scoped_ptr
<base::Value
>* value
) {
393 const char kGetPageSource
[] =
395 " return new XMLSerializer().serializeToString(document);"
397 base::ListValue args
;
398 return web_view
->CallFunction(
399 session
->GetCurrentFrameId(), kGetPageSource
, args
, value
);
402 Status
ExecuteFindElement(
406 const base::DictionaryValue
& params
,
407 scoped_ptr
<base::Value
>* value
) {
408 return FindElement(interval_ms
, true, NULL
, session
, web_view
, params
, value
);
411 Status
ExecuteFindElements(
415 const base::DictionaryValue
& params
,
416 scoped_ptr
<base::Value
>* value
) {
418 interval_ms
, false, NULL
, session
, web_view
, params
, value
);
421 Status
ExecuteGetCurrentUrl(
424 const base::DictionaryValue
& params
,
425 scoped_ptr
<base::Value
>* value
) {
427 Status status
= GetUrl(web_view
, session
->GetCurrentFrameId(), &url
);
428 if (status
.IsError())
430 value
->reset(new base::StringValue(url
));
434 Status
ExecuteGoBack(
437 const base::DictionaryValue
& params
,
438 scoped_ptr
<base::Value
>* value
) {
439 return web_view
->TraverseHistory(-1);
442 Status
ExecuteGoForward(
445 const base::DictionaryValue
& params
,
446 scoped_ptr
<base::Value
>* value
) {
447 return web_view
->TraverseHistory(1);
450 Status
ExecuteRefresh(
453 const base::DictionaryValue
& params
,
454 scoped_ptr
<base::Value
>* value
) {
455 return web_view
->Reload();
458 Status
ExecuteMouseMoveTo(
461 const base::DictionaryValue
& params
,
462 scoped_ptr
<base::Value
>* value
) {
463 std::string element_id
;
464 bool has_element
= params
.GetString("element", &element_id
);
467 bool has_offset
= params
.GetInteger("xoffset", &x_offset
) &&
468 params
.GetInteger("yoffset", &y_offset
);
469 if (!has_element
&& !has_offset
)
470 return Status(kUnknownError
, "at least an element or offset should be set");
474 WebPoint
offset(x_offset
, y_offset
);
475 Status status
= ScrollElementIntoView(session
, web_view
, element_id
,
476 has_offset
? &offset
: nullptr, &location
);
477 if (status
.IsError())
480 location
= session
->mouse_position
;
482 location
.Offset(x_offset
, y_offset
);
485 std::list
<MouseEvent
> events
;
487 MouseEvent(kMovedMouseEventType
, kNoneMouseButton
,
488 location
.x
, location
.y
, session
->sticky_modifiers
, 0));
490 web_view
->DispatchMouseEvents(events
, session
->GetCurrentFrameId());
492 session
->mouse_position
= location
;
496 Status
ExecuteMouseClick(
499 const base::DictionaryValue
& params
,
500 scoped_ptr
<base::Value
>* value
) {
502 Status status
= GetMouseButton(params
, &button
);
503 if (status
.IsError())
505 std::list
<MouseEvent
> events
;
507 MouseEvent(kPressedMouseEventType
, button
,
508 session
->mouse_position
.x
, session
->mouse_position
.y
,
509 session
->sticky_modifiers
, 1));
511 MouseEvent(kReleasedMouseEventType
, button
,
512 session
->mouse_position
.x
, session
->mouse_position
.y
,
513 session
->sticky_modifiers
, 1));
514 return web_view
->DispatchMouseEvents(events
, session
->GetCurrentFrameId());
517 Status
ExecuteMouseButtonDown(
520 const base::DictionaryValue
& params
,
521 scoped_ptr
<base::Value
>* value
) {
523 Status status
= GetMouseButton(params
, &button
);
524 if (status
.IsError())
526 std::list
<MouseEvent
> events
;
528 MouseEvent(kPressedMouseEventType
, button
,
529 session
->mouse_position
.x
, session
->mouse_position
.y
,
530 session
->sticky_modifiers
, 1));
531 return web_view
->DispatchMouseEvents(events
, session
->GetCurrentFrameId());
534 Status
ExecuteMouseButtonUp(
537 const base::DictionaryValue
& params
,
538 scoped_ptr
<base::Value
>* value
) {
540 Status status
= GetMouseButton(params
, &button
);
541 if (status
.IsError())
543 std::list
<MouseEvent
> events
;
545 MouseEvent(kReleasedMouseEventType
, button
,
546 session
->mouse_position
.x
, session
->mouse_position
.y
,
547 session
->sticky_modifiers
, 1));
548 return web_view
->DispatchMouseEvents(events
, session
->GetCurrentFrameId());
551 Status
ExecuteMouseDoubleClick(
554 const base::DictionaryValue
& params
,
555 scoped_ptr
<base::Value
>* value
) {
557 Status status
= GetMouseButton(params
, &button
);
558 if (status
.IsError())
560 std::list
<MouseEvent
> events
;
562 MouseEvent(kPressedMouseEventType
, button
,
563 session
->mouse_position
.x
, session
->mouse_position
.y
,
564 session
->sticky_modifiers
, 2));
566 MouseEvent(kReleasedMouseEventType
, button
,
567 session
->mouse_position
.x
, session
->mouse_position
.y
,
568 session
->sticky_modifiers
, 2));
569 return web_view
->DispatchMouseEvents(events
, session
->GetCurrentFrameId());
572 Status
ExecuteTouchDown(
575 const base::DictionaryValue
& params
,
576 scoped_ptr
<base::Value
>* value
) {
577 return ExecuteTouchEvent(session
, web_view
, kTouchStart
, params
);
580 Status
ExecuteTouchUp(
583 const base::DictionaryValue
& params
,
584 scoped_ptr
<base::Value
>* value
) {
585 return ExecuteTouchEvent(session
, web_view
, kTouchEnd
, params
);
588 Status
ExecuteTouchMove(
591 const base::DictionaryValue
& params
,
592 scoped_ptr
<base::Value
>* value
) {
593 return ExecuteTouchEvent(session
, web_view
, kTouchMove
, params
);
596 Status
ExecuteGetActiveElement(
599 const base::DictionaryValue
& params
,
600 scoped_ptr
<base::Value
>* value
) {
601 return GetActiveElement(session
, web_view
, value
);
604 Status
ExecuteSendKeysToActiveElement(
607 const base::DictionaryValue
& params
,
608 scoped_ptr
<base::Value
>* value
) {
609 const base::ListValue
* key_list
;
610 if (!params
.GetList("value", &key_list
))
611 return Status(kUnknownError
, "'value' must be a list");
612 return SendKeysOnWindow(
613 web_view
, key_list
, false, &session
->sticky_modifiers
);
616 Status
ExecuteGetAppCacheStatus(
619 const base::DictionaryValue
& params
,
620 scoped_ptr
<base::Value
>* value
) {
621 return web_view
->EvaluateScript(
622 session
->GetCurrentFrameId(),
623 "applicationCache.status",
627 Status
ExecuteIsBrowserOnline(
630 const base::DictionaryValue
& params
,
631 scoped_ptr
<base::Value
>* value
) {
632 return web_view
->EvaluateScript(
633 session
->GetCurrentFrameId(),
638 Status
ExecuteGetStorageItem(
642 const base::DictionaryValue
& params
,
643 scoped_ptr
<base::Value
>* value
) {
645 if (!params
.GetString("key", &key
))
646 return Status(kUnknownError
, "'key' must be a string");
647 base::ListValue args
;
648 args
.Append(new base::StringValue(key
));
649 return web_view
->CallFunction(
650 session
->GetCurrentFrameId(),
651 base::StringPrintf("function(key) { return %s[key]; }", storage
),
656 Status
ExecuteGetStorageKeys(
660 const base::DictionaryValue
& params
,
661 scoped_ptr
<base::Value
>* value
) {
662 const char script
[] =
664 "for (var key in %s) {"
668 return web_view
->EvaluateScript(
669 session
->GetCurrentFrameId(),
670 base::StringPrintf(script
, storage
),
674 Status
ExecuteSetStorageItem(
678 const base::DictionaryValue
& params
,
679 scoped_ptr
<base::Value
>* value
) {
681 if (!params
.GetString("key", &key
))
682 return Status(kUnknownError
, "'key' must be a string");
683 std::string storage_value
;
684 if (!params
.GetString("value", &storage_value
))
685 return Status(kUnknownError
, "'value' must be a string");
686 base::ListValue args
;
687 args
.Append(new base::StringValue(key
));
688 args
.Append(new base::StringValue(storage_value
));
689 return web_view
->CallFunction(
690 session
->GetCurrentFrameId(),
691 base::StringPrintf("function(key, value) { %s[key] = value; }", storage
),
696 Status
ExecuteRemoveStorageItem(
700 const base::DictionaryValue
& params
,
701 scoped_ptr
<base::Value
>* value
) {
703 if (!params
.GetString("key", &key
))
704 return Status(kUnknownError
, "'key' must be a string");
705 base::ListValue args
;
706 args
.Append(new base::StringValue(key
));
707 return web_view
->CallFunction(
708 session
->GetCurrentFrameId(),
709 base::StringPrintf("function(key) { %s.removeItem(key) }", storage
),
714 Status
ExecuteClearStorage(
718 const base::DictionaryValue
& params
,
719 scoped_ptr
<base::Value
>* value
) {
720 return web_view
->EvaluateScript(
721 session
->GetCurrentFrameId(),
722 base::StringPrintf("%s.clear()", storage
),
726 Status
ExecuteGetStorageSize(
730 const base::DictionaryValue
& params
,
731 scoped_ptr
<base::Value
>* value
) {
732 return web_view
->EvaluateScript(
733 session
->GetCurrentFrameId(),
734 base::StringPrintf("%s.length", storage
),
738 Status
ExecuteScreenshot(
741 const base::DictionaryValue
& params
,
742 scoped_ptr
<base::Value
>* value
) {
743 Status status
= session
->chrome
->ActivateWebView(web_view
->GetId());
744 if (status
.IsError())
747 std::string screenshot
;
748 ChromeDesktopImpl
* desktop
= NULL
;
749 status
= session
->chrome
->GetAsDesktop(&desktop
);
750 if (status
.IsOk() && !session
->force_devtools_screenshot
) {
751 AutomationExtension
* extension
= NULL
;
752 status
= desktop
->GetAutomationExtension(&extension
);
753 if (status
.IsError())
755 status
= extension
->CaptureScreenshot(&screenshot
);
756 // If the screenshot was forbidden, fallback to DevTools.
757 if (status
.code() == kForbidden
)
758 status
= web_view
->CaptureScreenshot(&screenshot
);
760 status
= web_view
->CaptureScreenshot(&screenshot
);
762 if (status
.IsError())
765 value
->reset(new base::StringValue(screenshot
));
769 Status
ExecuteGetCookies(
772 const base::DictionaryValue
& params
,
773 scoped_ptr
<base::Value
>* value
) {
774 std::list
<Cookie
> cookies
;
775 Status status
= GetVisibleCookies(web_view
, &cookies
);
776 if (status
.IsError())
778 scoped_ptr
<base::ListValue
> cookie_list(new base::ListValue());
779 for (std::list
<Cookie
>::const_iterator it
= cookies
.begin();
780 it
!= cookies
.end(); ++it
) {
781 cookie_list
->Append(CreateDictionaryFrom(*it
));
783 value
->reset(cookie_list
.release());
787 Status
ExecuteAddCookie(
790 const base::DictionaryValue
& params
,
791 scoped_ptr
<base::Value
>* value
) {
792 const base::DictionaryValue
* cookie
;
793 if (!params
.GetDictionary("cookie", &cookie
))
794 return Status(kUnknownError
, "missing 'cookie'");
795 base::ListValue args
;
796 args
.Append(cookie
->DeepCopy());
797 scoped_ptr
<base::Value
> result
;
798 return web_view
->CallFunction(
799 session
->GetCurrentFrameId(), kAddCookieScript
, args
, &result
);
802 Status
ExecuteDeleteCookie(
805 const base::DictionaryValue
& params
,
806 scoped_ptr
<base::Value
>* value
) {
808 if (!params
.GetString("name", &name
))
809 return Status(kUnknownError
, "missing 'name'");
810 base::DictionaryValue params_url
;
811 scoped_ptr
<base::Value
> value_url
;
813 Status status
= GetUrl(web_view
, session
->GetCurrentFrameId(), &url
);
814 if (status
.IsError())
816 return web_view
->DeleteCookie(name
, url
);
819 Status
ExecuteDeleteAllCookies(
822 const base::DictionaryValue
& params
,
823 scoped_ptr
<base::Value
>* value
) {
824 std::list
<Cookie
> cookies
;
825 Status status
= GetVisibleCookies(web_view
, &cookies
);
826 if (status
.IsError())
829 if (!cookies
.empty()) {
830 base::DictionaryValue params_url
;
831 scoped_ptr
<base::Value
> value_url
;
833 status
= GetUrl(web_view
, session
->GetCurrentFrameId(), &url
);
834 if (status
.IsError())
836 for (std::list
<Cookie
>::const_iterator it
= cookies
.begin();
837 it
!= cookies
.end(); ++it
) {
838 status
= web_view
->DeleteCookie(it
->name
, url
);
839 if (status
.IsError())
847 Status
ExecuteSetLocation(
850 const base::DictionaryValue
& params
,
851 scoped_ptr
<base::Value
>* value
) {
852 const base::DictionaryValue
* location
= NULL
;
853 Geoposition geoposition
;
854 if (!params
.GetDictionary("location", &location
) ||
855 !location
->GetDouble("latitude", &geoposition
.latitude
) ||
856 !location
->GetDouble("longitude", &geoposition
.longitude
))
857 return Status(kUnknownError
, "missing or invalid 'location'");
858 if (location
->HasKey("accuracy") &&
859 !location
->GetDouble("accuracy", &geoposition
.accuracy
)) {
860 return Status(kUnknownError
, "invalid 'accuracy'");
862 // |accuracy| is not part of the WebDriver spec yet, so if it is not given
863 // default to 100 meters accuracy.
864 geoposition
.accuracy
= 100;
867 Status status
= web_view
->OverrideGeolocation(geoposition
);
869 session
->overridden_geoposition
.reset(new Geoposition(geoposition
));
873 Status
ExecuteSetNetworkConditions(
876 const base::DictionaryValue
& params
,
877 scoped_ptr
<base::Value
>* value
) {
878 std::string network_name
;
879 const base::DictionaryValue
* conditions
= NULL
;
880 scoped_ptr
<NetworkConditions
> network_conditions(new NetworkConditions());
881 if (params
.GetString("network_name", &network_name
)) {
882 // Get conditions from preset list.
883 Status status
= FindPresetNetwork(network_name
, network_conditions
.get());
884 if (status
.IsError())
886 } else if (params
.GetDictionary("network_conditions", &conditions
)) {
887 // |latency| is required.
888 if (!conditions
->GetDouble("latency", &network_conditions
->latency
))
889 return Status(kUnknownError
,
890 "invalid 'network_conditions' is missing 'latency'");
892 // Either |throughput| or the pair |download_throughput| and
893 // |upload_throughput| is required.
894 if (conditions
->HasKey("throughput")) {
895 if (!conditions
->GetDouble("throughput",
896 &network_conditions
->download_throughput
))
897 return Status(kUnknownError
, "invalid 'throughput'");
898 conditions
->GetDouble("throughput",
899 &network_conditions
->upload_throughput
);
900 } else if (conditions
->HasKey("download_throughput") &&
901 conditions
->HasKey("upload_throughput")) {
902 if (!conditions
->GetDouble("download_throughput",
903 &network_conditions
->download_throughput
) ||
904 !conditions
->GetDouble("upload_throughput",
905 &network_conditions
->upload_throughput
))
906 return Status(kUnknownError
,
907 "invalid 'download_throughput' or 'upload_throughput'");
909 return Status(kUnknownError
,
910 "invalid 'network_conditions' is missing 'throughput' or "
911 "'download_throughput'/'upload_throughput' pair");
914 // |offline| is optional.
915 if (conditions
->HasKey("offline")) {
916 if (!conditions
->GetBoolean("offline", &network_conditions
->offline
))
917 return Status(kUnknownError
, "invalid 'offline'");
919 network_conditions
->offline
= false;
922 return Status(kUnknownError
,
923 "either 'network_conditions' or 'network_name' must be "
927 session
->overridden_network_conditions
.reset(
928 network_conditions
.release());
929 return web_view
->OverrideNetworkConditions(
930 *session
->overridden_network_conditions
);
933 Status
ExecuteDeleteNetworkConditions(
936 const base::DictionaryValue
& params
,
937 scoped_ptr
<base::Value
>* value
) {
938 // Chrome does not have any command to stop overriding network conditions, so
939 // we just override the network conditions with the "No throttling" preset.
940 NetworkConditions network_conditions
;
941 // Get conditions from preset list.
942 Status status
= FindPresetNetwork("No throttling", &network_conditions
);
943 if (status
.IsError())
946 status
= web_view
->OverrideNetworkConditions(network_conditions
);
947 if (status
.IsError())
950 // After we've successfully overridden the network conditions with
951 // "No throttling", we can delete them from |session|.
952 session
->overridden_network_conditions
.reset();
956 Status
ExecuteTakeHeapSnapshot(
959 const base::DictionaryValue
& params
,
960 scoped_ptr
<base::Value
>* value
) {
961 return web_view
->TakeHeapSnapshot(value
);