diff options
-rw-r--r-- | net/spdy/spdy_proxy_client_socket.cc | 7 | ||||
-rw-r--r-- | net/spdy/spdy_proxy_client_socket.h | 3 | ||||
-rw-r--r-- | net/spdy/spdy_proxy_client_socket_unittest.cc | 95 |
3 files changed, 103 insertions, 2 deletions
diff --git a/net/spdy/spdy_proxy_client_socket.cc b/net/spdy/spdy_proxy_client_socket.cc index 6ef88e7..484be0c 100644 --- a/net/spdy/spdy_proxy_client_socket.cc +++ b/net/spdy/spdy_proxy_client_socket.cc @@ -45,6 +45,7 @@ SpdyProxyClientSocket::SpdyProxyClientSocket( write_buffer_len_(0), write_bytes_outstanding_(0), eof_has_been_read_(false), + ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), net_log_(spdy_stream->net_log()) { request_.method = "CONNECT"; request_.url = url; @@ -516,6 +517,7 @@ void SpdyProxyClientSocket::OnClose(int status) { else next_state_ = STATE_DISCONNECTED; + base::WeakPtr<SpdyProxyClientSocket> weak_ptr = weak_factory_.GetWeakPtr(); OldCompletionCallback* write_callback = write_callback_; write_callback_ = NULL; write_buffer_len_ = 0; @@ -529,10 +531,11 @@ void SpdyProxyClientSocket::OnClose(int status) { read_callback_ = NULL; read_callback->Run(status); } else if (read_callback_) { - // If we have a read_callback, the we need to make sure we call it back + // If we have a read_callback_, the we need to make sure we call it back. OnDataReceived(NULL, 0); } - if (write_callback) + // This may have been deleted by read_callback_, so check first. + if (weak_ptr && write_callback) write_callback->Run(ERR_CONNECTION_CLOSED); } diff --git a/net/spdy/spdy_proxy_client_socket.h b/net/spdy/spdy_proxy_client_socket.h index 9875a05..24d19dd 100644 --- a/net/spdy/spdy_proxy_client_socket.h +++ b/net/spdy/spdy_proxy_client_socket.h @@ -11,6 +11,7 @@ #include "base/basictypes.h" #include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" #include "net/base/completion_callback.h" #include "net/base/host_port_pair.h" #include "net/base/net_log.h" @@ -160,6 +161,8 @@ class NET_EXPORT_PRIVATE SpdyProxyClientSocket : public ProxyClientSocket, scoped_ptr<SpdyHttpStream> response_stream_; + base::WeakPtrFactory<SpdyProxyClientSocket> weak_factory_; + const BoundNetLog net_log_; DISALLOW_COPY_AND_ASSIGN(SpdyProxyClientSocket); diff --git a/net/spdy/spdy_proxy_client_socket_unittest.cc b/net/spdy/spdy_proxy_client_socket_unittest.cc index 89aba7e..a7598dd 100644 --- a/net/spdy/spdy_proxy_client_socket_unittest.cc +++ b/net/spdy/spdy_proxy_client_socket_unittest.cc @@ -1238,4 +1238,99 @@ TEST_F(SpdyProxyClientSocketTest, DisconnectWithReadPending) { EXPECT_FALSE(read_callback_.have_result()); } +// If the socket is Reset when both a read and write are pending, +// both should be called back. +TEST_F(SpdyProxyClientSocketTest, RstWithReadAndWritePending) { + scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame()); + MockWrite writes[] = { + CreateMockWrite(*conn, 0, false), + MockWrite(true, ERR_IO_PENDING, 2), + }; + + scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame()); + scoped_ptr<spdy::SpdyFrame> rst(ConstructSpdyRstStream(1, spdy::CANCEL)); + MockRead reads[] = { + CreateMockRead(*resp, 1, true), + CreateMockRead(*rst, 3, true), + }; + + Initialize(reads, arraysize(reads), writes, arraysize(writes)); + + AssertConnectSucceeds(); + + EXPECT_TRUE(sock_->IsConnected()); + + scoped_refptr<IOBuffer> read_buf(new IOBuffer(kLen1)); + ASSERT_EQ(ERR_IO_PENDING, sock_->Read(read_buf, kLen1, &read_callback_)); + + scoped_refptr<IOBufferWithSize> write_buf(CreateBuffer(kMsg1, kLen1)); + EXPECT_EQ(ERR_IO_PENDING, sock_->Write(write_buf, write_buf->size(), + &write_callback_)); + + Run(2); + + EXPECT_TRUE(sock_.get()); + EXPECT_TRUE(read_callback_.have_result()); + EXPECT_TRUE(write_callback_.have_result()); +} + +// CompletionCallback that causes the SpdyProxyClientSocket to be +// deleted when Run is invoked. +class DeleteSockCallback : public TestOldCompletionCallback { + public: + explicit DeleteSockCallback(scoped_ptr<SpdyProxyClientSocket>* sock) + : sock_(sock) { + } + + virtual ~DeleteSockCallback() { + } + + virtual void RunWithParams(const Tuple1<int>& params) OVERRIDE { + sock_->reset(NULL); + TestOldCompletionCallback::RunWithParams(params); + } + + private: + scoped_ptr<SpdyProxyClientSocket>* sock_; +}; + +// If the socket is Reset when both a read and write are pending, and the +// read callback causes the socket to be deleted, the write callback should +// not be called. +TEST_F(SpdyProxyClientSocketTest, RstWithReadAndWritePendingDelete) { + scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame()); + MockWrite writes[] = { + CreateMockWrite(*conn, 0, false), + MockWrite(true, ERR_IO_PENDING, 2), + }; + + scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame()); + scoped_ptr<spdy::SpdyFrame> rst(ConstructSpdyRstStream(1, spdy::CANCEL)); + MockRead reads[] = { + CreateMockRead(*resp, 1, true), + CreateMockRead(*rst, 3, true), + }; + + Initialize(reads, arraysize(reads), writes, arraysize(writes)); + + AssertConnectSucceeds(); + + EXPECT_TRUE(sock_->IsConnected()); + + DeleteSockCallback read_callback(&sock_); + + scoped_refptr<IOBuffer> read_buf(new IOBuffer(kLen1)); + ASSERT_EQ(ERR_IO_PENDING, sock_->Read(read_buf, kLen1, &read_callback)); + + scoped_refptr<IOBufferWithSize> write_buf(CreateBuffer(kMsg1, kLen1)); + EXPECT_EQ(ERR_IO_PENDING, sock_->Write(write_buf, write_buf->size(), + &write_callback_)); + + Run(2); + + EXPECT_FALSE(sock_.get()); + EXPECT_TRUE(read_callback.have_result()); + EXPECT_FALSE(write_callback_.have_result()); +} + } // namespace net |