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/session_commands.h"
6
7 #include <list>
8
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/file_util.h"
12 #include "base/logging.h" // For CHECK macros.
13 #include "base/memory/ref_counted.h"
14 #include "base/message_loop/message_loop_proxy.h"
15 #include "base/synchronization/lock.h"
16 #include "base/synchronization/waitable_event.h"
17 #include "base/values.h"
18 #include "chrome/test/chromedriver/basic_types.h"
19 #include "chrome/test/chromedriver/capabilities.h"
20 #include "chrome/test/chromedriver/chrome/automation_extension.h"
21 #include "chrome/test/chromedriver/chrome/chrome.h"
22 #include "chrome/test/chromedriver/chrome/chrome_android_impl.h"
23 #include "chrome/test/chromedriver/chrome/chrome_desktop_impl.h"
24 #include "chrome/test/chromedriver/chrome/device_manager.h"
25 #include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
26 #include "chrome/test/chromedriver/chrome/geoposition.h"
27 #include "chrome/test/chromedriver/chrome/status.h"
28 #include "chrome/test/chromedriver/chrome/version.h"
29 #include "chrome/test/chromedriver/chrome/web_view.h"
30 #include "chrome/test/chromedriver/chrome_launcher.h"
31 #include "chrome/test/chromedriver/logging.h"
32 #include "chrome/test/chromedriver/net/url_request_context_getter.h"
33 #include "chrome/test/chromedriver/session.h"
34 #include "chrome/test/chromedriver/util.h"
35 #include "chrome/test/chromedriver/version.h"
36
37 namespace {
38
39 const char kWindowHandlePrefix[] = "CDwindow-";
40
WebViewIdToWindowHandle(const std::string & web_view_id)41 std::string WebViewIdToWindowHandle(const std::string& web_view_id) {
42 return kWindowHandlePrefix + web_view_id;
43 }
44
WindowHandleToWebViewId(const std::string & window_handle,std::string * web_view_id)45 bool WindowHandleToWebViewId(const std::string& window_handle,
46 std::string* web_view_id) {
47 if (window_handle.find(kWindowHandlePrefix) != 0u)
48 return false;
49 *web_view_id = window_handle.substr(
50 std::string(kWindowHandlePrefix).length());
51 return true;
52 }
53
54 } // namespace
55
InitSessionParams(scoped_refptr<URLRequestContextGetter> context_getter,const SyncWebSocketFactory & socket_factory,DeviceManager * device_manager,PortServer * port_server,PortManager * port_manager)56 InitSessionParams::InitSessionParams(
57 scoped_refptr<URLRequestContextGetter> context_getter,
58 const SyncWebSocketFactory& socket_factory,
59 DeviceManager* device_manager,
60 PortServer* port_server,
61 PortManager* port_manager)
62 : context_getter(context_getter),
63 socket_factory(socket_factory),
64 device_manager(device_manager),
65 port_server(port_server),
66 port_manager(port_manager) {}
67
~InitSessionParams()68 InitSessionParams::~InitSessionParams() {}
69
70 namespace {
71
CreateCapabilities(Chrome * chrome)72 scoped_ptr<base::DictionaryValue> CreateCapabilities(Chrome* chrome) {
73 scoped_ptr<base::DictionaryValue> caps(new base::DictionaryValue());
74 caps->SetString("browserName", "chrome");
75 caps->SetString("version", chrome->GetBrowserInfo()->browser_version);
76 caps->SetString("chrome.chromedriverVersion", kChromeDriverVersion);
77 caps->SetString("platform", chrome->GetOperatingSystemName());
78 caps->SetBoolean("javascriptEnabled", true);
79 caps->SetBoolean("takesScreenshot", true);
80 caps->SetBoolean("takesHeapSnapshot", true);
81 caps->SetBoolean("handlesAlerts", true);
82 caps->SetBoolean("databaseEnabled", false);
83 caps->SetBoolean("locationContextEnabled", true);
84 caps->SetBoolean("mobileEmulationEnabled",
85 chrome->IsMobileEmulationEnabled());
86 caps->SetBoolean("applicationCacheEnabled", false);
87 caps->SetBoolean("browserConnectionEnabled", false);
88 caps->SetBoolean("cssSelectorsEnabled", true);
89 caps->SetBoolean("webStorageEnabled", true);
90 caps->SetBoolean("rotatable", false);
91 caps->SetBoolean("acceptSslCerts", true);
92 caps->SetBoolean("nativeEvents", true);
93 scoped_ptr<base::DictionaryValue> chrome_caps(new base::DictionaryValue());
94 if (chrome->GetAsDesktop()) {
95 chrome_caps->SetString(
96 "userDataDir",
97 chrome->GetAsDesktop()->command().GetSwitchValueNative(
98 "user-data-dir"));
99 }
100 caps->Set("chrome", chrome_caps.release());
101 return caps.Pass();
102 }
103
InitSessionHelper(const InitSessionParams & bound_params,Session * session,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)104 Status InitSessionHelper(
105 const InitSessionParams& bound_params,
106 Session* session,
107 const base::DictionaryValue& params,
108 scoped_ptr<base::Value>* value) {
109 session->driver_log.reset(
110 new WebDriverLog(WebDriverLog::kDriverType, Log::kAll));
111 const base::DictionaryValue* desired_caps;
112 if (!params.GetDictionary("desiredCapabilities", &desired_caps))
113 return Status(kUnknownError, "cannot find dict 'desiredCapabilities'");
114
115 Capabilities capabilities;
116 Status status = capabilities.Parse(*desired_caps);
117 if (status.IsError())
118 return status;
119
120 Log::Level driver_level = Log::kWarning;
121 if (capabilities.logging_prefs.count(WebDriverLog::kDriverType))
122 driver_level = capabilities.logging_prefs[WebDriverLog::kDriverType];
123 session->driver_log->set_min_level(driver_level);
124
125 // Create Log's and DevToolsEventListener's for ones that are DevTools-based.
126 // Session will own the Log's, Chrome will own the listeners.
127 ScopedVector<DevToolsEventListener> devtools_event_listeners;
128 status = CreateLogs(capabilities,
129 &session->devtools_logs,
130 &devtools_event_listeners);
131 if (status.IsError())
132 return status;
133
134 status = LaunchChrome(bound_params.context_getter.get(),
135 bound_params.socket_factory,
136 bound_params.device_manager,
137 bound_params.port_server,
138 bound_params.port_manager,
139 capabilities,
140 devtools_event_listeners,
141 &session->chrome);
142 if (status.IsError())
143 return status;
144
145 std::list<std::string> web_view_ids;
146 status = session->chrome->GetWebViewIds(&web_view_ids);
147 if (status.IsError() || web_view_ids.empty()) {
148 return status.IsError() ? status :
149 Status(kUnknownError, "unable to discover open window in chrome");
150 }
151
152 session->window = web_view_ids.front();
153 session->detach = capabilities.detach;
154 session->force_devtools_screenshot = capabilities.force_devtools_screenshot;
155 session->capabilities = CreateCapabilities(session->chrome.get());
156 value->reset(session->capabilities->DeepCopy());
157 return Status(kOk);
158 }
159
160 } // namespace
161
ExecuteInitSession(const InitSessionParams & bound_params,Session * session,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)162 Status ExecuteInitSession(
163 const InitSessionParams& bound_params,
164 Session* session,
165 const base::DictionaryValue& params,
166 scoped_ptr<base::Value>* value) {
167 Status status = InitSessionHelper(bound_params, session, params, value);
168 if (status.IsError()) {
169 session->quit = true;
170 if (session->chrome != NULL)
171 session->chrome->Quit();
172 }
173 return status;
174 }
175
ExecuteQuit(bool allow_detach,Session * session,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)176 Status ExecuteQuit(
177 bool allow_detach,
178 Session* session,
179 const base::DictionaryValue& params,
180 scoped_ptr<base::Value>* value) {
181 session->quit = true;
182 if (allow_detach && session->detach)
183 return Status(kOk);
184 else
185 return session->chrome->Quit();
186 }
187
ExecuteGetSessionCapabilities(Session * session,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)188 Status ExecuteGetSessionCapabilities(
189 Session* session,
190 const base::DictionaryValue& params,
191 scoped_ptr<base::Value>* value) {
192 value->reset(session->capabilities->DeepCopy());
193 return Status(kOk);
194 }
195
ExecuteGetCurrentWindowHandle(Session * session,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)196 Status ExecuteGetCurrentWindowHandle(
197 Session* session,
198 const base::DictionaryValue& params,
199 scoped_ptr<base::Value>* value) {
200 WebView* web_view = NULL;
201 Status status = session->GetTargetWindow(&web_view);
202 if (status.IsError())
203 return status;
204
205 value->reset(
206 new base::StringValue(WebViewIdToWindowHandle(web_view->GetId())));
207 return Status(kOk);
208 }
209
ExecuteLaunchApp(Session * session,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)210 Status ExecuteLaunchApp(
211 Session* session,
212 const base::DictionaryValue& params,
213 scoped_ptr<base::Value>* value) {
214 std::string id;
215 if (!params.GetString("id", &id))
216 return Status(kUnknownError, "'id' must be a string");
217
218 if (!session->chrome->GetAsDesktop())
219 return Status(kUnknownError,
220 "apps can only be launched on desktop platforms");
221
222 AutomationExtension* extension = NULL;
223 Status status =
224 session->chrome->GetAsDesktop()->GetAutomationExtension(&extension);
225 if (status.IsError())
226 return status;
227
228 return extension->LaunchApp(id);
229 }
230
ExecuteClose(Session * session,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)231 Status ExecuteClose(
232 Session* session,
233 const base::DictionaryValue& params,
234 scoped_ptr<base::Value>* value) {
235 std::list<std::string> web_view_ids;
236 Status status = session->chrome->GetWebViewIds(&web_view_ids);
237 if (status.IsError())
238 return status;
239 bool is_last_web_view = web_view_ids.size() == 1u;
240 web_view_ids.clear();
241
242 WebView* web_view = NULL;
243 status = session->GetTargetWindow(&web_view);
244 if (status.IsError())
245 return status;
246
247 status = session->chrome->CloseWebView(web_view->GetId());
248 if (status.IsError())
249 return status;
250
251 status = session->chrome->GetWebViewIds(&web_view_ids);
252 if ((status.code() == kChromeNotReachable && is_last_web_view) ||
253 (status.IsOk() && web_view_ids.empty())) {
254 // If no window is open, close is the equivalent of calling "quit".
255 session->quit = true;
256 return session->chrome->Quit();
257 }
258
259 return status;
260 }
261
ExecuteGetWindowHandles(Session * session,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)262 Status ExecuteGetWindowHandles(
263 Session* session,
264 const base::DictionaryValue& params,
265 scoped_ptr<base::Value>* value) {
266 std::list<std::string> web_view_ids;
267 Status status = session->chrome->GetWebViewIds(&web_view_ids);
268 if (status.IsError())
269 return status;
270 scoped_ptr<base::ListValue> window_ids(new base::ListValue());
271 for (std::list<std::string>::const_iterator it = web_view_ids.begin();
272 it != web_view_ids.end(); ++it) {
273 window_ids->AppendString(WebViewIdToWindowHandle(*it));
274 }
275 value->reset(window_ids.release());
276 return Status(kOk);
277 }
278
ExecuteSwitchToWindow(Session * session,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)279 Status ExecuteSwitchToWindow(
280 Session* session,
281 const base::DictionaryValue& params,
282 scoped_ptr<base::Value>* value) {
283 std::string name;
284 if (!params.GetString("name", &name) || name.empty())
285 return Status(kUnknownError, "'name' must be a nonempty string");
286
287 std::list<std::string> web_view_ids;
288 Status status = session->chrome->GetWebViewIds(&web_view_ids);
289 if (status.IsError())
290 return status;
291
292 std::string web_view_id;
293 bool found = false;
294 if (WindowHandleToWebViewId(name, &web_view_id)) {
295 // Check if any web_view matches |web_view_id|.
296 for (std::list<std::string>::const_iterator it = web_view_ids.begin();
297 it != web_view_ids.end(); ++it) {
298 if (*it == web_view_id) {
299 found = true;
300 break;
301 }
302 }
303 } else {
304 // Check if any of the tab window names match |name|.
305 const char* kGetWindowNameScript = "function() { return window.name; }";
306 base::ListValue args;
307 for (std::list<std::string>::const_iterator it = web_view_ids.begin();
308 it != web_view_ids.end(); ++it) {
309 scoped_ptr<base::Value> result;
310 WebView* web_view;
311 status = session->chrome->GetWebViewById(*it, &web_view);
312 if (status.IsError())
313 return status;
314 status = web_view->ConnectIfNecessary();
315 if (status.IsError())
316 return status;
317 status = web_view->CallFunction(
318 std::string(), kGetWindowNameScript, args, &result);
319 if (status.IsError())
320 return status;
321 std::string window_name;
322 if (!result->GetAsString(&window_name))
323 return Status(kUnknownError, "failed to get window name");
324 if (window_name == name) {
325 web_view_id = *it;
326 found = true;
327 break;
328 }
329 }
330 }
331
332 if (!found)
333 return Status(kNoSuchWindow);
334
335 if (session->overridden_geoposition) {
336 WebView* web_view;
337 status = session->chrome->GetWebViewById(web_view_id, &web_view);
338 if (status.IsError())
339 return status;
340 status = web_view->ConnectIfNecessary();
341 if (status.IsError())
342 return status;
343 status = web_view->OverrideGeolocation(*session->overridden_geoposition);
344 if (status.IsError())
345 return status;
346 }
347
348 session->window = web_view_id;
349 session->SwitchToTopFrame();
350 session->mouse_position = WebPoint(0, 0);
351 return Status(kOk);
352 }
353
ExecuteSetTimeout(Session * session,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)354 Status ExecuteSetTimeout(
355 Session* session,
356 const base::DictionaryValue& params,
357 scoped_ptr<base::Value>* value) {
358 double ms_double;
359 if (!params.GetDouble("ms", &ms_double))
360 return Status(kUnknownError, "'ms' must be a double");
361 std::string type;
362 if (!params.GetString("type", &type))
363 return Status(kUnknownError, "'type' must be a string");
364
365 base::TimeDelta timeout =
366 base::TimeDelta::FromMilliseconds(static_cast<int>(ms_double));
367 // TODO(frankf): implicit and script timeout should be cleared
368 // if negative timeout is specified.
369 if (type == "implicit") {
370 session->implicit_wait = timeout;
371 } else if (type == "script") {
372 session->script_timeout = timeout;
373 } else if (type == "page load") {
374 session->page_load_timeout =
375 ((timeout < base::TimeDelta()) ? Session::kDefaultPageLoadTimeout
376 : timeout);
377 } else {
378 return Status(kUnknownError, "unknown type of timeout:" + type);
379 }
380 return Status(kOk);
381 }
382
ExecuteSetScriptTimeout(Session * session,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)383 Status ExecuteSetScriptTimeout(
384 Session* session,
385 const base::DictionaryValue& params,
386 scoped_ptr<base::Value>* value) {
387 double ms;
388 if (!params.GetDouble("ms", &ms) || ms < 0)
389 return Status(kUnknownError, "'ms' must be a non-negative number");
390 session->script_timeout =
391 base::TimeDelta::FromMilliseconds(static_cast<int>(ms));
392 return Status(kOk);
393 }
394
ExecuteImplicitlyWait(Session * session,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)395 Status ExecuteImplicitlyWait(
396 Session* session,
397 const base::DictionaryValue& params,
398 scoped_ptr<base::Value>* value) {
399 double ms;
400 if (!params.GetDouble("ms", &ms) || ms < 0)
401 return Status(kUnknownError, "'ms' must be a non-negative number");
402 session->implicit_wait =
403 base::TimeDelta::FromMilliseconds(static_cast<int>(ms));
404 return Status(kOk);
405 }
406
ExecuteIsLoading(Session * session,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)407 Status ExecuteIsLoading(
408 Session* session,
409 const base::DictionaryValue& params,
410 scoped_ptr<base::Value>* value) {
411 WebView* web_view = NULL;
412 Status status = session->GetTargetWindow(&web_view);
413 if (status.IsError())
414 return status;
415
416 status = web_view->ConnectIfNecessary();
417 if (status.IsError())
418 return status;
419
420 bool is_pending;
421 status = web_view->IsPendingNavigation(
422 session->GetCurrentFrameId(), &is_pending);
423 if (status.IsError())
424 return status;
425 value->reset(new base::FundamentalValue(is_pending));
426 return Status(kOk);
427 }
428
ExecuteGetLocation(Session * session,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)429 Status ExecuteGetLocation(
430 Session* session,
431 const base::DictionaryValue& params,
432 scoped_ptr<base::Value>* value) {
433 if (!session->overridden_geoposition) {
434 return Status(kUnknownError,
435 "Location must be set before it can be retrieved");
436 }
437 base::DictionaryValue location;
438 location.SetDouble("latitude", session->overridden_geoposition->latitude);
439 location.SetDouble("longitude", session->overridden_geoposition->longitude);
440 location.SetDouble("accuracy", session->overridden_geoposition->accuracy);
441 // Set a dummy altitude to make WebDriver clients happy.
442 // https://code.google.com/p/chromedriver/issues/detail?id=281
443 location.SetDouble("altitude", 0);
444 value->reset(location.DeepCopy());
445 return Status(kOk);
446 }
447
ExecuteGetWindowPosition(Session * session,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)448 Status ExecuteGetWindowPosition(
449 Session* session,
450 const base::DictionaryValue& params,
451 scoped_ptr<base::Value>* value) {
452 ChromeDesktopImpl* desktop = session->chrome->GetAsDesktop();
453 if (!desktop) {
454 return Status(
455 kUnknownError,
456 "command only supported for desktop Chrome without debuggerAddress");
457 }
458
459 AutomationExtension* extension = NULL;
460 Status status = desktop->GetAutomationExtension(&extension);
461 if (status.IsError())
462 return status;
463
464 int x, y;
465 status = extension->GetWindowPosition(&x, &y);
466 if (status.IsError())
467 return status;
468
469 base::DictionaryValue position;
470 position.SetInteger("x", x);
471 position.SetInteger("y", y);
472 value->reset(position.DeepCopy());
473 return Status(kOk);
474 }
475
ExecuteSetWindowPosition(Session * session,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)476 Status ExecuteSetWindowPosition(
477 Session* session,
478 const base::DictionaryValue& params,
479 scoped_ptr<base::Value>* value) {
480 double x, y;
481 if (!params.GetDouble("x", &x) || !params.GetDouble("y", &y))
482 return Status(kUnknownError, "missing or invalid 'x' or 'y'");
483
484 ChromeDesktopImpl* desktop = session->chrome->GetAsDesktop();
485 if (!desktop) {
486 return Status(
487 kUnknownError,
488 "command only supported for desktop Chrome without debuggerAddress");
489 }
490
491 AutomationExtension* extension = NULL;
492 Status status = desktop->GetAutomationExtension(&extension);
493 if (status.IsError())
494 return status;
495
496 return extension->SetWindowPosition(static_cast<int>(x), static_cast<int>(y));
497 }
498
ExecuteGetWindowSize(Session * session,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)499 Status ExecuteGetWindowSize(
500 Session* session,
501 const base::DictionaryValue& params,
502 scoped_ptr<base::Value>* value) {
503 ChromeDesktopImpl* desktop = session->chrome->GetAsDesktop();
504 if (!desktop) {
505 return Status(
506 kUnknownError,
507 "command only supported for desktop Chrome without debuggerAddress");
508 }
509
510 AutomationExtension* extension = NULL;
511 Status status = desktop->GetAutomationExtension(&extension);
512 if (status.IsError())
513 return status;
514
515 int width, height;
516 status = extension->GetWindowSize(&width, &height);
517 if (status.IsError())
518 return status;
519
520 base::DictionaryValue size;
521 size.SetInteger("width", width);
522 size.SetInteger("height", height);
523 value->reset(size.DeepCopy());
524 return Status(kOk);
525 }
526
ExecuteSetWindowSize(Session * session,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)527 Status ExecuteSetWindowSize(
528 Session* session,
529 const base::DictionaryValue& params,
530 scoped_ptr<base::Value>* value) {
531 double width, height;
532 if (!params.GetDouble("width", &width) ||
533 !params.GetDouble("height", &height))
534 return Status(kUnknownError, "missing or invalid 'width' or 'height'");
535
536 ChromeDesktopImpl* desktop = session->chrome->GetAsDesktop();
537 if (!desktop) {
538 return Status(
539 kUnknownError,
540 "command only supported for desktop Chrome without debuggerAddress");
541 }
542
543 AutomationExtension* extension = NULL;
544 Status status = desktop->GetAutomationExtension(&extension);
545 if (status.IsError())
546 return status;
547
548 return extension->SetWindowSize(
549 static_cast<int>(width), static_cast<int>(height));
550 }
551
ExecuteMaximizeWindow(Session * session,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)552 Status ExecuteMaximizeWindow(
553 Session* session,
554 const base::DictionaryValue& params,
555 scoped_ptr<base::Value>* value) {
556 ChromeDesktopImpl* desktop = session->chrome->GetAsDesktop();
557 if (!desktop) {
558 return Status(
559 kUnknownError,
560 "command only supported for desktop Chrome without debuggerAddress");
561 }
562
563 AutomationExtension* extension = NULL;
564 Status status = desktop->GetAutomationExtension(&extension);
565 if (status.IsError())
566 return status;
567
568 return extension->MaximizeWindow();
569 }
570
ExecuteGetAvailableLogTypes(Session * session,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)571 Status ExecuteGetAvailableLogTypes(
572 Session* session,
573 const base::DictionaryValue& params,
574 scoped_ptr<base::Value>* value) {
575 scoped_ptr<base::ListValue> types(new base::ListValue());
576 std::vector<WebDriverLog*> logs = session->GetAllLogs();
577 for (std::vector<WebDriverLog*>::const_iterator log = logs.begin();
578 log != logs.end();
579 ++log) {
580 types->AppendString((*log)->type());
581 }
582 *value = types.Pass();
583 return Status(kOk);
584 }
585
ExecuteGetLog(Session * session,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)586 Status ExecuteGetLog(
587 Session* session,
588 const base::DictionaryValue& params,
589 scoped_ptr<base::Value>* value) {
590 std::string log_type;
591 if (!params.GetString("type", &log_type)) {
592 return Status(kUnknownError, "missing or invalid 'type'");
593 }
594 std::vector<WebDriverLog*> logs = session->GetAllLogs();
595 for (std::vector<WebDriverLog*>::const_iterator log = logs.begin();
596 log != logs.end();
597 ++log) {
598 if (log_type == (*log)->type()) {
599 *value = (*log)->GetAndClearEntries();
600 return Status(kOk);
601 }
602 }
603 return Status(kUnknownError, "log type '" + log_type + "' not found");
604 }
605
ExecuteUploadFile(Session * session,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)606 Status ExecuteUploadFile(
607 Session* session,
608 const base::DictionaryValue& params,
609 scoped_ptr<base::Value>* value) {
610 std::string base64_zip_data;
611 if (!params.GetString("file", &base64_zip_data))
612 return Status(kUnknownError, "missing or invalid 'file'");
613 std::string zip_data;
614 if (!Base64Decode(base64_zip_data, &zip_data))
615 return Status(kUnknownError, "unable to decode 'file'");
616
617 if (!session->temp_dir.IsValid()) {
618 if (!session->temp_dir.CreateUniqueTempDir())
619 return Status(kUnknownError, "unable to create temp dir");
620 }
621 base::FilePath upload_dir;
622 if (!base::CreateTemporaryDirInDir(session->temp_dir.path(),
623 FILE_PATH_LITERAL("upload"),
624 &upload_dir)) {
625 return Status(kUnknownError, "unable to create temp dir");
626 }
627 std::string error_msg;
628 base::FilePath upload;
629 Status status = UnzipSoleFile(upload_dir, zip_data, &upload);
630 if (status.IsError())
631 return Status(kUnknownError, "unable to unzip 'file'", status);
632
633 value->reset(new base::StringValue(upload.value()));
634 return Status(kOk);
635 }
636
ExecuteIsAutoReporting(Session * session,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)637 Status ExecuteIsAutoReporting(
638 Session* session,
639 const base::DictionaryValue& params,
640 scoped_ptr<base::Value>* value) {
641 value->reset(new base::FundamentalValue(session->auto_reporting_enabled));
642 return Status(kOk);
643 }
644
ExecuteSetAutoReporting(Session * session,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)645 Status ExecuteSetAutoReporting(
646 Session* session,
647 const base::DictionaryValue& params,
648 scoped_ptr<base::Value>* value) {
649 bool enabled;
650 if (!params.GetBoolean("enabled", &enabled))
651 return Status(kUnknownError, "missing parameter 'enabled'");
652 session->auto_reporting_enabled = enabled;
653 return Status(kOk);
654 }
655