summaryrefslogtreecommitdiffstats
path: root/net/spdy/spdy_session_unittest.cc
diff options
context:
space:
mode:
authorwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-07 16:02:32 +0000
committerwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-07 16:02:32 +0000
commit72efdea11ed4f7d4f192d55650e0e5d9ee3e1900 (patch)
treecc59dddd21b8f1096530534508e00386399400d3 /net/spdy/spdy_session_unittest.cc
parentba020f959d7acdc1361d8148e77d2f4f855a667c (diff)
downloadchromium_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.cc119
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.