PageRenderTime 76ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/external/chromium/net/test/test_server.cc

https://gitlab.com/brian0218/rk3188_r-box_android4.2.2_sdk
C++ | 397 lines | 316 code | 64 blank | 17 comment | 48 complexity | 63767aaf38532abdc415884d1166e93f MD5 | raw file
  1. // Copyright (c) 2011 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. #include "net/test/test_server.h"
  5. #include <algorithm>
  6. #include <string>
  7. #include <vector>
  8. #include "build/build_config.h"
  9. #if defined(OS_MACOSX)
  10. #include "net/base/x509_certificate.h"
  11. #endif
  12. #include "base/base64.h"
  13. #include "base/command_line.h"
  14. #include "base/debug/leak_annotations.h"
  15. #include "base/file_util.h"
  16. #include "base/json/json_reader.h"
  17. #include "base/logging.h"
  18. #include "base/memory/scoped_ptr.h"
  19. #include "base/path_service.h"
  20. #include "base/string_number_conversions.h"
  21. #include "base/utf_string_conversions.h"
  22. #include "base/values.h"
  23. #include "googleurl/src/gurl.h"
  24. #include "net/base/host_port_pair.h"
  25. #include "net/base/host_resolver.h"
  26. #include "net/base/net_errors.h"
  27. #include "net/base/test_completion_callback.h"
  28. #include "net/base/test_root_certs.h"
  29. #include "net/socket/tcp_client_socket.h"
  30. #include "net/test/python_utils.h"
  31. #include "testing/platform_test.h"
  32. namespace net {
  33. namespace {
  34. // Number of connection attempts for tests.
  35. const int kServerConnectionAttempts = 10;
  36. // Connection timeout in milliseconds for tests.
  37. const int kServerConnectionTimeoutMs = 1000;
  38. std::string GetHostname(TestServer::Type type,
  39. const TestServer::HTTPSOptions& options) {
  40. if (type == TestServer::TYPE_HTTPS &&
  41. options.server_certificate ==
  42. TestServer::HTTPSOptions::CERT_MISMATCHED_NAME) {
  43. // Return a different hostname string that resolves to the same hostname.
  44. return "localhost";
  45. }
  46. return "127.0.0.1";
  47. }
  48. } // namespace
  49. TestServer::HTTPSOptions::HTTPSOptions()
  50. : server_certificate(CERT_OK),
  51. request_client_certificate(false),
  52. bulk_ciphers(HTTPSOptions::BULK_CIPHER_ANY) {}
  53. TestServer::HTTPSOptions::HTTPSOptions(
  54. TestServer::HTTPSOptions::ServerCertificate cert)
  55. : server_certificate(cert),
  56. request_client_certificate(false),
  57. bulk_ciphers(HTTPSOptions::BULK_CIPHER_ANY) {}
  58. TestServer::HTTPSOptions::~HTTPSOptions() {}
  59. FilePath TestServer::HTTPSOptions::GetCertificateFile() const {
  60. switch (server_certificate) {
  61. case CERT_OK:
  62. case CERT_MISMATCHED_NAME:
  63. return FilePath(FILE_PATH_LITERAL("ok_cert.pem"));
  64. case CERT_EXPIRED:
  65. return FilePath(FILE_PATH_LITERAL("expired_cert.pem"));
  66. default:
  67. NOTREACHED();
  68. }
  69. return FilePath();
  70. }
  71. TestServer::TestServer(Type type, const FilePath& document_root)
  72. : type_(type),
  73. started_(false) {
  74. Init(document_root);
  75. }
  76. TestServer::TestServer(const HTTPSOptions& https_options,
  77. const FilePath& document_root)
  78. : https_options_(https_options),
  79. type_(TYPE_HTTPS),
  80. started_(false) {
  81. Init(document_root);
  82. }
  83. TestServer::~TestServer() {
  84. TestRootCerts* root_certs = TestRootCerts::GetInstance();
  85. root_certs->Clear();
  86. Stop();
  87. }
  88. bool TestServer::Start() {
  89. if (type_ == TYPE_HTTPS) {
  90. if (!LoadTestRootCert())
  91. return false;
  92. }
  93. // Get path to python server script
  94. FilePath testserver_path;
  95. if (!PathService::Get(base::DIR_SOURCE_ROOT, &testserver_path)) {
  96. LOG(ERROR) << "Failed to get DIR_SOURCE_ROOT";
  97. return false;
  98. }
  99. testserver_path = testserver_path
  100. .Append(FILE_PATH_LITERAL("net"))
  101. .Append(FILE_PATH_LITERAL("tools"))
  102. .Append(FILE_PATH_LITERAL("testserver"))
  103. .Append(FILE_PATH_LITERAL("testserver.py"));
  104. if (!SetPythonPath())
  105. return false;
  106. if (!LaunchPython(testserver_path))
  107. return false;
  108. if (!WaitToStart()) {
  109. Stop();
  110. return false;
  111. }
  112. allowed_port_.reset(new ScopedPortException(host_port_pair_.port()));
  113. started_ = true;
  114. return true;
  115. }
  116. bool TestServer::Stop() {
  117. if (!process_handle_)
  118. return true;
  119. started_ = false;
  120. // First check if the process has already terminated.
  121. bool ret = base::WaitForSingleProcess(process_handle_, 0);
  122. if (!ret)
  123. ret = base::KillProcess(process_handle_, 1, true);
  124. if (ret) {
  125. base::CloseProcessHandle(process_handle_);
  126. process_handle_ = base::kNullProcessHandle;
  127. } else {
  128. VLOG(1) << "Kill failed?";
  129. }
  130. allowed_port_.reset();
  131. return ret;
  132. }
  133. const HostPortPair& TestServer::host_port_pair() const {
  134. DCHECK(started_);
  135. return host_port_pair_;
  136. }
  137. const DictionaryValue& TestServer::server_data() const {
  138. DCHECK(started_);
  139. return *server_data_;
  140. }
  141. std::string TestServer::GetScheme() const {
  142. switch (type_) {
  143. case TYPE_FTP:
  144. return "ftp";
  145. case TYPE_HTTP:
  146. case TYPE_SYNC:
  147. return "http";
  148. case TYPE_HTTPS:
  149. return "https";
  150. default:
  151. NOTREACHED();
  152. }
  153. return std::string();
  154. }
  155. bool TestServer::GetAddressList(AddressList* address_list) const {
  156. DCHECK(address_list);
  157. scoped_ptr<HostResolver> resolver(
  158. CreateSystemHostResolver(HostResolver::kDefaultParallelism, NULL, NULL));
  159. HostResolver::RequestInfo info(host_port_pair_);
  160. int rv = resolver->Resolve(info, address_list, NULL, NULL, BoundNetLog());
  161. if (rv != net::OK) {
  162. LOG(ERROR) << "Failed to resolve hostname: " << host_port_pair_.host();
  163. return false;
  164. }
  165. return true;
  166. }
  167. GURL TestServer::GetURL(const std::string& path) const {
  168. return GURL(GetScheme() + "://" + host_port_pair_.ToString() +
  169. "/" + path);
  170. }
  171. GURL TestServer::GetURLWithUser(const std::string& path,
  172. const std::string& user) const {
  173. return GURL(GetScheme() + "://" + user + "@" +
  174. host_port_pair_.ToString() +
  175. "/" + path);
  176. }
  177. GURL TestServer::GetURLWithUserAndPassword(const std::string& path,
  178. const std::string& user,
  179. const std::string& password) const {
  180. return GURL(GetScheme() + "://" + user + ":" + password +
  181. "@" + host_port_pair_.ToString() +
  182. "/" + path);
  183. }
  184. // static
  185. bool TestServer::GetFilePathWithReplacements(
  186. const std::string& original_file_path,
  187. const std::vector<StringPair>& text_to_replace,
  188. std::string* replacement_path) {
  189. std::string new_file_path = original_file_path;
  190. bool first_query_parameter = true;
  191. const std::vector<StringPair>::const_iterator end = text_to_replace.end();
  192. for (std::vector<StringPair>::const_iterator it = text_to_replace.begin();
  193. it != end;
  194. ++it) {
  195. const std::string& old_text = it->first;
  196. const std::string& new_text = it->second;
  197. std::string base64_old;
  198. std::string base64_new;
  199. if (!base::Base64Encode(old_text, &base64_old))
  200. return false;
  201. if (!base::Base64Encode(new_text, &base64_new))
  202. return false;
  203. if (first_query_parameter) {
  204. new_file_path += "?";
  205. first_query_parameter = false;
  206. } else {
  207. new_file_path += "&";
  208. }
  209. new_file_path += "replace_text=";
  210. new_file_path += base64_old;
  211. new_file_path += ":";
  212. new_file_path += base64_new;
  213. }
  214. *replacement_path = new_file_path;
  215. return true;
  216. }
  217. void TestServer::Init(const FilePath& document_root) {
  218. // At this point, the port that the testserver will listen on is unknown.
  219. // The testserver will listen on an ephemeral port, and write the port
  220. // number out over a pipe that this TestServer object will read from. Once
  221. // that is complete, the host_port_pair_ will contain the actual port.
  222. host_port_pair_ = HostPortPair(GetHostname(type_, https_options_), 0);
  223. process_handle_ = base::kNullProcessHandle;
  224. FilePath src_dir;
  225. PathService::Get(base::DIR_SOURCE_ROOT, &src_dir);
  226. document_root_ = src_dir.Append(document_root);
  227. certificates_dir_ = src_dir.Append(FILE_PATH_LITERAL("net"))
  228. .Append(FILE_PATH_LITERAL("data"))
  229. .Append(FILE_PATH_LITERAL("ssl"))
  230. .Append(FILE_PATH_LITERAL("certificates"));
  231. }
  232. bool TestServer::SetPythonPath() {
  233. FilePath third_party_dir;
  234. if (!PathService::Get(base::DIR_SOURCE_ROOT, &third_party_dir)) {
  235. LOG(ERROR) << "Failed to get DIR_SOURCE_ROOT";
  236. return false;
  237. }
  238. third_party_dir = third_party_dir.Append(FILE_PATH_LITERAL("third_party"));
  239. // For simplejson. (simplejson, unlike all the other python modules
  240. // we include, doesn't have an extra 'simplejson' directory, so we
  241. // need to include its parent directory, i.e. third_party_dir).
  242. AppendToPythonPath(third_party_dir);
  243. AppendToPythonPath(third_party_dir.Append(FILE_PATH_LITERAL("tlslite")));
  244. AppendToPythonPath(third_party_dir.Append(FILE_PATH_LITERAL("pyftpdlib")));
  245. // Locate the Python code generated by the protocol buffers compiler.
  246. FilePath pyproto_code_dir;
  247. if (!GetPyProtoPath(&pyproto_code_dir)) {
  248. LOG(WARNING) << "Cannot find pyproto dir for generated code. "
  249. << "Testserver features that rely on it will not work";
  250. return true;
  251. }
  252. AppendToPythonPath(pyproto_code_dir);
  253. AppendToPythonPath(pyproto_code_dir.Append(FILE_PATH_LITERAL("sync_pb")));
  254. AppendToPythonPath(pyproto_code_dir.Append(
  255. FILE_PATH_LITERAL("device_management_pb")));
  256. return true;
  257. }
  258. bool TestServer::ParseServerData(const std::string& server_data) {
  259. VLOG(1) << "Server data: " << server_data;
  260. base::JSONReader json_reader;
  261. scoped_ptr<Value> value(json_reader.JsonToValue(server_data, true, false));
  262. if (!value.get() ||
  263. !value->IsType(Value::TYPE_DICTIONARY)) {
  264. LOG(ERROR) << "Could not parse server data: "
  265. << json_reader.GetErrorMessage();
  266. return false;
  267. }
  268. server_data_.reset(static_cast<DictionaryValue*>(value.release()));
  269. int port = 0;
  270. if (!server_data_->GetInteger("port", &port)) {
  271. LOG(ERROR) << "Could not find port value";
  272. return false;
  273. }
  274. if ((port <= 0) || (port > kuint16max)) {
  275. LOG(ERROR) << "Invalid port value: " << port;
  276. return false;
  277. }
  278. host_port_pair_.set_port(port);
  279. return true;
  280. }
  281. FilePath TestServer::GetRootCertificatePath() const {
  282. return certificates_dir_.AppendASCII("root_ca_cert.crt");
  283. }
  284. bool TestServer::LoadTestRootCert() {
  285. TestRootCerts* root_certs = TestRootCerts::GetInstance();
  286. return root_certs->AddFromFile(GetRootCertificatePath());
  287. }
  288. bool TestServer::AddCommandLineArguments(CommandLine* command_line) const {
  289. command_line->AppendSwitchASCII("port",
  290. base::IntToString(host_port_pair_.port()));
  291. command_line->AppendSwitchPath("data-dir", document_root_);
  292. if (logging::GetMinLogLevel() == logging::LOG_VERBOSE) {
  293. command_line->AppendArg("--log-to-console");
  294. }
  295. if (type_ == TYPE_FTP) {
  296. command_line->AppendArg("-f");
  297. } else if (type_ == TYPE_SYNC) {
  298. command_line->AppendArg("--sync");
  299. } else if (type_ == TYPE_HTTPS) {
  300. FilePath certificate_path(certificates_dir_);
  301. certificate_path = certificate_path.Append(
  302. https_options_.GetCertificateFile());
  303. if (!file_util::PathExists(certificate_path)) {
  304. LOG(ERROR) << "Certificate path " << certificate_path.value()
  305. << " doesn't exist. Can't launch https server.";
  306. return false;
  307. }
  308. command_line->AppendSwitchPath("https", certificate_path);
  309. if (https_options_.request_client_certificate)
  310. command_line->AppendSwitch("ssl-client-auth");
  311. for (std::vector<FilePath>::const_iterator it =
  312. https_options_.client_authorities.begin();
  313. it != https_options_.client_authorities.end(); ++it) {
  314. if (!file_util::PathExists(*it)) {
  315. LOG(ERROR) << "Client authority path " << it->value()
  316. << " doesn't exist. Can't launch https server.";
  317. return false;
  318. }
  319. command_line->AppendSwitchPath("ssl-client-ca", *it);
  320. }
  321. const char kBulkCipherSwitch[] = "ssl-bulk-cipher";
  322. if (https_options_.bulk_ciphers & HTTPSOptions::BULK_CIPHER_RC4)
  323. command_line->AppendSwitchASCII(kBulkCipherSwitch, "rc4");
  324. if (https_options_.bulk_ciphers & HTTPSOptions::BULK_CIPHER_AES128)
  325. command_line->AppendSwitchASCII(kBulkCipherSwitch, "aes128");
  326. if (https_options_.bulk_ciphers & HTTPSOptions::BULK_CIPHER_AES256)
  327. command_line->AppendSwitchASCII(kBulkCipherSwitch, "aes256");
  328. if (https_options_.bulk_ciphers & HTTPSOptions::BULK_CIPHER_3DES)
  329. command_line->AppendSwitchASCII(kBulkCipherSwitch, "3des");
  330. }
  331. return true;
  332. }
  333. } // namespace net