1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
|
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/test/spawned_test_server/local_test_server.h"
#include "base/command_line.h"
#include "base/json/json_reader.h"
#include "base/logging.h"
#include "base/notreached.h"
#include "base/path_service.h"
#include "base/strings/string_number_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "base/values.h"
#include "net/base/host_port_pair.h"
#include "net/base/net_errors.h"
#include "net/test/python_utils.h"
#include "url/gurl.h"
namespace net {
namespace {
bool AppendArgumentFromJSONValue(const std::string& key,
const base::Value& value_node,
base::CommandLine* command_line) {
std::string argument_name = "--" + key;
switch (value_node.type()) {
case base::Value::Type::NONE:
command_line->AppendArg(argument_name);
break;
case base::Value::Type::INTEGER: {
command_line->AppendArg(argument_name + "=" +
base::NumberToString(value_node.GetInt()));
break;
}
case base::Value::Type::STRING: {
if (!value_node.is_string())
return false;
const std::string value = value_node.GetString();
if (value.empty())
return false;
command_line->AppendArg(argument_name + "=" + value);
break;
}
case base::Value::Type::BOOLEAN:
case base::Value::Type::DOUBLE:
case base::Value::Type::LIST:
case base::Value::Type::DICT:
case base::Value::Type::BINARY:
default:
NOTREACHED() << "improper json type";
}
return true;
}
} // namespace
LocalTestServer::LocalTestServer(Type type, const base::FilePath& document_root)
: BaseTestServer(type) {
if (!Init(document_root))
NOTREACHED();
}
LocalTestServer::LocalTestServer(Type type,
const SSLOptions& ssl_options,
const base::FilePath& document_root)
: BaseTestServer(type, ssl_options) {
if (!Init(document_root))
NOTREACHED();
}
LocalTestServer::~LocalTestServer() {
Stop();
}
bool LocalTestServer::GetTestServerPath(base::FilePath* testserver_path) const {
base::FilePath testserver_dir;
if (!base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &testserver_dir)) {
LOG(ERROR) << "Failed to get DIR_SRC_TEST_DATA_ROOT";
return false;
}
testserver_dir = testserver_dir.Append(FILE_PATH_LITERAL("net"))
.Append(FILE_PATH_LITERAL("tools"))
.Append(FILE_PATH_LITERAL("testserver"));
*testserver_path = testserver_dir.Append(FILE_PATH_LITERAL("testserver.py"));
return true;
}
bool LocalTestServer::StartInBackground() {
DCHECK(!started());
base::ScopedAllowBlockingForTesting allow_blocking;
// Get path to Python server script.
base::FilePath testserver_path;
if (!GetTestServerPath(&testserver_path)) {
LOG(ERROR) << "Could not get test server path.";
return false;
}
std::optional<std::vector<base::FilePath>> python_path = GetPythonPath();
if (!python_path) {
LOG(ERROR) << "Could not get Python path.";
return false;
}
if (!LaunchPython(testserver_path, *python_path)) {
LOG(ERROR) << "Could not launch Python with path " << testserver_path;
return false;
}
return true;
}
bool LocalTestServer::BlockUntilStarted() {
if (!WaitToStart()) {
Stop();
return false;
}
return SetupWhenServerStarted();
}
bool LocalTestServer::Stop() {
CleanUpWhenStoppingServer();
if (!process_.IsValid())
return true;
// First check if the process has already terminated.
bool ret = process_.WaitForExitWithTimeout(base::TimeDelta(), nullptr);
if (!ret) {
base::ScopedAllowBaseSyncPrimitivesForTesting allow_wait_process;
ret = process_.Terminate(1, true);
}
if (ret)
process_.Close();
else
VLOG(1) << "Kill failed?";
return ret;
}
bool LocalTestServer::Init(const base::FilePath& document_root) {
if (document_root.IsAbsolute())
return false;
// At this point, the port that the test server will listen on is unknown.
// The test server will listen on an ephemeral port, and write the port
// number out over a pipe that this TestServer object will read from. Once
// that is complete, the host port pair will contain the actual port.
DCHECK(!GetPort());
base::FilePath src_dir;
if (!base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &src_dir)) {
return false;
}
SetResourcePath(src_dir.Append(document_root),
src_dir.AppendASCII("net")
.AppendASCII("data")
.AppendASCII("ssl")
.AppendASCII("certificates"));
return true;
}
std::optional<std::vector<base::FilePath>> LocalTestServer::GetPythonPath()
const {
base::FilePath third_party_dir;
if (!base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &third_party_dir)) {
LOG(ERROR) << "Failed to get DIR_SRC_TEST_DATA_ROOT";
return std::nullopt;
}
third_party_dir = third_party_dir.AppendASCII("third_party");
std::vector<base::FilePath> ret = {
third_party_dir.AppendASCII("pywebsocket3").AppendASCII("src"),
};
return ret;
}
bool LocalTestServer::AddCommandLineArguments(
base::CommandLine* command_line) const {
std::optional<base::Value::Dict> arguments_dict = GenerateArguments();
if (!arguments_dict)
return false;
// Serialize the argument dictionary into CommandLine.
for (auto it = arguments_dict->begin(); it != arguments_dict->end(); ++it) {
const base::Value& value = it->second;
const std::string& key = it->first;
// Add arguments from a list.
if (value.is_list()) {
if (value.GetList().empty())
return false;
for (const auto& entry : value.GetList()) {
if (!AppendArgumentFromJSONValue(key, entry, command_line))
return false;
}
} else if (!AppendArgumentFromJSONValue(key, value, command_line)) {
return false;
}
}
// Append the appropriate server type argument.
switch (type()) {
case TYPE_WS:
case TYPE_WSS:
command_line->AppendArg("--websocket");
break;
case TYPE_BASIC_AUTH_PROXY:
command_line->AppendArg("--basic-auth-proxy");
break;
case TYPE_PROXY:
command_line->AppendArg("--proxy");
break;
default:
NOTREACHED();
}
return true;
}
} // namespace net
|