Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(12)

Side by Side Diff: net/socket/ssl_client_socket_unittest.cc

Issue 17105003: Gracefully handle an asynchronous write disconnect when an SSL read is pending (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Comment updates Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/base/nss_memio.c ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/socket/ssl_client_socket.h" 5 #include "net/socket/ssl_client_socket.h"
6 6
7 #include "base/callback_helpers.h" 7 #include "base/callback_helpers.h"
8 #include "base/memory/ref_counted.h" 8 #include "base/memory/ref_counted.h"
9 #include "net/base/address_list.h" 9 #include "net/base/address_list.h"
10 #include "net/base/io_buffer.h" 10 #include "net/base/io_buffer.h"
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after
250 public: 250 public:
251 explicit SynchronousErrorStreamSocket(scoped_ptr<StreamSocket> transport); 251 explicit SynchronousErrorStreamSocket(scoped_ptr<StreamSocket> transport);
252 virtual ~SynchronousErrorStreamSocket() {} 252 virtual ~SynchronousErrorStreamSocket() {}
253 253
254 // Socket implementation: 254 // Socket implementation:
255 virtual int Read(net::IOBuffer* buf, int buf_len, 255 virtual int Read(net::IOBuffer* buf, int buf_len,
256 const net::CompletionCallback& callback) OVERRIDE; 256 const net::CompletionCallback& callback) OVERRIDE;
257 virtual int Write(net::IOBuffer* buf, int buf_len, 257 virtual int Write(net::IOBuffer* buf, int buf_len,
258 const net::CompletionCallback& callback) OVERRIDE; 258 const net::CompletionCallback& callback) OVERRIDE;
259 259
260 // Sets the the next Read() call to return |error|. 260 // Sets the next Read() call and all future calls to return |error|.
261 // If there is already a pending asynchronous read, the configured error 261 // If there is already a pending asynchronous read, the configured error
262 // will not be returned until that asynchronous read has completed and Read() 262 // will not be returned until that asynchronous read has completed and Read()
263 // is called again. 263 // is called again.
264 void SetNextReadError(net::Error error) { 264 void SetNextReadError(net::Error error) {
265 DCHECK_GE(0, error); 265 DCHECK_GE(0, error);
266 have_read_error_ = true; 266 have_read_error_ = true;
267 pending_read_error_ = error; 267 pending_read_error_ = error;
268 } 268 }
269 269
270 // Sets the the next Write() call to return |error|. 270 // Sets the next Write() call and all future calls to return |error|.
271 // If there is already a pending asynchronous write, the configured error 271 // If there is already a pending asynchronous write, the configured error
272 // will not be returned until that asynchronous write has completed and 272 // will not be returned until that asynchronous write has completed and
273 // Write() is called again. 273 // Write() is called again.
274 void SetNextWriteError(net::Error error) { 274 void SetNextWriteError(net::Error error) {
275 DCHECK_GE(0, error); 275 DCHECK_GE(0, error);
276 have_write_error_ = true; 276 have_write_error_ = true;
277 pending_write_error_ = error; 277 pending_write_error_ = error;
278 } 278 }
279 279
280 private: 280 private:
(...skipping 12 matching lines...) Expand all
293 have_read_error_(false), 293 have_read_error_(false),
294 pending_read_error_(net::OK), 294 pending_read_error_(net::OK),
295 have_write_error_(false), 295 have_write_error_(false),
296 pending_write_error_(net::OK) { 296 pending_write_error_(net::OK) {
297 } 297 }
298 298
299 int SynchronousErrorStreamSocket::Read( 299 int SynchronousErrorStreamSocket::Read(
300 net::IOBuffer* buf, 300 net::IOBuffer* buf,
301 int buf_len, 301 int buf_len,
302 const net::CompletionCallback& callback) { 302 const net::CompletionCallback& callback) {
303 if (have_read_error_) { 303 if (have_read_error_)
304 have_read_error_ = false;
305 return pending_read_error_; 304 return pending_read_error_;
306 }
307 return transport_->Read(buf, buf_len, callback); 305 return transport_->Read(buf, buf_len, callback);
308 } 306 }
309 307
310 int SynchronousErrorStreamSocket::Write( 308 int SynchronousErrorStreamSocket::Write(
311 net::IOBuffer* buf, 309 net::IOBuffer* buf,
312 int buf_len, 310 int buf_len,
313 const net::CompletionCallback& callback) { 311 const net::CompletionCallback& callback) {
314 if (have_write_error_) { 312 if (have_write_error_)
315 have_write_error_ = false;
316 return pending_write_error_; 313 return pending_write_error_;
317 }
318 return transport_->Write(buf, buf_len, callback); 314 return transport_->Write(buf, buf_len, callback);
319 } 315 }
320 316
321 // FakeBlockingStreamSocket wraps an existing StreamSocket and simulates the 317 // FakeBlockingStreamSocket wraps an existing StreamSocket and simulates the
322 // underlying transport needing to complete things asynchronously in a 318 // underlying transport needing to complete things asynchronously in a
323 // deterministic manner (e.g.: independent of the TestServer and the OS's 319 // deterministic manner (e.g.: independent of the TestServer and the OS's
324 // semantics). 320 // semantics).
325 class FakeBlockingStreamSocket : public WrappedStreamSocket { 321 class FakeBlockingStreamSocket : public WrappedStreamSocket {
326 public: 322 public:
327 explicit FakeBlockingStreamSocket(scoped_ptr<StreamSocket> transport); 323 explicit FakeBlockingStreamSocket(scoped_ptr<StreamSocket> transport);
(...skipping 581 matching lines...) Expand 10 before | Expand all | Expand 10 after
909 transport->SetNextReadError(net::ERR_CONNECTION_RESET); 905 transport->SetNextReadError(net::ERR_CONNECTION_RESET);
910 906
911 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(4096)); 907 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(4096));
912 908
913 // Note: This test will hang if this bug has regressed. Simply checking that 909 // Note: This test will hang if this bug has regressed. Simply checking that
914 // rv != ERR_IO_PENDING is insufficient, as ERR_IO_PENDING is a legitimate 910 // rv != ERR_IO_PENDING is insufficient, as ERR_IO_PENDING is a legitimate
915 // result when using a dedicated task runner for NSS. 911 // result when using a dedicated task runner for NSS.
916 rv = callback.GetResult(sock->Read(buf.get(), 4096, callback.callback())); 912 rv = callback.GetResult(sock->Read(buf.get(), 4096, callback.callback()));
917 913
918 #if !defined(USE_OPENSSL) 914 #if !defined(USE_OPENSSL)
919 // NSS records the error exactly 915 // SSLClientSocketNSS records the error exactly
920 EXPECT_EQ(net::ERR_CONNECTION_RESET, rv); 916 EXPECT_EQ(net::ERR_CONNECTION_RESET, rv);
921 #else 917 #else
922 // OpenSSL treats any errors as a simple EOF. 918 // SSLClientSocketOpenSSL treats any errors as a simple EOF.
923 EXPECT_EQ(0, rv); 919 EXPECT_EQ(0, rv);
924 #endif 920 #endif
925 } 921 }
922
923 // Tests that the SSLClientSocket properly handles when the underlying transport
924 // asynchronously returns an error code while writing data - such as if an
925 // intermediary terminates the socket connection uncleanly.
926 // This is a regression test for http://crbug.com/249848
927 TEST_F(SSLClientSocketTest, Write_WithSynchronousError) {
928 net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTPS,
929 net::SpawnedTestServer::kLocalhost,
930 base::FilePath());
931 ASSERT_TRUE(test_server.Start());
932
933 net::AddressList addr;
934 ASSERT_TRUE(test_server.GetAddressList(&addr));
935
936 net::TestCompletionCallback callback;
937 scoped_ptr<net::StreamSocket> real_transport(new net::TCPClientSocket(
938 addr, NULL, net::NetLog::Source()));
939 // Note: |error_socket|'s ownership is handed to |transport|, but the pointer
940 // is retained in order to configure additional errors.
941 SynchronousErrorStreamSocket* error_socket = new SynchronousErrorStreamSocket(
942 real_transport.Pass());
943 FakeBlockingStreamSocket* transport = new FakeBlockingStreamSocket(
944 scoped_ptr<net::StreamSocket>(error_socket));
945 int rv = callback.GetResult(transport->Connect(callback.callback()));
946 EXPECT_EQ(net::OK, rv);
947
948 // Disable TLS False Start to avoid handshake non-determinism.
949 net::SSLConfig ssl_config;
950 ssl_config.false_start_enabled = false;
951
952 scoped_ptr<net::SSLClientSocket> sock(
953 CreateSSLClientSocket(transport, test_server.host_port_pair(),
954 ssl_config));
955
956 rv = callback.GetResult(sock->Connect(callback.callback()));
957 EXPECT_EQ(net::OK, rv);
958 EXPECT_TRUE(sock->IsConnected());
959
960 const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
961 static const int kRequestTextSize =
962 static_cast<int>(arraysize(request_text) - 1);
963 scoped_refptr<net::IOBuffer> request_buffer(
964 new net::IOBuffer(kRequestTextSize));
965 memcpy(request_buffer->data(), request_text, kRequestTextSize);
966
967 // Simulate an unclean/forcible shutdown on the underlying socket.
968 // However, simulate this error asynchronously.
969 error_socket->SetNextWriteError(net::ERR_CONNECTION_RESET);
970 transport->SetNextWriteShouldBlock();
971
972 // This write should complete synchronously, because the TLS ciphertext
973 // can be created and placed into the outgoing buffers independent of the
974 // underlying transport.
975 rv = callback.GetResult(
976 sock->Write(request_buffer.get(), kRequestTextSize, callback.callback()));
977 EXPECT_EQ(kRequestTextSize, rv);
978
979 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(4096));
980
981 rv = sock->Read(buf.get(), 4096, callback.callback());
982 EXPECT_EQ(net::ERR_IO_PENDING, rv);
983
984 // Now unblock the outgoing request, having it fail with the connection
985 // being reset.
986 transport->UnblockWrite();
987
988 // Note: This will cause an inifite loop if this bug has regressed. Simply
989 // checking that rv != ERR_IO_PENDING is insufficient, as ERR_IO_PENDING
990 // is a legitimate result when using a dedicated task runner for NSS.
991 rv = callback.GetResult(rv);
992
993 #if !defined(USE_OPENSSL)
994 // SSLClientSocketNSS records the error exactly
995 EXPECT_EQ(net::ERR_CONNECTION_RESET, rv);
996 #else
997 // SSLClientSocketOpenSSL treats any errors as a simple EOF.
998 EXPECT_EQ(0, rv);
999 #endif
1000 }
926 1001
927 // Test the full duplex mode, with Read and Write pending at the same time. 1002 // Test the full duplex mode, with Read and Write pending at the same time.
928 // This test also serves as a regression test for http://crbug.com/29815. 1003 // This test also serves as a regression test for http://crbug.com/29815.
929 TEST_F(SSLClientSocketTest, Read_FullDuplex) { 1004 TEST_F(SSLClientSocketTest, Read_FullDuplex) {
930 net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTPS, 1005 net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTPS,
931 net::SpawnedTestServer::kLocalhost, 1006 net::SpawnedTestServer::kLocalhost,
932 base::FilePath()); 1007 base::FilePath());
933 ASSERT_TRUE(test_server.Start()); 1008 ASSERT_TRUE(test_server.Start());
934 1009
935 net::AddressList addr; 1010 net::AddressList addr;
(...skipping 804 matching lines...) Expand 10 before | Expand all | Expand 10 after
1740 scoped_refptr<net::SSLCertRequestInfo> request_info = 1815 scoped_refptr<net::SSLCertRequestInfo> request_info =
1741 GetCertRequest(ssl_options); 1816 GetCertRequest(ssl_options);
1742 ASSERT_TRUE(request_info.get()); 1817 ASSERT_TRUE(request_info.get());
1743 ASSERT_EQ(2u, request_info->cert_authorities.size()); 1818 ASSERT_EQ(2u, request_info->cert_authorities.size());
1744 EXPECT_EQ(std::string(reinterpret_cast<const char*>(kThawteDN), kThawteLen), 1819 EXPECT_EQ(std::string(reinterpret_cast<const char*>(kThawteDN), kThawteLen),
1745 request_info->cert_authorities[0]); 1820 request_info->cert_authorities[0]);
1746 EXPECT_EQ( 1821 EXPECT_EQ(
1747 std::string(reinterpret_cast<const char*>(kDiginotarDN), kDiginotarLen), 1822 std::string(reinterpret_cast<const char*>(kDiginotarDN), kDiginotarLen),
1748 request_info->cert_authorities[1]); 1823 request_info->cert_authorities[1]);
1749 } 1824 }
OLDNEW
« no previous file with comments | « net/base/nss_memio.c ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698