Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(106)

Side by Side Diff: chrome/test/webdriver/webdriver_capabilities_parser.cc

Issue 23526047: Delete old chromedriver code, and remove mongoose webserver. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 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/webdriver/webdriver_capabilities_parser.h"
6
7 #include "base/file_util.h"
8 #include "base/format_macros.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/values.h"
12 #include "chrome/common/chrome_switches.h"
13 #include "chrome/test/webdriver/webdriver_error.h"
14 #include "chrome/test/webdriver/webdriver_logging.h"
15 #include "chrome/test/webdriver/webdriver_util.h"
16
17 using base::DictionaryValue;
18 using base::Value;
19
20 namespace webdriver {
21
22 namespace {
23
24 Error* CreateBadInputError(const std::string& name,
25 Value::Type type,
26 const Value* option) {
27 return new Error(kBadRequest, base::StringPrintf(
28 "%s must be of type %s, not %s. Received: %s",
29 name.c_str(), GetJsonTypeName(type),
30 GetJsonTypeName(option->GetType()),
31 JsonStringifyForDisplay(option).c_str()));
32 }
33
34 } // namespace
35
36 Capabilities::Capabilities()
37 : command(CommandLine::NO_PROGRAM),
38 detach(false),
39 load_async(false),
40 local_state(new DictionaryValue()),
41 no_website_testing_defaults(false),
42 prefs(new DictionaryValue()) {
43 log_levels[LogType::kDriver] = kAllLogLevel;
44 }
45
46 Capabilities::~Capabilities() { }
47
48 CapabilitiesParser::CapabilitiesParser(
49 const DictionaryValue* capabilities_dict,
50 const base::FilePath& root_path,
51 const Logger& logger,
52 Capabilities* capabilities)
53 : dict_(capabilities_dict),
54 root_(root_path),
55 logger_(logger),
56 caps_(capabilities) {
57 }
58
59 CapabilitiesParser::~CapabilitiesParser() { }
60
61 Error* CapabilitiesParser::Parse() {
62 // Parse WebDriver standard capabilities.
63 typedef Error* (CapabilitiesParser::*Parser)(const Value*);
64
65 struct NameAndParser {
66 const char* name;
67 Parser parser;
68 };
69 NameAndParser name_and_parser[] = {
70 { "proxy", &CapabilitiesParser::ParseProxy },
71 { "loggingPrefs", &CapabilitiesParser::ParseLoggingPrefs }
72 };
73 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(name_and_parser); ++i) {
74 const Value* value;
75 if (dict_->Get(name_and_parser[i].name, &value)) {
76 Error* error = (this->*name_and_parser[i].parser)(value);
77 if (error)
78 return error;
79 }
80 }
81
82 // Parse Chrome custom capabilities (a.k.a., ChromeOptions).
83 const char kOptionsKey[] = "chromeOptions";
84 const DictionaryValue* options = dict_;
85 bool legacy_options = true;
86 const Value* options_value;
87 if (dict_->Get(kOptionsKey, &options_value)) {
88 legacy_options = false;
89 if (options_value->IsType(Value::TYPE_DICTIONARY)) {
90 options = static_cast<const DictionaryValue*>(options_value);
91 } else {
92 return CreateBadInputError(
93 kOptionsKey, Value::TYPE_DICTIONARY, options_value);
94 }
95 }
96
97 std::map<std::string, Parser> parser_map;
98 if (legacy_options) {
99 parser_map["chrome.binary"] = &CapabilitiesParser::ParseBinary;
100 parser_map["chrome.channel"] = &CapabilitiesParser::ParseChannel;
101 parser_map["chrome.detach"] = &CapabilitiesParser::ParseDetach;
102 parser_map["chrome.extensions"] = &CapabilitiesParser::ParseExtensions;
103 parser_map["chrome.loadAsync"] = &CapabilitiesParser::ParseLoadAsync;
104 parser_map["chrome.localState"] = &CapabilitiesParser::ParseLocalState;
105 parser_map["chrome.nativeEvents"] = &CapabilitiesParser::ParseNativeEvents;
106 parser_map["chrome.prefs"] = &CapabilitiesParser::ParsePrefs;
107 parser_map["chrome.profile"] = &CapabilitiesParser::ParseProfile;
108 parser_map["chrome.switches"] = &CapabilitiesParser::ParseArgs;
109 parser_map["chrome.noWebsiteTestingDefaults"] =
110 &CapabilitiesParser::ParseNoWebsiteTestingDefaults;
111 parser_map["chrome.excludeSwitches"] =
112 &CapabilitiesParser::ParseExcludeSwitches;
113 } else {
114 parser_map["args"] = &CapabilitiesParser::ParseArgs;
115 parser_map["binary"] = &CapabilitiesParser::ParseBinary;
116 parser_map["channel"] = &CapabilitiesParser::ParseChannel;
117 parser_map["detach"] = &CapabilitiesParser::ParseDetach;
118 parser_map["extensions"] = &CapabilitiesParser::ParseExtensions;
119 parser_map["loadAsync"] = &CapabilitiesParser::ParseLoadAsync;
120 parser_map["localState"] = &CapabilitiesParser::ParseLocalState;
121 parser_map["nativeEvents"] = &CapabilitiesParser::ParseNativeEvents;
122 parser_map["prefs"] = &CapabilitiesParser::ParsePrefs;
123 parser_map["profile"] = &CapabilitiesParser::ParseProfile;
124 parser_map["noWebsiteTestingDefaults"] =
125 &CapabilitiesParser::ParseNoWebsiteTestingDefaults;
126 parser_map["excludeSwitches"] =
127 &CapabilitiesParser::ParseExcludeSwitches;
128 }
129
130 for (DictionaryValue::Iterator iter(*options); !iter.IsAtEnd();
131 iter.Advance()) {
132 if (parser_map.find(iter.key()) == parser_map.end()) {
133 if (!legacy_options)
134 return new Error(kBadRequest,
135 "Unrecognized chrome capability: " + iter.key());
136 continue;
137 }
138 const Value* option = &iter.value();
139 Error* error = (this->*parser_map[iter.key()])(option);
140 if (error) {
141 error->AddDetails(base::StringPrintf(
142 "Error occurred while processing capability '%s'",
143 iter.key().c_str()));
144 return error;
145 }
146 }
147 return NULL;
148 }
149
150 Error* CapabilitiesParser::ParseArgs(const Value* option) {
151 const base::ListValue* args;
152 if (!option->GetAsList(&args))
153 return CreateBadInputError("arguments", Value::TYPE_LIST, option);
154 for (size_t i = 0; i < args->GetSize(); ++i) {
155 std::string arg_string;
156 if (!args->GetString(i, &arg_string))
157 return CreateBadInputError("argument", Value::TYPE_STRING, option);
158 size_t separator_index = arg_string.find("=");
159 if (separator_index != std::string::npos) {
160 CommandLine::StringType arg_string_native;
161 if (!args->GetString(i, &arg_string_native))
162 return CreateBadInputError("argument", Value::TYPE_STRING, option);
163 caps_->command.AppendSwitchNative(
164 arg_string.substr(0, separator_index),
165 arg_string_native.substr(separator_index + 1));
166 } else {
167 caps_->command.AppendSwitch(arg_string);
168 }
169 }
170 return NULL;
171 }
172
173 Error* CapabilitiesParser::ParseBinary(const Value* option) {
174 base::FilePath::StringType path;
175 if (!option->GetAsString(&path)) {
176 return CreateBadInputError("binary path", Value::TYPE_STRING, option);
177 }
178 caps_->command.SetProgram(base::FilePath(path));
179 return NULL;
180 }
181
182 Error* CapabilitiesParser::ParseChannel(const Value* option) {
183 if (!option->GetAsString(&caps_->channel))
184 return CreateBadInputError("channel", Value::TYPE_STRING, option);
185 return NULL;
186 }
187
188 Error* CapabilitiesParser::ParseDetach(const Value* option) {
189 if (!option->GetAsBoolean(&caps_->detach))
190 return CreateBadInputError("detach", Value::TYPE_BOOLEAN, option);
191 return NULL;
192 }
193
194 Error* CapabilitiesParser::ParseExtensions(const Value* option) {
195 const base::ListValue* extensions;
196 if (!option->GetAsList(&extensions))
197 return CreateBadInputError("extensions", Value::TYPE_LIST, option);
198 for (size_t i = 0; i < extensions->GetSize(); ++i) {
199 std::string extension_base64;
200 if (!extensions->GetString(i, &extension_base64)) {
201 return new Error(kBadRequest,
202 "Each extension must be a base64 encoded string");
203 }
204 base::FilePath extension = root_.AppendASCII(
205 base::StringPrintf("extension%" PRIuS ".crx", i));
206 std::string decoded_extension;
207 if (!Base64Decode(extension_base64, &decoded_extension))
208 return new Error(kUnknownError, "Failed to base64 decode extension");
209 int size = static_cast<int>(decoded_extension.length());
210 if (file_util::WriteFile(
211 extension, decoded_extension.c_str(), size) != size)
212 return new Error(kUnknownError, "Failed to write extension file");
213 caps_->extensions.push_back(extension);
214 }
215 return NULL;
216 }
217
218 Error* CapabilitiesParser::ParseLoadAsync(const Value* option) {
219 if (!option->GetAsBoolean(&caps_->load_async))
220 return CreateBadInputError("loadAsync", Value::TYPE_BOOLEAN, option);
221 return NULL;
222 }
223
224 Error* CapabilitiesParser::ParseLocalState(const Value* option) {
225 const base::DictionaryValue* local_state;
226 if (!option->GetAsDictionary(&local_state))
227 return CreateBadInputError("localState", Value::TYPE_DICTIONARY, option);
228 caps_->local_state.reset(local_state->DeepCopy());
229 return NULL;
230 }
231
232 Error* CapabilitiesParser::ParseLoggingPrefs(const base::Value* option) {
233 const DictionaryValue* logging_prefs;
234 if (!option->GetAsDictionary(&logging_prefs))
235 return CreateBadInputError("loggingPrefs", Value::TYPE_DICTIONARY, option);
236
237 for (DictionaryValue::Iterator iter(*logging_prefs); !iter.IsAtEnd();
238 iter.Advance()) {
239 LogType log_type;
240 if (!LogType::FromString(iter.key(), &log_type))
241 continue;
242
243 std::string level_name;
244 if (!iter.value().GetAsString(&level_name)) {
245 return CreateBadInputError(
246 std::string("loggingPrefs.") + iter.key(),
247 Value::TYPE_STRING,
248 &iter.value());
249 }
250 caps_->log_levels[log_type.type()] = LogLevelFromString(level_name);
251 }
252 return NULL;
253 }
254
255 Error* CapabilitiesParser::ParseNativeEvents(const Value* option) {
256 bool native_events;
257 if (!option->GetAsBoolean(&native_events))
258 return CreateBadInputError("nativeEvents", Value::TYPE_BOOLEAN, option);
259 if (native_events)
260 return new Error(kUnknownError, "OS-level events are not supported");
261 return NULL;
262 }
263
264 Error* CapabilitiesParser::ParsePrefs(const Value* option) {
265 const base::DictionaryValue* prefs;
266 if (!option->GetAsDictionary(&prefs))
267 return CreateBadInputError("prefs", Value::TYPE_DICTIONARY, option);
268 caps_->prefs.reset(prefs->DeepCopy());
269 return NULL;
270 }
271
272 Error* CapabilitiesParser::ParseProfile(const Value* option) {
273 std::string profile_base64;
274 if (!option->GetAsString(&profile_base64))
275 return CreateBadInputError("profile", Value::TYPE_STRING, option);
276 std::string error_msg;
277 caps_->profile = root_.AppendASCII("profile");
278 if (!Base64DecodeAndUnzip(caps_->profile, profile_base64, &error_msg))
279 return new Error(kUnknownError, "unable to unpack profile: " + error_msg);
280 return NULL;
281 }
282
283 Error* CapabilitiesParser::ParseProxy(const base::Value* option) {
284 const DictionaryValue* options;
285 if (!option->GetAsDictionary(&options))
286 return CreateBadInputError("proxy", Value::TYPE_DICTIONARY, option);
287
288 // Quick check of proxy capabilities.
289 std::set<std::string> proxy_options;
290 proxy_options.insert("autodetect");
291 proxy_options.insert("ftpProxy");
292 proxy_options.insert("httpProxy");
293 proxy_options.insert("noProxy");
294 proxy_options.insert("proxyType");
295 proxy_options.insert("proxyAutoconfigUrl");
296 proxy_options.insert("sslProxy");
297 proxy_options.insert("class"); // Created by BeanToJSONConverter.
298
299 for (DictionaryValue::Iterator iter(*options); !iter.IsAtEnd();
300 iter.Advance()) {
301 if (proxy_options.find(iter.key()) == proxy_options.end()) {
302 logger_.Log(kInfoLogLevel,
303 "Unrecognized proxy capability: " + iter.key());
304 }
305 }
306
307 typedef Error* (CapabilitiesParser::*Parser)(const DictionaryValue*);
308 std::map<std::string, Parser> proxy_type_parser_map;
309 proxy_type_parser_map["autodetect"] =
310 &CapabilitiesParser::ParseProxyAutoDetect;
311 proxy_type_parser_map["pac"] =
312 &CapabilitiesParser::ParseProxyAutoconfigUrl;
313 proxy_type_parser_map["manual"] = &CapabilitiesParser::ParseProxyServers;
314 proxy_type_parser_map["direct"] = NULL;
315 proxy_type_parser_map["system"] = NULL;
316
317 const Value* proxy_type_value;
318 if (!options->Get("proxyType", &proxy_type_value))
319 return new Error(kBadRequest, "Missing 'proxyType' capability.");
320
321 std::string proxy_type;
322 if (!proxy_type_value->GetAsString(&proxy_type))
323 return CreateBadInputError("proxyType", Value::TYPE_STRING,
324 proxy_type_value);
325
326 proxy_type = StringToLowerASCII(proxy_type);
327 if (proxy_type_parser_map.find(proxy_type) == proxy_type_parser_map.end())
328 return new Error(kBadRequest, "Unrecognized 'proxyType': " + proxy_type);
329
330 if (proxy_type == "direct") {
331 caps_->command.AppendSwitch(switches::kNoProxyServer);
332 } else if (proxy_type == "system") {
333 // Chrome default.
334 } else {
335 Error* error = (this->*proxy_type_parser_map[proxy_type])(options);
336 if (error) {
337 error->AddDetails("Error occurred while processing 'proxyType': " +
338 proxy_type);
339 return error;
340 }
341 }
342 return NULL;
343 }
344
345 Error* CapabilitiesParser::ParseProxyAutoDetect(
346 const DictionaryValue* options) {
347 const char kProxyAutoDetectKey[] = "autodetect";
348 bool proxy_auto_detect = false;
349 if (!options->GetBoolean(kProxyAutoDetectKey, &proxy_auto_detect))
350 return CreateBadInputError(kProxyAutoDetectKey,
351 Value::TYPE_BOOLEAN, options);
352 if (proxy_auto_detect)
353 caps_->command.AppendSwitch(switches::kProxyAutoDetect);
354 return NULL;
355 }
356
357 Error* CapabilitiesParser::ParseProxyAutoconfigUrl(
358 const DictionaryValue* options){
359 const char kProxyAutoconfigUrlKey[] = "proxyAutoconfigUrl";
360 CommandLine::StringType proxy_pac_url;
361 if (!options->GetString(kProxyAutoconfigUrlKey, &proxy_pac_url))
362 return CreateBadInputError(kProxyAutoconfigUrlKey,
363 Value::TYPE_STRING, options);
364 caps_->command.AppendSwitchNative(switches::kProxyPacUrl, proxy_pac_url);
365 return NULL;
366 }
367
368 Error* CapabilitiesParser::ParseProxyServers(
369 const DictionaryValue* options) {
370 const char kNoProxy[] = "noProxy";
371 const char kFtpProxy[] = "ftpProxy";
372 const char kHttpProxy[] = "httpProxy";
373 const char kSslProxy[] = "sslProxy";
374
375 std::set<std::string> proxy_servers_options;
376 proxy_servers_options.insert(kFtpProxy);
377 proxy_servers_options.insert(kHttpProxy);
378 proxy_servers_options.insert(kSslProxy);
379
380 Error* error = NULL;
381 const Value* option = NULL;
382 bool has_manual_settings = false;
383 if (options->Get(kNoProxy, &option) && !option->IsType(Value::TYPE_NULL)) {
384 error = ParseNoProxy(option);
385 if (error)
386 return error;
387 has_manual_settings = true;
388 }
389
390 std::vector<std::string> proxy_servers;
391 std::set<std::string>::const_iterator iter = proxy_servers_options.begin();
392 for (; iter != proxy_servers_options.end(); ++iter) {
393 if (options->Get(*iter, &option) && !option->IsType(Value::TYPE_NULL)) {
394 std::string value;
395 if (!option->GetAsString(&value))
396 return CreateBadInputError(*iter, Value::TYPE_STRING, option);
397 has_manual_settings = true;
398 // Converts into Chrome proxy scheme.
399 // Example: "http=localhost:9000;ftp=localhost:8000".
400 if (*iter == kFtpProxy)
401 value = "ftp=" + value;
402 if (*iter == kHttpProxy)
403 value = "http=" + value;
404 if (*iter == kSslProxy)
405 value = "https=" + value;
406 proxy_servers.push_back(value);
407 }
408 }
409
410 if (!has_manual_settings)
411 return new Error(kBadRequest, "proxyType is 'manual' but no manual "
412 "proxy capabilities were found.");
413
414 std::string proxy_server_value = JoinString(proxy_servers, ';');
415 caps_->command.AppendSwitchASCII(switches::kProxyServer, proxy_server_value);
416
417 return NULL;
418 }
419
420 Error* CapabilitiesParser::ParseNoProxy(const base::Value* option){
421 std::string proxy_bypass_list;
422 if (!option->GetAsString(&proxy_bypass_list))
423 return CreateBadInputError("noProxy", Value::TYPE_STRING, option);
424 if (!proxy_bypass_list.empty())
425 caps_->command.AppendSwitchASCII(switches::kProxyBypassList,
426 proxy_bypass_list);
427 return NULL;
428 }
429
430 Error* CapabilitiesParser::ParseNoWebsiteTestingDefaults(const Value* option) {
431 if (!option->GetAsBoolean(&caps_->no_website_testing_defaults))
432 return CreateBadInputError("noWebsiteTestingDefaults",
433 Value::TYPE_BOOLEAN, option);
434 return NULL;
435 }
436
437 Error* CapabilitiesParser::ParseExcludeSwitches(const Value* option) {
438 const base::ListValue* switches;
439 if (!option->GetAsList(&switches))
440 return CreateBadInputError("excludeSwitches", Value::TYPE_LIST,
441 option);
442 for (size_t i = 0; i < switches->GetSize(); ++i) {
443 std::string switch_name;
444 if (!switches->GetString(i, &switch_name)) {
445 return new Error(kBadRequest,
446 "Each switch to be removed must be a string");
447 }
448 caps_->exclude_switches.insert(switch_name);
449 }
450 return NULL;
451 }
452
453 } // namespace webdriver
OLDNEW
« no previous file with comments | « chrome/test/webdriver/webdriver_capabilities_parser.h ('k') | chrome/test/webdriver/webdriver_capabilities_parser_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698