summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/spdy/spdy_proxy_client_socket.cc7
-rw-r--r--net/spdy/spdy_proxy_client_socket.h3
-rw-r--r--net/spdy/spdy_proxy_client_socket_unittest.cc95
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