Chromium Code Reviews| Index: net/socket/ssl_client_socket_unittest.cc |
| diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc |
| index 2639870e81f36f4fefef5ad4626ced9bc629da13..ccb41fdac4736876576098dec454f18dc578c893 100644 |
| --- a/net/socket/ssl_client_socket_unittest.cc |
| +++ b/net/socket/ssl_client_socket_unittest.cc |
| @@ -599,9 +599,7 @@ class SSLClientSocketTest : public PlatformTest { |
| } |
| protected: |
| - // Sets up a TCP connection to a HTTPS server. To actually do the SSL |
| - // handshake, follow up with call to CreateAndConnectSSLClientSocket() below. |
| - bool ConnectToTestServer(SpawnedTestServer::SSLOptions& ssl_options) { |
| + bool StartTestServer(const SpawnedTestServer::SSLOptions& ssl_options) { |
| test_server_.reset(new SpawnedTestServer( |
| SpawnedTestServer::TYPE_HTTPS, ssl_options, base::FilePath())); |
| if (!test_server_->Start()) { |
| @@ -613,6 +611,14 @@ class SSLClientSocketTest : public PlatformTest { |
| LOG(ERROR) << "Could not get SpawnedTestServer address list"; |
| return false; |
| } |
| + return true; |
| + } |
| + |
| + // Sets up a TCP connection to a HTTPS server. To actually do the SSL |
| + // handshake, follow up with call to CreateAndConnectSSLClientSocket() below. |
| + bool ConnectToTestServer(const SpawnedTestServer::SSLOptions& ssl_options) { |
| + if (!StartTestServer(ssl_options)) |
| + return false; |
| transport_.reset(new TCPClientSocket(addr_, &log_, NetLog::Source())); |
| int rv = callback_.GetResult(transport_->Connect(callback_.callback())); |
| @@ -660,12 +666,12 @@ class SSLClientSocketTest : public PlatformTest { |
| SSLClientSocketContext context_; |
| scoped_ptr<SSLClientSocket> sock_; |
| CapturingNetLog log_; |
| + AddressList addr_; |
| + scoped_ptr<SpawnedTestServer> test_server_; |
|
Ryan Sleevi
2014/06/02 20:52:45
You don't actually need to expose these as protect
davidben
2014/06/03 19:02:47
Done.
|
| private: |
| scoped_ptr<StreamSocket> transport_; |
| - scoped_ptr<SpawnedTestServer> test_server_; |
| TestCompletionCallback callback_; |
| - AddressList addr_; |
| }; |
| // Verifies the correctness of GetSSLCertRequestInfo. |
| @@ -713,58 +719,82 @@ class SSLClientSocketCertRequestInfoTest : public SSLClientSocketTest { |
| class SSLClientSocketFalseStartTest : public SSLClientSocketTest { |
| protected: |
| - void TestFalseStart(const SpawnedTestServer::SSLOptions& server_options, |
| - const SSLConfig& client_config, |
| - bool expect_false_start) { |
| - SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS, |
| - server_options, |
| - base::FilePath()); |
| - ASSERT_TRUE(test_server.Start()); |
| - |
| - AddressList addr; |
| - ASSERT_TRUE(test_server.GetAddressList(&addr)); |
| + // Creates an SSLClientSocket with |client_config| attached to a |
| + // FakeBlockingStreamSocket, returning both in |*out_raw_transport| and |
| + // |*out_sock|. The FakeBlockingStreamSocket is owned by the SSLClientSocket, |
| + // so |*out_raw_transport| is a raw pointer. |
| + // |
| + // The client socket will begin a connect using |callback| but |
| + // stop before the server's finished message is received. The finished message |
| + // will be blocked in |*out_raw_transport|. |
| + // |
| + // If the client successfully false started with the server, |
| + // |callback.WaitForResult()| will return OK without unblocking transport |
| + // reads. |
| + // |
| + // Must be called after StartTestServer is called. |
|
Ryan Sleevi
2014/06/02 20:52:45
I'm guessing to continue the handshake, the caller
davidben
2014/06/03 19:02:47
Done.
|
| + void CreateAndConnectUntilServerFinishedReceived( |
| + const SSLConfig& client_config, |
| + TestCompletionCallback* callback, |
| + FakeBlockingStreamSocket** out_raw_transport, |
| + scoped_ptr<SSLClientSocket>* out_sock) { |
| + CHECK(test_server_); |
| - TestCompletionCallback callback; |
| scoped_ptr<StreamSocket> real_transport( |
| - new TCPClientSocket(addr, NULL, NetLog::Source())); |
| + new TCPClientSocket(addr_, NULL, NetLog::Source())); |
| scoped_ptr<FakeBlockingStreamSocket> transport( |
| new FakeBlockingStreamSocket(real_transport.Pass())); |
| - int rv = callback.GetResult(transport->Connect(callback.callback())); |
| + int rv = callback->GetResult(transport->Connect(callback->callback())); |
| EXPECT_EQ(OK, rv); |
| FakeBlockingStreamSocket* raw_transport = transport.get(); |
| - scoped_ptr<SSLClientSocket> sock( |
| + scoped_ptr<SSLClientSocket> sock = |
| CreateSSLClientSocket(transport.PassAs<StreamSocket>(), |
| - test_server.host_port_pair(), |
| - client_config)); |
| + test_server_->host_port_pair(), |
| + client_config); |
| // Connect. Stop before the client processes the first server leg |
| // (ServerHello, etc.) |
| raw_transport->BlockReadResult(); |
| - rv = sock->Connect(callback.callback()); |
| + rv = sock->Connect(callback->callback()); |
| EXPECT_EQ(ERR_IO_PENDING, rv); |
| raw_transport->WaitForReadResult(); |
| // Release the ServerHello and wait for the client to write |
| // ClientKeyExchange, etc. (A proxy for waiting for the entirety of the |
| // server's leg to complete, since it may span multiple reads.) |
| - EXPECT_FALSE(callback.have_result()); |
| + EXPECT_FALSE(callback->have_result()); |
| raw_transport->BlockWrite(); |
| raw_transport->UnblockReadResult(); |
| raw_transport->WaitForWrite(); |
| // And, finally, release that and block the next server leg |
| - // (ChangeCipherSpec, Finished). Note: callback.have_result() may or may not |
| - // be true at this point depending on whether the SSL implementation waits |
| - // for the client second leg to clear the internal write buffer and hit the |
| - // network. |
| + // (ChangeCipherSpec, Finished). Note: callback->have_result() may or may |
| + // not be true at this point depending on whether the SSL implementation |
| + // waits for the client second leg to clear the internal write buffer and |
| + // hit the network. |
| raw_transport->BlockReadResult(); |
| raw_transport->UnblockWrite(); |
| + *out_raw_transport = raw_transport; |
| + *out_sock = sock.Pass(); |
| + } |
| + |
| + void TestFalseStart(const SpawnedTestServer::SSLOptions& server_options, |
| + const SSLConfig& client_config, |
| + bool expect_false_start) { |
| + ASSERT_TRUE(StartTestServer(server_options)); |
| + |
| + TestCompletionCallback callback; |
| + FakeBlockingStreamSocket* raw_transport; |
| + scoped_ptr<SSLClientSocket> sock; |
| + ASSERT_NO_FATAL_FAILURE(CreateAndConnectUntilServerFinishedReceived( |
| + client_config, &callback, &raw_transport, &sock)); |
| + |
| if (expect_false_start) { |
| // When False Starting, the handshake should complete before receiving the |
| // Change Cipher Spec and Finished messages. |
| - rv = callback.GetResult(rv); |
| + int rv = callback.WaitForResult(); |
|
Ryan Sleevi
2014/06/02 20:52:45
Should you first ASSERT_TRUE(callback.have_result(
davidben
2014/06/03 19:02:47
It didn't end up being true for NSS. There's a com
|
| EXPECT_EQ(OK, rv); |
| EXPECT_TRUE(sock->IsConnected()); |
| @@ -2458,7 +2488,8 @@ TEST_F(SSLClientSocketFalseStartTest, FalseStartEnabled) { |
| server_options.enable_npn = true; |
| SSLConfig client_config; |
| client_config.next_protos.push_back("http/1.1"); |
| - TestFalseStart(server_options, client_config, true); |
| + ASSERT_NO_FATAL_FAILURE( |
| + TestFalseStart(server_options, client_config, true)); |
| } |
| // Test that False Start is disabled without NPN. |
| @@ -2468,7 +2499,8 @@ TEST_F(SSLClientSocketFalseStartTest, NoNPN) { |
| SpawnedTestServer::SSLOptions::KEY_EXCHANGE_DHE_RSA; |
| SSLConfig client_config; |
| client_config.next_protos.clear(); |
| - TestFalseStart(server_options, client_config, false); |
| + ASSERT_NO_FATAL_FAILURE( |
| + TestFalseStart(server_options, client_config, false)); |
| } |
| // Test that False Start is disabled without a forward-secret cipher suite. |
| @@ -2479,7 +2511,79 @@ TEST_F(SSLClientSocketFalseStartTest, NoForwardSecrecy) { |
| server_options.enable_npn = true; |
| SSLConfig client_config; |
| client_config.next_protos.push_back("http/1.1"); |
| - TestFalseStart(server_options, client_config, false); |
| + ASSERT_NO_FATAL_FAILURE( |
| + TestFalseStart(server_options, client_config, false)); |
| +} |
| + |
| +// Test that sessions are resumable after receiving the server Finished message. |
| +TEST_F(SSLClientSocketFalseStartTest, SessionResumption) { |
| + // Start a server. |
| + SpawnedTestServer::SSLOptions server_options; |
| + server_options.key_exchanges = |
| + SpawnedTestServer::SSLOptions::KEY_EXCHANGE_DHE_RSA; |
| + server_options.enable_npn = true; |
| + SSLConfig client_config; |
| + client_config.next_protos.push_back("http/1.1"); |
| + |
| + // Let a full handshake complete with False Start. |
| + ASSERT_NO_FATAL_FAILURE( |
| + TestFalseStart(server_options, client_config, true)); |
| + |
| + // Make a second connection. |
| + TestCompletionCallback callback; |
| + scoped_ptr<StreamSocket> transport2( |
| + new TCPClientSocket(addr_, &log_, NetLog::Source())); |
| + EXPECT_EQ(OK, callback.GetResult(transport2->Connect(callback.callback()))); |
| + scoped_ptr<SSLClientSocket> sock2 = CreateSSLClientSocket( |
| + transport2.Pass(), test_server_->host_port_pair(), client_config); |
| + EXPECT_EQ(OK, callback.GetResult(sock2->Connect(callback.callback()))); |
|
Ryan Sleevi
2014/06/02 20:52:45
ASSERT_TRUE(sock2.get())?
davidben
2014/06/03 19:02:47
Done.
|
| + |
| + // It should resume the session. |
| + SSLInfo ssl_info; |
| + EXPECT_TRUE(sock2->GetSSLInfo(&ssl_info)); |
| + EXPECT_EQ(SSLInfo::HANDSHAKE_RESUME, ssl_info.handshake_type); |
| +} |
| + |
| +// Test that sessions are not resumable before receiving the server Finished |
| +// message. |
| +TEST_F(SSLClientSocketFalseStartTest, NoSessionResumptionBeforeFinish) { |
| + // Start a server. |
| + SpawnedTestServer::SSLOptions server_options; |
| + server_options.key_exchanges = |
| + SpawnedTestServer::SSLOptions::KEY_EXCHANGE_DHE_RSA; |
| + server_options.enable_npn = true; |
| + ASSERT_TRUE(StartTestServer(server_options)); |
| + |
| + SSLConfig client_config; |
| + client_config.next_protos.push_back("http/1.1"); |
| + |
| + // Start a handshake up to the server Finished message. |
| + TestCompletionCallback callback; |
| + FakeBlockingStreamSocket* raw_transport1; |
| + scoped_ptr<SSLClientSocket> sock1; |
| + ASSERT_NO_FATAL_FAILURE(CreateAndConnectUntilServerFinishedReceived( |
| + client_config, &callback, &raw_transport1, &sock1)); |
| + // Although raw_transport1 has the server Finished blocked, the handshake |
| + // still completes. |
| + EXPECT_EQ(OK, callback.WaitForResult()); |
|
Ryan Sleevi
2014/06/02 20:52:45
Is this meant to be testing false starting worked?
davidben
2014/06/03 19:02:47
More just for waiting for the connect callback to
|
| + |
| + // Drop the old socket. This is needed because the Python test server can't |
| + // service two sockets in parallel. |
| + sock1.reset(); |
| + |
| + // Start a second connection. |
| + scoped_ptr<StreamSocket> transport2( |
| + new TCPClientSocket(addr_, &log_, NetLog::Source())); |
| + EXPECT_EQ(OK, callback.GetResult(transport2->Connect(callback.callback()))); |
| + scoped_ptr<SSLClientSocket> sock2 = CreateSSLClientSocket( |
| + transport2.Pass(), test_server_->host_port_pair(), client_config); |
| + EXPECT_EQ(OK, callback.GetResult(sock2->Connect(callback.callback()))); |
| + |
| + // No session resumption because the first connection never received a server |
| + // Finished message. |
| + SSLInfo ssl_info; |
| + EXPECT_TRUE(sock2->GetSSLInfo(&ssl_info)); |
| + EXPECT_EQ(SSLInfo::HANDSHAKE_FULL, ssl_info.handshake_type); |
| } |
| // Connect to a server using channel id. It should allow the connection. |