diff options
author | willchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-07 16:02:32 +0000 |
---|---|---|
committer | willchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-07 16:02:32 +0000 |
commit | 72efdea11ed4f7d4f192d55650e0e5d9ee3e1900 (patch) | |
tree | cc59dddd21b8f1096530534508e00386399400d3 /net/spdy/spdy_session_unittest.cc | |
parent | ba020f959d7acdc1361d8148e77d2f4f855a667c (diff) | |
download | chromium_src-72efdea11ed4f7d4f192d55650e0e5d9ee3e1900.zip chromium_src-72efdea11ed4f7d4f192d55650e0e5d9ee3e1900.tar.gz chromium_src-72efdea11ed4f7d4f192d55650e0e5d9ee3e1900.tar.bz2 |
SPDY: Fix stream cancellation during ReadResponseBody() callback.
BUG=44800
Review URL: http://codereview.chromium.org/2565005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@49061 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/spdy/spdy_session_unittest.cc')
-rw-r--r-- | net/spdy/spdy_session_unittest.cc | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc index d022232..71c42bf 100644 --- a/net/spdy/spdy_session_unittest.cc +++ b/net/spdy/spdy_session_unittest.cc @@ -9,11 +9,13 @@ #include "net/base/ssl_config_service_defaults.h" #include "net/base/test_completion_callback.h" #include "net/http/http_network_session.h" +#include "net/http/http_response_info.h" #include "net/proxy/proxy_service.h" #include "net/socket/socket_test_util.h" #include "net/spdy/spdy_session.h" #include "net/spdy/spdy_session_pool.h" #include "net/spdy/spdy_stream.h" +#include "net/spdy/spdy_test_util.h" #include "testing/platform_test.h" namespace net { @@ -156,6 +158,123 @@ TEST_F(SpdySessionTest, GoAway) { session2 = NULL; } +// StreamCanceler is used for SpdySessionTest.CancelStreamOnClose. It is used +// for two callbacks: the stream's SendRequest() and ReadResponseBody() +// callbacks. +class StreamCanceler { + public: + enum State { + WAITING_FOR_CONNECT, + WAITING_FOR_RESPONSE, + STATE_DONE + }; + + explicit StreamCanceler(const scoped_refptr<SpdyStream>& stream) + : stream_(stream), + ALLOW_THIS_IN_INITIALIZER_LIST( + callback_(this, &StreamCanceler::OnIOComplete)), + buf_(new IOBufferWithSize(64)), + state_(WAITING_FOR_CONNECT) {} + + CompletionCallback* callback() { return &callback_; } + + State state() const { return state_; } + + private: + void OnIOComplete(int result) { + MessageLoop::current()->Quit(); + switch (state_) { + case WAITING_FOR_CONNECT: + // After receiving this callback, start the ReadResponseBody() request. + // We need to do this here rather than elsewhere, since the MessageLoop + // will keep processing the pending read tasks until there aren't any + // more, so we won't get a chance to get an asynchronous callback for + // ReadResponseBody() unless we call it here in the callback for + // SendRequest(). + EXPECT_EQ(OK, result); + state_ = WAITING_FOR_RESPONSE; + EXPECT_EQ(ERR_IO_PENDING, stream_->ReadResponseBody( + buf_.get(), buf_->size(), &callback_)); + break; + case WAITING_FOR_RESPONSE: + // The result should be the 6 bytes of the body. The next read will + // succeed synchronously, indicating the stream is closed. We cancel + // the stream during the callback for the first ReadResponseBody() call + // which will deactivate the stream. The code should handle this case. + EXPECT_EQ(6, result); + EXPECT_EQ(OK, + stream_->ReadResponseBody( + buf_.get(), buf_->size(), &callback_)); + stream_->Cancel(); + state_ = STATE_DONE; + break; + default: + NOTREACHED(); + break; + } + } + + const scoped_refptr<SpdyStream> stream_; + CompletionCallbackImpl<StreamCanceler> callback_; + scoped_refptr<IOBufferWithSize> buf_; + State state_; + + DISALLOW_COPY_AND_ASSIGN(StreamCanceler); +}; + +TEST_F(SpdySessionTest, CancelStreamOnClose) { + SpdySessionTest::TurnOffCompression(); + SessionDependencies session_deps; + session_deps.host_resolver->set_synchronous_mode(true); + + MockConnect connect_data(false, OK); + MockRead reads[] = { + MockRead(true, reinterpret_cast<const char*>(kGetSynReply), + arraysize(kGetSynReply)), + MockRead(true, reinterpret_cast<const char*>(kGetBodyFrame), + arraysize(kGetBodyFrame)), + MockRead(true, 0, 0) // EOF + }; + StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); + data.set_connect_data(connect_data); + session_deps.socket_factory.AddSocketDataProvider(&data); + + SSLSocketDataProvider ssl(false, OK); + session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); + + scoped_refptr<HttpNetworkSession> http_session(CreateSession(&session_deps)); + + const std::string kTestHost("www.google.com"); + const int kTestPort = 80; + HostPortPair test_host_port_pair; + test_host_port_pair.host = kTestHost; + test_host_port_pair.port = kTestPort; + + scoped_refptr<SpdySessionPool> spdy_session_pool( + http_session->spdy_session_pool()); + EXPECT_FALSE(spdy_session_pool->HasSession(test_host_port_pair)); + scoped_refptr<SpdySession> session = + spdy_session_pool->Get( + test_host_port_pair, http_session.get(), BoundNetLog()); + + HttpRequestInfo request; + request.url = GURL("http://www.google.com"); + + scoped_refptr<SpdyStream> stream = + session->GetOrCreateStream(request, NULL, BoundNetLog()); + TCPSocketParams tcp_params(kTestHost, kTestPort, MEDIUM, GURL(), false); + int rv = session->Connect(kTestHost, tcp_params, MEDIUM); + ASSERT_EQ(OK, rv); + + HttpResponseInfo response; + TestCompletionCallback callback; + StreamCanceler canceler(stream); + rv = stream->SendRequest(NULL, &response, canceler.callback()); + ASSERT_EQ(ERR_IO_PENDING, rv); + while (canceler.state() != StreamCanceler::STATE_DONE) + MessageLoop::current()->Run(); +} + // kPush is a server-issued SYN_STREAM with stream id 2, and // associated stream id 1. It also includes 3 headers of path, // status, and HTTP version. |