Suppression for crbug/241044.
[chromium-blink-merge.git] / chrome / test / chromedriver / capabilities.cc
blobc07c12fa307a10c2fa305b7abc1fa6172270827a
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/test/chromedriver/capabilities.h"
7 #include <map>
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/string_util.h"
12 #include "base/stringprintf.h"
13 #include "base/values.h"
14 #include "chrome/test/chromedriver/chrome/status.h"
16 namespace {
18 typedef base::Callback<Status(const base::Value&, Capabilities*)> Parser;
20 Status ParseChromeBinary(
21 const base::Value& option,
22 Capabilities* capabilities) {
23 base::FilePath::StringType path_str;
24 if (!option.GetAsString(&path_str))
25 return Status(kUnknownError, "'binary' must be a string");
26 base::FilePath chrome_exe(path_str);
27 capabilities->command.SetProgram(chrome_exe);
28 return Status(kOk);
31 Status ParseLogPath(const base::Value& option, Capabilities* capabilities) {
32 if (!option.GetAsString(&capabilities->log_path))
33 return Status(kUnknownError, "'logPath' must be a string");
34 return Status(kOk);
37 Status ParseArgs(const base::Value& option, Capabilities* capabilities) {
38 const base::ListValue* args_list = NULL;
39 if (!option.GetAsList(&args_list))
40 return Status(kUnknownError, "'args' must be a list");
41 for (size_t i = 0; i < args_list->GetSize(); ++i) {
42 std::string arg_string;
43 if (!args_list->GetString(i, &arg_string))
44 return Status(kUnknownError, "each argument must be a string");
45 size_t separator_index = arg_string.find("=");
46 if (separator_index != std::string::npos) {
47 CommandLine::StringType arg_string_native;
48 if (!args_list->GetString(i, &arg_string_native))
49 return Status(kUnknownError, "each argument must be a string");
50 capabilities->command.AppendSwitchNative(
51 arg_string.substr(0, separator_index),
52 arg_string_native.substr(separator_index + 1));
53 } else {
54 capabilities->command.AppendSwitch(arg_string);
57 return Status(kOk);
60 Status ParsePrefs(const base::Value& option, Capabilities* capabilities) {
61 const base::DictionaryValue* prefs = NULL;
62 if (!option.GetAsDictionary(&prefs))
63 return Status(kUnknownError, "'prefs' must be a dictionary");
64 capabilities->prefs.reset(prefs->DeepCopy());
65 return Status(kOk);
68 Status ParseLocalState(const base::Value& option, Capabilities* capabilities) {
69 const base::DictionaryValue* local_state = NULL;
70 if (!option.GetAsDictionary(&local_state))
71 return Status(kUnknownError, "'localState' must be a dictionary");
72 capabilities->local_state.reset(local_state->DeepCopy());
73 return Status(kOk);
76 Status ParseExtensions(const base::Value& option, Capabilities* capabilities) {
77 const base::ListValue* extensions = NULL;
78 if (!option.GetAsList(&extensions))
79 return Status(kUnknownError, "'extensions' must be a list");
80 for (size_t i = 0; i < extensions->GetSize(); ++i) {
81 std::string extension;
82 if (!extensions->GetString(i, &extension)) {
83 return Status(kUnknownError,
84 "each extension must be a base64 encoded string");
86 capabilities->extensions.push_back(extension);
88 return Status(kOk);
91 Status ParseProxy(const base::Value& option, Capabilities* capabilities) {
92 const base::DictionaryValue* proxy_dict;
93 if (!option.GetAsDictionary(&proxy_dict))
94 return Status(kUnknownError, "'proxy' must be a dictionary");
95 std::string proxy_type;
96 if (!proxy_dict->GetString("proxyType", &proxy_type))
97 return Status(kUnknownError, "'proxyType' must be a string");
98 proxy_type = StringToLowerASCII(proxy_type);
99 if (proxy_type == "direct") {
100 capabilities->command.AppendSwitch("no-proxy-server");
101 } else if (proxy_type == "system") {
102 // Chrome default.
103 } else if (proxy_type == "pac") {
104 CommandLine::StringType proxy_pac_url;
105 if (!proxy_dict->GetString("proxyAutoconfigUrl", &proxy_pac_url))
106 return Status(kUnknownError, "'proxyAutoconfigUrl' must be a string");
107 capabilities->command.AppendSwitchNative("proxy-pac-url", proxy_pac_url);
108 } else if (proxy_type == "autodetect") {
109 capabilities->command.AppendSwitch("proxy-auto-detect");
110 } else if (proxy_type == "manual") {
111 const char* proxy_servers_options[][2] = {
112 {"ftpProxy", "ftp"}, {"httpProxy", "http"}, {"sslProxy", "https"}};
113 const base::Value* option_value = NULL;
114 std::string proxy_servers;
115 for (size_t i = 0; i < arraysize(proxy_servers_options); ++i) {
116 if (!proxy_dict->Get(proxy_servers_options[i][0], &option_value) ||
117 option_value->IsType(base::Value::TYPE_NULL)) {
118 continue;
120 std::string value;
121 if (!option_value->GetAsString(&value)) {
122 return Status(
123 kUnknownError,
124 base::StringPrintf("'%s' must be a string",
125 proxy_servers_options[i][0]));
127 // Converts into Chrome proxy scheme.
128 // Example: "http=localhost:9000;ftp=localhost:8000".
129 if (!proxy_servers.empty())
130 proxy_servers += ";";
131 proxy_servers += base::StringPrintf(
132 "%s=%s", proxy_servers_options[i][1], value.c_str());
135 std::string proxy_bypass_list;
136 if (proxy_dict->Get("noProxy", &option_value) &&
137 !option_value->IsType(base::Value::TYPE_NULL)) {
138 if (!option_value->GetAsString(&proxy_bypass_list))
139 return Status(kUnknownError, "'noProxy' must be a string");
142 if (proxy_servers.empty() && proxy_bypass_list.empty()) {
143 return Status(kUnknownError,
144 "proxyType is 'manual' but no manual "
145 "proxy capabilities were found");
147 if (!proxy_servers.empty())
148 capabilities->command.AppendSwitchASCII("proxy-server", proxy_servers);
149 if (!proxy_bypass_list.empty()) {
150 capabilities->command.AppendSwitchASCII("proxy-bypass-list",
151 proxy_bypass_list);
153 } else {
154 return Status(kUnknownError, "unrecognized proxy type:" + proxy_type);
156 return Status(kOk);
159 Status ParseDesktopChromeOption(
160 const base::Value& capability,
161 Capabilities* capabilities) {
162 const base::DictionaryValue* chrome_options = NULL;
163 if (!capability.GetAsDictionary(&chrome_options))
164 return Status(kUnknownError, "'chromeOptions' must be a dictionary");
166 std::map<std::string, Parser> parser_map;
168 parser_map["binary"] = base::Bind(&ParseChromeBinary);
169 parser_map["logPath"] = base::Bind(&ParseLogPath);
170 parser_map["args"] = base::Bind(&ParseArgs);
171 parser_map["prefs"] = base::Bind(&ParsePrefs);
172 parser_map["localState"] = base::Bind(&ParseLocalState);
173 parser_map["extensions"] = base::Bind(&ParseExtensions);
175 for (base::DictionaryValue::Iterator it(*chrome_options); !it.IsAtEnd();
176 it.Advance()) {
177 if (parser_map.find(it.key()) == parser_map.end()) {
178 return Status(kUnknownError,
179 "unrecognized chrome option: " + it.key());
181 Status status = parser_map[it.key()].Run(it.value(), capabilities);
182 if (status.IsError())
183 return status;
185 return Status(kOk);
188 Status ParseAndroidChromeCapabilities(const base::DictionaryValue& desired_caps,
189 Capabilities* capabilities) {
190 const base::Value* chrome_options = NULL;
191 if (desired_caps.Get("chromeOptions", &chrome_options)) {
192 const base::DictionaryValue* chrome_options_dict = NULL;
193 if (!chrome_options->GetAsDictionary(&chrome_options_dict))
194 return Status(kUnknownError, "'chromeOptions' must be a dictionary");
196 const base::Value* android_package_value;
197 if (chrome_options_dict->Get("androidPackage", &android_package_value)) {
198 if (!android_package_value->GetAsString(&capabilities->android_package) ||
199 capabilities->android_package.empty()) {
200 return Status(kUnknownError,
201 "'androidPackage' must be a non-empty string");
205 return Status(kOk);
208 Status ParseLoggingPrefs(const base::DictionaryValue& desired_caps,
209 Capabilities* capabilities) {
210 const base::Value* logging_prefs = NULL;
211 if (desired_caps.Get("loggingPrefs", &logging_prefs)) {
212 const base::DictionaryValue* logging_prefs_dict = NULL;
213 if (!logging_prefs->GetAsDictionary(&logging_prefs_dict)) {
214 return Status(kUnknownError, "'loggingPrefs' must be a dictionary");
216 // TODO(klm): verify log types.
217 // TODO(klm): verify log levels.
218 capabilities->logging_prefs.reset(logging_prefs_dict->DeepCopy());
220 return Status(kOk);
223 } // namespace
225 Capabilities::Capabilities() : command(CommandLine::NO_PROGRAM) {}
227 Capabilities::~Capabilities() {}
229 bool Capabilities::IsAndroid() const {
230 return !android_package.empty();
233 Status Capabilities::Parse(const base::DictionaryValue& desired_caps) {
234 Status status = ParseLoggingPrefs(desired_caps, this);
235 if (status.IsError())
236 return status;
237 status = ParseAndroidChromeCapabilities(desired_caps, this);
238 if (status.IsError())
239 return status;
240 if (IsAndroid())
241 return Status(kOk);
243 std::map<std::string, Parser> parser_map;
244 parser_map["proxy"] = base::Bind(&ParseProxy);
245 parser_map["chromeOptions"] = base::Bind(&ParseDesktopChromeOption);
246 for (std::map<std::string, Parser>::iterator it = parser_map.begin();
247 it != parser_map.end(); ++it) {
248 const base::Value* capability = NULL;
249 if (desired_caps.Get(it->first, &capability)) {
250 status = it->second.Run(*capability, this);
251 if (status.IsError())
252 return status;
255 return Status(kOk);