| 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/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_util.h" | |
| 12 #include "base/string_number_conversions.h" | |
| 13 #include "base/values.h" | |
| 14 #include "googleurl/src/gurl.h" | |
| 15 #include "net/base/host_port_pair.h" | |
| 16 #include "net/base/net_errors.h" | |
| 17 #include "net/test/python_utils.h" | |
| 18 | |
| 19 namespace net { | |
| 20 | |
| 21 namespace { | |
| 22 | |
| 23 bool AppendArgumentFromJSONValue(const std::string& key, | |
| 24 const base::Value& value_node, | |
| 25 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 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_handle_) | |
| 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 if (ret) { | |
| 133 base::CloseProcessHandle(process_handle_); | |
| 134 process_handle_ = base::kNullProcessHandle; | |
| 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 process_handle_ = base::kNullProcessHandle; | |
| 152 | |
| 153 base::FilePath src_dir; | |
| 154 if (!PathService::Get(base::DIR_SOURCE_ROOT, &src_dir)) | |
| 155 return false; | |
| 156 SetResourcePath(src_dir.Append(document_root), | |
| 157 src_dir.AppendASCII("net") | |
| 158 .AppendASCII("data") | |
| 159 .AppendASCII("ssl") | |
| 160 .AppendASCII("certificates")); | |
| 161 return true; | |
| 162 } | |
| 163 | |
| 164 bool LocalTestServer::SetPythonPath() const { | |
| 165 base::FilePath third_party_dir; | |
| 166 if (!PathService::Get(base::DIR_SOURCE_ROOT, &third_party_dir)) { | |
| 167 LOG(ERROR) << "Failed to get DIR_SOURCE_ROOT"; | |
| 168 return false; | |
| 169 } | |
| 170 third_party_dir = third_party_dir.AppendASCII("third_party"); | |
| 171 | |
| 172 // For simplejson. (simplejson, unlike all the other Python modules | |
| 173 // we include, doesn't have an extra 'simplejson' directory, so we | |
| 174 // need to include its parent directory, i.e. third_party_dir). | |
| 175 AppendToPythonPath(third_party_dir); | |
| 176 | |
| 177 AppendToPythonPath(third_party_dir.AppendASCII("tlslite")); | |
| 178 AppendToPythonPath( | |
| 179 third_party_dir.AppendASCII("pyftpdlib").AppendASCII("src")); | |
| 180 AppendToPythonPath( | |
| 181 third_party_dir.AppendASCII("pywebsocket").AppendASCII("src")); | |
| 182 | |
| 183 // Locate the Python code generated by the protocol buffers compiler. | |
| 184 base::FilePath pyproto_dir; | |
| 185 if (!GetPyProtoPath(&pyproto_dir)) { | |
| 186 LOG(WARNING) << "Cannot find pyproto dir for generated code. " | |
| 187 << "Testserver features that rely on it will not work"; | |
| 188 return true; | |
| 189 } | |
| 190 AppendToPythonPath(pyproto_dir); | |
| 191 | |
| 192 return true; | |
| 193 } | |
| 194 | |
| 195 bool LocalTestServer::AddCommandLineArguments(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 (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(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 |