summaryrefslogtreecommitdiff
path: root/net/test
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2010-11-25 19:40:10 +0000
committerBen Murdoch <benm@google.com>2010-12-03 13:52:53 +0000
commit4a5e2dc747d50c653511c68ccb2cfbfb740bd5a7 (patch)
tree938665d93a11fe7a6d0124e3c1e020d1f9d3f947 /net/test
parent7c627d87728a355737862918d144f98f69406954 (diff)
downloadchromium-4a5e2dc747d50c653511c68ccb2cfbfb740bd5a7.tar.gz
Merge Chromium at r66597: Initial merge by git.
Change-Id: I9639f8a997f90ec219573aa22a49f5dbde78cc7b
Diffstat (limited to 'net/test')
-rw-r--r--net/test/openssl_helper.cc264
-rw-r--r--net/test/python_utils.cc30
-rw-r--r--net/test/python_utils.h4
-rw-r--r--net/test/test_server.cc151
-rw-r--r--net/test/test_server.h19
-rw-r--r--net/test/test_server_posix.cc47
-rw-r--r--net/test/test_server_win.cc26
7 files changed, 432 insertions, 109 deletions
diff --git a/net/test/openssl_helper.cc b/net/test/openssl_helper.cc
new file mode 100644
index 00000000..25989cb6
--- /dev/null
+++ b/net/test/openssl_helper.cc
@@ -0,0 +1,264 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This helper binary is only used for testing Chrome's SSL stack.
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <openssl/bio.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+static const char kDefaultPEMFile[] = "net/data/ssl/certificates/ok_cert.pem";
+
+// Server Name Indication callback from OpenSSL
+static int sni_cb(SSL *s, int *ad, void *arg) {
+ const char* servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
+ if (servername && strcmp(servername, "test.example.com") == 0)
+ *reinterpret_cast<bool*>(arg) = true;
+
+ return SSL_TLSEXT_ERR_OK;
+}
+
+// Client certificate verification callback from OpenSSL
+static int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) {
+ return 1;
+}
+
+// Next Protocol Negotiation callback from OpenSSL
+static int next_proto_cb(SSL *ssl, const unsigned char **out,
+ unsigned int *outlen, void *arg) {
+ bool* npn_mispredict = reinterpret_cast<bool*>(arg);
+ static char kProtos[] = "\003foo\003bar";
+ static char kProtos2[] = "\003baz\003boo";
+ static unsigned count = 0;
+
+ if (!*npn_mispredict || count == 0) {
+ *out = (const unsigned char*) kProtos;
+ *outlen = sizeof(kProtos) - 1;
+ } else {
+ *out = (const unsigned char*) kProtos2;
+ *outlen = sizeof(kProtos2) - 1;
+ }
+ count++;
+ return SSL_TLSEXT_ERR_OK;
+}
+
+int
+main(int argc, char **argv) {
+ SSL_library_init();
+ ERR_load_crypto_strings();
+ OpenSSL_add_all_algorithms();
+ SSL_load_error_strings();
+
+ bool sni = false, sni_good = false, snap_start = false;
+ bool snap_start_recovery = false, sslv3 = false, session_tickets = false;
+ bool fail_resume = false, client_cert = false, npn = false;
+ bool npn_mispredict = false;
+
+ const char* key_file = kDefaultPEMFile;
+ const char* cert_file = kDefaultPEMFile;
+
+ for (int i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "sni") == 0) {
+ // Require SNI
+ sni = true;
+ } else if (strcmp(argv[i], "snap-start") == 0) {
+ // Support Snap Start
+ snap_start = true;
+ } else if (strcmp(argv[i], "snap-start-recovery") == 0) {
+ // Support Snap Start, but always trigger a recovery
+ snap_start = true;
+ snap_start_recovery = true;
+ } else if (strcmp(argv[i], "sslv3") == 0) {
+ // Use SSLv3
+ sslv3 = true;
+ } else if (strcmp(argv[i], "session-tickets") == 0) {
+ // Enable Session Tickets
+ session_tickets = true;
+ } else if (strcmp(argv[i], "fail-resume") == 0) {
+ // Always fail to resume sessions
+ fail_resume = true;
+ } else if (strcmp(argv[i], "client-cert") == 0) {
+ // Request a client certificate
+ client_cert = true;
+ } else if (strcmp(argv[i], "npn") == 0) {
+ // Advertise NPN
+ npn = true;
+ } else if (strcmp(argv[i], "npn-mispredict") == 0) {
+ // Advertise NPN
+ npn = true;
+ npn_mispredict = true;
+ } else if (strcmp(argv[i], "--key-file") == 0) {
+ // Use alternative key file
+ i++;
+ if (i == argc) {
+ fprintf(stderr, "Missing argument to --key-file\n");
+ return 1;
+ }
+ key_file = argv[i];
+ } else if (strcmp(argv[i], "--cert-file") == 0) {
+ // Use alternative certificate file
+ i++;
+ if (i == argc) {
+ fprintf(stderr, "Missing argument to --cert-file\n");
+ return 1;
+ }
+ cert_file = argv[i];
+ } else {
+ fprintf(stderr, "Unknown argument: %s\n", argv[i]);
+ return 1;
+ }
+ }
+
+ SSL_CTX* ctx;
+
+ if (sslv3) {
+ ctx = SSL_CTX_new(SSLv3_server_method());
+ } else {
+ ctx = SSL_CTX_new(TLSv1_server_method());
+ }
+
+ if (sni) {
+ SSL_CTX_set_tlsext_servername_callback(ctx, sni_cb);
+ SSL_CTX_set_tlsext_servername_arg(ctx, &sni_good);
+ }
+
+ BIO* key = BIO_new(BIO_s_file());
+ if (BIO_read_filename(key, key_file) <= 0) {
+ fprintf(stderr, "Failed to read %s\n", key_file);
+ return 1;
+ }
+
+ EVP_PKEY *pkey = PEM_read_bio_PrivateKey(key, NULL, NULL, NULL);
+ if (!pkey) {
+ fprintf(stderr, "Failed to parse %s\n", key_file);
+ return 1;
+ }
+ BIO_free(key);
+
+
+ BIO* cert = BIO_new(BIO_s_file());
+ if (BIO_read_filename(cert, cert_file) <= 0) {
+ fprintf(stderr, "Failed to read %s\n", cert_file);
+ return 1;
+ }
+
+ X509 *pcert = PEM_read_bio_X509_AUX(cert, NULL, NULL, NULL);
+ if (!pcert) {
+ fprintf(stderr, "Failed to parse %s\n", cert_file);
+ return 1;
+ }
+ BIO_free(cert);
+
+ if (SSL_CTX_use_certificate(ctx, pcert) <= 0) {
+ fprintf(stderr, "Failed to load %s\n", cert_file);
+ return 1;
+ }
+
+ if (SSL_CTX_use_PrivateKey(ctx, pkey) <= 0) {
+ fprintf(stderr, "Failed to load %s\n", key_file);
+ return 1;
+ }
+
+ if (!SSL_CTX_check_private_key(ctx)) {
+ fprintf(stderr, "Public and private keys don't match\n");
+ return 1;
+ }
+
+ if (client_cert)
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_cb);
+
+ if (session_tickets)
+ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
+
+ if (snap_start) {
+ static const unsigned char orbit[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+ SSL_CTX_set_snap_start_orbit(ctx, orbit);
+ }
+
+ if (npn)
+ SSL_CTX_set_next_protos_advertised_cb(ctx, next_proto_cb, &npn_mispredict);
+
+ unsigned connection_limit = 1;
+ if (snap_start || session_tickets)
+ connection_limit = 2;
+ if (npn_mispredict)
+ connection_limit = 3;
+
+ for (unsigned connections = 0; connections < connection_limit;
+ connections++) {
+ const int fd = accept(3, NULL, NULL);
+
+ SSL* server = SSL_new(ctx);
+ BIO* bio = BIO_new_socket(fd, 1 /* take ownership of fd */);
+ SSL_set_bio(server, bio, bio);
+
+ if (fail_resume) {
+ SSL_set_session_id_context(server, (unsigned char*) &connections,
+ sizeof(connections));
+ }
+
+ int err;
+ for (;;) {
+ const int ret = SSL_accept(server);
+ if (ret == 1)
+ break;
+
+ err = SSL_get_error(server, ret);
+ if (err == SSL_ERROR_WANT_READ)
+ continue;
+ if (err == SSL_ERROR_SERVER_RANDOM_VALIDATION_PENDING && snap_start) {
+ SSL_set_suggested_server_random_validity(
+ server, !snap_start_recovery);
+ continue;
+ }
+ ERR_print_errors_fp(stderr);
+ fprintf(stderr, "SSL_accept failed: %d\n", err);
+ return 1;
+ }
+
+ if (sni && !sni_good) {
+ fprintf(stderr, "SNI failed\n");
+ return 1;
+ }
+
+ if (npn) {
+ const unsigned char *data, *expected_data;
+ unsigned len, expected_len;
+ SSL_get0_next_proto_negotiated(server, &data, &len);
+ if (!npn_mispredict || connections == 0) {
+ expected_data = (unsigned char*) "foo";
+ expected_len = 3;
+ } else {
+ expected_data = (unsigned char*) "baz";
+ expected_len = 3;
+ }
+ if (len != expected_len || memcmp(data, expected_data, len) != 0) {
+ fprintf(stderr, "Bad NPN: %d\n", len);
+ return 1;
+ }
+ }
+
+ unsigned char buffer[6];
+
+ int ret = SSL_read(server, buffer, sizeof(buffer));
+ if (ret == -1) {
+ err = SSL_get_error(server, ret);
+ ERR_print_errors_fp(stderr);
+ fprintf(stderr, "SSL_read failed: %d\n", err);
+ }
+ if (memcmp(buffer, "hello!", sizeof(buffer)) == 0) {
+ SSL_write(server, "goodbye!", 8);
+ }
+
+ SSL_shutdown(server);
+ SSL_shutdown(server);
+ }
+
+ SSL_CTX_free(ctx);
+
+ return 0;
+}
diff --git a/net/test/python_utils.cc b/net/test/python_utils.cc
index 438c3d72..13438f77 100644
--- a/net/test/python_utils.cc
+++ b/net/test/python_utils.cc
@@ -7,6 +7,7 @@
#include "base/base_paths.h"
#include "base/environment.h"
#include "base/file_path.h"
+#include "base/file_util.h"
#include "base/path_service.h"
#include "base/scoped_ptr.h"
#include "base/utf_string_conversions.h"
@@ -36,6 +37,34 @@ void AppendToPythonPath(const FilePath& dir) {
}
}
+bool GetPyProtoPath(FilePath* dir) {
+ // Locate the Python code generated by the protocol buffers compiler.
+ FilePath generated_code_dir;
+ if (!PathService::Get(base::DIR_EXE, &generated_code_dir)) {
+ return false;
+ }
+
+ const FilePath kPyProto(FILE_PATH_LITERAL("pyproto"));
+
+#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+ // On Mac and Chrome OS, DIR_EXE might be pointing deep into the Release/
+ // (or Debug/) directory and we can't depend on how far down it goes. So we
+ // walk upwards from DIR_EXE until we find a likely looking spot.
+ while (!file_util::DirectoryExists(generated_code_dir.Append(kPyProto))) {
+ FilePath parent = generated_code_dir.DirName();
+ if (parent == generated_code_dir) {
+ // We hit the root directory. Maybe we didn't build any targets which
+ // produced Python protocol buffers.
+ PathService::Get(base::DIR_EXE, &generated_code_dir);
+ return false;
+ }
+ generated_code_dir = parent;
+ }
+#endif
+ *dir = generated_code_dir.Append(kPyProto);
+ return true;
+}
+
bool GetPythonRunTime(FilePath* dir) {
#if defined(OS_WIN)
if (!PathService::Get(base::DIR_SOURCE_ROOT, dir))
@@ -48,4 +77,3 @@ bool GetPythonRunTime(FilePath* dir) {
#endif
return true;
}
-
diff --git a/net/test/python_utils.h b/net/test/python_utils.h
index 215569ca..bc3bdb1a 100644
--- a/net/test/python_utils.h
+++ b/net/test/python_utils.h
@@ -16,8 +16,10 @@ extern const char kPythonPathEnv[];
// Appends the dir to python path environment variable.
void AppendToPythonPath(const FilePath& dir);
+// Return the location of the compiler-generated python protobuf.
+bool GetPyProtoPath(FilePath* dir);
+
// Returns the path that should be used to launch Python.
bool GetPythonRunTime(FilePath* path) WARN_UNUSED_RESULT;
#endif // NET_TEST_PYTHON_UTILS_H_
-
diff --git a/net/test/test_server.cc b/net/test/test_server.cc
index 4b426eb4..0e8c4611 100644
--- a/net/test/test_server.cc
+++ b/net/test/test_server.cc
@@ -14,6 +14,7 @@
#include "net/base/x509_certificate.h"
#endif
+#include "base/base64.h"
#include "base/command_line.h"
#include "base/debug/leak_annotations.h"
#include "base/file_util.h"
@@ -40,59 +41,6 @@ const int kServerConnectionAttempts = 10;
// Connection timeout in milliseconds for tests.
const int kServerConnectionTimeoutMs = 1000;
-const char kTestServerShardFlag[] = "test-server-shard";
-
-int GetHTTPSPortBase(const TestServer::HTTPSOptions& options) {
- if (options.request_client_certificate)
- return 9543;
-
- switch (options.server_certificate) {
- case TestServer::HTTPSOptions::CERT_OK:
- return 9443;
- case TestServer::HTTPSOptions::CERT_MISMATCHED_NAME:
- return 9643;
- case TestServer::HTTPSOptions::CERT_EXPIRED:
- // TODO(phajdan.jr): Some tests rely on this hardcoded value.
- // Some uses of this are actually in .html/.js files.
- return 9666;
- default:
- NOTREACHED();
- }
- return -1;
-}
-
-int GetPortBase(TestServer::Type type,
- const TestServer::HTTPSOptions& options) {
- switch (type) {
- case TestServer::TYPE_FTP:
- return 3117;
- case TestServer::TYPE_HTTP:
- return 1337;
- case TestServer::TYPE_HTTPS:
- return GetHTTPSPortBase(options);
- default:
- NOTREACHED();
- }
- return -1;
-}
-
-int GetPort(TestServer::Type type,
- const TestServer::HTTPSOptions& options) {
- int port = GetPortBase(type, options);
- if (CommandLine::ForCurrentProcess()->HasSwitch(kTestServerShardFlag)) {
- std::string shard_str(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- kTestServerShardFlag));
- int shard = -1;
- if (base::StringToInt(shard_str, &shard)) {
- port += shard;
- } else {
- LOG(FATAL) << "Got invalid " << kTestServerShardFlag << " flag value. "
- << "An integer is expected.";
- }
- }
- return port;
-}
-
std::string GetHostname(TestServer::Type type,
const TestServer::HTTPSOptions& options) {
if (type == TestServer::TYPE_HTTPS &&
@@ -138,13 +86,16 @@ FilePath TestServer::HTTPSOptions::GetCertificateFile() const {
}
TestServer::TestServer(Type type, const FilePath& document_root)
- : type_(type) {
+ : type_(type),
+ started_(false) {
Init(document_root);
}
TestServer::TestServer(const HTTPSOptions& https_options,
const FilePath& document_root)
- : https_options_(https_options), type_(TYPE_HTTPS) {
+ : https_options_(https_options),
+ type_(TYPE_HTTPS),
+ started_(false) {
Init(document_root);
}
@@ -156,8 +107,11 @@ TestServer::~TestServer() {
}
void TestServer::Init(const FilePath& document_root) {
- host_port_pair_ = HostPortPair(GetHostname(type_, https_options_),
- GetPort(type_, https_options_));
+ // At this point, the port that the testserver will listen on is unknown.
+ // The testserver 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.
+ host_port_pair_ = HostPortPair(GetHostname(type_, https_options_), 0);
process_handle_ = base::kNullProcessHandle;
FilePath src_dir;
@@ -202,6 +156,7 @@ bool TestServer::Start() {
return false;
}
+ started_ = true;
return true;
}
@@ -209,6 +164,8 @@ bool TestServer::Stop() {
if (!process_handle_)
return true;
+ started_ = false;
+
// First check if the process has already terminated.
bool ret = base::WaitForSingleProcess(process_handle_, 0);
if (!ret)
@@ -224,11 +181,17 @@ bool TestServer::Stop() {
return ret;
}
+const HostPortPair& TestServer::host_port_pair() const {
+ DCHECK(started_);
+ return host_port_pair_;
+}
+
std::string TestServer::GetScheme() const {
switch (type_) {
case TYPE_FTP:
return "ftp";
case TYPE_HTTP:
+ case TYPE_SYNC:
return "http";
case TYPE_HTTPS:
return "https";
@@ -252,13 +215,13 @@ bool TestServer::GetAddressList(AddressList* address_list) const {
return true;
}
-GURL TestServer::GetURL(const std::string& path) {
+GURL TestServer::GetURL(const std::string& path) const {
return GURL(GetScheme() + "://" + host_port_pair_.ToString() +
"/" + path);
}
GURL TestServer::GetURLWithUser(const std::string& path,
- const std::string& user) {
+ const std::string& user) const {
return GURL(GetScheme() + "://" + user + "@" +
host_port_pair_.ToString() +
"/" + path);
@@ -266,12 +229,47 @@ GURL TestServer::GetURLWithUser(const std::string& path,
GURL TestServer::GetURLWithUserAndPassword(const std::string& path,
const std::string& user,
- const std::string& password) {
+ const std::string& password) const {
return GURL(GetScheme() + "://" + user + ":" + password +
"@" + host_port_pair_.ToString() +
"/" + path);
}
+// static
+bool TestServer::GetFilePathWithReplacements(
+ const std::string& original_file_path,
+ const std::vector<StringPair>& text_to_replace,
+ std::string* replacement_path) {
+ std::string new_file_path = original_file_path;
+ bool first_query_parameter = true;
+ const std::vector<StringPair>::const_iterator end = text_to_replace.end();
+ for (std::vector<StringPair>::const_iterator it = text_to_replace.begin();
+ it != end;
+ ++it) {
+ const std::string& old_text = it->first;
+ const std::string& new_text = it->second;
+ std::string base64_old;
+ std::string base64_new;
+ if (!base::Base64Encode(old_text, &base64_old))
+ return false;
+ if (!base::Base64Encode(new_text, &base64_new))
+ return false;
+ if (first_query_parameter) {
+ new_file_path += "?";
+ first_query_parameter = false;
+ } else {
+ new_file_path += "&";
+ }
+ new_file_path += "replace_text=";
+ new_file_path += base64_old;
+ new_file_path += ":";
+ new_file_path += base64_new;
+ }
+
+ *replacement_path = new_file_path;
+ return true;
+}
+
bool TestServer::SetPythonPath() {
FilePath third_party_dir;
if (!PathService::Get(base::DIR_SOURCE_ROOT, &third_party_dir)) {
@@ -284,33 +282,16 @@ bool TestServer::SetPythonPath() {
AppendToPythonPath(third_party_dir.Append(FILE_PATH_LITERAL("pyftpdlib")));
// Locate the Python code generated by the protocol buffers compiler.
- FilePath generated_code_dir;
- if (!PathService::Get(base::DIR_EXE, &generated_code_dir)) {
- LOG(ERROR) << "Failed to get DIR_EXE";
+ FilePath pyproto_code_dir;
+ if (!GetPyProtoPath(&pyproto_code_dir)) {
+ LOG(ERROR) << "Failed to get python dir for generated code.";
return false;
}
- static const FilePath kPyProto(FILE_PATH_LITERAL("pyproto"));
-
-#if defined(OS_MACOSX)
- // On Mac, DIR_EXE might be pointing deep into the Release/ (or Debug/)
- // directory and we can't depend on how far down it goes. So we walk upwards
- // from DIR_EXE until we find a likely looking spot.
- while (!file_util::DirectoryExists(generated_code_dir.Append(kPyProto))) {
- FilePath parent = generated_code_dir.DirName();
- if (parent == generated_code_dir) {
- // We hit the root directory. Maybe we didn't build any targets which
- // produced Python protocol buffers.
- PathService::Get(base::DIR_EXE, &generated_code_dir);
- break;
- }
- generated_code_dir = parent;
- }
-#endif
-
- AppendToPythonPath(generated_code_dir.Append(kPyProto));
- AppendToPythonPath(generated_code_dir.Append(kPyProto).
- Append(FILE_PATH_LITERAL("sync_pb")));
+ AppendToPythonPath(pyproto_code_dir);
+ AppendToPythonPath(pyproto_code_dir.Append(FILE_PATH_LITERAL("sync_pb")));
+ AppendToPythonPath(pyproto_code_dir.Append(
+ FILE_PATH_LITERAL("device_management_pb")));
return true;
}
@@ -350,6 +331,8 @@ bool TestServer::AddCommandLineArguments(CommandLine* command_line) const {
if (type_ == TYPE_FTP) {
command_line->AppendArg("-f");
+ } else if (type_ == TYPE_SYNC) {
+ command_line->AppendArg("--sync");
} else if (type_ == TYPE_HTTPS) {
FilePath certificate_path(certificates_dir_);
certificate_path = certificate_path.Append(
diff --git a/net/test/test_server.h b/net/test/test_server.h
index 8affc12b..f8193654 100644
--- a/net/test/test_server.h
+++ b/net/test/test_server.h
@@ -7,6 +7,7 @@
#pragma once
#include <string>
+#include <utility>
#include <vector>
#include "build/build_config.h"
@@ -41,6 +42,7 @@ class TestServer {
TYPE_FTP,
TYPE_HTTP,
TYPE_HTTPS,
+ TYPE_SYNC,
};
// Container for various options to control how the HTTPS server is
@@ -113,18 +115,24 @@ class TestServer {
bool Stop();
const FilePath& document_root() const { return document_root_; }
- const HostPortPair& host_port_pair() const { return host_port_pair_; }
+ const HostPortPair& host_port_pair() const;
std::string GetScheme() const;
bool GetAddressList(AddressList* address_list) const WARN_UNUSED_RESULT;
- GURL GetURL(const std::string& path);
+ GURL GetURL(const std::string& path) const;
GURL GetURLWithUser(const std::string& path,
- const std::string& user);
+ const std::string& user) const;
GURL GetURLWithUserAndPassword(const std::string& path,
const std::string& user,
- const std::string& password);
+ const std::string& password) const;
+
+ typedef std::pair<std::string, std::string> StringPair;
+ static bool GetFilePathWithReplacements(
+ const std::string& original_path,
+ const std::vector<StringPair>& text_to_replace,
+ std::string* replacement_path);
private:
void Init(const FilePath& document_root);
@@ -189,6 +197,9 @@ class TestServer {
Type type_;
+ // Has the server been started?
+ bool started_;
+
DISALLOW_COPY_AND_ASSIGN(TestServer);
};
diff --git a/net/test/test_server_posix.cc b/net/test/test_server_posix.cc
index 707eb931..9c0210b7 100644
--- a/net/test/test_server_posix.cc
+++ b/net/test/test_server_posix.cc
@@ -98,24 +98,45 @@ bool TestServer::LaunchPython(const FilePath& testserver_path) {
}
bool TestServer::WaitToStart() {
- struct pollfd poll_fds[1];
-
- poll_fds[0].fd = child_fd_;
- poll_fds[0].events = POLLIN | POLLPRI;
- poll_fds[0].revents = 0;
+ uint16 port;
+ uint8* buffer = reinterpret_cast<uint8*>(&port);
+ ssize_t bytes_read = 0;
+ ssize_t bytes_max = sizeof(port);
+ base::TimeDelta remaining_time = base::TimeDelta::FromMilliseconds(
+ TestTimeouts::action_max_timeout_ms());
+ base::Time previous_time = base::Time::Now();
+ while (bytes_read < bytes_max) {
+ struct pollfd poll_fds[1];
+
+ poll_fds[0].fd = child_fd_;
+ poll_fds[0].events = POLLIN | POLLPRI;
+ poll_fds[0].revents = 0;
+
+ int rv = HANDLE_EINTR(poll(poll_fds, 1, remaining_time.InMilliseconds()));
+ if (rv != 1) {
+ LOG(ERROR) << "Failed to poll for the child file descriptor.";
+ return false;
+ }
- int rv = HANDLE_EINTR(poll(poll_fds, 1,
- TestTimeouts::action_max_timeout_ms()));
- if (rv != 1) {
- LOG(ERROR) << "Failed to poll for the child file descriptor.";
- return false;
+ base::Time current_time = base::Time::Now();
+ base::TimeDelta elapsed_time_cycle = current_time - previous_time;
+ DCHECK(elapsed_time_cycle.InMilliseconds() >= 0);
+ remaining_time -= elapsed_time_cycle;
+ previous_time = current_time;
+
+ ssize_t num_bytes = HANDLE_EINTR(read(child_fd_, buffer + bytes_read,
+ bytes_max - bytes_read));
+ if (num_bytes <= 0)
+ break;
+ bytes_read += num_bytes;
}
- char buf[8];
- ssize_t n = HANDLE_EINTR(read(child_fd_, buf, sizeof(buf)));
// We don't need the FD anymore.
child_fd_closer_.reset(NULL);
- return n > 0;
+ if (bytes_read < bytes_max)
+ return false;
+ host_port_pair_.set_port(port);
+ return true;
}
bool TestServer::CheckCATrusted() {
diff --git a/net/test/test_server_win.cc b/net/test/test_server_win.cc
index c6e10d5b..64437cd4 100644
--- a/net/test/test_server_win.cc
+++ b/net/test/test_server_win.cc
@@ -156,11 +156,20 @@ bool TestServer::WaitToStart() {
NewRunnableFunction(UnblockPipe, child_write_fd_.Get(), &unblocked),
TestTimeouts::action_max_timeout_ms());
- char buf[8];
- DWORD bytes_read;
- BOOL result = ReadFile(child_read_fd_.Get(), buf, sizeof(buf), &bytes_read,
- NULL);
-
+ // Try to read two bytes from the pipe indicating the ephemeral port number.
+ uint16 port;
+ uint8* buffer = reinterpret_cast<uint8*>(&port);
+ DWORD bytes_read = 0;
+ DWORD bytes_max = sizeof(port);
+ while (bytes_read < bytes_max) {
+ DWORD num_bytes;
+ if (!ReadFile(child_read_fd_, buffer + bytes_read, bytes_max - bytes_read,
+ &num_bytes, NULL))
+ break;
+ if (num_bytes <= 0)
+ break;
+ bytes_read += num_bytes;
+ }
thread.Stop();
child_read_fd_.Close();
child_write_fd_.Close();
@@ -169,7 +178,12 @@ bool TestServer::WaitToStart() {
if (unblocked)
return false;
- return result && bytes_read > 0;
+ // If not enough bytes were read, fail.
+ if (bytes_read < bytes_max)
+ return false;
+
+ host_port_pair_.set_port(port);
+ return true;
}
bool TestServer::CheckCATrusted() {