diff options
author | dkegel@google.com <dkegel@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-14 23:14:35 +0000 |
---|---|---|
committer | dkegel@google.com <dkegel@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-14 23:14:35 +0000 |
commit | 518fdec3a07a94dc45d6e7e4ad1b529747dc03d3 (patch) | |
tree | fb2b17479a907a8960a8dc865630fe7272d041fc /net | |
parent | 5e997eacfb2234633831d06c91859ee76af44468 (diff) | |
download | chromium_src-518fdec3a07a94dc45d6e7e4ad1b529747dc03d3.zip chromium_src-518fdec3a07a94dc45d6e7e4ad1b529747dc03d3.tar.gz chromium_src-518fdec3a07a94dc45d6e7e4ad1b529747dc03d3.tar.bz2 |
Reverting r9823 (http://codereview.chromium.org/16207) because
1) the Interactive Tests (dbg) buildbot needs the SSL cert installed
2) the same buildbot showed a refcounting problem, e.g.
FATAL:ref_counted.cc(22)] Check failed: in_dtor_. RefCounted object deleted without calling Release()
c:\b\slave\chromium-dbg-builder\build\src\chrome\browser\views\find_bar_win_interactive_uitest.cc(57): error: Value of: NULL != server.get()
Actual: false
Expected: true
[ FAILED ] FindInPageTest.CrashEscHandlers (2109 ms)
3) the Webkit Linux buildbot failed four tests
redirect302-frames.html cross-frame-access-protocol-explicit-domain.html
cross-frame-access-protocol.html origin-header-for-https.html
I'm leaving the tcp_pinger files in for the moment, they shouldn't hurt anything.
Review URL: http://codereview.chromium.org/23028
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@9827 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/base/ssl_client_socket_nss.cc | 53 | ||||
-rw-r--r-- | net/base/ssl_client_socket_nss.h | 18 | ||||
-rw-r--r-- | net/base/ssl_client_socket_unittest.cc | 158 | ||||
-rw-r--r-- | net/base/ssl_test_util.cc | 226 | ||||
-rw-r--r-- | net/base/ssl_test_util.h | 73 | ||||
-rw-r--r-- | net/build/net_unittests.vcproj | 4 | ||||
-rw-r--r-- | net/net.xcodeproj/project.pbxproj | 18 | ||||
-rw-r--r-- | net/net_unittests.scons | 1 | ||||
-rw-r--r-- | net/url_request/url_request_unittest.cc | 17 | ||||
-rw-r--r-- | net/url_request/url_request_unittest.h | 479 |
10 files changed, 482 insertions, 565 deletions
diff --git a/net/base/ssl_client_socket_nss.cc b/net/base/ssl_client_socket_nss.cc index f67c246..5c33dc8 100644 --- a/net/base/ssl_client_socket_nss.cc +++ b/net/base/ssl_client_socket_nss.cc @@ -23,6 +23,21 @@ static const int kRecvBufferSize = 4096; +namespace { + +// NSS calls this if an incoming certificate is invalid. +SECStatus OwnBadCertHandler(void* arg, PRFileDesc* socket) { + PRErrorCode err = PR_GetError(); + LOG(INFO) << "server certificate is invalid; NSS error code " << err; + // Return SECSuccess to override the problem, + // or SECFailure to let the original function fail + // Chromium wants it to fail here, and may retry it later. + LOG(WARNING) << "TODO(dkegel): return SECFailure here"; + return SECSuccess; +} + +} // anonymous namespace + namespace net { // State machines are easier to debug if you log state transitions. @@ -64,8 +79,6 @@ int NetErrorFromNSPRError(PRErrorCode err) { case SEC_ERROR_REVOKED_KEY: return ERR_CERT_REVOKED; case SEC_ERROR_UNKNOWN_ISSUER: - case SEC_ERROR_UNTRUSTED_CERT: - case SEC_ERROR_UNTRUSTED_ISSUER: return ERR_CERT_AUTHORITY_INVALID; default: { @@ -106,7 +119,7 @@ SSLClientSocketNSS::SSLClientSocketNSS(ClientSocket* transport_socket, user_callback_(NULL), user_buf_(NULL), user_buf_len_(0), - server_cert_error_(0), + server_cert_status_(0), completed_handshake_(false), next_state_(STATE_NONE), nss_fd_(NULL), @@ -229,12 +242,9 @@ void SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) { << " for cipherSuite " << channel_info.cipherSuite; } } - if (server_cert_error_ != net::OK) - ssl_info->SetCertError(server_cert_error_); - X509Certificate::OSCertHandle nss_cert = SSL_PeerCertificate(nss_fd_); - if (nss_cert) - ssl_info->cert = X509Certificate::CreateFromHandle(nss_cert, - X509Certificate::SOURCE_FROM_NETWORK); + ssl_info->cert_status = server_cert_status_; + // TODO(port): implement X509Certificate so we can set the cert field! + // CERTCertificate *nssCert = SSL_PeerCertificate(nss_fd_); LeaveFunction(""); } @@ -391,19 +401,6 @@ int SSLClientSocketNSS::DoConnect() { return transport_->Connect(&io_callback_); } -// static -// NSS calls this if an incoming certificate is invalid. -SECStatus SSLClientSocketNSS::OwnBadCertHandler(void* arg, PRFileDesc* socket) { - SSLClientSocketNSS* that = reinterpret_cast<SSLClientSocketNSS*>(arg); - PRErrorCode prerr = PR_GetError(); - that->server_cert_error_ = NetErrorFromNSPRError(prerr); - LOG(INFO) << "server certificate is invalid; NSS error code " << prerr - << ", net error " << that->server_cert_error_; - // Return SECSuccess to override the problem. - // Chromium wants it to succeed here, and may abort the connection later. - return SECSuccess; -} - int SSLClientSocketNSS::DoConnectComplete(int result) { EnterFunction(result); if (result < 0) @@ -482,7 +479,7 @@ int SSLClientSocketNSS::DoConnectComplete(int result) { if (rv != SECSuccess) return ERR_UNEXPECTED; - rv = SSL_BadCertHook(nss_fd_, OwnBadCertHandler, this); + rv = SSL_BadCertHook(nss_fd_, OwnBadCertHandler, NULL); if (rv != SECSuccess) return ERR_UNEXPECTED; @@ -503,10 +500,11 @@ int SSLClientSocketNSS::DoHandshakeRead() { int rv = SSL_ForceHandshake(nss_fd_); if (rv == SECSuccess) { - net_error = server_cert_error_; + net_error = OK; // there's a callback for this, too completed_handshake_ = true; - // Done! + // Indicate we're ready to handle I/O. Badly named? + GotoState(STATE_NONE); } else { PRErrorCode prerr = PR_GetError(); net_error = NetErrorFromNSPRError(prerr); @@ -515,9 +513,10 @@ int SSLClientSocketNSS::DoHandshakeRead() { if (net_error == ERR_IO_PENDING) { GotoState(STATE_HANDSHAKE_READ); } else { - server_cert_error_ = net_error; + server_cert_status_ = MapNetErrorToCertStatus(net_error); LOG(ERROR) << "handshake failed; NSS error code " << prerr - << ", net_error " << net_error; + << ", net_error " << net_error << ", server_cert_status " + << server_cert_status_; } } diff --git a/net/base/ssl_client_socket_nss.h b/net/base/ssl_client_socket_nss.h index b16557c..5015e1e 100644 --- a/net/base/ssl_client_socket_nss.h +++ b/net/base/ssl_client_socket_nss.h @@ -5,13 +5,15 @@ #ifndef NET_BASE_SSL_CLIENT_SOCKET_NSS_H_ #define NET_BASE_SSL_CLIENT_SOCKET_NSS_H_ -#include <nspr.h> -#include <nss.h> +#include "build/build_config.h" + +#include <prio.h> +#include "net/base/nss_memio.h" + #include <string> #include "base/scoped_ptr.h" #include "net/base/completion_callback.h" -#include "net/base/nss_memio.h" #include "net/base/ssl_client_socket.h" #include "net/base/ssl_config_service.h" @@ -58,9 +60,6 @@ class SSLClientSocketNSS : public SSLClientSocket { void BufferSendComplete(int result); void BufferRecvComplete(int result); - // nss calls this on error. We pass 'this' as the first argument. - static SECStatus OwnBadCertHandler(void* arg, PRFileDesc* socket); - CompletionCallbackImpl<SSLClientSocketNSS> buffer_send_callback_; CompletionCallbackImpl<SSLClientSocketNSS> buffer_recv_callback_; bool transport_send_busy_; @@ -77,8 +76,7 @@ class SSLClientSocketNSS : public SSLClientSocket { char* user_buf_; int user_buf_len_; - // Set when handshake finishes. Value is net error code, see net_errors.h - int server_cert_error_; + int server_cert_status_; bool completed_handshake_; @@ -93,10 +91,10 @@ class SSLClientSocketNSS : public SSLClientSocket { }; State next_state_; - // The NSS SSL state machine + /* The NSS SSL state machine */ PRFileDesc* nss_fd_; - // Buffers for the network end of the SSL state machine + /* Buffers for the network end of the SSL state machine */ memio_Private* nss_bufs_; static bool nss_options_initialized_; diff --git a/net/base/ssl_client_socket_unittest.cc b/net/base/ssl_client_socket_unittest.cc index 4710151..faf5a4a 100644 --- a/net/base/ssl_client_socket_unittest.cc +++ b/net/base/ssl_client_socket_unittest.cc @@ -10,7 +10,6 @@ #include "net/base/net_errors.h" #include "net/base/ssl_client_socket.h" #include "net/base/ssl_config_service.h" -#include "net/base/ssl_test_util.h" #include "net/base/tcp_client_socket.h" #include "net/base/test_completion_callback.h" #include "testing/gtest/include/gtest/gtest.h" @@ -23,74 +22,41 @@ const net::SSLConfig kDefaultSSLConfig; class SSLClientSocketTest : public PlatformTest { public: SSLClientSocketTest() - : socket_factory_(net::ClientSocketFactory::GetDefaultFactory()) { - } - - void StartOKServer() { - bool success = server_.Start(net::TestServerLauncher::ProtoHTTP, - server_.kHostName, server_.kOKHTTPSPort, - FilePath(), server_.GetOKCertPath()); - ASSERT_TRUE(success); - } - - void StartMismatchedServer() { - bool success = server_.Start(net::TestServerLauncher::ProtoHTTP, - server_.kMismatchedHostName, server_.kOKHTTPSPort, - FilePath(), server_.GetOKCertPath()); - ASSERT_TRUE(success); - } - - void StartExpiredServer() { - bool success = server_.Start(net::TestServerLauncher::ProtoHTTP, - server_.kHostName, server_.kBadHTTPSPort, - FilePath(), server_.GetExpiredCertPath()); - ASSERT_TRUE(success); + : host_mapper_(new net::RuleBasedHostMapper()), + scoped_host_mapper_(host_mapper_.get()), + socket_factory_(net::ClientSocketFactory::GetDefaultFactory()) { + // TODO(darin): kill this exception once we have a way to test out the + // TCPClientSocket class using loopback connections. + host_mapper_->AddRule("bugs.webkit.org", "bugs.webkit.org"); } protected: + scoped_refptr<net::RuleBasedHostMapper> host_mapper_; + net::ScopedHostMapper scoped_host_mapper_; net::ClientSocketFactory* socket_factory_; - net::TestServerLauncher server_; }; //----------------------------------------------------------------------------- -#if defined(OS_MACOSX) -#define MAYBE_Connect DISABLED_Connect -#define MAYBE_ConnectExpired DISABLED_ConnectExpired -#define MAYBE_ConnectMismatched DISABLED_ConnectMismatched -#define MAYBE_Read DISABLED_Read -#define MAYBE_Read_SmallChunks DISABLED_Read_SmallChunks -#define MAYBE_Read_Interrupted DISABLED_Read_Interrupted -#else -#define MAYBE_Connect Connect -#define MAYBE_ConnectExpired ConnectExpired -#define MAYBE_ConnectMismatched ConnectMismatched -#define MAYBE_Read Read -#define MAYBE_Read_SmallChunks Read_SmallChunks -#define MAYBE_Read_Interrupted Read_Interrupted -#endif - -TEST_F(SSLClientSocketTest, MAYBE_Connect) { - StartOKServer(); - +// bug 1354783 +TEST_F(SSLClientSocketTest, DISABLED_Connect) { net::AddressList addr; net::HostResolver resolver; TestCompletionCallback callback; - int rv = resolver.Resolve(server_.kHostName, server_.kOKHTTPSPort, - &addr, NULL); + std::string hostname = "bugs.webkit.org"; + int rv = resolver.Resolve(hostname, 443, &addr, NULL); EXPECT_EQ(net::OK, rv); scoped_ptr<net::SSLClientSocket> sock( socket_factory_->CreateSSLClientSocket(new net::TCPClientSocket(addr), - server_.kHostName, kDefaultSSLConfig)); + hostname, kDefaultSSLConfig)); EXPECT_FALSE(sock->IsConnected()); rv = sock->Connect(&callback); if (rv != net::OK) { ASSERT_EQ(net::ERR_IO_PENDING, rv); - EXPECT_FALSE(sock->IsConnected()); rv = callback.WaitForResult(); EXPECT_EQ(net::OK, rv); @@ -102,79 +68,14 @@ TEST_F(SSLClientSocketTest, MAYBE_Connect) { EXPECT_FALSE(sock->IsConnected()); } -TEST_F(SSLClientSocketTest, MAYBE_ConnectExpired) { - StartExpiredServer(); - +// bug 1354783 +TEST_F(SSLClientSocketTest, DISABLED_Read) { net::AddressList addr; net::HostResolver resolver; TestCompletionCallback callback; - int rv = resolver.Resolve(server_.kHostName, server_.kBadHTTPSPort, - &addr, NULL); - EXPECT_EQ(net::OK, rv); - - scoped_ptr<net::SSLClientSocket> sock( - socket_factory_->CreateSSLClientSocket(new net::TCPClientSocket(addr), - server_.kHostName, kDefaultSSLConfig)); - - EXPECT_FALSE(sock->IsConnected()); - - rv = sock->Connect(&callback); - if (rv != net::OK) { - ASSERT_EQ(net::ERR_IO_PENDING, rv); - EXPECT_FALSE(sock->IsConnected()); - - rv = callback.WaitForResult(); - EXPECT_EQ(net::ERR_CERT_DATE_INVALID, rv); - } - - EXPECT_TRUE(sock->IsConnected()); -} - -TEST_F(SSLClientSocketTest, MAYBE_ConnectMismatched) { - StartMismatchedServer(); - - net::AddressList addr; - net::HostResolver resolver; - TestCompletionCallback callback; - - int rv = resolver.Resolve(server_.kMismatchedHostName, server_.kOKHTTPSPort, - &addr, NULL); - EXPECT_EQ(net::OK, rv); - - scoped_ptr<net::SSLClientSocket> sock( - socket_factory_->CreateSSLClientSocket(new net::TCPClientSocket(addr), - server_.kMismatchedHostName, kDefaultSSLConfig)); - - EXPECT_FALSE(sock->IsConnected()); - - rv = sock->Connect(&callback); - if (rv != net::ERR_CERT_COMMON_NAME_INVALID) { - ASSERT_EQ(net::ERR_IO_PENDING, rv); - EXPECT_FALSE(sock->IsConnected()); - - rv = callback.WaitForResult(); - EXPECT_EQ(net::ERR_CERT_COMMON_NAME_INVALID, rv); - } - - // The Windows code happens to keep the connection - // open now in spite of an error. The designers of - // this API intended to also allow the connection - // to be closed on error, in which case the caller - // should call ReconnectIgnoringLastError, but - // that's currently unimplemented. - EXPECT_TRUE(sock->IsConnected()); -} - -TEST_F(SSLClientSocketTest, MAYBE_Read) { - StartOKServer(); - - net::AddressList addr; - net::HostResolver resolver; - TestCompletionCallback callback; - - int rv = resolver.Resolve(server_.kHostName, server_.kOKHTTPSPort, - &addr, &callback); + std::string hostname = "bugs.webkit.org"; + int rv = resolver.Resolve(hostname, 443, &addr, &callback); EXPECT_EQ(net::ERR_IO_PENDING, rv); rv = callback.WaitForResult(); @@ -182,8 +83,7 @@ TEST_F(SSLClientSocketTest, MAYBE_Read) { scoped_ptr<net::SSLClientSocket> sock( socket_factory_->CreateSSLClientSocket(new net::TCPClientSocket(addr), - server_.kHostName, - kDefaultSSLConfig)); + hostname, kDefaultSSLConfig)); rv = sock->Connect(&callback); if (rv != net::OK) { @@ -217,20 +117,19 @@ TEST_F(SSLClientSocketTest, MAYBE_Read) { } } -TEST_F(SSLClientSocketTest, MAYBE_Read_SmallChunks) { - StartOKServer(); - +// bug 1354783 +TEST_F(SSLClientSocketTest, DISABLED_Read_SmallChunks) { net::AddressList addr; net::HostResolver resolver; TestCompletionCallback callback; - int rv = resolver.Resolve(server_.kHostName, server_.kOKHTTPSPort, - &addr, NULL); + std::string hostname = "bugs.webkit.org"; + int rv = resolver.Resolve(hostname, 443, &addr, NULL); EXPECT_EQ(net::OK, rv); scoped_ptr<net::SSLClientSocket> sock( socket_factory_->CreateSSLClientSocket(new net::TCPClientSocket(addr), - server_.kHostName, kDefaultSSLConfig)); + hostname, kDefaultSSLConfig)); rv = sock->Connect(&callback); if (rv != net::OK) { @@ -263,20 +162,19 @@ TEST_F(SSLClientSocketTest, MAYBE_Read_SmallChunks) { } } -TEST_F(SSLClientSocketTest, MAYBE_Read_Interrupted) { - StartOKServer(); - +// bug 1354783 +TEST_F(SSLClientSocketTest, DISABLED_Read_Interrupted) { net::AddressList addr; net::HostResolver resolver; TestCompletionCallback callback; - int rv = resolver.Resolve(server_.kHostName, server_.kOKHTTPSPort, - &addr, NULL); + std::string hostname = "bugs.webkit.org"; + int rv = resolver.Resolve(hostname, 443, &addr, NULL); EXPECT_EQ(net::OK, rv); scoped_ptr<net::SSLClientSocket> sock( socket_factory_->CreateSSLClientSocket(new net::TCPClientSocket(addr), - server_.kHostName, kDefaultSSLConfig)); + hostname, kDefaultSSLConfig)); rv = sock->Connect(&callback); if (rv != net::OK) { diff --git a/net/base/ssl_test_util.cc b/net/base/ssl_test_util.cc index a6ad137..d22e4fd 100644 --- a/net/base/ssl_test_util.cc +++ b/net/base/ssl_test_util.cc @@ -5,8 +5,6 @@ #include <string> #include <algorithm> -#include "net/base/ssl_test_util.h" - #include "build/build_config.h" #if defined(OS_WIN) @@ -29,15 +27,16 @@ #include "base/file_util.h" #include "base/logging.h" #include "base/path_service.h" -#include "base/platform_thread.h" -#include "base/string_util.h" -#include "net/base/tcp_pinger.h" -#include "net/base/host_resolver.h" -#include "net/base/tcp_client_socket.h" -#include "net/base/test_completion_callback.h" -#include "testing/platform_test.h" -namespace { +#include "net/base/ssl_test_util.h" + +// static +const char SSLTestUtil::kHostName[] = "127.0.0.1"; +const int SSLTestUtil::kOKHTTPSPort = 9443; +const int SSLTestUtil::kBadHTTPSPort = 9666; + +// The issuer name of the cert that should be trusted for the test to work. +const wchar_t SSLTestUtil::kCertIssuerName[] = L"Test CA"; #if defined(OS_LINUX) static CERTCertificate* LoadTemporaryCert(const FilePath& filename) { @@ -68,231 +67,57 @@ static CERTCertificate* LoadTemporaryCert(const FilePath& filename) { rv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert, &trust); if (rv != SECSuccess) { - LOG(ERROR) << "Can't change trust for certificate " + LOG(ERROR) << "Can't change trust for certificate " << filename.ToWStringHack(); CERT_DestroyCertificate(cert); return NULL; } - // TODO(dkegel): figure out how to get this to only happen once? + LOG(INFO) << "Loaded temporary certificate " << filename.ToWStringHack(); return cert; } #endif -} // namespace - -namespace net { - -// static -const char TestServerLauncher::kHostName[] = "127.0.0.1"; -const char TestServerLauncher::kMismatchedHostName[] = "localhost"; -const int TestServerLauncher::kOKHTTPSPort = 9443; -const int TestServerLauncher::kBadHTTPSPort = 9666; - -// The issuer name of the cert that should be trusted for the test to work. -const wchar_t TestServerLauncher::kCertIssuerName[] = L"Test CA"; - -TestServerLauncher::TestServerLauncher() : process_handle_(NULL) -#if defined(OS_LINUX) -, cert_(NULL) -#endif -{ - PathService::Get(base::DIR_SOURCE_ROOT, &data_dir_); - data_dir_ = data_dir_.Append(FILE_PATH_LITERAL("net")) - .Append(FILE_PATH_LITERAL("data")) - .Append(FILE_PATH_LITERAL("ssl")); - cert_dir_ = data_dir_.Append(FILE_PATH_LITERAL("certificates")); -} - -namespace { - -void AppendToPythonPath(FilePath dir) { - // Do nothing if dir already on path. - -#if defined(OS_WIN) - const wchar_t kPythonPath[] = L"PYTHONPATH"; - // FIXME(dkegel): handle longer PYTHONPATH variables - wchar_t oldpath[4096]; - if (GetEnvironmentVariable(kPythonPath, oldpath, sizeof(oldpath)) == 0) { - SetEnvironmentVariableW(kPythonPath, dir.value().c_str()); - } else if (!wcsstr(oldpath, dir.value().c_str())) { - std::wstring newpath(oldpath); - newpath.append(L":"); - newpath.append(dir.value()); - SetEnvironmentVariableW(kPythonPath, newpath.c_str()); - } -#elif defined(OS_POSIX) - const char kPythonPath[] = "PYTHONPATH"; - const char* oldpath = getenv(kPythonPath); - if (!oldpath) { - setenv(kPythonPath, dir.value().c_str(), 1); - } else if (!strstr(oldpath, dir.value().c_str())) { - std::string newpath(oldpath); - newpath.append(":"); - newpath.append(dir.value()); - setenv(kPythonPath, newpath.c_str(), 1); - } -#endif -} - -} // end namespace - -void TestServerLauncher::SetPythonPath() { - FilePath third_party_dir; - ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &third_party_dir)); - third_party_dir = third_party_dir.Append(FILE_PATH_LITERAL("third_party")); - - AppendToPythonPath(third_party_dir.Append(FILE_PATH_LITERAL("tlslite"))); - AppendToPythonPath(third_party_dir.Append(FILE_PATH_LITERAL("pyftpdlib"))); -} - -bool TestServerLauncher::Start(Protocol protocol, - const std::string& host_name, int port, - const FilePath& document_root, - const FilePath& cert_path) { - if (!TestServerLauncher::CheckCATrusted()) - return false; - - std::string port_str = IntToString(port); - - // Get path to python server script - FilePath testserver_path; - if (!PathService::Get(base::DIR_SOURCE_ROOT, &testserver_path)) - return false; - testserver_path = testserver_path - .Append(FILE_PATH_LITERAL("net")) - .Append(FILE_PATH_LITERAL("tools")) - .Append(FILE_PATH_LITERAL("testserver")) - .Append(FILE_PATH_LITERAL("testserver.py")); - - FilePath test_data_directory; - PathService::Get(base::DIR_SOURCE_ROOT, &test_data_directory); - test_data_directory = test_data_directory.Append(document_root); +SSLTestUtil::SSLTestUtil() { + PathService::Get(base::DIR_SOURCE_ROOT, &cert_dir_); + cert_dir_ = cert_dir_.AppendASCII("net"); + cert_dir_ = cert_dir_.AppendASCII("data"); + cert_dir_ = cert_dir_.AppendASCII("ssl"); + cert_dir_ = cert_dir_.AppendASCII("certificates"); #if defined(OS_LINUX) - if (!cert_ && !cert_path.value().empty()) { - cert_ = reinterpret_cast<PrivateCERTCertificate*>( + cert_ = reinterpret_cast<PrivateCERTCertificate*>( LoadTemporaryCert(GetRootCertPath())); - DCHECK(cert_); - } + DCHECK(cert_); #endif - - SetPythonPath(); - -#if defined(OS_WIN) - // Get path to python interpreter - if (!PathService::Get(base::DIR_SOURCE_ROOT, &python_runtime_)) - return false; - python_runtime_ = python_runtime_ - .Append(FILE_PATH_LITERAL("third_party")) - .Append(FILE_PATH_LITERAL("python_24")) - .Append(FILE_PATH_LITERAL("python.exe")); - - std::wstring command_line = - L"\"" + python_runtime_.ToWStringHack() + L"\" " + - L"\"" + testserver_path.ToWStringHack() + - L"\" --port=" + UTF8ToWide(port_str) + - L" --data-dir=\"" + test_data_directory.ToWStringHack() + L"\""; - if (protocol == ProtoFTP) - command_line.append(L" -f"); - if (!cert_path.value().empty()) { - command_line.append(L" --https=\""); - command_line.append(cert_path.ToWStringHack()); - command_line.append(L"\""); - } - - if (!base::LaunchApp(command_line, false, true, &process_handle_)) { - LOG(ERROR) << "Failed to launch " << command_line; - return false; - } -#elif defined(OS_POSIX) - std::vector<std::string> command_line; - command_line.push_back("python"); - command_line.push_back(WideToUTF8(testserver_path.ToWStringHack())); - command_line.push_back("--port=" + port_str); - command_line.push_back("--data-dir=" + - WideToUTF8(test_data_directory.ToWStringHack())); - if (protocol == ProtoFTP) - command_line.push_back("-f"); - if (!cert_path.value().empty()) - command_line.push_back("--https=" + WideToUTF8(cert_path.ToWStringHack())); - - base::file_handle_mapping_vector no_mappings; - LOG(INFO) << "Trying to launch " << command_line[0] << " ..."; - if (!base::LaunchApp(command_line, no_mappings, false, &process_handle_)) { - LOG(ERROR) << "Failed to launch " << command_line[0] << " ..."; - return false; - } -#endif - - // Let the server start, then verify that it's up. - // Our server is Python, and takes about 500ms to start - // up the first time, and about 200ms after that. - if (!Wait(host_name, port)) { - LOG(ERROR) << "Failed to connect to server"; - Stop(); - return false; - } - - LOG(INFO) << "Started on port " << port_str; - return true; -} - -bool TestServerLauncher::Wait(const std::string& host_name, int port) { - // Verify that the webserver is actually started. - // Otherwise tests can fail if they run faster than Python can start. - net::AddressList addr; - net::HostResolver resolver; - int rv = resolver.Resolve(host_name, port, &addr, NULL); - if (rv != net::OK) - return false; - - net::TCPPinger pinger(addr); - rv = pinger.Ping(); - return rv == net::OK; -} - -void TestServerLauncher::Stop() { - if (!process_handle_) - return; - - base::KillProcess(process_handle_, 1, true); - -#if defined(OS_WIN) - CloseHandle(process_handle_); -#endif - - process_handle_ = NULL; - LOG(INFO) << "Stopped."; } -TestServerLauncher::~TestServerLauncher() { +SSLTestUtil::~SSLTestUtil() { #if defined(OS_LINUX) if (cert_) CERT_DestroyCertificate(reinterpret_cast<CERTCertificate*>(cert_)); #endif - Stop(); } -FilePath TestServerLauncher::GetRootCertPath() { +FilePath SSLTestUtil::GetRootCertPath() { FilePath path(cert_dir_); path = path.AppendASCII("root_ca_cert.crt"); return path; } -FilePath TestServerLauncher::GetOKCertPath() { +FilePath SSLTestUtil::GetOKCertPath() { FilePath path(cert_dir_); path = path.AppendASCII("ok_cert.pem"); return path; } -FilePath TestServerLauncher::GetExpiredCertPath() { +FilePath SSLTestUtil::GetExpiredCertPath() { FilePath path(cert_dir_); path = path.AppendASCII("expired_cert.pem"); return path; } -bool TestServerLauncher::CheckCATrusted() { +bool SSLTestUtil::CheckCATrusted() { // TODO(port): Port either this or LoadTemporaryCert to MacOSX. #if defined(OS_WIN) HCERTSTORE cert_store = CertOpenSystemStore(NULL, L"ROOT"); @@ -321,6 +146,3 @@ bool TestServerLauncher::CheckCATrusted() { #endif return true; } - -} // namespace net - diff --git a/net/base/ssl_test_util.h b/net/base/ssl_test_util.h index dd6d95d..9daa4cc 100644 --- a/net/base/ssl_test_util.h +++ b/net/base/ssl_test_util.h @@ -5,98 +5,49 @@ #ifndef NET_BASE_SSL_TEST_UTIL_H_ #define NET_BASE_SSL_TEST_UTIL_H_ -#include <string> +#include "build/build_config.h" #include "base/file_path.h" -#include "base/process_util.h" -#include "base/ref_counted.h" -#include "build/build_config.h" -// TODO(dkegel): share this between net/base and +// TODO(dkegel): share this between net/base and // chrome/browser without putting it in net.lib -namespace net { - -// This object bounds the lifetime of an external python-based HTTP/HTTPS/FTP -// server that can provide various responses useful for testing. -// A few basic convenience methods are provided, but no -// URL handling methods (those belong at a higher layer, e.g. in -// url_request_unittest.h). - -class TestServerLauncher { +class SSLTestUtil { public: - TestServerLauncher(); - - virtual ~TestServerLauncher(); - - enum Protocol { - ProtoHTTP, ProtoFTP - }; + SSLTestUtil(); - // Start src/net/tools/test_server/test_server.py and - // ask it to serve the given protocol. - // If protocol is HTTP, and cert_path is not empty, serves HTTPS. - // Returns true on success, false if files not found or root cert - // not trusted. - bool Start(Protocol protocol, - const std::string& host_name, int port, - const FilePath& document_root, - const FilePath& cert_path); + ~SSLTestUtil(); - // Stop the server started by Start(). - void Stop(); + FilePath GetRootCertPath(); - // Paths to a good, an expired, and an invalid server certificate - // (use as arguments to Start()). FilePath GetOKCertPath(); - FilePath GetExpiredCertPath(); - // Issuer name of the root cert that should be trusted for the test to work. - static const wchar_t kCertIssuerName[]; + FilePath GetExpiredCertPath(); // Hostname to use for test server static const char kHostName[]; - // Different hostname to use for test server (that still resolves to same IP) - static const char kMismatchedHostName[]; - // Port to use for test server static const int kOKHTTPSPort; // Port to use for bad test server static const int kBadHTTPSPort; - private: - // Wait a while for the server to start, return whether - // we were able to make a connection to it. - bool Wait(const std::string& host_name, int port); - - // Append to PYTHONPATH so Python can find pyftpdlib and tlslite. - void SetPythonPath(); - - // Path to our test root certificate. - FilePath GetRootCertPath(); + // Issuer name of the cert that should be trusted for the test to work. + static const wchar_t kCertIssuerName[]; // Returns false if our test root certificate is not trusted. bool CheckCATrusted(); - FilePath data_dir_; - + private: FilePath cert_dir_; - FilePath python_runtime_; - - base::ProcessHandle process_handle_; - #if defined(OS_LINUX) struct PrivateCERTCertificate; PrivateCERTCertificate *cert_; #endif - DISALLOW_COPY_AND_ASSIGN(TestServerLauncher); + DISALLOW_COPY_AND_ASSIGN(SSLTestUtil); }; -} - -#endif // NET_BASE_SSL_TEST_UTIL_H_ - +#endif // NET_BASE_SSL_TEST_UTIL_H_ diff --git a/net/build/net_unittests.vcproj b/net/build/net_unittests.vcproj index 738879f..2323492e 100644 --- a/net/build/net_unittests.vcproj +++ b/net/build/net_unittests.vcproj @@ -367,10 +367,6 @@ > </File> <File - RelativePath="..\base\tcp_pinger_unittest.cc" - > - </File> - <File RelativePath="..\base\tcp_client_socket_unittest.cc" > </File> diff --git a/net/net.xcodeproj/project.pbxproj b/net/net.xcodeproj/project.pbxproj index 42a1750..37df32e 100644 --- a/net/net.xcodeproj/project.pbxproj +++ b/net/net.xcodeproj/project.pbxproj @@ -52,8 +52,6 @@ 04C626D80E8DE3AA0067E92A /* http_auth_handler_basic_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 04C626D70E8DE3AA0067E92A /* http_auth_handler_basic_unittest.cc */; }; 04C626DA0E8DE3BA0067E92A /* http_auth_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 04C626D90E8DE3BA0067E92A /* http_auth_unittest.cc */; }; 04E7BD550EC4ECF60078FE58 /* http_auth_cache.cc in Sources */ = {isa = PBXBuildFile; fileRef = 04E7BD540EC4ECF60078FE58 /* http_auth_cache.cc */; }; - 07B79D4A0F4221D7001EA432 /* ssl_test_util.cc in Sources */ = {isa = PBXBuildFile; fileRef = 07B79D480F4221D7001EA432 /* ssl_test_util.cc */; }; - 07FE37F10F424D9F00049AB8 /* tcp_pinger_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 07FE37F00F424D9F00049AB8 /* tcp_pinger_unittest.cc */; }; 4D4C5BE20EF1B89E002CA805 /* directory_lister_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED325A0E5A181C00A747DB /* directory_lister_unittest.cc */; }; 4D4C5C060EF1B8C5002CA805 /* filter_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D4C5C050EF1B8C5002CA805 /* filter_unittest.cc */; }; 4D4C5C070EF1B915002CA805 /* http_cache_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED33550E5A194700A747DB /* http_cache_unittest.cc */; }; @@ -157,6 +155,7 @@ 8220FABD0E914ACA008170A9 /* ssl_client_socket_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32950E5A181C00A747DB /* ssl_client_socket_unittest.cc */; }; 8220FAFC0E915561008170A9 /* ssl_client_socket_mac.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32970E5A181C00A747DB /* ssl_client_socket_mac.cc */; }; 825C2FCC0E5C968B00FDEAB7 /* ev_root_ca_metadata.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32BE0E5A181C00A747DB /* ev_root_ca_metadata.cc */; }; + 826F15770EE48CEA00D973C7 /* ssl_test_util.cc in Sources */ = {isa = PBXBuildFile; fileRef = 826F15760EE48CEA00D973C7 /* ssl_test_util.cc */; }; 827E139D0E81611D00183614 /* x509_certificate_mac.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32800E5A181C00A747DB /* x509_certificate_mac.cc */; }; 82ECB3090E5B651D00A913E3 /* mime_sniffer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32AD0E5A181C00A747DB /* mime_sniffer.cc */; }; 93D11DCE0E91463000C36437 /* file_stream_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = 93D11DCD0E91463000C36437 /* file_stream_posix.cc */; }; @@ -441,8 +440,6 @@ 04C626D90E8DE3BA0067E92A /* http_auth_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = http_auth_unittest.cc; sourceTree = "<group>"; }; 04E7BD540EC4ECF60078FE58 /* http_auth_cache.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = http_auth_cache.cc; sourceTree = "<group>"; }; 04E7BD560EC4ED020078FE58 /* http_auth_cache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = http_auth_cache.h; sourceTree = "<group>"; }; - 07B79D480F4221D7001EA432 /* ssl_test_util.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ssl_test_util.cc; sourceTree = "<group>"; }; - 07FE37F00F424D9F00049AB8 /* tcp_pinger_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tcp_pinger_unittest.cc; sourceTree = "<group>"; }; 0E81748E2B2E8B814DBB78EC /* ftp_auth_cache.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ftp_auth_cache.cc; path = ftp/ftp_auth_cache.cc; sourceTree = SOURCE_ROOT; }; 15C6370BF6FE62308A559648 /* ftp_auth_cache_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ftp_auth_cache_unittest.cc; path = ftp/ftp_auth_cache_unittest.cc; sourceTree = SOURCE_ROOT; }; 4D4C5C050EF1B8C5002CA805 /* filter_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = filter_unittest.cc; sourceTree = "<group>"; }; @@ -686,6 +683,8 @@ 82113A270E84360200E3848F /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = "<group>"; }; 82113BBC0E892E5800E3848F /* x509_certificate.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = x509_certificate.cc; sourceTree = "<group>"; }; 8249C4920EA786B100A4A54B /* ssl_client_socket_mac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ssl_client_socket_mac.h; sourceTree = "<group>"; }; + 826F15750EE48CEA00D973C7 /* ssl_test_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ssl_test_util.h; sourceTree = "<group>"; }; + 826F15760EE48CEA00D973C7 /* ssl_test_util.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ssl_test_util.cc; sourceTree = "<group>"; }; 936882DC0E9154E200043405 /* file_stream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file_stream.h; sourceTree = "<group>"; }; 93D11DCD0E91463000C36437 /* file_stream_posix.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file_stream_posix.cc; sourceTree = "<group>"; }; A5AB7BFB0EB7DBA10070A7D3 /* file_stream_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file_stream_unittest.cc; sourceTree = "<group>"; }; @@ -913,7 +912,6 @@ 7BED326C0E5A181C00A747DB /* client_socket_pool.cc */, 7BED326B0E5A181C00A747DB /* client_socket_pool.h */, 7BED326A0E5A181C00A747DB /* client_socket_pool_unittest.cc */, - 07FE37F00F424D9F00049AB8 /* tcp_pinger_unittest.cc */, 7BED32680E5A181C00A747DB /* completion_callback.h */, F17062083BCE6F0A42F4C479 /* connection_type_histograms.cc */, D4726BC70CCE10F4FF2A5E12 /* connection_type_histograms.h */, @@ -994,7 +992,8 @@ 7BED32930E5A181C00A747DB /* ssl_config_service.h */, 7BED32920E5A181C00A747DB /* ssl_config_service_unittest.cc */, 7BED32910E5A181C00A747DB /* ssl_info.h */, - 07B79D480F4221D7001EA432 /* ssl_test_util.cc */, + 826F15760EE48CEA00D973C7 /* ssl_test_util.cc */, + 826F15750EE48CEA00D973C7 /* ssl_test_util.h */, 7BED328F0E5A181C00A747DB /* tcp_client_socket.h */, E47E933E0E8924DC00CA613E /* tcp_client_socket_libevent.cc */, 7BED328E0E5A181C00A747DB /* tcp_client_socket_unittest.cc */, @@ -1528,14 +1527,12 @@ 533102E70E5E3EBF00FF8E32 /* net_util_posix.cc in Sources */, 7B85043C0E5B2E6400730B43 /* platform_mime_util_mac.cc in Sources */, 820701040EB6611F005CD9E7 /* proxy_resolver_mac.cc in Sources */, - 043C23DB0EFC592900658F5E /* proxy_script_fetcher.cc in Sources */, E49DD3370E8933A2003C7A87 /* proxy_service.cc in Sources */, 7B85043D0E5B2E6400730B43 /* rankings.cc in Sources */, 7B8B5B560E5CEADE002F9A97 /* registry_controlled_domain.cc in Sources */, 7BA362B60E8C3D020023C8B9 /* sdch_filter.cc in Sources */, E49DD2EA0E892F8C003C7A87 /* sdch_manager.cc in Sources */, 8220FAFC0E915561008170A9 /* ssl_client_socket_mac.cc in Sources */, - 07B79D4A0F4221D7001EA432 /* ssl_test_util.cc in Sources */, 7B8504410E5B2E9600730B43 /* stats.cc in Sources */, DFEE18270E882E3600666107 /* stats_histogram.cc in Sources */, E47E933F0E8924DC00CA613E /* tcp_client_socket_libevent.cc in Sources */, @@ -1559,6 +1556,7 @@ 821F20A50E5CD414003C7E38 /* url_request_view_cache_job.cc in Sources */, 82113BBD0E892E5800E3848F /* x509_certificate.cc in Sources */, 827E139D0E81611D00183614 /* x509_certificate_mac.cc in Sources */, + 043C23DB0EFC592900658F5E /* proxy_script_fetcher.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1572,7 +1570,6 @@ 7BD8F70C0E65DCD800034DE9 /* block_files_unittest.cc in Sources */, 7BA015210E5A1B9800044150 /* bzip2_filter_unittest.cc in Sources */, 7B4DF64A0E5B98DF004D7619 /* client_socket_pool_unittest.cc in Sources */, - 07FE37F10F424D9F00049AB8 /* tcp_pinger_unittest.cc in Sources */, 7B8B5B530E5CEAC7002F9A97 /* cookie_monster_unittest.cc in Sources */, 7BA3614E0E8C347E0023C8B9 /* cookie_policy_unittest.cc in Sources */, 7B4DF6A90E5B98E7004D7619 /* data_url_unittest.cc in Sources */, @@ -1603,18 +1600,19 @@ 7B4DF9AC0E5C906A004D7619 /* mime_sniffer_unittest.cc in Sources */, 048268090E5B3B4800A30786 /* mime_util_unittest.cc in Sources */, BAA46E3B0E5CE99A00E77460 /* net_util_unittest.cc in Sources */, - 043C23D90EFC592000658F5E /* proxy_script_fetcher_unittest.cc in Sources */, 7BA361ED0E8C38D30023C8B9 /* proxy_service_unittest.cc in Sources */, 7B8B5B9E0E5D188E002F9A97 /* registry_controlled_domain_unittest.cc in Sources */, E4AFA6430E5241B400201347 /* run_all_unittests.cc in Sources */, 7BA362B70E8C3D040023C8B9 /* sdch_filter_unittest.cc in Sources */, 8220FABD0E914ACA008170A9 /* ssl_client_socket_unittest.cc in Sources */, + 826F15770EE48CEA00D973C7 /* ssl_test_util.cc in Sources */, 7BD8F7110E65DCF500034DE9 /* storage_block_unittest.cc in Sources */, E47E93430E8924EE00CA613E /* tcp_client_socket_unittest.cc in Sources */, A50055BF0EBF7CB2007B0A90 /* telnet_server_unittest.cc in Sources */, 7BA361450E8C341F0023C8B9 /* test_completion_callback_unittest.cc in Sources */, 048133550ED27FEF005C5BBC /* url_request_unittest.cc in Sources */, 82113A1D0E8434EE00E3848F /* x509_certificate_unittest.cc in Sources */, + 043C23D90EFC592000658F5E /* proxy_script_fetcher_unittest.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/net/net_unittests.scons b/net/net_unittests.scons index 05712ce..4f35414 100644 --- a/net/net_unittests.scons +++ b/net/net_unittests.scons @@ -76,7 +76,6 @@ input_files = ChromeFileList([ 'base/base64_unittest.cc', 'base/bzip2_filter_unittest.cc', 'base/client_socket_pool_unittest.cc', - 'base/tcp_pinger_unittest.cc', 'base/cookie_monster_unittest.cc', 'base/cookie_policy_unittest.cc', 'base/data_url_unittest.cc', diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index 4ab4285..21d1c72 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc @@ -180,14 +180,17 @@ TEST_F(URLRequestTest, GetTest) { } class HTTPSRequestTest : public testing::Test { + protected: + HTTPSRequestTest() : util_() {} + + SSLTestUtil util_; }; #if defined(OS_MACOSX) -// ssl_client_socket_mac.cc crashes currently in GetSSLInfo -// when called on a connection with an unrecognized certificate -#define MAYBE_HTTPSGetTest DISABLED_HTTPSGetTest +// TODO(port): support temporary root cert on mac +#define MAYBE_HTTPSGetTest DISABLED_HTTPSGetTest #else -#define MAYBE_HTTPSGetTest HTTPSGetTest +#define MAYBE_HTTPSGetTest HTTPSGetTest #endif TEST_F(HTTPSRequestTest, MAYBE_HTTPSGetTest) { @@ -196,9 +199,11 @@ TEST_F(HTTPSRequestTest, MAYBE_HTTPSGetTest) { // so this test doesn't really need to specify a document root. // But if it did, a good one would be net/data/ssl. scoped_refptr<HTTPSTestServer> server = - HTTPSTestServer::CreateGoodServer(L"net/data/ssl"); + HTTPSTestServer::CreateServer(util_.kHostName, util_.kOKHTTPSPort, + L"net/data/ssl", util_.GetOKCertPath().ToWStringHack()); ASSERT_TRUE(NULL != server.get()); + EXPECT_TRUE(util_.CheckCATrusted()); TestDelegate d; { TestURLRequest r(server->TestServerPage(""), &d); @@ -217,8 +222,6 @@ TEST_F(HTTPSRequestTest, MAYBE_HTTPSGetTest) { #endif } -// TODO(dkegel): add test for expired and mismatched certificates here - TEST_F(URLRequestTest, CancelTest) { TestDelegate d; { diff --git a/net/url_request/url_request_unittest.h b/net/url_request/url_request_unittest.h index e6f4da6..7107d50 100644 --- a/net/url_request/url_request_unittest.h +++ b/net/url_request/url_request_unittest.h @@ -13,7 +13,6 @@ #include "base/file_path.h" #include "base/file_util.h" -#include "base/logging.h" #include "base/message_loop.h" #include "base/path_service.h" #include "base/platform_thread.h" @@ -24,7 +23,6 @@ #include "base/waitable_event.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" -#include "net/base/ssl_test_util.h" #include "net/http/http_network_layer.h" #include "net/url_request/url_request.h" #include "net/proxy/proxy_service.h" @@ -212,9 +210,48 @@ class TestDelegate : public URLRequest::Delegate { // that can provide various responses useful for testing. class BaseTestServer : public base::RefCounted<BaseTestServer> { protected: - BaseTestServer() { } + BaseTestServer() + : process_handle_(NULL) { + } public: + virtual ~BaseTestServer() { + if (!IsFinished()) + if (!WaitToFinish(1000)) + Kill(); + } + + bool IsFinished() { + return WaitToFinish(0); + } + + void Kill() { + if (process_handle_) { +#if defined(OS_WIN) + base::KillProcess(process_handle_, 0, true); +#elif defined(OS_POSIX) + // Make sure the process has exited and clean up the process to avoid + // a zombie. + kill(process_handle_, SIGINT); + waitpid(process_handle_, 0, 0); +#endif + base::CloseProcessHandle(process_handle_); + process_handle_ = NULL; + } + } + + bool WaitToFinish(int milliseconds) { + if (process_handle_ == 0) + return true; + bool ret = base::WaitForSingleProcess(process_handle_, milliseconds); + if (ret) { + base::CloseProcessHandle(process_handle_); + process_handle_ = NULL; + } + + return ret; + } + GURL TestServerPage(const std::string& base_address, const std::string& path) { return GURL(base_address + path); @@ -228,50 +265,142 @@ class BaseTestServer : public base::RefCounted<BaseTestServer> { return GURL(base_address_ + WideToUTF8(path)); } - virtual bool MakeGETRequest(const std::string& page_name) = 0; + void SetPythonPaths() { +#if defined(OS_WIN) + // Set up PYTHONPATH so that Python is able to find the in-tree copy of + // pyftpdlib. + static bool set_python_path = false; + if (!set_python_path) { + FilePath pyftpdlib_path; + ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &pyftpdlib_path)); + pyftpdlib_path = pyftpdlib_path.Append(L"third_party"); + pyftpdlib_path = pyftpdlib_path.Append(L"pyftpdlib"); + + const wchar_t kPythonPath[] = L"PYTHONPATH"; + wchar_t python_path_c[1024]; + if (GetEnvironmentVariable(kPythonPath, python_path_c, 1023) > 0) { + // PYTHONPATH is already set, append to it. + std::wstring python_path(python_path_c); + python_path.append(L":"); + python_path.append(pyftpdlib_path.value()); + SetEnvironmentVariableW(kPythonPath, python_path.c_str()); + } else { + SetEnvironmentVariableW(kPythonPath, pyftpdlib_path.value().c_str()); + } - protected: - bool Start(net::TestServerLauncher::Protocol protocol, - const std::string& host_name, int port, - const FilePath& document_root, - const FilePath& cert_path) { - std::string blank; - return Start(protocol, host_name, port, document_root, cert_path, - blank, blank); - } - - bool Start(net::TestServerLauncher::Protocol protocol, - const std::string& host_name, int port, - const FilePath& document_root, - const FilePath& cert_path, - const std::string& url_user, - const std::string& url_password) { - if (!launcher_.Start(protocol, - host_name, port, document_root, cert_path)) - return false; + set_python_path = true; + } +#elif defined(OS_POSIX) + // Set up PYTHONPATH so that Python is able to find the in-tree copy of + // tlslite and pyftpdlib. + static bool set_python_path = false; + if (!set_python_path) { + FilePath tlslite_path; + FilePath pyftpdlib_path; + ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &tlslite_path)); + tlslite_path = tlslite_path.Append("third_party"); + tlslite_path = tlslite_path.Append("tlslite"); + + ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &pyftpdlib_path)); + pyftpdlib_path = pyftpdlib_path.Append("third_party"); + pyftpdlib_path = pyftpdlib_path.Append("pyftpdlib"); + + const char kPythonPath[] = "PYTHONPATH"; + char* python_path_c = getenv(kPythonPath); + if (python_path_c) { + // PYTHONPATH is already set, append to it. + std::string python_path(python_path_c); + python_path.append(":"); + python_path.append(tlslite_path.value()); + python_path.append(":"); + python_path.append(pyftpdlib_path.value()); + setenv(kPythonPath, python_path.c_str(), 1); + } else { + std::string python_path = tlslite_path.value().c_str(); + python_path.append(":"); + python_path.append(pyftpdlib_path.value()); + setenv(kPythonPath, python_path.c_str(), 1); + } + set_python_path = true; + } +#endif + } - std::string scheme; - if (protocol == net::TestServerLauncher::ProtoFTP) - scheme = "ftp"; - else - scheme = "http"; - if (!cert_path.empty()) - scheme.push_back('s'); - - std::string port_str = IntToString(port); - if (url_user.empty()) { - base_address_ = scheme + "://" + host_name + ":" + port_str + "/"; + void SetAppPath(const std::string& host_name, int port, + const std::wstring& document_root, const std::string& scheme, + std::wstring* testserver_path, std::wstring* test_data_directory) { + port_str_ = IntToString(port); + if (url_user_.empty()) { + base_address_ = scheme + "://" + host_name + ":" + port_str_ + "/"; } else { - if (url_password.empty()) - base_address_ = scheme + "://" + url_user + "@" + - host_name + ":" + port_str + "/"; + if (url_password_.empty()) + base_address_ = scheme + "://" + url_user_ + "@" + + host_name + ":" + port_str_ + "/"; else - base_address_ = scheme + "://" + url_user + ":" + url_password + - "@" + host_name + ":" + port_str + "/"; + base_address_ = scheme + "://" + url_user_ + ":" + url_password_ + + "@" + host_name + ":" + port_str_ + "/"; + } + + ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, testserver_path)); + file_util::AppendToPath(testserver_path, L"net"); + file_util::AppendToPath(testserver_path, L"tools"); + file_util::AppendToPath(testserver_path, L"testserver"); + file_util::AppendToPath(testserver_path, L"testserver.py"); + + ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &python_runtime_)); + file_util::AppendToPath(&python_runtime_, L"third_party"); + file_util::AppendToPath(&python_runtime_, L"python_24"); + file_util::AppendToPath(&python_runtime_, L"python.exe"); + + PathService::Get(base::DIR_SOURCE_ROOT, test_data_directory); + std::wstring normalized_document_root = document_root; + +#if defined(OS_WIN) + // It is just for windows only and have no effect on other OS + std::replace(normalized_document_root.begin(), + normalized_document_root.end(), + L'/', FilePath::kSeparators[0]); +#endif + if (!normalized_document_root.empty()) + file_util::AppendToPath(test_data_directory, normalized_document_root); + data_directory_ = *test_data_directory; + } + +#if defined(OS_WIN) + void LaunchApp(const std::wstring& command_line) { + ASSERT_TRUE(base::LaunchApp(command_line, false, true, &process_handle_)) << + "Failed to launch " << command_line; + } +#elif defined(OS_POSIX) + void LaunchApp(const std::vector<std::string>& command_line) { + base::file_handle_mapping_vector fds_empty; + ASSERT_TRUE(base::LaunchApp(command_line, fds_empty, false, + &process_handle_)) << + "Failed to launch " << command_line[0] << " ..."; + } +#endif + + virtual bool MakeGETRequest(const std::string& page_name) = 0; + + // Verify that the Server is actually started. + // Otherwise tests can fail if they run faster than Python can start. + bool VerifyLaunchApp(const std::string& page_name) { + int retries = 10; + bool success; + while ((success = MakeGETRequest(page_name)) == false && retries > 0) { + retries--; + PlatformThread::Sleep(500); } + if (!success) + return false; return true; } + std::wstring GetDataDirectory() { + return data_directory_; + } + + protected: // Used by MakeGETRequest to implement sync load behavior. class SyncTestDelegate : public TestDelegate { public: @@ -294,13 +423,18 @@ class BaseTestServer : public base::RefCounted<BaseTestServer> { bool success_; DISALLOW_COPY_AND_ASSIGN(SyncTestDelegate); }; - net::TestServerLauncher launcher_; + std::string host_name_; std::string base_address_; + std::string url_user_; + std::string url_password_; + std::wstring python_runtime_; + std::wstring data_directory_; + base::ProcessHandle process_handle_; + std::string port_str_; + }; - -// HTTP class HTTPTestServer : public BaseTestServer { protected: explicit HTTPTestServer() : loop_(NULL) { @@ -313,16 +447,37 @@ class HTTPTestServer : public BaseTestServer { MessageLoop* loop) { HTTPTestServer* test_server = new HTTPTestServer(); test_server->loop_ = loop; - FilePath no_cert; - FilePath docroot = FilePath::FromWStringHack(document_root); - if (!test_server->Start(net::TestServerLauncher::ProtoHTTP, - kDefaultHostName, kHTTPDefaultPort, docroot, no_cert)) { + if (!test_server->Init(kDefaultHostName, kHTTPDefaultPort, document_root)) { delete test_server; return NULL; } return test_server; } + bool Init(const std::string& host_name, int port, + const std::wstring& document_root) { + std::wstring testserver_path; + std::wstring test_data_directory; + host_name_ = host_name; +#if defined(OS_WIN) + std::wstring command_line; +#elif defined(OS_POSIX) + std::vector<std::string> command_line; +#endif + + // Set PYTHONPATH for tlslite and pyftpdlib + SetPythonPaths(); + SetAppPath(host_name, port, document_root, scheme(), + &testserver_path, &test_data_directory); + SetCommandLineOption(testserver_path, test_data_directory, &command_line); + LaunchApp(command_line); + if (!VerifyLaunchApp("hello.html")) { + LOG(ERROR) << "Webserver not starting properly"; + return false; + } + return true; + } + // A subclass may wish to send the request in a different manner virtual bool MakeGETRequest(const std::string& page_name) { const GURL& url = TestServerPage(page_name); @@ -361,8 +516,54 @@ class HTTPTestServer : public BaseTestServer { EXPECT_TRUE(request->is_pending()); } + virtual ~HTTPTestServer() { + Stop(); + } + + void Stop() { + if (IsFinished()) + return; + + // here we append the time to avoid problems where the kill page + // is being cached rather than being executed on the server + std::string page_name = StringPrintf("kill?%u", + static_cast<int>(base::Time::Now().ToInternalValue())); + int retry_count = 5; + while (retry_count > 0) { + bool r = MakeGETRequest(page_name); + // BUG #1048625 causes the kill GET to fail. For now we just retry. + // Once the bug is fixed, we should remove the while loop and put back + // the following DCHECK. + // DCHECK(r); + if (r) + break; + retry_count--; + } + // Make sure we were successfull in stopping the testserver. + DCHECK(retry_count > 0); + } + virtual std::string scheme() { return "http"; } +#if defined(OS_WIN) + virtual void SetCommandLineOption(const std::wstring& testserver_path, + const std::wstring& test_data_directory, + std::wstring* command_line ) { + command_line->append(L"\"" + python_runtime_ + L"\" " + L"\"" + + testserver_path + L"\" --port=" + UTF8ToWide(port_str_) + + L" --data-dir=\"" + test_data_directory + L"\""); + } +#elif defined(OS_POSIX) + virtual void SetCommandLineOption(const std::wstring& testserver_path, + const std::wstring& test_data_directory, + std::vector<std::string>* command_line) { + command_line->push_back("python"); + command_line->push_back(WideToUTF8(testserver_path)); + command_line->push_back("--port=" + port_str_); + command_line->push_back("--data-dir=" + WideToUTF8(test_data_directory)); + } +#endif + private: // If non-null a background thread isn't created and instead this message loop // is used. @@ -371,75 +572,51 @@ class HTTPTestServer : public BaseTestServer { class HTTPSTestServer : public HTTPTestServer { protected: - explicit HTTPSTestServer() { + explicit HTTPSTestServer(const std::wstring& cert_path) + : cert_path_(cert_path) { } public: - // Create a server with a valid certificate - // TODO(dkegel): HTTPSTestServer should not require an instance to specify - // stock test certificates - static HTTPSTestServer* CreateGoodServer(const std::wstring& document_root) { - HTTPSTestServer* test_server = new HTTPSTestServer(); - FilePath docroot = FilePath::FromWStringHack(document_root); - FilePath certpath = test_server->launcher_.GetOKCertPath(); - if (!test_server->Start(net::TestServerLauncher::ProtoHTTP, - net::TestServerLauncher::kHostName, - net::TestServerLauncher::kOKHTTPSPort, - docroot, certpath)) { - delete test_server; - return NULL; - } - return test_server; - } - - // Create a server with an up to date certificate for the wrong hostname - // for this host - static HTTPSTestServer* CreateMismatchedServer( - const std::wstring& document_root) { - HTTPSTestServer* test_server = new HTTPSTestServer(); - FilePath docroot = FilePath::FromWStringHack(document_root); - FilePath certpath = test_server->launcher_.GetOKCertPath(); - if (!test_server->Start(net::TestServerLauncher::ProtoHTTP, - net::TestServerLauncher::kMismatchedHostName, - net::TestServerLauncher::kOKHTTPSPort, - docroot, certpath)) { - delete test_server; - return NULL; - } - return test_server; - } - - // Create a server with an expired certificate - static HTTPSTestServer* CreateExpiredServer( - const std::wstring& document_root) { - HTTPSTestServer* test_server = new HTTPSTestServer(); - FilePath docroot = FilePath::FromWStringHack(document_root); - FilePath certpath = test_server->launcher_.GetExpiredCertPath(); - if (!test_server->Start(net::TestServerLauncher::ProtoHTTP, - net::TestServerLauncher::kHostName, - net::TestServerLauncher::kBadHTTPSPort, - docroot, certpath)) { - delete test_server; - return NULL; - } - return test_server; - } - - // Create a server with an arbitrary certificate static HTTPSTestServer* CreateServer(const std::string& host_name, int port, const std::wstring& document_root, const std::wstring& cert_path) { - HTTPSTestServer* test_server = new HTTPSTestServer(); - FilePath docroot = FilePath::FromWStringHack(document_root); - FilePath certpath = FilePath::FromWStringHack(cert_path); - if (!test_server->Start(net::TestServerLauncher::ProtoHTTP, - host_name, port, docroot, certpath)) { + HTTPSTestServer* test_server = new HTTPSTestServer(cert_path); + if (!test_server->Init(host_name, port, document_root)) { delete test_server; return NULL; } return test_server; } +#if defined(OS_WIN) + virtual void SetCommandLineOption(const std::wstring& testserver_path, + const std::wstring& test_data_directory, + std::wstring* command_line ) { + command_line->append(L"\"" + python_runtime_ + L"\" " + L"\"" + + testserver_path + L"\"" + L" --port=" + + UTF8ToWide(port_str_) + L" --data-dir=\"" + + test_data_directory + L"\""); + if (!cert_path_.empty()) { + command_line->append(L" --https=\""); + command_line->append(cert_path_); + command_line->append(L"\""); + } + } +#elif defined(OS_POSIX) + virtual void SetCommandLineOption(const std::wstring& testserver_path, + const std::wstring& test_data_directory, + std::vector<std::string>* command_line) { + command_line->push_back("python"); + command_line->push_back(WideToUTF8(testserver_path)); + command_line->push_back("--port=" + port_str_); + command_line->push_back("--data-dir=" + WideToUTF8(test_data_directory)); + if (!cert_path_.empty()) + command_line->push_back("--https=" + WideToUTF8(cert_path_)); +} +#endif + + virtual std::string scheme() { return "https"; } + virtual ~HTTPSTestServer() { } @@ -449,32 +626,88 @@ class HTTPSTestServer : public HTTPTestServer { class FTPTestServer : public BaseTestServer { - public: + protected: FTPTestServer() { } + public: + FTPTestServer(const std::string& url_user, const std::string& url_password) { + url_user_ = url_user; + url_password_ = url_password; + } + static FTPTestServer* CreateServer(const std::wstring& document_root) { - std::string blank; - return CreateServer(document_root, blank, blank); + FTPTestServer* test_server = new FTPTestServer(); + if (!test_server->Init(kDefaultHostName, kFTPDefaultPort, document_root)) { + delete test_server; + return NULL; + } + return test_server; } static FTPTestServer* CreateServer(const std::wstring& document_root, const std::string& url_user, const std::string& url_password) { - FTPTestServer* test_server = new FTPTestServer(); - FilePath docroot = FilePath::FromWStringHack(document_root); - FilePath no_cert; - if (!test_server->Start(net::TestServerLauncher::ProtoFTP, - kDefaultHostName, kFTPDefaultPort, docroot, no_cert, - url_user, url_password)) { + FTPTestServer* test_server = new FTPTestServer(url_user, url_password); + if (!test_server->Init(kDefaultHostName, kFTPDefaultPort, document_root)) { delete test_server; return NULL; } return test_server; } + bool Init(const std::string& host_name, int port, + const std::wstring& document_root) { + std::wstring testserver_path; + std::wstring test_data_directory; + host_name_ = host_name; + +#if defined(OS_WIN) + std::wstring command_line; +#elif defined(OS_POSIX) + std::vector<std::string> command_line; +#endif + + // Set PYTHONPATH for tlslite and pyftpdlib + SetPythonPaths(); + SetAppPath(kDefaultHostName, port, document_root, scheme(), + &testserver_path, &test_data_directory); + SetCommandLineOption(testserver_path, test_data_directory, &command_line); + LaunchApp(command_line); + if (!VerifyLaunchApp("/LICENSE")) { + LOG(ERROR) << "FTPServer not starting properly."; + return false; + } + return true; + } + + virtual ~FTPTestServer() { + Stop(); + } + + void Stop() { + if (IsFinished()) + return; + + const std::string base_address = scheme() + "://" + host_name_ + ":" + + port_str_ + "/"; + const GURL& url = TestServerPage(base_address, "kill"); + TestDelegate d; + URLRequest request(url, &d); + request.set_context(new TestURLRequestContext()); + request.set_method("GET"); + request.Start(); + EXPECT_TRUE(request.is_pending()); + + MessageLoop::current()->Run(); + } + + virtual std::string scheme() { return "ftp"; } + virtual bool MakeGETRequest(const std::string& page_name) { - const GURL& url = TestServerPage(base_address_, page_name); + const std::string base_address = scheme() + "://" + host_name_ + ":" + + port_str_ + "/"; + const GURL& url = TestServerPage(base_address, page_name); TestDelegate d; URLRequest request(url, &d); request.set_context(new TestURLRequestContext()); @@ -489,6 +722,26 @@ class FTPTestServer : public BaseTestServer { return true; } +#if defined(OS_WIN) + virtual void SetCommandLineOption(const std::wstring& testserver_path, + const std::wstring& test_data_directory, + std::wstring* command_line ) { + command_line->append(L"\"" + python_runtime_ + L"\" " + L"\"" + + testserver_path + L"\"" + L" -f " + L" --port=" + + UTF8ToWide(port_str_) + L" --data-dir=\"" + + test_data_directory + L"\""); + } +#elif defined(OS_POSIX) + virtual void SetCommandLineOption(const std::wstring& testserver_path, + const std::wstring& test_data_directory, + std::vector<std::string>* command_line) { + command_line->push_back("python"); + command_line->push_back(WideToUTF8(testserver_path)); + command_line->push_back(" -f "); + command_line->push_back("--data-dir=" + WideToUTF8(test_data_directory)); + command_line->push_back("--port=" + port_str_); + } +#endif }; #endif // NET_URL_REQUEST_URL_REQUEST_UNITTEST_H_ |