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