OLD | NEW |
| (Empty) |
1 // Copyright 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 "net/test/spawned_test_server/local_test_server.h" | |
6 | |
7 #include "base/command_line.h" | |
8 #include "base/json/json_reader.h" | |
9 #include "base/logging.h" | |
10 #include "base/path_service.h" | |
11 #include "base/process/kill.h" | |
12 #include "base/strings/string_number_conversions.h" | |
13 #include "base/values.h" | |
14 #include "net/base/host_port_pair.h" | |
15 #include "net/base/net_errors.h" | |
16 #include "net/test/python_utils.h" | |
17 #include "url/gurl.h" | |
18 | |
19 namespace net { | |
20 | |
21 namespace { | |
22 | |
23 bool AppendArgumentFromJSONValue(const std::string& key, | |
24 const base::Value& value_node, | |
25 base::CommandLine* command_line) { | |
26 std::string argument_name = "--" + key; | |
27 switch (value_node.GetType()) { | |
28 case base::Value::TYPE_NULL: | |
29 command_line->AppendArg(argument_name); | |
30 break; | |
31 case base::Value::TYPE_INTEGER: { | |
32 int value; | |
33 bool result = value_node.GetAsInteger(&value); | |
34 DCHECK(result); | |
35 command_line->AppendArg(argument_name + "=" + base::IntToString(value)); | |
36 break; | |
37 } | |
38 case base::Value::TYPE_STRING: { | |
39 std::string value; | |
40 bool result = value_node.GetAsString(&value); | |
41 if (!result || value.empty()) | |
42 return false; | |
43 command_line->AppendArg(argument_name + "=" + value); | |
44 break; | |
45 } | |
46 case base::Value::TYPE_BOOLEAN: | |
47 case base::Value::TYPE_DOUBLE: | |
48 case base::Value::TYPE_LIST: | |
49 case base::Value::TYPE_DICTIONARY: | |
50 case base::Value::TYPE_BINARY: | |
51 default: | |
52 NOTREACHED() << "improper json type"; | |
53 return false; | |
54 } | |
55 return true; | |
56 } | |
57 | |
58 } // namespace | |
59 | |
60 LocalTestServer::LocalTestServer(Type type, | |
61 const std::string& host, | |
62 const base::FilePath& document_root) | |
63 : BaseTestServer(type, host) { | |
64 if (!Init(document_root)) | |
65 NOTREACHED(); | |
66 } | |
67 | |
68 LocalTestServer::LocalTestServer(Type type, | |
69 const SSLOptions& ssl_options, | |
70 const base::FilePath& document_root) | |
71 : BaseTestServer(type, ssl_options) { | |
72 if (!Init(document_root)) | |
73 NOTREACHED(); | |
74 } | |
75 | |
76 LocalTestServer::~LocalTestServer() { | |
77 Stop(); | |
78 } | |
79 | |
80 bool LocalTestServer::GetTestServerPath(base::FilePath* testserver_path) const { | |
81 base::FilePath testserver_dir; | |
82 if (!PathService::Get(base::DIR_SOURCE_ROOT, &testserver_dir)) { | |
83 LOG(ERROR) << "Failed to get DIR_SOURCE_ROOT"; | |
84 return false; | |
85 } | |
86 testserver_dir = testserver_dir.Append(FILE_PATH_LITERAL("net")) | |
87 .Append(FILE_PATH_LITERAL("tools")) | |
88 .Append(FILE_PATH_LITERAL("testserver")); | |
89 *testserver_path = testserver_dir.Append(FILE_PATH_LITERAL("testserver.py")); | |
90 return true; | |
91 } | |
92 | |
93 bool LocalTestServer::Start() { | |
94 return StartInBackground() && BlockUntilStarted(); | |
95 } | |
96 | |
97 bool LocalTestServer::StartInBackground() { | |
98 // Get path to Python server script. | |
99 base::FilePath testserver_path; | |
100 if (!GetTestServerPath(&testserver_path)) | |
101 return false; | |
102 | |
103 if (!SetPythonPath()) | |
104 return false; | |
105 | |
106 if (!LaunchPython(testserver_path)) | |
107 return false; | |
108 | |
109 return true; | |
110 } | |
111 | |
112 bool LocalTestServer::BlockUntilStarted() { | |
113 if (!WaitToStart()) { | |
114 Stop(); | |
115 return false; | |
116 } | |
117 | |
118 return SetupWhenServerStarted(); | |
119 } | |
120 | |
121 bool LocalTestServer::Stop() { | |
122 CleanUpWhenStoppingServer(); | |
123 | |
124 if (!process_.IsValid()) | |
125 return true; | |
126 | |
127 // First check if the process has already terminated. | |
128 bool ret = base::WaitForSingleProcess(process_.Handle(), base::TimeDelta()); | |
129 if (!ret) { | |
130 ret = base::KillProcess(process_.Handle(), 1, true); | |
131 } | |
132 | |
133 if (ret) { | |
134 process_.Close(); | |
135 } else { | |
136 VLOG(1) << "Kill failed?"; | |
137 } | |
138 | |
139 return ret; | |
140 } | |
141 | |
142 bool LocalTestServer::Init(const base::FilePath& document_root) { | |
143 if (document_root.IsAbsolute()) | |
144 return false; | |
145 | |
146 // At this point, the port that the test server will listen on is unknown. | |
147 // The test server will listen on an ephemeral port, and write the port | |
148 // number out over a pipe that this TestServer object will read from. Once | |
149 // that is complete, the host port pair will contain the actual port. | |
150 DCHECK(!GetPort()); | |
151 | |
152 base::FilePath src_dir; | |
153 if (!PathService::Get(base::DIR_SOURCE_ROOT, &src_dir)) | |
154 return false; | |
155 SetResourcePath(src_dir.Append(document_root), | |
156 src_dir.AppendASCII("net") | |
157 .AppendASCII("data") | |
158 .AppendASCII("ssl") | |
159 .AppendASCII("certificates")); | |
160 return true; | |
161 } | |
162 | |
163 bool LocalTestServer::SetPythonPath() const { | |
164 base::FilePath third_party_dir; | |
165 if (!PathService::Get(base::DIR_SOURCE_ROOT, &third_party_dir)) { | |
166 LOG(ERROR) << "Failed to get DIR_SOURCE_ROOT"; | |
167 return false; | |
168 } | |
169 third_party_dir = third_party_dir.AppendASCII("third_party"); | |
170 | |
171 // For simplejson. (simplejson, unlike all the other Python modules | |
172 // we include, doesn't have an extra 'simplejson' directory, so we | |
173 // need to include its parent directory, i.e. third_party_dir). | |
174 AppendToPythonPath(third_party_dir); | |
175 | |
176 AppendToPythonPath(third_party_dir.AppendASCII("tlslite")); | |
177 AppendToPythonPath( | |
178 third_party_dir.AppendASCII("pyftpdlib").AppendASCII("src")); | |
179 AppendToPythonPath( | |
180 third_party_dir.AppendASCII("pywebsocket").AppendASCII("src")); | |
181 | |
182 // Locate the Python code generated by the protocol buffers compiler. | |
183 base::FilePath pyproto_dir; | |
184 if (!GetPyProtoPath(&pyproto_dir)) { | |
185 LOG(WARNING) << "Cannot find pyproto dir for generated code. " | |
186 << "Testserver features that rely on it will not work"; | |
187 return true; | |
188 } | |
189 AppendToPythonPath(pyproto_dir); | |
190 | |
191 return true; | |
192 } | |
193 | |
194 bool LocalTestServer::AddCommandLineArguments( | |
195 base::CommandLine* command_line) const { | |
196 base::DictionaryValue arguments_dict; | |
197 if (!GenerateArguments(&arguments_dict)) | |
198 return false; | |
199 | |
200 // Serialize the argument dictionary into CommandLine. | |
201 for (base::DictionaryValue::Iterator it(arguments_dict); !it.IsAtEnd(); | |
202 it.Advance()) { | |
203 const base::Value& value = it.value(); | |
204 const std::string& key = it.key(); | |
205 | |
206 // Add arguments from a list. | |
207 if (value.IsType(base::Value::TYPE_LIST)) { | |
208 const base::ListValue* list = NULL; | |
209 if (!value.GetAsList(&list) || !list || list->empty()) | |
210 return false; | |
211 for (base::ListValue::const_iterator list_it = list->begin(); | |
212 list_it != list->end(); ++list_it) { | |
213 if (!AppendArgumentFromJSONValue(key, *(*list_it), command_line)) | |
214 return false; | |
215 } | |
216 } else if (!AppendArgumentFromJSONValue(key, value, command_line)) { | |
217 return false; | |
218 } | |
219 } | |
220 | |
221 // Append the appropriate server type argument. | |
222 switch (type()) { | |
223 case TYPE_HTTP: // The default type is HTTP, no argument required. | |
224 break; | |
225 case TYPE_HTTPS: | |
226 command_line->AppendArg("--https"); | |
227 break; | |
228 case TYPE_WS: | |
229 case TYPE_WSS: | |
230 command_line->AppendArg("--websocket"); | |
231 break; | |
232 case TYPE_FTP: | |
233 command_line->AppendArg("--ftp"); | |
234 break; | |
235 case TYPE_TCP_ECHO: | |
236 command_line->AppendArg("--tcp-echo"); | |
237 break; | |
238 case TYPE_UDP_ECHO: | |
239 command_line->AppendArg("--udp-echo"); | |
240 break; | |
241 case TYPE_BASIC_AUTH_PROXY: | |
242 command_line->AppendArg("--basic-auth-proxy"); | |
243 break; | |
244 default: | |
245 NOTREACHED(); | |
246 return false; | |
247 } | |
248 | |
249 return true; | |
250 } | |
251 | |
252 } // namespace net | |
OLD | NEW |