OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/test/chromedriver/capabilities_parser.h" | |
6 | |
7 #include <map> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/callback.h" | |
11 #include "base/string_util.h" | |
12 #include "base/stringprintf.h" | |
kkania
2013/04/06 17:17:52
base/strings/
chrisgao (Use stgao instead)
2013/04/08 08:26:56
no stringprintf.h in directory "base/strings/".
An
| |
13 #include "base/values.h" | |
14 #include "chrome/test/chromedriver/chrome/status.h" | |
15 | |
16 namespace { | |
17 | |
18 typedef base::Callback<Status(const base::Value&, Capabilities*)> Parser; | |
19 | |
20 Status ParseChromeBinary( | |
21 const base::Callback<bool(const base::FilePath&)>& file_checker, | |
kkania
2013/04/06 17:17:52
i notice this is the only place where we use the f
chrisgao (Use stgao instead)
2013/04/08 08:26:56
Done.
| |
22 const base::Value& option, | |
23 Capabilities* capabilities) { | |
24 base::FilePath::StringType path_str; | |
25 if (!option.GetAsString(&path_str)) | |
26 return Status(kUnknownError, "'binary' must be a string"); | |
27 base::FilePath chrome_exe(path_str); | |
28 if (!file_checker.Run(chrome_exe)) { | |
29 return Status(kUnknownError, | |
30 base::StringPrintf("no chrome binary at %" PRFilePath, | |
31 path_str.c_str())); | |
32 } | |
33 capabilities->command.SetProgram(chrome_exe); | |
34 return Status(kOk); | |
35 } | |
36 | |
37 Status ParseLogPath(const base::Value& option, Capabilities* capabilities) { | |
38 if (!option.GetAsString(&capabilities->log_path)) | |
39 return Status(kUnknownError, "'logPath' must be a string"); | |
40 return Status(kOk); | |
41 } | |
42 | |
43 Status ParseArgs(const base::Value& option, Capabilities* capabilities) { | |
44 const base::ListValue* args_list = NULL; | |
45 if (!option.GetAsList(&args_list)) | |
46 return Status(kUnknownError, "'args' must be a list"); | |
47 for (size_t i = 0; i < args_list->GetSize(); ++i) { | |
48 std::string arg_string; | |
49 if (!args_list->GetString(i, &arg_string)) | |
50 return Status(kUnknownError, "each argument must be a string"); | |
51 size_t separator_index = arg_string.find("="); | |
52 if (separator_index != std::string::npos) { | |
53 CommandLine::StringType arg_string_native; | |
54 if (!args_list->GetString(i, &arg_string_native)) | |
55 return Status(kUnknownError, "each argument must be a string"); | |
56 capabilities->command.AppendSwitchNative( | |
57 arg_string.substr(0, separator_index), | |
58 arg_string_native.substr(separator_index + 1)); | |
59 } else { | |
60 capabilities->command.AppendSwitch(arg_string); | |
61 } | |
62 } | |
63 return Status(kOk); | |
64 } | |
65 | |
66 Status ParsePrefs(const base::Value& option, Capabilities* capabilities) { | |
67 const base::DictionaryValue* prefs = NULL; | |
68 if (!option.GetAsDictionary(&prefs)) | |
69 return Status(kUnknownError, "'prefs' must be a dictionary"); | |
70 capabilities->prefs.reset(prefs->DeepCopy()); | |
71 return Status(kOk); | |
72 } | |
73 | |
74 Status ParseLocalState(const base::Value& option, Capabilities* capabilities) { | |
75 const base::DictionaryValue* local_state = NULL; | |
76 if (!option.GetAsDictionary(&local_state)) | |
77 return Status(kUnknownError, "'localState' must be a dictionary"); | |
78 capabilities->local_state.reset(local_state->DeepCopy()); | |
79 return Status(kOk); | |
80 } | |
81 | |
82 Status ParseExtensions(const base::Value& option, Capabilities* capabilities) { | |
83 const base::ListValue* extensions = NULL; | |
84 if (!option.GetAsList(&extensions)) | |
85 return Status(kUnknownError, "'extensions' must be a list"); | |
86 for (size_t i = 0; i < extensions->GetSize(); ++i) { | |
87 std::string extension; | |
88 if (!extensions->GetString(i, &extension)) { | |
89 return Status(kUnknownError, | |
90 "each extension must be a base64 encoded string"); | |
91 } | |
92 capabilities->extensions.push_back(extension); | |
93 } | |
94 return Status(kOk); | |
95 } | |
96 | |
97 Status ParseProxy(const base::Value& option, Capabilities* capabilities) { | |
98 const base::DictionaryValue* proxy_dict; | |
99 if (!option.GetAsDictionary(&proxy_dict)) | |
100 return Status(kUnknownError, "'proxy' must be a dictionary"); | |
101 std::string proxy_type; | |
102 if (!proxy_dict->GetString("proxyType", &proxy_type)) | |
103 return Status(kUnknownError, "'proxyType' must be a string"); | |
104 proxy_type = StringToLowerASCII(proxy_type); | |
105 if (proxy_type == "direct") { | |
106 capabilities->command.AppendSwitch("no-proxy-server"); | |
107 } else if (proxy_type == "system") { | |
108 // Chrome default. | |
109 } else if (proxy_type == "pac") { | |
110 CommandLine::StringType proxy_pac_url; | |
111 if (!proxy_dict->GetString("proxyAutoconfigUrl", &proxy_pac_url)) | |
112 return Status(kUnknownError, "'proxyAutoconfigUrl' must be a string"); | |
113 capabilities->command.AppendSwitchNative("proxy-pac-url", proxy_pac_url); | |
114 } else if (proxy_type == "autodetect") { | |
115 capabilities->command.AppendSwitch("proxy-auto-detect"); | |
116 } else if (proxy_type == "manual") { | |
117 const char* proxy_servers_options[][2] = { | |
118 {"ftpProxy", "ftp"}, {"httpProxy", "http"}, {"sslProxy", "https"}}; | |
119 std::string proxy_servers; | |
120 for (size_t i = 0; i < arraysize(proxy_servers_options); ++i) { | |
121 if (!proxy_dict->HasKey(proxy_servers_options[i][0])) | |
122 continue; | |
123 std::string value; | |
124 if (!proxy_dict->GetString(proxy_servers_options[i][0], &value)) { | |
125 return Status( | |
126 kUnknownError, | |
127 base::StringPrintf("'%s' must be a string", | |
128 proxy_servers_options[i][0])); | |
129 } | |
130 // Converts into Chrome proxy scheme. | |
131 // Example: "http=localhost:9000;ftp=localhost:8000". | |
132 if (!proxy_servers.empty()) | |
133 proxy_servers += ";"; | |
134 proxy_servers += base::StringPrintf( | |
135 "%s=%s", proxy_servers_options[i][1], value.c_str()); | |
136 } | |
137 | |
138 std::string proxy_bypass_list; | |
139 if (proxy_dict->HasKey("noProxy")) { | |
140 if (!proxy_dict->GetString("noProxy", & proxy_bypass_list)) | |
kkania
2013/04/06 17:17:52
no space
chrisgao (Use stgao instead)
2013/04/08 08:26:56
Done.
| |
141 return Status(kUnknownError, "'noProxy' must be a string"); | |
142 } | |
143 | |
144 if (proxy_servers.empty() && proxy_bypass_list.empty()) { | |
145 return Status(kUnknownError, | |
146 "proxyType is 'manual' but no manual " | |
147 "proxy capabilities were found"); | |
148 } | |
149 if (!proxy_servers.empty()) | |
150 capabilities->command.AppendSwitchASCII("proxy-server", proxy_servers); | |
151 if (!proxy_bypass_list.empty()) { | |
152 capabilities->command.AppendSwitchASCII("proxy-bypass-list", | |
153 proxy_bypass_list); | |
154 } | |
155 } else { | |
156 return Status(kUnknownError, "unrecognized proxy type:" + proxy_type); | |
157 } | |
158 return Status(kOk); | |
159 } | |
160 | |
161 Status ParseDesktopChromeOption( | |
162 const base::Callback<bool(const base::FilePath&)>& file_checker, | |
163 const base::Value& capability, | |
164 Capabilities* capabilities) { | |
165 const base::DictionaryValue* chrome_options = NULL; | |
166 if (!capability.GetAsDictionary(&chrome_options)) | |
167 return Status(kUnknownError, "'chromeOptions' must be a dictionary"); | |
168 | |
169 std::map<std::string, Parser> parser_map; | |
170 | |
171 parser_map["binary"] = base::Bind(&ParseChromeBinary, file_checker); | |
172 parser_map["logPath"] = base::Bind(&ParseLogPath); | |
173 parser_map["args"] = base::Bind(&ParseArgs); | |
174 parser_map["prefs"] = base::Bind(&ParsePrefs); | |
175 parser_map["localState"] = base::Bind(&ParseLocalState); | |
176 parser_map["extensions"] = base::Bind(&ParseExtensions); | |
177 | |
178 for (base::DictionaryValue::Iterator it(*chrome_options); !it.IsAtEnd(); | |
179 it.Advance()) { | |
180 if (parser_map.find(it.key()) == parser_map.end()) { | |
181 return Status(kUnknownError, | |
182 "unrecognized chrome option: " + it.key()); | |
183 } | |
184 Status status = parser_map[it.key()].Run(it.value(), capabilities); | |
185 if (status.IsError()) | |
186 return status; | |
187 } | |
188 return Status(kOk); | |
189 } | |
190 | |
191 Status ParseAndroidChromeCapabilities(const base::DictionaryValue& desired_caps, | |
192 Capabilities* capabilities) { | |
193 const base::Value* chrome_options = NULL; | |
194 if (desired_caps.Get("chromeOptions", &chrome_options)) { | |
195 const base::DictionaryValue* chrome_options_dict = NULL; | |
196 if (!chrome_options->GetAsDictionary(&chrome_options_dict)) | |
197 return Status(kUnknownError, "'chromeOptions' must be a dictionary"); | |
198 | |
199 const base::Value* android_package_value; | |
200 if (chrome_options_dict->Get("android_package", &android_package_value)) { | |
201 if (!android_package_value->GetAsString(&capabilities->android_package) || | |
202 capabilities->android_package.empty()) { | |
203 return Status(kUnknownError, | |
204 "'android_package' must be a non-empty string"); | |
205 } | |
206 } | |
207 } | |
208 return Status(kOk); | |
209 } | |
210 | |
211 } // namespace | |
212 | |
213 Capabilities::Capabilities() : command(CommandLine::NO_PROGRAM) {} | |
214 | |
215 Capabilities::~Capabilities() {} | |
216 | |
217 bool Capabilities::IsAndroid() const { | |
218 return !android_package.empty(); | |
219 } | |
220 | |
221 Status Capabilities::Parse( | |
222 const base::DictionaryValue& desired_caps, | |
223 const base::Callback<bool(const base::FilePath&)>& file_checker) { | |
224 Status status = ParseAndroidChromeCapabilities(desired_caps, this); | |
225 if (status.IsError()) | |
226 return status; | |
227 if (IsAndroid()) | |
228 return Status(kOk); | |
229 | |
230 std::map<std::string, Parser> parser_map; | |
231 parser_map["proxy"] = base::Bind(&ParseProxy); | |
232 parser_map["chromeOptions"] = base::Bind(&ParseDesktopChromeOption, | |
233 file_checker); | |
234 for (std::map<std::string, Parser>::iterator it = parser_map.begin(); | |
235 it != parser_map.end(); ++it) { | |
236 const base::Value* capability = NULL; | |
237 if (desired_caps.Get(it->first, &capability)) { | |
238 status = it->second.Run(*capability, this); | |
239 if (status.IsError()) | |
240 return status; | |
241 } | |
242 } | |
243 return Status(kOk); | |
244 } | |
OLD | NEW |