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 704211382cfacd554d24d096d7ac20c0ece152e2..ca2c3d0f320095908ec88c3f5c3f228d874e8f65 100644 |
| --- a/net/socket/ssl_client_socket_unittest.cc |
| +++ b/net/socket/ssl_client_socket_unittest.cc |
| @@ -300,10 +300,8 @@ int SynchronousErrorStreamSocket::Read( |
| net::IOBuffer* buf, |
| int buf_len, |
| const net::CompletionCallback& callback) { |
| - if (have_read_error_) { |
| - have_read_error_ = false; |
| + if (have_read_error_) |
| return pending_read_error_; |
| - } |
| return transport_->Read(buf, buf_len, callback); |
| } |
| @@ -311,10 +309,8 @@ int SynchronousErrorStreamSocket::Write( |
| net::IOBuffer* buf, |
| int buf_len, |
| const net::CompletionCallback& callback) { |
| - if (have_write_error_) { |
| - have_write_error_ = false; |
| + if (have_write_error_) |
| return pending_write_error_; |
| - } |
| return transport_->Write(buf, buf_len, callback); |
| } |
| @@ -924,6 +920,85 @@ TEST_F(SSLClientSocketTest, Read_WithSynchronousError) { |
| #endif |
| } |
| +// Tests that the SSLClientSocket properly handles when the underlying transport |
| +// synchronously returns an error code - such as if an intermediary terminates |
| +// the socket connection uncleanly. |
| +// This is a regression test for http://crbug.com/249848 |
| +TEST_F(SSLClientSocketTest, Write_WithSynchronousError) { |
| + net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTPS, |
| + net::SpawnedTestServer::kLocalhost, |
| + base::FilePath()); |
| + ASSERT_TRUE(test_server.Start()); |
| + |
| + net::AddressList addr; |
| + ASSERT_TRUE(test_server.GetAddressList(&addr)); |
| + |
| + net::TestCompletionCallback callback; |
| + scoped_ptr<net::StreamSocket> real_transport(new net::TCPClientSocket( |
| + addr, NULL, net::NetLog::Source())); |
| + // Note: |error_socket|'s ownership is handed to |transport|, but the pointer |
| + // is retained in order to configure additional errors. |
| + SynchronousErrorStreamSocket* error_socket = new SynchronousErrorStreamSocket( |
| + real_transport.Pass()); |
| + FakeBlockingStreamSocket* transport = new FakeBlockingStreamSocket( |
| + scoped_ptr<net::StreamSocket>(error_socket)); |
| + int rv = callback.GetResult(transport->Connect(callback.callback())); |
| + EXPECT_EQ(net::OK, rv); |
| + |
| + // Disable TLS False Start to avoid handshake non-determinism. |
| + net::SSLConfig ssl_config; |
| + ssl_config.false_start_enabled = false; |
| + |
| + scoped_ptr<net::SSLClientSocket> sock( |
| + CreateSSLClientSocket(transport, test_server.host_port_pair(), |
| + ssl_config)); |
| + |
| + rv = callback.GetResult(sock->Connect(callback.callback())); |
| + EXPECT_EQ(net::OK, rv); |
| + EXPECT_TRUE(sock->IsConnected()); |
| + |
| + const char request_text[] = "GET / HTTP/1.0\r\n\r\n"; |
| + static const int kRequestTextSize = |
| + static_cast<int>(arraysize(request_text) - 1); |
| + scoped_refptr<net::IOBuffer> request_buffer( |
| + new net::IOBuffer(kRequestTextSize)); |
| + memcpy(request_buffer->data(), request_text, kRequestTextSize); |
| + |
| + // Simulate an unclean/forcible shutdown on the underlying socket. |
| + // However, simulate this error asynchronously. |
| + error_socket->SetNextWriteError(net::ERR_CONNECTION_RESET); |
| + transport->SetNextWriteShouldBlock(); |
| + |
| + // This write should complete synchronously, because the TLS ciphertext |
| + // can be created and placed into the outgoing buffers independent of the |
| + // underlying transport. |
| + rv = callback.GetResult( |
| + sock->Write(request_buffer.get(), kRequestTextSize, callback.callback())); |
| + EXPECT_EQ(kRequestTextSize, rv); |
| + |
| + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(4096)); |
| + |
| + rv = sock->Read(buf.get(), 4096, callback.callback()); |
| + EXPECT_EQ(net::ERR_IO_PENDING, rv); |
| + |
| + // Now unblock the outgoing request, having it fail with the connection |
| + // being reset. |
| + transport->UnblockWrite(); |
| + |
| + // Note: This will hang if this bug has regressed. Simply checking that |
|
wtc
2013/06/14 21:45:07
"Hang" usually implies an idle wait. This bug is a
|
| + // rv != ERR_IO_PENDING is insufficient, as ERR_IO_PENDING is a legitimate |
| + // result when using a dedicated task runner for NSS. |
| + rv = callback.GetResult(rv); |
| + |
| +#if !defined(USE_OPENSSL) |
| + // NSS records the error exactly |
| + EXPECT_EQ(net::ERR_CONNECTION_RESET, rv); |
| +#else |
| + // OpenSSL treats any errors as a simple EOF. |
|
wtc
2013/06/14 21:45:07
These comments are actually referring to SSLClient
|
| + EXPECT_EQ(0, rv); |
| +#endif |
| +} |
| + |
| // Test the full duplex mode, with Read and Write pending at the same time. |
| // This test also serves as a regression test for http://crbug.com/29815. |
| TEST_F(SSLClientSocketTest, Read_FullDuplex) { |