OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/test/chromedriver/capabilities.h" | 5 #include "chrome/test/chromedriver/capabilities.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/callback.h" | 10 #include "base/callback.h" |
| 11 #include "base/json/string_escape.h" |
11 #include "base/strings/string_number_conversions.h" | 12 #include "base/strings/string_number_conversions.h" |
12 #include "base/strings/string_split.h" | 13 #include "base/strings/string_split.h" |
13 #include "base/strings/string_tokenizer.h" | 14 #include "base/strings/string_tokenizer.h" |
14 #include "base/strings/string_util.h" | 15 #include "base/strings/string_util.h" |
15 #include "base/strings/stringprintf.h" | 16 #include "base/strings/stringprintf.h" |
| 17 #include "base/strings/utf_string_conversions.h" |
16 #include "base/values.h" | 18 #include "base/values.h" |
17 #include "chrome/test/chromedriver/chrome/log.h" | 19 #include "chrome/test/chromedriver/chrome/log.h" |
18 #include "chrome/test/chromedriver/chrome/status.h" | 20 #include "chrome/test/chromedriver/chrome/status.h" |
19 #include "net/base/net_util.h" | 21 #include "net/base/net_util.h" |
20 | 22 |
21 namespace { | 23 namespace { |
22 | 24 |
23 typedef base::Callback<Status(const base::Value&, Capabilities*)> Parser; | 25 typedef base::Callback<Status(const base::Value&, Capabilities*)> Parser; |
24 | 26 |
25 Status ParseBoolean( | 27 Status ParseBoolean( |
26 bool* to_set, | 28 bool* to_set, |
27 const base::Value& option, | 29 const base::Value& option, |
28 Capabilities* capabilities) { | 30 Capabilities* capabilities) { |
29 if (!option.GetAsBoolean(to_set)) | 31 if (!option.GetAsBoolean(to_set)) |
30 return Status(kUnknownError, "value must be a boolean"); | 32 return Status(kUnknownError, "must be a boolean"); |
31 return Status(kOk); | 33 return Status(kOk); |
32 } | 34 } |
33 | 35 |
34 Status ParseString(std::string* to_set, | 36 Status ParseString(std::string* to_set, |
35 const base::Value& option, | 37 const base::Value& option, |
36 Capabilities* capabilities) { | 38 Capabilities* capabilities) { |
37 std::string str; | 39 std::string str; |
38 if (!option.GetAsString(&str)) | 40 if (!option.GetAsString(&str)) |
39 return Status(kUnknownError, "value must be a string"); | 41 return Status(kUnknownError, "must be a string"); |
40 if (str.empty()) | 42 if (str.empty()) |
41 return Status(kUnknownError, "value cannot be empty"); | 43 return Status(kUnknownError, "cannot be empty"); |
42 *to_set = str; | 44 *to_set = str; |
43 return Status(kOk); | 45 return Status(kOk); |
44 } | 46 } |
45 | 47 |
| 48 Status ParseFilePath(base::FilePath* to_set, |
| 49 const base::Value& option, |
| 50 Capabilities* capabilities) { |
| 51 base::FilePath::StringType str; |
| 52 if (!option.GetAsString(&str)) |
| 53 return Status(kUnknownError, "must be a string"); |
| 54 if (str.empty()) |
| 55 return Status(kUnknownError, "cannot be empty"); |
| 56 *to_set = base::FilePath(str); |
| 57 return Status(kOk); |
| 58 } |
| 59 |
| 60 Status ParseDict(scoped_ptr<base::DictionaryValue>* to_set, |
| 61 const base::Value& option, |
| 62 Capabilities* capabilities) { |
| 63 const base::DictionaryValue* dict = NULL; |
| 64 if (!option.GetAsDictionary(&dict)) |
| 65 return Status(kUnknownError, "must be a dictionary"); |
| 66 to_set->reset(dict->DeepCopy()); |
| 67 return Status(kOk); |
| 68 } |
| 69 |
46 Status IgnoreDeprecatedOption( | 70 Status IgnoreDeprecatedOption( |
47 Log* log, | 71 Log* log, |
48 const char* option_name, | 72 const char* option_name, |
49 const base::Value& option, | 73 const base::Value& option, |
50 Capabilities* capabilities) { | 74 Capabilities* capabilities) { |
51 log->AddEntry(Log::kWarning, | 75 log->AddEntry(Log::kWarning, |
52 base::StringPrintf("deprecated chrome option is ignored: '%s'", | 76 base::StringPrintf("deprecated chrome option is ignored: '%s'", |
53 option_name)); | 77 option_name)); |
54 return Status(kOk); | 78 return Status(kOk); |
55 } | 79 } |
56 | 80 |
57 Status IgnoreCapability(const base::Value& option, Capabilities* capabilities) { | 81 Status IgnoreCapability(const base::Value& option, Capabilities* capabilities) { |
58 return Status(kOk); | 82 return Status(kOk); |
59 } | 83 } |
60 | 84 |
61 Status ParseChromeBinary( | |
62 const base::Value& option, | |
63 Capabilities* capabilities) { | |
64 base::FilePath::StringType path_str; | |
65 if (!option.GetAsString(&path_str)) | |
66 return Status(kUnknownError, "'binary' must be a string"); | |
67 base::FilePath chrome_exe(path_str); | |
68 capabilities->command.SetProgram(chrome_exe); | |
69 return Status(kOk); | |
70 } | |
71 | |
72 Status ParseLogPath(const base::Value& option, Capabilities* capabilities) { | 85 Status ParseLogPath(const base::Value& option, Capabilities* capabilities) { |
73 if (!option.GetAsString(&capabilities->log_path)) | 86 if (!option.GetAsString(&capabilities->log_path)) |
74 return Status(kUnknownError, "'logPath' must be a string"); | 87 return Status(kUnknownError, "must be a string"); |
75 return Status(kOk); | 88 return Status(kOk); |
76 } | 89 } |
77 | 90 |
78 Status ParseArgs(bool is_android, | 91 Status ParseSwitches(const base::Value& option, |
79 const base::Value& option, | 92 Capabilities* capabilities) { |
80 Capabilities* capabilities) { | 93 const base::ListValue* switches_list = NULL; |
81 const base::ListValue* args_list = NULL; | 94 if (!option.GetAsList(&switches_list)) |
82 if (!option.GetAsList(&args_list)) | 95 return Status(kUnknownError, "must be a list"); |
83 return Status(kUnknownError, "'args' must be a list"); | 96 for (size_t i = 0; i < switches_list->GetSize(); ++i) { |
84 for (size_t i = 0; i < args_list->GetSize(); ++i) { | |
85 std::string arg_string; | 97 std::string arg_string; |
86 if (!args_list->GetString(i, &arg_string)) | 98 if (!switches_list->GetString(i, &arg_string)) |
87 return Status(kUnknownError, "each argument must be a string"); | 99 return Status(kUnknownError, "each argument must be a string"); |
88 if (is_android) { | 100 capabilities->switches.SetUnparsedSwitch(arg_string); |
89 capabilities->android_args += "--" + arg_string + " "; | |
90 } else { | |
91 size_t separator_index = arg_string.find("="); | |
92 if (separator_index != std::string::npos) { | |
93 CommandLine::StringType arg_string_native; | |
94 if (!args_list->GetString(i, &arg_string_native)) | |
95 return Status(kUnknownError, "each argument must be a string"); | |
96 capabilities->command.AppendSwitchNative( | |
97 arg_string.substr(0, separator_index), | |
98 arg_string_native.substr(separator_index + 1)); | |
99 } else { | |
100 capabilities->command.AppendSwitch(arg_string); | |
101 } | |
102 } | |
103 } | 101 } |
104 return Status(kOk); | 102 return Status(kOk); |
105 } | 103 } |
106 | 104 |
107 Status ParsePrefs(const base::Value& option, Capabilities* capabilities) { | |
108 const base::DictionaryValue* prefs = NULL; | |
109 if (!option.GetAsDictionary(&prefs)) | |
110 return Status(kUnknownError, "'prefs' must be a dictionary"); | |
111 capabilities->prefs.reset(prefs->DeepCopy()); | |
112 return Status(kOk); | |
113 } | |
114 | |
115 Status ParseLocalState(const base::Value& option, Capabilities* capabilities) { | |
116 const base::DictionaryValue* local_state = NULL; | |
117 if (!option.GetAsDictionary(&local_state)) | |
118 return Status(kUnknownError, "'localState' must be a dictionary"); | |
119 capabilities->local_state.reset(local_state->DeepCopy()); | |
120 return Status(kOk); | |
121 } | |
122 | |
123 Status ParseExtensions(const base::Value& option, Capabilities* capabilities) { | 105 Status ParseExtensions(const base::Value& option, Capabilities* capabilities) { |
124 const base::ListValue* extensions = NULL; | 106 const base::ListValue* extensions = NULL; |
125 if (!option.GetAsList(&extensions)) | 107 if (!option.GetAsList(&extensions)) |
126 return Status(kUnknownError, "'extensions' must be a list"); | 108 return Status(kUnknownError, "must be a list"); |
127 for (size_t i = 0; i < extensions->GetSize(); ++i) { | 109 for (size_t i = 0; i < extensions->GetSize(); ++i) { |
128 std::string extension; | 110 std::string extension; |
129 if (!extensions->GetString(i, &extension)) { | 111 if (!extensions->GetString(i, &extension)) { |
130 return Status(kUnknownError, | 112 return Status(kUnknownError, |
131 "each extension must be a base64 encoded string"); | 113 "each extension must be a base64 encoded string"); |
132 } | 114 } |
133 capabilities->extensions.push_back(extension); | 115 capabilities->extensions.push_back(extension); |
134 } | 116 } |
135 return Status(kOk); | 117 return Status(kOk); |
136 } | 118 } |
137 | 119 |
138 Status ParseProxy(const base::Value& option, Capabilities* capabilities) { | 120 Status ParseProxy(const base::Value& option, Capabilities* capabilities) { |
139 const base::DictionaryValue* proxy_dict; | 121 const base::DictionaryValue* proxy_dict; |
140 if (!option.GetAsDictionary(&proxy_dict)) | 122 if (!option.GetAsDictionary(&proxy_dict)) |
141 return Status(kUnknownError, "'proxy' must be a dictionary"); | 123 return Status(kUnknownError, "must be a dictionary"); |
142 std::string proxy_type; | 124 std::string proxy_type; |
143 if (!proxy_dict->GetString("proxyType", &proxy_type)) | 125 if (!proxy_dict->GetString("proxyType", &proxy_type)) |
144 return Status(kUnknownError, "'proxyType' must be a string"); | 126 return Status(kUnknownError, "'proxyType' must be a string"); |
145 proxy_type = StringToLowerASCII(proxy_type); | 127 proxy_type = StringToLowerASCII(proxy_type); |
146 if (proxy_type == "direct") { | 128 if (proxy_type == "direct") { |
147 capabilities->command.AppendSwitch("no-proxy-server"); | 129 capabilities->switches.SetSwitch("no-proxy-server"); |
148 } else if (proxy_type == "system") { | 130 } else if (proxy_type == "system") { |
149 // Chrome default. | 131 // Chrome default. |
150 } else if (proxy_type == "pac") { | 132 } else if (proxy_type == "pac") { |
151 CommandLine::StringType proxy_pac_url; | 133 CommandLine::StringType proxy_pac_url; |
152 if (!proxy_dict->GetString("proxyAutoconfigUrl", &proxy_pac_url)) | 134 if (!proxy_dict->GetString("proxyAutoconfigUrl", &proxy_pac_url)) |
153 return Status(kUnknownError, "'proxyAutoconfigUrl' must be a string"); | 135 return Status(kUnknownError, "'proxyAutoconfigUrl' must be a string"); |
154 capabilities->command.AppendSwitchNative("proxy-pac-url", proxy_pac_url); | 136 capabilities->switches.SetSwitch("proxy-pac-url", proxy_pac_url); |
155 } else if (proxy_type == "autodetect") { | 137 } else if (proxy_type == "autodetect") { |
156 capabilities->command.AppendSwitch("proxy-auto-detect"); | 138 capabilities->switches.SetSwitch("proxy-auto-detect"); |
157 } else if (proxy_type == "manual") { | 139 } else if (proxy_type == "manual") { |
158 const char* proxy_servers_options[][2] = { | 140 const char* proxy_servers_options[][2] = { |
159 {"ftpProxy", "ftp"}, {"httpProxy", "http"}, {"sslProxy", "https"}}; | 141 {"ftpProxy", "ftp"}, {"httpProxy", "http"}, {"sslProxy", "https"}}; |
160 const base::Value* option_value = NULL; | 142 const base::Value* option_value = NULL; |
161 std::string proxy_servers; | 143 std::string proxy_servers; |
162 for (size_t i = 0; i < arraysize(proxy_servers_options); ++i) { | 144 for (size_t i = 0; i < arraysize(proxy_servers_options); ++i) { |
163 if (!proxy_dict->Get(proxy_servers_options[i][0], &option_value) || | 145 if (!proxy_dict->Get(proxy_servers_options[i][0], &option_value) || |
164 option_value->IsType(base::Value::TYPE_NULL)) { | 146 option_value->IsType(base::Value::TYPE_NULL)) { |
165 continue; | 147 continue; |
166 } | 148 } |
(...skipping 18 matching lines...) Expand all Loading... |
185 if (!option_value->GetAsString(&proxy_bypass_list)) | 167 if (!option_value->GetAsString(&proxy_bypass_list)) |
186 return Status(kUnknownError, "'noProxy' must be a string"); | 168 return Status(kUnknownError, "'noProxy' must be a string"); |
187 } | 169 } |
188 | 170 |
189 if (proxy_servers.empty() && proxy_bypass_list.empty()) { | 171 if (proxy_servers.empty() && proxy_bypass_list.empty()) { |
190 return Status(kUnknownError, | 172 return Status(kUnknownError, |
191 "proxyType is 'manual' but no manual " | 173 "proxyType is 'manual' but no manual " |
192 "proxy capabilities were found"); | 174 "proxy capabilities were found"); |
193 } | 175 } |
194 if (!proxy_servers.empty()) | 176 if (!proxy_servers.empty()) |
195 capabilities->command.AppendSwitchASCII("proxy-server", proxy_servers); | 177 capabilities->switches.SetSwitch("proxy-server", proxy_servers); |
196 if (!proxy_bypass_list.empty()) { | 178 if (!proxy_bypass_list.empty()) { |
197 capabilities->command.AppendSwitchASCII("proxy-bypass-list", | 179 capabilities->switches.SetSwitch("proxy-bypass-list", |
198 proxy_bypass_list); | 180 proxy_bypass_list); |
199 } | 181 } |
200 } else { | 182 } else { |
201 return Status(kUnknownError, "unrecognized proxy type:" + proxy_type); | 183 return Status(kUnknownError, "unrecognized proxy type:" + proxy_type); |
202 } | 184 } |
203 return Status(kOk); | 185 return Status(kOk); |
204 } | 186 } |
205 | 187 |
206 Status ParseExcludeSwitches(const base::Value& option, | 188 Status ParseExcludeSwitches(const base::Value& option, |
207 Capabilities* capabilities) { | 189 Capabilities* capabilities) { |
208 const base::ListValue* switches = NULL; | 190 const base::ListValue* switches = NULL; |
209 if (!option.GetAsList(&switches)) | 191 if (!option.GetAsList(&switches)) |
210 return Status(kUnknownError, "'excludeSwitches' must be a list"); | 192 return Status(kUnknownError, "must be a list"); |
211 for (size_t i = 0; i < switches->GetSize(); ++i) { | 193 for (size_t i = 0; i < switches->GetSize(); ++i) { |
212 std::string switch_name; | 194 std::string switch_name; |
213 if (!switches->GetString(i, &switch_name)) { | 195 if (!switches->GetString(i, &switch_name)) { |
214 return Status(kUnknownError, | 196 return Status(kUnknownError, |
215 "each switch to be removed must be a string"); | 197 "each switch to be removed must be a string"); |
216 } | 198 } |
217 capabilities->exclude_switches.insert(switch_name); | 199 capabilities->exclude_switches.insert(switch_name); |
218 } | 200 } |
219 return Status(kOk); | 201 return Status(kOk); |
220 } | 202 } |
221 | 203 |
222 Status ParseUseExistingBrowser(const base::Value& option, | 204 Status ParseUseExistingBrowser(const base::Value& option, |
223 Capabilities* capabilities) { | 205 Capabilities* capabilities) { |
224 std::string server_addr; | 206 std::string server_addr; |
225 if (!option.GetAsString(&server_addr)) | 207 if (!option.GetAsString(&server_addr)) |
226 return Status(kUnknownError, "must be 'host:port'"); | 208 return Status(kUnknownError, "must be 'host:port'"); |
227 | 209 |
228 std::vector<std::string> values; | 210 std::vector<std::string> values; |
229 base::SplitString(server_addr, ':', &values); | 211 base::SplitString(server_addr, ':', &values); |
230 if (values.size() != 2) | 212 if (values.size() != 2) |
231 return Status(kUnknownError, "must be 'host:port'"); | 213 return Status(kUnknownError, "must be 'host:port'"); |
232 | 214 |
233 int port = 0; | 215 int port = 0; |
234 base::StringToInt(values[1], &port); | 216 base::StringToInt(values[1], &port); |
235 if (port <= 0) | 217 if (port <= 0) |
236 return Status(kUnknownError, "port must be >= 0"); | 218 return Status(kUnknownError, "port must be > 0"); |
237 | 219 |
238 capabilities->use_existing_browser = NetAddress(values[0], port); | 220 capabilities->debugger_address = NetAddress(values[0], port); |
239 return Status(kOk); | 221 return Status(kOk); |
240 } | 222 } |
241 | 223 |
242 Status ParseLoggingPrefs(const base::Value& option, | 224 Status ParseLoggingPrefs(const base::Value& option, |
243 Capabilities* capabilities) { | 225 Capabilities* capabilities) { |
244 const base::DictionaryValue* logging_prefs_dict = NULL; | 226 const base::DictionaryValue* logging_prefs_dict = NULL; |
245 if (!option.GetAsDictionary(&logging_prefs_dict)) | 227 if (!option.GetAsDictionary(&logging_prefs_dict)) |
246 return Status(kUnknownError, "'loggingPrefs' must be a dictionary"); | 228 return Status(kUnknownError, "must be a dictionary"); |
247 | 229 |
248 // TODO(klm): verify log types. | 230 // TODO(klm): verify log types. |
249 // TODO(klm): verify log levels. | 231 // TODO(klm): verify log levels. |
250 capabilities->logging_prefs.reset(logging_prefs_dict->DeepCopy()); | 232 capabilities->logging_prefs.reset(logging_prefs_dict->DeepCopy()); |
251 return Status(kOk); | 233 return Status(kOk); |
252 } | 234 } |
253 | 235 |
254 Status ParseChromeOptions( | 236 Status ParseChromeOptions( |
255 Log* log, | 237 Log* log, |
256 const base::Value& capability, | 238 const base::Value& capability, |
257 Capabilities* capabilities) { | 239 Capabilities* capabilities) { |
258 const base::DictionaryValue* chrome_options = NULL; | 240 const base::DictionaryValue* chrome_options = NULL; |
259 if (!capability.GetAsDictionary(&chrome_options)) | 241 if (!capability.GetAsDictionary(&chrome_options)) |
260 return Status(kUnknownError, "'chromeOptions' must be a dictionary"); | 242 return Status(kUnknownError, "must be a dictionary"); |
261 | 243 |
262 bool is_android = chrome_options->HasKey("androidPackage"); | 244 bool is_android = chrome_options->HasKey("androidPackage"); |
263 bool is_existing = chrome_options->HasKey("useExistingBrowser"); | 245 bool is_existing = chrome_options->HasKey("debuggerAddress"); |
264 | 246 |
265 std::map<std::string, Parser> parser_map; | 247 std::map<std::string, Parser> parser_map; |
266 // Ignore 'binary' and 'extensions' capability, since the Java client | 248 // Ignore 'args', 'binary' and 'extensions' capabilities by default, since the |
267 // always passes them. | 249 // Java client always passes them. |
| 250 parser_map["args"] = base::Bind(&IgnoreCapability); |
268 parser_map["binary"] = base::Bind(&IgnoreCapability); | 251 parser_map["binary"] = base::Bind(&IgnoreCapability); |
269 parser_map["extensions"] = base::Bind(&IgnoreCapability); | 252 parser_map["extensions"] = base::Bind(&IgnoreCapability); |
270 if (is_android) { | 253 if (is_android) { |
271 parser_map["androidActivity"] = | 254 parser_map["androidActivity"] = |
272 base::Bind(&ParseString, &capabilities->android_activity); | 255 base::Bind(&ParseString, &capabilities->android_activity); |
273 parser_map["androidDeviceSerial"] = | 256 parser_map["androidDeviceSerial"] = |
274 base::Bind(&ParseString, &capabilities->android_device_serial); | 257 base::Bind(&ParseString, &capabilities->android_device_serial); |
275 parser_map["androidPackage"] = | 258 parser_map["androidPackage"] = |
276 base::Bind(&ParseString, &capabilities->android_package); | 259 base::Bind(&ParseString, &capabilities->android_package); |
277 parser_map["androidProcess"] = | 260 parser_map["androidProcess"] = |
278 base::Bind(&ParseString, &capabilities->android_process); | 261 base::Bind(&ParseString, &capabilities->android_process); |
279 parser_map["args"] = base::Bind(&ParseArgs, true); | 262 parser_map["args"] = base::Bind(&ParseSwitches); |
280 } else if (is_existing) { | 263 } else if (is_existing) { |
281 parser_map["args"] = base::Bind(&IgnoreCapability); | 264 parser_map["debuggerAddress"] = base::Bind(&ParseUseExistingBrowser); |
282 parser_map["useExistingBrowser"] = base::Bind(&ParseUseExistingBrowser); | |
283 } else { | 265 } else { |
284 parser_map["forceDevToolsScreenshot"] = base::Bind( | 266 parser_map["args"] = base::Bind(&ParseSwitches); |
285 &ParseBoolean, &capabilities->force_devtools_screenshot); | 267 parser_map["binary"] = base::Bind(&ParseFilePath, &capabilities->binary); |
286 parser_map["args"] = base::Bind(&ParseArgs, false); | |
287 parser_map["binary"] = base::Bind(&ParseChromeBinary); | |
288 parser_map["detach"] = base::Bind(&ParseBoolean, &capabilities->detach); | 268 parser_map["detach"] = base::Bind(&ParseBoolean, &capabilities->detach); |
289 parser_map["excludeSwitches"] = base::Bind(&ParseExcludeSwitches); | 269 parser_map["excludeSwitches"] = base::Bind(&ParseExcludeSwitches); |
290 parser_map["extensions"] = base::Bind(&ParseExtensions); | 270 parser_map["extensions"] = base::Bind(&ParseExtensions); |
| 271 parser_map["forceDevToolsScreenshot"] = base::Bind( |
| 272 &ParseBoolean, &capabilities->force_devtools_screenshot); |
291 parser_map["loadAsync"] = | 273 parser_map["loadAsync"] = |
292 base::Bind(&IgnoreDeprecatedOption, log, "loadAsync"); | 274 base::Bind(&IgnoreDeprecatedOption, log, "loadAsync"); |
293 parser_map["localState"] = base::Bind(&ParseLocalState); | 275 parser_map["localState"] = |
| 276 base::Bind(&ParseDict, &capabilities->local_state); |
294 parser_map["logPath"] = base::Bind(&ParseLogPath); | 277 parser_map["logPath"] = base::Bind(&ParseLogPath); |
295 parser_map["prefs"] = base::Bind(&ParsePrefs); | 278 parser_map["prefs"] = base::Bind(&ParseDict, &capabilities->prefs); |
296 } | 279 } |
297 | 280 |
298 for (base::DictionaryValue::Iterator it(*chrome_options); !it.IsAtEnd(); | 281 for (base::DictionaryValue::Iterator it(*chrome_options); !it.IsAtEnd(); |
299 it.Advance()) { | 282 it.Advance()) { |
300 if (parser_map.find(it.key()) == parser_map.end()) { | 283 if (parser_map.find(it.key()) == parser_map.end()) { |
301 return Status(kUnknownError, | 284 return Status(kUnknownError, |
302 "unrecognized chrome option: " + it.key()); | 285 "unrecognized chrome option: " + it.key()); |
303 } | 286 } |
304 Status status = parser_map[it.key()].Run(it.value(), capabilities); | 287 Status status = parser_map[it.key()].Run(it.value(), capabilities); |
305 if (status.IsError()) | 288 if (status.IsError()) |
306 return Status(kUnknownError, "cannot parse " + it.key(), status); | 289 return Status(kUnknownError, "cannot parse " + it.key(), status); |
307 } | 290 } |
308 return Status(kOk); | 291 return Status(kOk); |
309 } | 292 } |
310 | 293 |
311 } // namespace | 294 } // namespace |
312 | 295 |
| 296 Switches::Switches() {} |
| 297 |
| 298 Switches::~Switches() {} |
| 299 |
| 300 void Switches::SetSwitch(const std::string& name) { |
| 301 SetSwitch(name, NativeString()); |
| 302 } |
| 303 |
| 304 void Switches::SetSwitch(const std::string& name, const std::string& value) { |
| 305 #if defined(OS_WIN) |
| 306 SetSwitch(name, UTF8ToUTF16(value)); |
| 307 #else |
| 308 switch_map_[name] = value; |
| 309 #endif |
| 310 } |
| 311 |
| 312 void Switches::SetSwitch(const std::string& name, const string16& value) { |
| 313 #if defined(OS_WIN) |
| 314 switch_map_[name] = value; |
| 315 #else |
| 316 SetSwitch(name, UTF16ToUTF8(value)); |
| 317 #endif |
| 318 } |
| 319 |
| 320 void Switches::SetSwitch(const std::string& name, const base::FilePath& value) { |
| 321 SetSwitch(name, value.value()); |
| 322 } |
| 323 |
| 324 void Switches::SetFromSwitches(const Switches& switches) { |
| 325 for (SwitchMap::const_iterator iter = switches.switch_map_.begin(); |
| 326 iter != switches.switch_map_.end(); |
| 327 ++iter) { |
| 328 switch_map_[iter->first] = iter->second; |
| 329 } |
| 330 } |
| 331 |
| 332 void Switches::SetUnparsedSwitch(const std::string& unparsed_switch) { |
| 333 std::string value; |
| 334 size_t equals_index = unparsed_switch.find('='); |
| 335 if (equals_index != std::string::npos) |
| 336 value = unparsed_switch.substr(equals_index + 1); |
| 337 |
| 338 std::string name; |
| 339 size_t start_index = 0; |
| 340 if (unparsed_switch.substr(0, 2) == "--") |
| 341 start_index = 2; |
| 342 name = unparsed_switch.substr(start_index, equals_index - start_index); |
| 343 |
| 344 SetSwitch(name, value); |
| 345 } |
| 346 |
| 347 void Switches::RemoveSwitch(const std::string& name) { |
| 348 switch_map_.erase(name); |
| 349 } |
| 350 |
| 351 bool Switches::HasSwitch(const std::string& name) const { |
| 352 return switch_map_.count(name) > 0; |
| 353 } |
| 354 |
| 355 std::string Switches::GetSwitchValue(const std::string& name) const { |
| 356 NativeString value = GetSwitchValueNative(name); |
| 357 #if defined(OS_WIN) |
| 358 return UTF16ToUTF8(value); |
| 359 #else |
| 360 return value; |
| 361 #endif |
| 362 } |
| 363 |
| 364 Switches::NativeString Switches::GetSwitchValueNative( |
| 365 const std::string& name) const { |
| 366 SwitchMap::const_iterator iter = switch_map_.find(name); |
| 367 if (iter == switch_map_.end()) |
| 368 return NativeString(); |
| 369 return iter->second; |
| 370 } |
| 371 |
| 372 size_t Switches::GetSize() const { |
| 373 return switch_map_.size(); |
| 374 } |
| 375 |
| 376 void Switches::AppendToCommandLine(CommandLine* command) const { |
| 377 for (SwitchMap::const_iterator iter = switch_map_.begin(); |
| 378 iter != switch_map_.end(); |
| 379 ++iter) { |
| 380 command->AppendSwitchNative(iter->first, iter->second); |
| 381 } |
| 382 } |
| 383 |
| 384 std::string Switches::ToString() const { |
| 385 std::string str; |
| 386 SwitchMap::const_iterator iter = switch_map_.begin(); |
| 387 while (iter != switch_map_.end()) { |
| 388 str += "--" + iter->first; |
| 389 std::string value = GetSwitchValue(iter->first); |
| 390 if (value.length()) { |
| 391 if (value.find(' ') != std::string::npos) |
| 392 value = base::GetDoubleQuotedJson(value); |
| 393 str += "=" + value; |
| 394 } |
| 395 ++iter; |
| 396 if (iter == switch_map_.end()) |
| 397 break; |
| 398 str += " "; |
| 399 } |
| 400 return str; |
| 401 } |
| 402 |
313 Capabilities::Capabilities() | 403 Capabilities::Capabilities() |
314 : force_devtools_screenshot(false), | 404 : detach(false), |
315 detach(false), | 405 force_devtools_screenshot(false) {} |
316 command(CommandLine::NO_PROGRAM) {} | |
317 | 406 |
318 Capabilities::~Capabilities() {} | 407 Capabilities::~Capabilities() {} |
319 | 408 |
320 bool Capabilities::IsAndroid() const { | 409 bool Capabilities::IsAndroid() const { |
321 return !android_package.empty(); | 410 return !android_package.empty(); |
322 } | 411 } |
323 | 412 |
324 bool Capabilities::IsExistingBrowser() const { | 413 bool Capabilities::IsExistingBrowser() const { |
325 return use_existing_browser.IsValid(); | 414 return debugger_address.IsValid(); |
326 } | 415 } |
327 | 416 |
328 Status Capabilities::Parse( | 417 Status Capabilities::Parse( |
329 const base::DictionaryValue& desired_caps, | 418 const base::DictionaryValue& desired_caps, |
330 Log* log) { | 419 Log* log) { |
331 std::map<std::string, Parser> parser_map; | 420 std::map<std::string, Parser> parser_map; |
332 parser_map["chromeOptions"] = base::Bind(&ParseChromeOptions, log); | 421 parser_map["chromeOptions"] = base::Bind(&ParseChromeOptions, log); |
333 parser_map["loggingPrefs"] = base::Bind(&ParseLoggingPrefs); | 422 parser_map["loggingPrefs"] = base::Bind(&ParseLoggingPrefs); |
334 parser_map["proxy"] = base::Bind(&ParseProxy); | 423 parser_map["proxy"] = base::Bind(&ParseProxy); |
335 for (std::map<std::string, Parser>::iterator it = parser_map.begin(); | 424 for (std::map<std::string, Parser>::iterator it = parser_map.begin(); |
336 it != parser_map.end(); ++it) { | 425 it != parser_map.end(); ++it) { |
337 const base::Value* capability = NULL; | 426 const base::Value* capability = NULL; |
338 if (desired_caps.Get(it->first, &capability)) { | 427 if (desired_caps.Get(it->first, &capability)) { |
339 Status status = it->second.Run(*capability, this); | 428 Status status = it->second.Run(*capability, this); |
340 if (status.IsError()) { | 429 if (status.IsError()) { |
341 return Status( | 430 return Status( |
342 kUnknownError, "cannot parse capability: " + it->first, status); | 431 kUnknownError, "cannot parse capability: " + it->first, status); |
343 } | 432 } |
344 } | 433 } |
345 } | 434 } |
346 return Status(kOk); | 435 return Status(kOk); |
347 } | 436 } |
OLD | NEW |