Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / test / chromedriver / window_commands.cc
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 ExecuteSwitchToParentFrame(
359     Session* session,
360     WebView* web_view,
361     const base::DictionaryValue& params,
362     scoped_ptr<base::Value>* value) {
363   session->SwitchToParentFrame();
364   return Status(kOk);
365 }
366
367 Status ExecuteGetTitle(
368     Session* session,
369     WebView* web_view,
370     const base::DictionaryValue& params,
371     scoped_ptr<base::Value>* value) {
372   const char* kGetTitleScript =
373       "function() {"
374       "  if (document.title)"
375       "    return document.title;"
376       "  else"
377       "    return document.URL;"
378       "}";
379   base::ListValue args;
380   return web_view->CallFunction(std::string(), kGetTitleScript, args, value);
381 }
382
383 Status ExecuteGetPageSource(
384     Session* session,
385     WebView* web_view,
386     const base::DictionaryValue& params,
387     scoped_ptr<base::Value>* value) {
388   const char* kGetPageSource =
389       "function() {"
390       "  return new XMLSerializer().serializeToString(document);"
391       "}";
392   base::ListValue args;
393   return web_view->CallFunction(
394       session->GetCurrentFrameId(), kGetPageSource, args, value);
395 }
396
397 Status ExecuteFindElement(
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(interval_ms, true, NULL, session, web_view, params, value);
404 }
405
406 Status ExecuteFindElements(
407     int interval_ms,
408     Session* session,
409     WebView* web_view,
410     const base::DictionaryValue& params,
411     scoped_ptr<base::Value>* value) {
412   return FindElement(
413       interval_ms, false, NULL, session, web_view, params, value);
414 }
415
416 Status ExecuteGetCurrentUrl(
417     Session* session,
418     WebView* web_view,
419     const base::DictionaryValue& params,
420     scoped_ptr<base::Value>* value) {
421   std::string url;
422   Status status = GetUrl(web_view, session->GetCurrentFrameId(), &url);
423   if (status.IsError())
424     return status;
425   value->reset(new base::StringValue(url));
426   return Status(kOk);
427 }
428
429 Status ExecuteGoBack(
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.back();", value);
436 }
437
438 Status ExecuteGoForward(
439     Session* session,
440     WebView* web_view,
441     const base::DictionaryValue& params,
442     scoped_ptr<base::Value>* value) {
443   return web_view->EvaluateScript(
444       std::string(), "window.history.forward();", value);
445 }
446
447 Status ExecuteRefresh(
448     Session* session,
449     WebView* web_view,
450     const base::DictionaryValue& params,
451     scoped_ptr<base::Value>* value) {
452   return web_view->Reload();
453 }
454
455 Status ExecuteMouseMoveTo(
456     Session* session,
457     WebView* web_view,
458     const base::DictionaryValue& params,
459     scoped_ptr<base::Value>* value) {
460   std::string element_id;
461   bool has_element = params.GetString("element", &element_id);
462   int x_offset = 0;
463   int y_offset = 0;
464   bool has_offset = params.GetInteger("xoffset", &x_offset) &&
465       params.GetInteger("yoffset", &y_offset);
466   if (!has_element && !has_offset)
467     return Status(kUnknownError, "at least an element or offset should be set");
468
469   WebPoint location;
470   if (has_element) {
471     Status status = ScrollElementIntoView(
472         session, web_view, element_id, &location);
473     if (status.IsError())
474       return status;
475   } else {
476     location = session->mouse_position;
477   }
478
479   if (has_offset) {
480     location.Offset(x_offset, y_offset);
481   } else {
482     WebSize size;
483     Status status = GetElementSize(session, web_view, element_id, &size);
484     if (status.IsError())
485       return status;
486     location.Offset(size.width / 2, size.height / 2);
487   }
488
489   std::list<MouseEvent> events;
490   events.push_back(
491       MouseEvent(kMovedMouseEventType, kNoneMouseButton,
492                  location.x, location.y, session->sticky_modifiers, 0));
493   Status status =
494       web_view->DispatchMouseEvents(events, session->GetCurrentFrameId());
495   if (status.IsOk())
496     session->mouse_position = location;
497   return status;
498 }
499
500 Status ExecuteMouseClick(
501     Session* session,
502     WebView* web_view,
503     const base::DictionaryValue& params,
504     scoped_ptr<base::Value>* value) {
505   MouseButton button;
506   Status status = GetMouseButton(params, &button);
507   if (status.IsError())
508     return status;
509   std::list<MouseEvent> events;
510   events.push_back(
511       MouseEvent(kPressedMouseEventType, button,
512                  session->mouse_position.x, session->mouse_position.y,
513                  session->sticky_modifiers, 1));
514   events.push_back(
515       MouseEvent(kReleasedMouseEventType, button,
516                  session->mouse_position.x, session->mouse_position.y,
517                  session->sticky_modifiers, 1));
518   return web_view->DispatchMouseEvents(events, session->GetCurrentFrameId());
519 }
520
521 Status ExecuteMouseButtonDown(
522     Session* session,
523     WebView* web_view,
524     const base::DictionaryValue& params,
525     scoped_ptr<base::Value>* value) {
526   MouseButton button;
527   Status status = GetMouseButton(params, &button);
528   if (status.IsError())
529     return status;
530   std::list<MouseEvent> events;
531   events.push_back(
532       MouseEvent(kPressedMouseEventType, button,
533                  session->mouse_position.x, session->mouse_position.y,
534                  session->sticky_modifiers, 1));
535   return web_view->DispatchMouseEvents(events, session->GetCurrentFrameId());
536 }
537
538 Status ExecuteMouseButtonUp(
539     Session* session,
540     WebView* web_view,
541     const base::DictionaryValue& params,
542     scoped_ptr<base::Value>* value) {
543   MouseButton button;
544   Status status = GetMouseButton(params, &button);
545   if (status.IsError())
546     return status;
547   std::list<MouseEvent> events;
548   events.push_back(
549       MouseEvent(kReleasedMouseEventType, button,
550                  session->mouse_position.x, session->mouse_position.y,
551                  session->sticky_modifiers, 1));
552   return web_view->DispatchMouseEvents(events, session->GetCurrentFrameId());
553 }
554
555 Status ExecuteMouseDoubleClick(
556     Session* session,
557     WebView* web_view,
558     const base::DictionaryValue& params,
559     scoped_ptr<base::Value>* value) {
560   MouseButton button;
561   Status status = GetMouseButton(params, &button);
562   if (status.IsError())
563     return status;
564   std::list<MouseEvent> events;
565   events.push_back(
566       MouseEvent(kPressedMouseEventType, button,
567                  session->mouse_position.x, session->mouse_position.y,
568                  session->sticky_modifiers, 2));
569   events.push_back(
570       MouseEvent(kReleasedMouseEventType, button,
571                  session->mouse_position.x, session->mouse_position.y,
572                  session->sticky_modifiers, 2));
573   return web_view->DispatchMouseEvents(events, session->GetCurrentFrameId());
574 }
575
576 Status ExecuteTouchDown(
577     Session* session,
578     WebView* web_view,
579     const base::DictionaryValue& params,
580     scoped_ptr<base::Value>* value) {
581   return ExecuteTouchEvent(session, web_view, kTouchStart, params);
582 }
583
584 Status ExecuteTouchUp(
585     Session* session,
586     WebView* web_view,
587     const base::DictionaryValue& params,
588     scoped_ptr<base::Value>* value) {
589   return ExecuteTouchEvent(session, web_view, kTouchEnd, params);
590 }
591
592 Status ExecuteTouchMove(
593     Session* session,
594     WebView* web_view,
595     const base::DictionaryValue& params,
596     scoped_ptr<base::Value>* value) {
597   return ExecuteTouchEvent(session, web_view, kTouchMove, params);
598 }
599
600 Status ExecuteGetActiveElement(
601     Session* session,
602     WebView* web_view,
603     const base::DictionaryValue& params,
604     scoped_ptr<base::Value>* value) {
605   return GetActiveElement(session, web_view, value);
606 }
607
608 Status ExecuteSendKeysToActiveElement(
609     Session* session,
610     WebView* web_view,
611     const base::DictionaryValue& params,
612     scoped_ptr<base::Value>* value) {
613   const base::ListValue* key_list;
614   if (!params.GetList("value", &key_list))
615     return Status(kUnknownError, "'value' must be a list");
616   return SendKeysOnWindow(
617       web_view, key_list, false, &session->sticky_modifiers);
618 }
619
620 Status ExecuteGetAppCacheStatus(
621     Session* session,
622     WebView* web_view,
623     const base::DictionaryValue& params,
624     scoped_ptr<base::Value>* value) {
625   return web_view->EvaluateScript(
626       session->GetCurrentFrameId(),
627       "applicationCache.status",
628       value);
629 }
630
631 Status ExecuteIsBrowserOnline(
632     Session* session,
633     WebView* web_view,
634     const base::DictionaryValue& params,
635     scoped_ptr<base::Value>* value) {
636   return web_view->EvaluateScript(
637       session->GetCurrentFrameId(),
638       "navigator.onLine",
639       value);
640 }
641
642 Status ExecuteGetStorageItem(
643     const char* storage,
644     Session* session,
645     WebView* web_view,
646     const base::DictionaryValue& params,
647     scoped_ptr<base::Value>* value) {
648   std::string key;
649   if (!params.GetString("key", &key))
650     return Status(kUnknownError, "'key' must be a string");
651   base::ListValue args;
652   args.Append(new base::StringValue(key));
653   return web_view->CallFunction(
654       session->GetCurrentFrameId(),
655       base::StringPrintf("function(key) { return %s[key]; }", storage),
656       args,
657       value);
658 }
659
660 Status ExecuteGetStorageKeys(
661     const char* storage,
662     Session* session,
663     WebView* web_view,
664     const base::DictionaryValue& params,
665     scoped_ptr<base::Value>* value) {
666   const char script[] =
667       "var keys = [];"
668       "for (var key in %s) {"
669       "  keys.push(key);"
670       "}"
671       "keys";
672   return web_view->EvaluateScript(
673       session->GetCurrentFrameId(),
674       base::StringPrintf(script, storage),
675       value);
676 }
677
678 Status ExecuteSetStorageItem(
679     const char* storage,
680     Session* session,
681     WebView* web_view,
682     const base::DictionaryValue& params,
683     scoped_ptr<base::Value>* value) {
684   std::string key;
685   if (!params.GetString("key", &key))
686     return Status(kUnknownError, "'key' must be a string");
687   std::string storage_value;
688   if (!params.GetString("value", &storage_value))
689     return Status(kUnknownError, "'value' must be a string");
690   base::ListValue args;
691   args.Append(new base::StringValue(key));
692   args.Append(new base::StringValue(storage_value));
693   return web_view->CallFunction(
694       session->GetCurrentFrameId(),
695       base::StringPrintf("function(key, value) { %s[key] = value; }", storage),
696       args,
697       value);
698 }
699
700 Status ExecuteRemoveStorageItem(
701     const char* storage,
702     Session* session,
703     WebView* web_view,
704     const base::DictionaryValue& params,
705     scoped_ptr<base::Value>* value) {
706   std::string key;
707   if (!params.GetString("key", &key))
708     return Status(kUnknownError, "'key' must be a string");
709   base::ListValue args;
710   args.Append(new base::StringValue(key));
711   return web_view->CallFunction(
712       session->GetCurrentFrameId(),
713       base::StringPrintf("function(key) { %s.removeItem(key) }", storage),
714       args,
715       value);
716 }
717
718 Status ExecuteClearStorage(
719     const char* storage,
720     Session* session,
721     WebView* web_view,
722     const base::DictionaryValue& params,
723     scoped_ptr<base::Value>* value) {
724   return web_view->EvaluateScript(
725       session->GetCurrentFrameId(),
726       base::StringPrintf("%s.clear()", storage),
727       value);
728 }
729
730 Status ExecuteGetStorageSize(
731     const char* storage,
732     Session* session,
733     WebView* web_view,
734     const base::DictionaryValue& params,
735     scoped_ptr<base::Value>* value) {
736   return web_view->EvaluateScript(
737       session->GetCurrentFrameId(),
738       base::StringPrintf("%s.length", storage),
739       value);
740 }
741
742 Status ExecuteScreenshot(
743     Session* session,
744     WebView* web_view,
745     const base::DictionaryValue& params,
746     scoped_ptr<base::Value>* value) {
747   Status status = session->chrome->ActivateWebView(web_view->GetId());
748   if (status.IsError())
749     return status;
750
751   std::string screenshot;
752   if (session->chrome->GetAsDesktop() && !session->force_devtools_screenshot) {
753     AutomationExtension* extension = NULL;
754     status =
755         session->chrome->GetAsDesktop()->GetAutomationExtension(&extension);
756     if (status.IsError())
757       return status;
758     status = extension->CaptureScreenshot(&screenshot);
759     // If the screenshot was forbidden, fallback to DevTools.
760     if (status.code() == kForbidden)
761       status = web_view->CaptureScreenshot(&screenshot);
762   } else {
763     status = web_view->CaptureScreenshot(&screenshot);
764   }
765   if (status.IsError())
766     return status;
767
768   value->reset(new base::StringValue(screenshot));
769   return Status(kOk);
770 }
771
772 Status ExecuteGetCookies(
773     Session* session,
774     WebView* web_view,
775     const base::DictionaryValue& params,
776     scoped_ptr<base::Value>* value) {
777   std::list<Cookie> cookies;
778   Status status = GetVisibleCookies(web_view, &cookies);
779   if (status.IsError())
780     return status;
781   scoped_ptr<base::ListValue> cookie_list(new base::ListValue());
782   for (std::list<Cookie>::const_iterator it = cookies.begin();
783        it != cookies.end(); ++it) {
784     cookie_list->Append(CreateDictionaryFrom(*it));
785   }
786   value->reset(cookie_list.release());
787   return Status(kOk);
788 }
789
790 Status ExecuteAddCookie(
791     Session* session,
792     WebView* web_view,
793     const base::DictionaryValue& params,
794     scoped_ptr<base::Value>* value) {
795   const base::DictionaryValue* cookie;
796   if (!params.GetDictionary("cookie", &cookie))
797     return Status(kUnknownError, "missing 'cookie'");
798   base::ListValue args;
799   args.Append(cookie->DeepCopy());
800   scoped_ptr<base::Value> result;
801   return web_view->CallFunction(
802       session->GetCurrentFrameId(), kAddCookieScript, args, &result);
803 }
804
805 Status ExecuteDeleteCookie(
806     Session* session,
807     WebView* web_view,
808     const base::DictionaryValue& params,
809     scoped_ptr<base::Value>* value) {
810   std::string name;
811   if (!params.GetString("name", &name))
812     return Status(kUnknownError, "missing 'name'");
813   base::DictionaryValue params_url;
814   scoped_ptr<base::Value> value_url;
815   std::string url;
816   Status status = GetUrl(web_view, session->GetCurrentFrameId(), &url);
817   if (status.IsError())
818     return status;
819   return web_view->DeleteCookie(name, url);
820 }
821
822 Status ExecuteDeleteAllCookies(
823     Session* session,
824     WebView* web_view,
825     const base::DictionaryValue& params,
826     scoped_ptr<base::Value>* value) {
827   std::list<Cookie> cookies;
828   Status status = GetVisibleCookies(web_view, &cookies);
829   if (status.IsError())
830     return status;
831
832   if (!cookies.empty()) {
833     base::DictionaryValue params_url;
834     scoped_ptr<base::Value> value_url;
835     std::string url;
836     status = GetUrl(web_view, session->GetCurrentFrameId(), &url);
837     if (status.IsError())
838       return status;
839     for (std::list<Cookie>::const_iterator it = cookies.begin();
840          it != cookies.end(); ++it) {
841       status = web_view->DeleteCookie(it->name, url);
842       if (status.IsError())
843         return status;
844     }
845   }
846
847   return Status(kOk);
848 }
849
850 Status ExecuteSetLocation(
851     Session* session,
852     WebView* web_view,
853     const base::DictionaryValue& params,
854     scoped_ptr<base::Value>* value) {
855   const base::DictionaryValue* location = NULL;
856   Geoposition geoposition;
857   if (!params.GetDictionary("location", &location) ||
858       !location->GetDouble("latitude", &geoposition.latitude) ||
859       !location->GetDouble("longitude", &geoposition.longitude))
860     return Status(kUnknownError, "missing or invalid 'location'");
861   if (location->HasKey("accuracy") &&
862       !location->GetDouble("accuracy", &geoposition.accuracy)) {
863     return Status(kUnknownError, "invalid 'accuracy'");
864   } else {
865     // |accuracy| is not part of the WebDriver spec yet, so if it is not given
866     // default to 100 meters accuracy.
867     geoposition.accuracy = 100;
868   }
869
870   Status status = web_view->OverrideGeolocation(geoposition);
871   if (status.IsOk())
872     session->overridden_geoposition.reset(new Geoposition(geoposition));
873   return status;
874 }
875
876 Status ExecuteTakeHeapSnapshot(
877     Session* session,
878     WebView* web_view,
879     const base::DictionaryValue& params,
880     scoped_ptr<base::Value>* value) {
881   return web_view->TakeHeapSnapshot(value);
882 }