[Cronet] Delay StartNetLog and StopNetLog until native request context is initialized
[chromium-blink-merge.git] / chrome / test / chromedriver / window_commands.cc
blob075f8b1143b1f1c2ef5fe57dc832bde7b532027c
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"
7 #include <list>
8 #include <string>
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"
32 namespace {
34 Status GetMouseButton(const base::DictionaryValue& params,
35 MouseButton* button) {
36 int button_num;
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);
44 return Status(kOk);
47 Status GetUrl(WebView* web_view, const std::string& frame, std::string* url) {
48 scoped_ptr<base::Value> value;
49 base::ListValue args;
50 Status status = web_view->CallFunction(
51 frame, "function() { return document.URL; }", args, &value);
52 if (status.IsError())
53 return status;
54 if (!value->GetAsString(url))
55 return Status(kUnknownError, "javascript failed to return the url");
56 return Status(kOk);
59 struct Cookie {
60 Cookie(const std::string& name,
61 const std::string& value,
62 const std::string& domain,
63 const std::string& path,
64 double expiry,
65 bool secure,
66 bool session)
67 : name(name), value(value), domain(domain), path(path), expiry(expiry),
68 secure(secure), session(session) {}
70 std::string name;
71 std::string value;
72 std::string domain;
73 std::string path;
74 double expiry;
75 bool secure;
76 bool 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);
87 if (!cookie.session)
88 dict->SetDouble("expiry", cookie.expiry);
89 dict->SetBoolean("secure", cookie.secure);
90 return dict;
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);
97 if (status.IsError())
98 return status;
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");
105 std::string name;
106 cookie_dict->GetString("name", &name);
107 std::string value;
108 cookie_dict->GetString("value", &value);
109 std::string domain;
110 cookie_dict->GetString("domain", &domain);
111 std::string path;
112 cookie_dict->GetString("path", &path);
113 double expiry = 0;
114 cookie_dict->GetDouble("expires", &expiry);
115 expiry /= 1000; // Convert from millisecond to second.
116 bool session = false;
117 cookie_dict->GetBoolean("session", &session);
118 bool secure = false;
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);
125 return Status(kOk);
128 Status ScrollCoordinateInToView(
129 Session* session, WebView* web_view, int x, int y, int* offset_x,
130 int* offset_y) {
131 scoped_ptr<base::Value> value;
132 base::ListValue args;
133 args.AppendInteger(x);
134 args.AppendInteger(y);
135 Status status = web_view->CallFunction(
136 std::string(),
137 "function(x, y) {"
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);"
143 " }"
144 " return {"
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)};"
149 "}",
150 args,
151 &value);
152 if (!status.IsOk())
153 return status;
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");
166 return Status(kOk);
169 Status ExecuteTouchEvent(
170 Session* session, WebView* web_view, TouchEventType type,
171 const base::DictionaryValue& params) {
172 int x, y;
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");
177 int relative_x = x;
178 int relative_y = y;
179 Status status = ScrollCoordinateInToView(
180 session, web_view, x, y, &relative_x, &relative_y);
181 if (!status.IsOk())
182 return status;
183 std::list<TouchEvent> events;
184 events.push_back(
185 TouchEvent(type, relative_x, relative_y));
186 return web_view->DispatchTouchEvents(events);
189 } // namespace
191 Status ExecuteWindowCommand(
192 const WindowCommand& command,
193 Session* session,
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())
199 return status;
201 status = web_view->ConnectIfNecessary();
202 if (status.IsError())
203 return status;
205 status = web_view->HandleReceivedEvents();
206 if (status.IsError())
207 return status;
209 if (web_view->GetJavaScriptDialogManager()->IsDialogOpen())
210 return Status(kUnexpectedAlertOpen);
212 Status nav_status(kOk);
213 for (int attempt = 0; attempt < 2; attempt++) {
214 if (attempt == 1) {
215 if (status.code() == kNoSuchExecutionContext)
216 // Switch to main frame and retry command if subframe no longer exists.
217 session->SwitchToTopFrame();
218 else
219 break;
221 nav_status = web_view->WaitForPendingNavigations(
222 session->GetCurrentFrameId(), session->page_load_timeout, true);
223 if (nav_status.IsError())
224 return nav_status;
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)
234 return nav_status;
235 if (status.code() == kUnexpectedAlertOpen)
236 return Status(kOk);
237 return status;
240 Status ExecuteGet(
241 Session* session,
242 WebView* web_view,
243 const base::DictionaryValue& params,
244 scoped_ptr<base::Value>* value) {
245 std::string url;
246 if (!params.GetString("url", &url))
247 return Status(kUnknownError, "'url' must be a string");
248 return web_view->Load(url);
251 Status ExecuteExecuteScript(
252 Session* session,
253 WebView* web_view,
254 const base::DictionaryValue& params,
255 scoped_ptr<base::Value>* value) {
256 std::string script;
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);
265 } else {
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(
276 Session* session,
277 WebView* web_view,
278 const base::DictionaryValue& params,
279 scoped_ptr<base::Value>* value) {
280 std::string script;
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(
293 Session* session,
294 WebView* web_view,
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();
303 return Status(kOk);
306 std::string script;
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());
312 } else {
313 script =
314 "function(xpath) {"
315 " return document.evaluate(xpath, document, null, "
316 " XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;"
317 "}";
318 std::string xpath = "(/html/body//iframe|/html/frameset/frame)";
319 std::string id_string;
320 int id_int;
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);
326 } else {
327 return Status(kUnknownError, "invalid 'id'");
329 args.Append(new base::StringValue(xpath));
331 std::string frame;
332 Status status = web_view->GetFrameByFunction(
333 session->GetCurrentFrameId(), script, args, &frame);
334 if (status.IsError())
335 return status;
337 scoped_ptr<base::Value> result;
338 status = web_view->CallFunction(
339 session->GetCurrentFrameId(), script, args, &result);
340 if (status.IsError())
341 return status;
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);"
350 "}";
351 base::ListValue new_args;
352 new_args.Append(element->DeepCopy());
353 new_args.AppendString(chrome_driver_id);
354 result.reset(NULL);
355 status = web_view->CallFunction(
356 session->GetCurrentFrameId(), kSetFrameIdentifier, new_args, &result);
357 if (status.IsError())
358 return status;
359 session->SwitchToSubFrame(frame, chrome_driver_id);
360 return Status(kOk);
363 Status ExecuteSwitchToParentFrame(
364 Session* session,
365 WebView* web_view,
366 const base::DictionaryValue& params,
367 scoped_ptr<base::Value>* value) {
368 session->SwitchToParentFrame();
369 return Status(kOk);
372 Status ExecuteGetTitle(
373 Session* session,
374 WebView* web_view,
375 const base::DictionaryValue& params,
376 scoped_ptr<base::Value>* value) {
377 const char kGetTitleScript[] =
378 "function() {"
379 " if (document.title)"
380 " return document.title;"
381 " else"
382 " return document.URL;"
383 "}";
384 base::ListValue args;
385 return web_view->CallFunction(std::string(), kGetTitleScript, args, value);
388 Status ExecuteGetPageSource(
389 Session* session,
390 WebView* web_view,
391 const base::DictionaryValue& params,
392 scoped_ptr<base::Value>* value) {
393 const char kGetPageSource[] =
394 "function() {"
395 " return new XMLSerializer().serializeToString(document);"
396 "}";
397 base::ListValue args;
398 return web_view->CallFunction(
399 session->GetCurrentFrameId(), kGetPageSource, args, value);
402 Status ExecuteFindElement(
403 int interval_ms,
404 Session* session,
405 WebView* web_view,
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(
412 int interval_ms,
413 Session* session,
414 WebView* web_view,
415 const base::DictionaryValue& params,
416 scoped_ptr<base::Value>* value) {
417 return FindElement(
418 interval_ms, false, NULL, session, web_view, params, value);
421 Status ExecuteGetCurrentUrl(
422 Session* session,
423 WebView* web_view,
424 const base::DictionaryValue& params,
425 scoped_ptr<base::Value>* value) {
426 std::string url;
427 Status status = GetUrl(web_view, session->GetCurrentFrameId(), &url);
428 if (status.IsError())
429 return status;
430 value->reset(new base::StringValue(url));
431 return Status(kOk);
434 Status ExecuteGoBack(
435 Session* session,
436 WebView* web_view,
437 const base::DictionaryValue& params,
438 scoped_ptr<base::Value>* value) {
439 return web_view->TraverseHistory(-1);
442 Status ExecuteGoForward(
443 Session* session,
444 WebView* web_view,
445 const base::DictionaryValue& params,
446 scoped_ptr<base::Value>* value) {
447 return web_view->TraverseHistory(1);
450 Status ExecuteRefresh(
451 Session* session,
452 WebView* web_view,
453 const base::DictionaryValue& params,
454 scoped_ptr<base::Value>* value) {
455 return web_view->Reload();
458 Status ExecuteMouseMoveTo(
459 Session* session,
460 WebView* web_view,
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);
465 int x_offset = 0;
466 int y_offset = 0;
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");
472 WebPoint location;
473 if (has_element) {
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())
478 return status;
479 } else {
480 location = session->mouse_position;
481 if (has_offset)
482 location.Offset(x_offset, y_offset);
485 std::list<MouseEvent> events;
486 events.push_back(
487 MouseEvent(kMovedMouseEventType, kNoneMouseButton,
488 location.x, location.y, session->sticky_modifiers, 0));
489 Status status =
490 web_view->DispatchMouseEvents(events, session->GetCurrentFrameId());
491 if (status.IsOk())
492 session->mouse_position = location;
493 return status;
496 Status ExecuteMouseClick(
497 Session* session,
498 WebView* web_view,
499 const base::DictionaryValue& params,
500 scoped_ptr<base::Value>* value) {
501 MouseButton button;
502 Status status = GetMouseButton(params, &button);
503 if (status.IsError())
504 return status;
505 std::list<MouseEvent> events;
506 events.push_back(
507 MouseEvent(kPressedMouseEventType, button,
508 session->mouse_position.x, session->mouse_position.y,
509 session->sticky_modifiers, 1));
510 events.push_back(
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(
518 Session* session,
519 WebView* web_view,
520 const base::DictionaryValue& params,
521 scoped_ptr<base::Value>* value) {
522 MouseButton button;
523 Status status = GetMouseButton(params, &button);
524 if (status.IsError())
525 return status;
526 std::list<MouseEvent> events;
527 events.push_back(
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(
535 Session* session,
536 WebView* web_view,
537 const base::DictionaryValue& params,
538 scoped_ptr<base::Value>* value) {
539 MouseButton button;
540 Status status = GetMouseButton(params, &button);
541 if (status.IsError())
542 return status;
543 std::list<MouseEvent> events;
544 events.push_back(
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(
552 Session* session,
553 WebView* web_view,
554 const base::DictionaryValue& params,
555 scoped_ptr<base::Value>* value) {
556 MouseButton button;
557 Status status = GetMouseButton(params, &button);
558 if (status.IsError())
559 return status;
560 std::list<MouseEvent> events;
561 events.push_back(
562 MouseEvent(kPressedMouseEventType, button,
563 session->mouse_position.x, session->mouse_position.y,
564 session->sticky_modifiers, 2));
565 events.push_back(
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(
573 Session* session,
574 WebView* web_view,
575 const base::DictionaryValue& params,
576 scoped_ptr<base::Value>* value) {
577 return ExecuteTouchEvent(session, web_view, kTouchStart, params);
580 Status ExecuteTouchUp(
581 Session* session,
582 WebView* web_view,
583 const base::DictionaryValue& params,
584 scoped_ptr<base::Value>* value) {
585 return ExecuteTouchEvent(session, web_view, kTouchEnd, params);
588 Status ExecuteTouchMove(
589 Session* session,
590 WebView* web_view,
591 const base::DictionaryValue& params,
592 scoped_ptr<base::Value>* value) {
593 return ExecuteTouchEvent(session, web_view, kTouchMove, params);
596 Status ExecuteGetActiveElement(
597 Session* session,
598 WebView* web_view,
599 const base::DictionaryValue& params,
600 scoped_ptr<base::Value>* value) {
601 return GetActiveElement(session, web_view, value);
604 Status ExecuteSendKeysToActiveElement(
605 Session* session,
606 WebView* web_view,
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(
617 Session* session,
618 WebView* web_view,
619 const base::DictionaryValue& params,
620 scoped_ptr<base::Value>* value) {
621 return web_view->EvaluateScript(
622 session->GetCurrentFrameId(),
623 "applicationCache.status",
624 value);
627 Status ExecuteIsBrowserOnline(
628 Session* session,
629 WebView* web_view,
630 const base::DictionaryValue& params,
631 scoped_ptr<base::Value>* value) {
632 return web_view->EvaluateScript(
633 session->GetCurrentFrameId(),
634 "navigator.onLine",
635 value);
638 Status ExecuteGetStorageItem(
639 const char* storage,
640 Session* session,
641 WebView* web_view,
642 const base::DictionaryValue& params,
643 scoped_ptr<base::Value>* value) {
644 std::string key;
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),
652 args,
653 value);
656 Status ExecuteGetStorageKeys(
657 const char* storage,
658 Session* session,
659 WebView* web_view,
660 const base::DictionaryValue& params,
661 scoped_ptr<base::Value>* value) {
662 const char script[] =
663 "var keys = [];"
664 "for (var key in %s) {"
665 " keys.push(key);"
667 "keys";
668 return web_view->EvaluateScript(
669 session->GetCurrentFrameId(),
670 base::StringPrintf(script, storage),
671 value);
674 Status ExecuteSetStorageItem(
675 const char* storage,
676 Session* session,
677 WebView* web_view,
678 const base::DictionaryValue& params,
679 scoped_ptr<base::Value>* value) {
680 std::string key;
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),
692 args,
693 value);
696 Status ExecuteRemoveStorageItem(
697 const char* storage,
698 Session* session,
699 WebView* web_view,
700 const base::DictionaryValue& params,
701 scoped_ptr<base::Value>* value) {
702 std::string key;
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),
710 args,
711 value);
714 Status ExecuteClearStorage(
715 const char* storage,
716 Session* session,
717 WebView* web_view,
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),
723 value);
726 Status ExecuteGetStorageSize(
727 const char* storage,
728 Session* session,
729 WebView* web_view,
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),
735 value);
738 Status ExecuteScreenshot(
739 Session* session,
740 WebView* web_view,
741 const base::DictionaryValue& params,
742 scoped_ptr<base::Value>* value) {
743 Status status = session->chrome->ActivateWebView(web_view->GetId());
744 if (status.IsError())
745 return status;
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())
754 return status;
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);
759 } else {
760 status = web_view->CaptureScreenshot(&screenshot);
762 if (status.IsError())
763 return status;
765 value->reset(new base::StringValue(screenshot));
766 return Status(kOk);
769 Status ExecuteGetCookies(
770 Session* session,
771 WebView* web_view,
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())
777 return status;
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());
784 return Status(kOk);
787 Status ExecuteAddCookie(
788 Session* session,
789 WebView* web_view,
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(
803 Session* session,
804 WebView* web_view,
805 const base::DictionaryValue& params,
806 scoped_ptr<base::Value>* value) {
807 std::string name;
808 if (!params.GetString("name", &name))
809 return Status(kUnknownError, "missing 'name'");
810 base::DictionaryValue params_url;
811 scoped_ptr<base::Value> value_url;
812 std::string url;
813 Status status = GetUrl(web_view, session->GetCurrentFrameId(), &url);
814 if (status.IsError())
815 return status;
816 return web_view->DeleteCookie(name, url);
819 Status ExecuteDeleteAllCookies(
820 Session* session,
821 WebView* web_view,
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())
827 return status;
829 if (!cookies.empty()) {
830 base::DictionaryValue params_url;
831 scoped_ptr<base::Value> value_url;
832 std::string url;
833 status = GetUrl(web_view, session->GetCurrentFrameId(), &url);
834 if (status.IsError())
835 return status;
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())
840 return status;
844 return Status(kOk);
847 Status ExecuteSetLocation(
848 Session* session,
849 WebView* web_view,
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'");
861 } else {
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);
868 if (status.IsOk())
869 session->overridden_geoposition.reset(new Geoposition(geoposition));
870 return status;
873 Status ExecuteSetNetworkConditions(
874 Session* session,
875 WebView* web_view,
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())
885 return status;
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'");
908 } else {
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'");
918 } else {
919 network_conditions->offline = false;
921 } else {
922 return Status(kUnknownError,
923 "either 'network_conditions' or 'network_name' must be "
924 "supplied");
927 session->overridden_network_conditions.reset(
928 network_conditions.release());
929 return web_view->OverrideNetworkConditions(
930 *session->overridden_network_conditions);
933 Status ExecuteDeleteNetworkConditions(
934 Session* session,
935 WebView* web_view,
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())
944 return status;
946 status = web_view->OverrideNetworkConditions(network_conditions);
947 if (status.IsError())
948 return status;
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();
953 return status;
956 Status ExecuteTakeHeapSnapshot(
957 Session* session,
958 WebView* web_view,
959 const base::DictionaryValue& params,
960 scoped_ptr<base::Value>* value) {
961 return web_view->TakeHeapSnapshot(value);