1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file.
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/test/chromedriver/capabilities.h"
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <map>
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/bind.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/callback.h"
1158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/json/string_escape.h"
1258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/logging.h"
13424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
14424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/strings/string_split.h"
15424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/strings/string_tokenizer.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
1858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/strings/utf_string_conversions.h"
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/values.h"
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/test/chromedriver/chrome/mobile_device.h"
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/test/chromedriver/chrome/status.h"
2258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/test/chromedriver/logging.h"
23424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "net/base/net_util.h"
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace {
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)typedef base::Callback<Status(const base::Value&, Capabilities*)> Parser;
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
29424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)Status ParseBoolean(
30424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    bool* to_set,
3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const base::Value& option,
3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    Capabilities* capabilities) {
33424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (!option.GetAsBoolean(to_set))
3458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return Status(kUnknownError, "must be a boolean");
35424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return Status(kOk);
36424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
37424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
38424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)Status ParseString(std::string* to_set,
39424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                   const base::Value& option,
40424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                   Capabilities* capabilities) {
41424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  std::string str;
42424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (!option.GetAsString(&str))
4358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return Status(kUnknownError, "must be a string");
44424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (str.empty())
4558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return Status(kUnknownError, "cannot be empty");
46424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  *to_set = str;
4790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return Status(kOk);
4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)Status ParseInterval(int* to_set,
5103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                     const base::Value& option,
5203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                     Capabilities* capabilities) {
5303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  int parsed_int = 0;
5403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!option.GetAsInteger(&parsed_int))
5503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return Status(kUnknownError, "must be an integer");
5603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (parsed_int <= 0)
5703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return Status(kUnknownError, "must be positive");
5803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  *to_set = parsed_int;
5903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return Status(kOk);
6003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
6103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
6258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)Status ParseFilePath(base::FilePath* to_set,
6358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                     const base::Value& option,
6458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                     Capabilities* capabilities) {
6558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  base::FilePath::StringType str;
6658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!option.GetAsString(&str))
6758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return Status(kUnknownError, "must be a string");
6858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  *to_set = base::FilePath(str);
69c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  return Status(kOk);
70c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
71c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
7258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)Status ParseDict(scoped_ptr<base::DictionaryValue>* to_set,
7358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                 const base::Value& option,
7458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                 Capabilities* capabilities) {
7558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const base::DictionaryValue* dict = NULL;
7658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!option.GetAsDictionary(&dict))
7758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return Status(kUnknownError, "must be a dictionary");
7858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  to_set->reset(dict->DeepCopy());
79424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return Status(kOk);
80424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
81424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
8258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)Status IgnoreDeprecatedOption(
8358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const char* option_name,
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::Value& option,
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    Capabilities* capabilities) {
8658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  LOG(WARNING) << "Deprecated chrome option is ignored: " << option_name;
8758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return Status(kOk);
8858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
8958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
9058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)Status IgnoreCapability(const base::Value& option, Capabilities* capabilities) {
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return Status(kOk);
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)Status ParseLogPath(const base::Value& option, Capabilities* capabilities) {
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!option.GetAsString(&capabilities->log_path))
9658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return Status(kUnknownError, "must be a string");
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return Status(kOk);
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)Status ParseDeviceName(std::string device_name, Capabilities* capabilities) {
101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<MobileDevice> device;
102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Status status = FindMobileDevice(device_name, &device);
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (status.IsError()) {
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return Status(kUnknownError,
106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                  "'" + device_name + "' must be a valid device",
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                  status);
108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  capabilities->device_metrics.reset(device->device_metrics.release());
111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  capabilities->switches.SetSwitch("user-agent", device->user_agent);
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return Status(kOk);
114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)Status ParseMobileEmulation(const base::Value& option,
117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                            Capabilities* capabilities) {
118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const base::DictionaryValue* mobile_emulation;
119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!option.GetAsDictionary(&mobile_emulation))
120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return Status(kUnknownError, "'mobileEmulation' must be a dictionary");
121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (mobile_emulation->HasKey("deviceName")) {
123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Cannot use any other options with deviceName.
124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (mobile_emulation->size() > 1)
125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return Status(kUnknownError, "'deviceName' must be used alone");
126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    std::string device_name;
128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!mobile_emulation->GetString("deviceName", &device_name))
129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return Status(kUnknownError, "'deviceName' must be a string");
130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return ParseDeviceName(device_name, capabilities);
132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (mobile_emulation->HasKey("deviceMetrics")) {
135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const base::DictionaryValue* metrics;
136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!mobile_emulation->GetDictionary("deviceMetrics", &metrics))
137cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return Status(kUnknownError, "'deviceMetrics' must be a dictionary");
138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    int width = 0;
140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    int height = 0;
141116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    double device_scale_factor = 0;
142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!metrics->GetInteger("width", &width) ||
143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        !metrics->GetInteger("height", &height) ||
144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        !metrics->GetDouble("pixelRatio", &device_scale_factor))
145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return Status(kUnknownError, "invalid 'deviceMetrics'");
146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DeviceMetrics* device_metrics =
148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        new DeviceMetrics(width, height, device_scale_factor);
149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    capabilities->device_metrics =
150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        scoped_ptr<DeviceMetrics>(device_metrics);
151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (mobile_emulation->HasKey("userAgent")) {
154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    std::string user_agent;
155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!mobile_emulation->GetString("userAgent", &user_agent))
156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return Status(kUnknownError, "'userAgent' must be a string");
157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    capabilities->switches.SetSwitch("user-agent", user_agent);
159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return Status(kOk);
162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
16458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)Status ParseSwitches(const base::Value& option,
16558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                     Capabilities* capabilities) {
16658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const base::ListValue* switches_list = NULL;
16758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!option.GetAsList(&switches_list))
16858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return Status(kUnknownError, "must be a list");
16958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  for (size_t i = 0; i < switches_list->GetSize(); ++i) {
170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::string arg_string;
17158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (!switches_list->GetString(i, &arg_string))
172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return Status(kUnknownError, "each argument must be a string");
17358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    capabilities->switches.SetUnparsedSwitch(arg_string);
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return Status(kOk);
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)Status ParseExtensions(const base::Value& option, Capabilities* capabilities) {
179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const base::ListValue* extensions = NULL;
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!option.GetAsList(&extensions))
18158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return Status(kUnknownError, "must be a list");
182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (size_t i = 0; i < extensions->GetSize(); ++i) {
183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::string extension;
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!extensions->GetString(i, &extension)) {
185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return Status(kUnknownError,
186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    "each extension must be a base64 encoded string");
187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    capabilities->extensions.push_back(extension);
189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return Status(kOk);
191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)Status ParseProxy(const base::Value& option, Capabilities* capabilities) {
194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const base::DictionaryValue* proxy_dict;
195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!option.GetAsDictionary(&proxy_dict))
19658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return Status(kUnknownError, "must be a dictionary");
197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string proxy_type;
198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!proxy_dict->GetString("proxyType", &proxy_type))
199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return Status(kUnknownError, "'proxyType' must be a string");
2006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  proxy_type = base::StringToLowerASCII(proxy_type);
201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (proxy_type == "direct") {
20258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    capabilities->switches.SetSwitch("no-proxy-server");
203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else if (proxy_type == "system") {
204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Chrome default.
205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else if (proxy_type == "pac") {
206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    CommandLine::StringType proxy_pac_url;
207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!proxy_dict->GetString("proxyAutoconfigUrl", &proxy_pac_url))
208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return Status(kUnknownError, "'proxyAutoconfigUrl' must be a string");
20958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    capabilities->switches.SetSwitch("proxy-pac-url", proxy_pac_url);
210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else if (proxy_type == "autodetect") {
21158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    capabilities->switches.SetSwitch("proxy-auto-detect");
212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else if (proxy_type == "manual") {
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const char* proxy_servers_options[][2] = {
214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        {"ftpProxy", "ftp"}, {"httpProxy", "http"}, {"sslProxy", "https"}};
215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::Value* option_value = NULL;
216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::string proxy_servers;
217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for (size_t i = 0; i < arraysize(proxy_servers_options); ++i) {
218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (!proxy_dict->Get(proxy_servers_options[i][0], &option_value) ||
219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          option_value->IsType(base::Value::TYPE_NULL)) {
220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        continue;
221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      std::string value;
223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (!option_value->GetAsString(&value)) {
224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return Status(
225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            kUnknownError,
226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            base::StringPrintf("'%s' must be a string",
227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                               proxy_servers_options[i][0]));
228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Converts into Chrome proxy scheme.
230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Example: "http=localhost:9000;ftp=localhost:8000".
231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (!proxy_servers.empty())
232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        proxy_servers += ";";
233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      proxy_servers += base::StringPrintf(
234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          "%s=%s", proxy_servers_options[i][1], value.c_str());
235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::string proxy_bypass_list;
238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (proxy_dict->Get("noProxy", &option_value) &&
239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        !option_value->IsType(base::Value::TYPE_NULL)) {
240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (!option_value->GetAsString(&proxy_bypass_list))
241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return Status(kUnknownError, "'noProxy' must be a string");
242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (proxy_servers.empty() && proxy_bypass_list.empty()) {
245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return Status(kUnknownError,
246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    "proxyType is 'manual' but no manual "
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    "proxy capabilities were found");
248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!proxy_servers.empty())
25058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      capabilities->switches.SetSwitch("proxy-server", proxy_servers);
251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!proxy_bypass_list.empty()) {
25258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      capabilities->switches.SetSwitch("proxy-bypass-list",
25358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                       proxy_bypass_list);
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return Status(kUnknownError, "unrecognized proxy type:" + proxy_type);
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return Status(kOk);
259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)Status ParseExcludeSwitches(const base::Value& option,
2623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                            Capabilities* capabilities) {
2633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const base::ListValue* switches = NULL;
2643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!option.GetAsList(&switches))
26558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return Status(kUnknownError, "must be a list");
2663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (size_t i = 0; i < switches->GetSize(); ++i) {
2673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    std::string switch_name;
2683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (!switches->GetString(i, &switch_name)) {
2693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return Status(kUnknownError,
2703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    "each switch to be removed must be a string");
2713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
2723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    capabilities->exclude_switches.insert(switch_name);
2733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
2743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return Status(kOk);
2753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
2763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
277cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)Status ParseUseRemoteBrowser(const base::Value& option,
278424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                               Capabilities* capabilities) {
279424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  std::string server_addr;
280424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (!option.GetAsString(&server_addr))
281424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return Status(kUnknownError, "must be 'host:port'");
282424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
283424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  std::vector<std::string> values;
284424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  base::SplitString(server_addr, ':', &values);
285424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (values.size() != 2)
286424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return Status(kUnknownError, "must be 'host:port'");
287424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
288424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  int port = 0;
289424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  base::StringToInt(values[1], &port);
290424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (port <= 0)
29158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return Status(kUnknownError, "port must be > 0");
292424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
29358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  capabilities->debugger_address = NetAddress(values[0], port);
294424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return Status(kOk);
295424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
296424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
297424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)Status ParseLoggingPrefs(const base::Value& option,
298424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                         Capabilities* capabilities) {
29958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const base::DictionaryValue* logging_prefs = NULL;
30058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!option.GetAsDictionary(&logging_prefs))
30158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return Status(kUnknownError, "must be a dictionary");
30258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
30358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  for (base::DictionaryValue::Iterator pref(*logging_prefs);
30458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)       !pref.IsAtEnd(); pref.Advance()) {
30558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    std::string type = pref.key();
30658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    Log::Level level;
30758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    std::string level_name;
30858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (!pref.value().GetAsString(&level_name) ||
30958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        !WebDriverLog::NameToLevel(level_name, &level)) {
31058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return Status(kUnknownError, "invalid log level for '" + type + "' log");
31158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
31258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    capabilities->logging_prefs.insert(std::make_pair(type, level));
31358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
314424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return Status(kOk);
315424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
316424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
3175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)Status ParseInspectorDomainStatus(
3185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    PerfLoggingPrefs::InspectorDomainStatus* to_set,
3195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const base::Value& option,
3205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    Capabilities* capabilities) {
3215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  bool desired_value;
3225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!option.GetAsBoolean(&desired_value))
3235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return Status(kUnknownError, "must be a boolean");
3245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (desired_value)
3255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    *to_set = PerfLoggingPrefs::InspectorDomainStatus::kExplicitlyEnabled;
3265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  else
3275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    *to_set = PerfLoggingPrefs::InspectorDomainStatus::kExplicitlyDisabled;
3285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return Status(kOk);
3295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)Status ParsePerfLoggingPrefs(const base::Value& option,
3325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                             Capabilities* capabilities) {
3335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const base::DictionaryValue* perf_logging_prefs = NULL;
3345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!option.GetAsDictionary(&perf_logging_prefs))
3355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return Status(kUnknownError, "must be a dictionary");
3365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::map<std::string, Parser> parser_map;
33803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  parser_map["bufferUsageReportingInterval"] = base::Bind(&ParseInterval,
33903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      &capabilities->perf_logging_prefs.buffer_usage_reporting_interval);
3405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  parser_map["enableNetwork"] = base::Bind(
3415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      &ParseInspectorDomainStatus, &capabilities->perf_logging_prefs.network);
3425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  parser_map["enablePage"] = base::Bind(
3435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      &ParseInspectorDomainStatus, &capabilities->perf_logging_prefs.page);
3445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  parser_map["enableTimeline"] = base::Bind(
3455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      &ParseInspectorDomainStatus, &capabilities->perf_logging_prefs.timeline);
3465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  parser_map["traceCategories"] = base::Bind(
3475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      &ParseString, &capabilities->perf_logging_prefs.trace_categories);
3485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  for (base::DictionaryValue::Iterator it(*perf_logging_prefs); !it.IsAtEnd();
3505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       it.Advance()) {
3515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     if (parser_map.find(it.key()) == parser_map.end())
3525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       return Status(kUnknownError, "unrecognized performance logging "
3535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                     "option: " + it.key());
3545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     Status status = parser_map[it.key()].Run(it.value(), capabilities);
3555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     if (status.IsError())
3565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       return Status(kUnknownError, "cannot parse " + it.key(), status);
3575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   }
3585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   return Status(kOk);
3595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
361424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)Status ParseChromeOptions(
362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::Value& capability,
363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    Capabilities* capabilities) {
364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const base::DictionaryValue* chrome_options = NULL;
365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!capability.GetAsDictionary(&chrome_options))
36658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return Status(kUnknownError, "must be a dictionary");
367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
368424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  bool is_android = chrome_options->HasKey("androidPackage");
369cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  bool is_remote = chrome_options->HasKey("debuggerAddress");
370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
371424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  std::map<std::string, Parser> parser_map;
37258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Ignore 'args', 'binary' and 'extensions' capabilities by default, since the
37358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Java client always passes them.
37458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  parser_map["args"] = base::Bind(&IgnoreCapability);
375424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  parser_map["binary"] = base::Bind(&IgnoreCapability);
376424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  parser_map["extensions"] = base::Bind(&IgnoreCapability);
3775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  parser_map["perfLoggingPrefs"] = base::Bind(&ParsePerfLoggingPrefs);
3795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
380424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (is_android) {
381424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    parser_map["androidActivity"] =
382424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        base::Bind(&ParseString, &capabilities->android_activity);
383424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    parser_map["androidDeviceSerial"] =
384424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        base::Bind(&ParseString, &capabilities->android_device_serial);
385424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    parser_map["androidPackage"] =
386424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        base::Bind(&ParseString, &capabilities->android_package);
387424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    parser_map["androidProcess"] =
388424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        base::Bind(&ParseString, &capabilities->android_process);
389a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    parser_map["androidUseRunningApp"] =
390a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        base::Bind(&ParseBoolean, &capabilities->android_use_running_app);
39158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    parser_map["args"] = base::Bind(&ParseSwitches);
3921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    parser_map["excludeSwitches"] = base::Bind(&ParseExcludeSwitches);
3935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    parser_map["loadAsync"] = base::Bind(&IgnoreDeprecatedOption, "loadAsync");
394cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else if (is_remote) {
395cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    parser_map["debuggerAddress"] = base::Bind(&ParseUseRemoteBrowser);
396424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  } else {
39758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    parser_map["args"] = base::Bind(&ParseSwitches);
39858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    parser_map["binary"] = base::Bind(&ParseFilePath, &capabilities->binary);
399424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    parser_map["detach"] = base::Bind(&ParseBoolean, &capabilities->detach);
400424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    parser_map["excludeSwitches"] = base::Bind(&ParseExcludeSwitches);
401424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    parser_map["extensions"] = base::Bind(&ParseExtensions);
40258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    parser_map["forceDevToolsScreenshot"] = base::Bind(
40358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        &ParseBoolean, &capabilities->force_devtools_screenshot);
40458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    parser_map["loadAsync"] = base::Bind(&IgnoreDeprecatedOption, "loadAsync");
40558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    parser_map["localState"] =
40658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        base::Bind(&ParseDict, &capabilities->local_state);
407424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    parser_map["logPath"] = base::Bind(&ParseLogPath);
4081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    parser_map["minidumpPath"] =
4091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        base::Bind(&ParseString, &capabilities->minidump_path);
4101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    parser_map["mobileEmulation"] = base::Bind(&ParseMobileEmulation);
41158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    parser_map["prefs"] = base::Bind(&ParseDict, &capabilities->prefs);
412424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
413c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
414c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (base::DictionaryValue::Iterator it(*chrome_options); !it.IsAtEnd();
415c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)       it.Advance()) {
416c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (parser_map.find(it.key()) == parser_map.end()) {
417c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return Status(kUnknownError,
418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    "unrecognized chrome option: " + it.key());
419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    Status status = parser_map[it.key()].Run(it.value(), capabilities);
421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (status.IsError())
422424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      return Status(kUnknownError, "cannot parse " + it.key(), status);
423c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
424c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return Status(kOk);
425c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
426c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
427c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace
428c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
42958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)Switches::Switches() {}
43058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
43158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)Switches::~Switches() {}
43258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
43358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void Switches::SetSwitch(const std::string& name) {
43458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  SetSwitch(name, NativeString());
43558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
43658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
43758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void Switches::SetSwitch(const std::string& name, const std::string& value) {
43858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#if defined(OS_WIN)
4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SetSwitch(name, base::UTF8ToUTF16(value));
44058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#else
44158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  switch_map_[name] = value;
44258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#endif
44358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
44458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void Switches::SetSwitch(const std::string& name, const base::string16& value) {
44658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#if defined(OS_WIN)
44758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  switch_map_[name] = value;
44858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#else
4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SetSwitch(name, base::UTF16ToUTF8(value));
45058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#endif
45158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
45258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
45358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void Switches::SetSwitch(const std::string& name, const base::FilePath& value) {
45458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  SetSwitch(name, value.value());
45558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
45658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
45758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void Switches::SetFromSwitches(const Switches& switches) {
45858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  for (SwitchMap::const_iterator iter = switches.switch_map_.begin();
45958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)       iter != switches.switch_map_.end();
46058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)       ++iter) {
46158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    switch_map_[iter->first] = iter->second;
46258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
46358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
46458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
46558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void Switches::SetUnparsedSwitch(const std::string& unparsed_switch) {
46658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::string value;
46758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  size_t equals_index = unparsed_switch.find('=');
46858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (equals_index != std::string::npos)
46958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    value = unparsed_switch.substr(equals_index + 1);
47058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
47158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::string name;
47258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  size_t start_index = 0;
47358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (unparsed_switch.substr(0, 2) == "--")
47458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    start_index = 2;
47558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  name = unparsed_switch.substr(start_index, equals_index - start_index);
47658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
47758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  SetSwitch(name, value);
47858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
47958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
48058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void Switches::RemoveSwitch(const std::string& name) {
48158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  switch_map_.erase(name);
48258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
48358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
48458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool Switches::HasSwitch(const std::string& name) const {
48558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return switch_map_.count(name) > 0;
48658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
48758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
48858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)std::string Switches::GetSwitchValue(const std::string& name) const {
48958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  NativeString value = GetSwitchValueNative(name);
49058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#if defined(OS_WIN)
4915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return base::UTF16ToUTF8(value);
49258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#else
49358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return value;
49458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#endif
49558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
49658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
49758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)Switches::NativeString Switches::GetSwitchValueNative(
49858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::string& name) const {
49958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  SwitchMap::const_iterator iter = switch_map_.find(name);
50058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (iter == switch_map_.end())
50158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return NativeString();
50258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return iter->second;
50358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
50458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
50558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)size_t Switches::GetSize() const {
50658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return switch_map_.size();
50758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
50858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
50958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void Switches::AppendToCommandLine(CommandLine* command) const {
51058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  for (SwitchMap::const_iterator iter = switch_map_.begin();
51158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)       iter != switch_map_.end();
51258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)       ++iter) {
51358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    command->AppendSwitchNative(iter->first, iter->second);
51458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
51558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
51658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
51758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)std::string Switches::ToString() const {
51858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::string str;
51958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  SwitchMap::const_iterator iter = switch_map_.begin();
52058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  while (iter != switch_map_.end()) {
52158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    str += "--" + iter->first;
52258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    std::string value = GetSwitchValue(iter->first);
52358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (value.length()) {
52458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      if (value.find(' ') != std::string::npos)
5255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        value = base::GetQuotedJSONString(value);
52658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      str += "=" + value;
52758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
52858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    ++iter;
52958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (iter == switch_map_.end())
53058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      break;
53158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    str += " ";
53258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
53358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return str;
53458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
53558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
5365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)PerfLoggingPrefs::PerfLoggingPrefs()
5375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    : network(InspectorDomainStatus::kDefaultEnabled),
5385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      page(InspectorDomainStatus::kDefaultEnabled),
5395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      timeline(InspectorDomainStatus::kDefaultEnabled),
54003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      trace_categories(),
54103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      buffer_usage_reporting_interval(1000) {}
5425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)PerfLoggingPrefs::~PerfLoggingPrefs() {}
5445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
54590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)Capabilities::Capabilities()
546a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    : android_use_running_app(false),
547a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      detach(false),
54858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      force_devtools_screenshot(false) {}
549c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
550c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)Capabilities::~Capabilities() {}
551c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
552c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool Capabilities::IsAndroid() const {
553c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return !android_package.empty();
554c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
555c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
556cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool Capabilities::IsRemoteBrowser() const {
55758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return debugger_address.IsValid();
558424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
559424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
56058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)Status Capabilities::Parse(const base::DictionaryValue& desired_caps) {
561c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::map<std::string, Parser> parser_map;
56258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  parser_map["chromeOptions"] = base::Bind(&ParseChromeOptions);
563424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  parser_map["loggingPrefs"] = base::Bind(&ParseLoggingPrefs);
564c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  parser_map["proxy"] = base::Bind(&ParseProxy);
565c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (std::map<std::string, Parser>::iterator it = parser_map.begin();
566c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)       it != parser_map.end(); ++it) {
567c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::Value* capability = NULL;
568c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (desired_caps.Get(it->first, &capability)) {
569424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      Status status = it->second.Run(*capability, this);
570424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      if (status.IsError()) {
571424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        return Status(
572424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            kUnknownError, "cannot parse capability: " + it->first, status);
573424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      }
574c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
575c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
5765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Perf log must be enabled if perf log prefs are specified; otherwise, error.
5775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  LoggingPrefs::const_iterator iter = logging_prefs.find(
5785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      WebDriverLog::kPerformanceType);
5795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (iter == logging_prefs.end() || iter->second == Log::kOff) {
5805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const base::DictionaryValue* chrome_options = NULL;
5815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (desired_caps.GetDictionary("chromeOptions", &chrome_options) &&
5825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        chrome_options->HasKey("perfLoggingPrefs")) {
5835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return Status(kUnknownError, "perfLoggingPrefs specified, "
5845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    "but performance logging was not enabled");
5855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
5865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
587c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return Status(kOk);
588c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
589