diff options
author | rch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-28 02:13:14 +0000 |
---|---|---|
committer | rch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-28 02:13:14 +0000 |
commit | 82e41413604a57eb4862799987c327e13b198435 (patch) | |
tree | c7797cdc1515f038458bcbc09228a9a48d15997c /net/spdy | |
parent | 272de5778249e7b01f9d3567ba8def67130872bf (diff) | |
download | chromium_src-82e41413604a57eb4862799987c327e13b198435.zip chromium_src-82e41413604a57eb4862799987c327e13b198435.tar.gz chromium_src-82e41413604a57eb4862799987c327e13b198435.tar.bz2 |
Fix a SPDY crash bug where a CHECK() is hit because a cancelled stream is considered active by the spdy session.
BUG=139375
TEST=SpdySessionSpdy2Test.CancelStream
Review URL: https://chromiumcodereview.appspot.com/10829066
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@148865 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/spdy')
-rw-r--r-- | net/spdy/spdy_session_spdy2_unittest.cc | 106 | ||||
-rw-r--r-- | net/spdy/spdy_session_spdy3_unittest.cc | 106 | ||||
-rw-r--r-- | net/spdy/spdy_stream.cc | 4 |
3 files changed, 216 insertions, 0 deletions
diff --git a/net/spdy/spdy_session_spdy2_unittest.cc b/net/spdy/spdy_session_spdy2_unittest.cc index a592810..50e8524 100644 --- a/net/spdy/spdy_session_spdy2_unittest.cc +++ b/net/spdy/spdy_session_spdy2_unittest.cc @@ -1280,4 +1280,110 @@ TEST_F(SpdySessionSpdy2Test, OutOfOrderSynStreams) { spdy_stream2 = NULL; } +TEST_F(SpdySessionSpdy2Test, CancelStream) { + MockConnect connect_data(SYNCHRONOUS, OK); + // Request 1, at HIGHEST priority, will be cancelled before it writes data. + // Request 2, at LOWEST priority, will be a full request and will be id 1. + scoped_ptr<SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); + MockWrite writes[] = { + CreateMockWrite(*req2, 0), + }; + + scoped_ptr<SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 1)); + scoped_ptr<SpdyFrame> body2(ConstructSpdyBodyFrame(1, true)); + MockRead reads[] = { + CreateMockRead(*resp2, 1), + CreateMockRead(*body2, 2), + MockRead(ASYNC, 0, 3) // EOF + }; + + SpdySessionDependencies session_deps; + session_deps.host_resolver->set_synchronous_mode(true); + + DeterministicSocketData data(reads, arraysize(reads), + writes, arraysize(writes)); + data.set_connect_data(connect_data); + session_deps.deterministic_socket_factory->AddSocketDataProvider(&data); + + SSLSocketDataProvider ssl(SYNCHRONOUS, OK); + session_deps.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); + + scoped_refptr<HttpNetworkSession> http_session( + SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps)); + + const std::string kTestHost("www.foo.com"); + const int kTestPort = 80; + HostPortPair test_host_port_pair(kTestHost, kTestPort); + HostPortProxyPair pair(test_host_port_pair, ProxyServer::Direct()); + + SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); + + // Create a session. + EXPECT_FALSE(spdy_session_pool->HasSession(pair)); + scoped_refptr<SpdySession> session = + spdy_session_pool->Get(pair, BoundNetLog()); + ASSERT_TRUE(spdy_session_pool->HasSession(pair)); + + scoped_refptr<TransportSocketParams> transport_params( + new TransportSocketParams(test_host_port_pair, + MEDIUM, + false, + false, + OnHostResolutionCallback())); + scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); + EXPECT_EQ(OK, connection->Init(test_host_port_pair.ToString(), + transport_params, MEDIUM, CompletionCallback(), + http_session->GetTransportSocketPool( + HttpNetworkSession::NORMAL_SOCKET_POOL), + BoundNetLog())); + EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), false, OK)); + + scoped_refptr<SpdyStream> spdy_stream1; + TestCompletionCallback callback1; + GURL url1("http://www.google.com"); + EXPECT_EQ(OK, session->CreateStream(url1, HIGHEST, &spdy_stream1, + BoundNetLog(), callback1.callback())); + EXPECT_EQ(0u, spdy_stream1->stream_id()); + + scoped_refptr<SpdyStream> spdy_stream2; + TestCompletionCallback callback2; + GURL url2("http://www.google.com"); + EXPECT_EQ(OK, session->CreateStream(url2, LOWEST, &spdy_stream2, + BoundNetLog(), callback2.callback())); + EXPECT_EQ(0u, spdy_stream2->stream_id()); + + scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock); + (*headers)["method"] = "GET"; + (*headers)["scheme"] = url1.scheme(); + (*headers)["host"] = url1.host(); + (*headers)["url"] = url1.path(); + (*headers)["version"] = "HTTP/1.1"; + scoped_ptr<SpdyHeaderBlock> headers2(new SpdyHeaderBlock); + *headers2 = *headers; + + spdy_stream1->set_spdy_headers(headers.Pass()); + EXPECT_TRUE(spdy_stream1->HasUrl()); + + spdy_stream2->set_spdy_headers(headers2.Pass()); + EXPECT_TRUE(spdy_stream2->HasUrl()); + + spdy_stream1->SendRequest(false); + spdy_stream2->SendRequest(false); + + EXPECT_EQ(0u, spdy_stream1->stream_id()); + + spdy_stream1->Cancel(); + + EXPECT_EQ(0u, spdy_stream1->stream_id()); + + data.RunFor(1); + + EXPECT_EQ(0u, spdy_stream1->stream_id()); + EXPECT_EQ(1u, spdy_stream2->stream_id()); + + spdy_stream1 = NULL; + spdy_stream2->Cancel(); + spdy_stream2 = NULL; +} + } // namespace net diff --git a/net/spdy/spdy_session_spdy3_unittest.cc b/net/spdy/spdy_session_spdy3_unittest.cc index 5b88415..4abd887 100644 --- a/net/spdy/spdy_session_spdy3_unittest.cc +++ b/net/spdy/spdy_session_spdy3_unittest.cc @@ -1450,4 +1450,110 @@ TEST_F(SpdySessionSpdy3Test, OutOfOrderSynStreams) { spdy_stream2 = NULL; } +TEST_F(SpdySessionSpdy3Test, CancelStream) { + MockConnect connect_data(SYNCHRONOUS, OK); + // Request 1, at HIGHEST priority, will be cancelled before it writes data. + // Request 2, at LOWEST priority, will be a full request and will be id 1. + scoped_ptr<SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); + MockWrite writes[] = { + CreateMockWrite(*req2, 0), + }; + + scoped_ptr<SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 1)); + scoped_ptr<SpdyFrame> body2(ConstructSpdyBodyFrame(1, true)); + MockRead reads[] = { + CreateMockRead(*resp2, 1), + CreateMockRead(*body2, 2), + MockRead(ASYNC, 0, 3) // EOF + }; + + SpdySessionDependencies session_deps; + session_deps.host_resolver->set_synchronous_mode(true); + + DeterministicSocketData data(reads, arraysize(reads), + writes, arraysize(writes)); + data.set_connect_data(connect_data); + session_deps.deterministic_socket_factory->AddSocketDataProvider(&data); + + SSLSocketDataProvider ssl(SYNCHRONOUS, OK); + session_deps.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); + + scoped_refptr<HttpNetworkSession> http_session( + SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps)); + + const std::string kTestHost("www.foo.com"); + const int kTestPort = 80; + HostPortPair test_host_port_pair(kTestHost, kTestPort); + HostPortProxyPair pair(test_host_port_pair, ProxyServer::Direct()); + + SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); + + // Create a session. + EXPECT_FALSE(spdy_session_pool->HasSession(pair)); + scoped_refptr<SpdySession> session = + spdy_session_pool->Get(pair, BoundNetLog()); + ASSERT_TRUE(spdy_session_pool->HasSession(pair)); + + scoped_refptr<TransportSocketParams> transport_params( + new TransportSocketParams(test_host_port_pair, + MEDIUM, + false, + false, + OnHostResolutionCallback())); + scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); + EXPECT_EQ(OK, connection->Init(test_host_port_pair.ToString(), + transport_params, MEDIUM, CompletionCallback(), + http_session->GetTransportSocketPool( + HttpNetworkSession::NORMAL_SOCKET_POOL), + BoundNetLog())); + EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), false, OK)); + + scoped_refptr<SpdyStream> spdy_stream1; + TestCompletionCallback callback1; + GURL url1("http://www.google.com"); + EXPECT_EQ(OK, session->CreateStream(url1, HIGHEST, &spdy_stream1, + BoundNetLog(), callback1.callback())); + EXPECT_EQ(0u, spdy_stream1->stream_id()); + + scoped_refptr<SpdyStream> spdy_stream2; + TestCompletionCallback callback2; + GURL url2("http://www.google.com"); + EXPECT_EQ(OK, session->CreateStream(url2, LOWEST, &spdy_stream2, + BoundNetLog(), callback2.callback())); + EXPECT_EQ(0u, spdy_stream2->stream_id()); + + scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock); + (*headers)[":method"] = "GET"; + (*headers)[":scheme"] = url1.scheme(); + (*headers)[":host"] = url1.host(); + (*headers)[":path"] = url1.path(); + (*headers)[":version"] = "HTTP/1.1"; + scoped_ptr<SpdyHeaderBlock> headers2(new SpdyHeaderBlock); + *headers2 = *headers; + + spdy_stream1->set_spdy_headers(headers.Pass()); + EXPECT_TRUE(spdy_stream1->HasUrl()); + + spdy_stream2->set_spdy_headers(headers2.Pass()); + EXPECT_TRUE(spdy_stream2->HasUrl()); + + spdy_stream1->SendRequest(false); + spdy_stream2->SendRequest(false); + + EXPECT_EQ(0u, spdy_stream1->stream_id()); + + spdy_stream1->Cancel(); + + EXPECT_EQ(0u, spdy_stream1->stream_id()); + + data.RunFor(1); + + EXPECT_EQ(0u, spdy_stream1->stream_id()); + EXPECT_EQ(1u, spdy_stream2->stream_id()); + + spdy_stream1 = NULL; + spdy_stream2->Cancel(); + spdy_stream2 = NULL; +} + } // namespace net diff --git a/net/spdy/spdy_stream.cc b/net/spdy/spdy_stream.cc index f3828d6..2771886 100644 --- a/net/spdy/spdy_stream.cc +++ b/net/spdy/spdy_stream.cc @@ -87,6 +87,8 @@ class SpdyStream::SpdyStreamIOBufferProducer } virtual SpdyIOBuffer* ProduceNextBuffer(SpdySession* session) OVERRIDE { + if (stream_->cancelled()) + return NULL; if (stream_->stream_id() == 0) SpdySession::SpdyIOBufferProducer::ActivateStream(session, stream_); frame_.reset(stream_->ProduceNextFrame()); @@ -526,6 +528,8 @@ void SpdyStream::Cancel() { cancelled_ = true; if (session_->IsStreamActive(stream_id_)) session_->ResetStream(stream_id_, CANCEL, ""); + else if (stream_id_ == 0) + session_->CloseCreatedStream(this, CANCEL); } void SpdyStream::Close() { |