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