This source file includes following definitions.
- TheNearFuture
- StallSessionOnly
- StallStreamOnly
- StallSessionStream
- StallStreamSession
- UnstallSessionOnly
- UnstallStreamOnly
- UnstallSessionStream
- UnstallStreamSession
- key_
- SetUp
- CreateDeterministicNetworkSession
- CreateNetworkSession
- StallSessionSend
- UnstallSessionSend
- StallStreamSend
- UnstallStreamSend
- TEST_P
- SetRequestToDestroy
- MakeCallback
- OnComplete
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- session_to_close_
- OnClose
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- session_
- OnClose
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- OnDataReceived
- TEST_P
- TEST_P
- TEST_P
- RunResumeAfterUnstallTest
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- TEST_P
- set_stream_to_close
- OnDataSent
- TEST_P
- TEST_P
- TEST
- TEST
#include "net/spdy/spdy_session.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "net/base/io_buffer.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_log_unittest.h"
#include "net/base/request_priority.h"
#include "net/base/test_data_directory.h"
#include "net/base/test_data_stream.h"
#include "net/socket/client_socket_pool_manager.h"
#include "net/socket/next_proto.h"
#include "net/socket/socket_test_util.h"
#include "net/spdy/spdy_http_utils.h"
#include "net/spdy/spdy_session_pool.h"
#include "net/spdy/spdy_session_test_util.h"
#include "net/spdy/spdy_stream.h"
#include "net/spdy/spdy_stream_test_util.h"
#include "net/spdy/spdy_test_util_common.h"
#include "net/spdy/spdy_test_utils.h"
#include "net/test/cert_test_util.h"
#include "testing/platform_test.h"
namespace net {
namespace {
static const char kTestUrl[] = "http://www.example.org/";
static const char kTestHost[] = "www.example.org";
static const int kTestPort = 80;
const char kBodyData[] = "Body data";
const size_t kBodyDataSize = arraysize(kBodyData);
const base::StringPiece kBodyDataStringPiece(kBodyData, kBodyDataSize);
static base::TimeDelta g_time_delta;
base::TimeTicks TheNearFuture() {
return base::TimeTicks::Now() + g_time_delta;
}
}
class SpdySessionTest : public PlatformTest,
public ::testing::WithParamInterface<NextProto> {
public:
void StallSessionOnly(SpdySession* session, SpdyStream* stream) {
StallSessionSend(session);
}
void StallStreamOnly(SpdySession* session, SpdyStream* stream) {
StallStreamSend(stream);
}
void StallSessionStream(SpdySession* session, SpdyStream* stream) {
StallSessionSend(session);
StallStreamSend(stream);
}
void StallStreamSession(SpdySession* session, SpdyStream* stream) {
StallStreamSend(stream);
StallSessionSend(session);
}
void UnstallSessionOnly(SpdySession* session,
SpdyStream* stream,
int32 delta_window_size) {
UnstallSessionSend(session, delta_window_size);
}
void UnstallStreamOnly(SpdySession* session,
SpdyStream* stream,
int32 delta_window_size) {
UnstallStreamSend(stream, delta_window_size);
}
void UnstallSessionStream(SpdySession* session,
SpdyStream* stream,
int32 delta_window_size) {
UnstallSessionSend(session, delta_window_size);
UnstallStreamSend(stream, delta_window_size);
}
void UnstallStreamSession(SpdySession* session,
SpdyStream* stream,
int32 delta_window_size) {
UnstallStreamSend(stream, delta_window_size);
UnstallSessionSend(session, delta_window_size);
}
protected:
SpdySessionTest()
: old_max_group_sockets_(ClientSocketPoolManager::max_sockets_per_group(
HttpNetworkSession::NORMAL_SOCKET_POOL)),
old_max_pool_sockets_(ClientSocketPoolManager::max_sockets_per_pool(
HttpNetworkSession::NORMAL_SOCKET_POOL)),
spdy_util_(GetParam()),
session_deps_(GetParam()),
spdy_session_pool_(NULL),
test_url_(kTestUrl),
test_host_port_pair_(kTestHost, kTestPort),
key_(test_host_port_pair_, ProxyServer::Direct(),
PRIVACY_MODE_DISABLED) {
}
virtual ~SpdySessionTest() {
ClientSocketPoolManager::set_max_sockets_per_pool(
HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_pool_sockets_);
ClientSocketPoolManager::set_max_sockets_per_group(
HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_group_sockets_);
}
virtual void SetUp() OVERRIDE {
g_time_delta = base::TimeDelta();
}
void CreateDeterministicNetworkSession() {
http_session_ =
SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
spdy_session_pool_ = http_session_->spdy_session_pool();
}
void CreateNetworkSession() {
http_session_ =
SpdySessionDependencies::SpdyCreateSession(&session_deps_);
spdy_session_pool_ = http_session_->spdy_session_pool();
}
void StallSessionSend(SpdySession* session) {
while (session->session_send_window_size_ > 0) {
session->DecreaseSendWindowSize(
std::min(kMaxSpdyFrameChunkSize, session->session_send_window_size_));
}
}
void UnstallSessionSend(SpdySession* session, int32 delta_window_size) {
session->IncreaseSendWindowSize(delta_window_size);
}
void StallStreamSend(SpdyStream* stream) {
while (stream->send_window_size() > 0) {
stream->DecreaseSendWindowSize(
std::min(kMaxSpdyFrameChunkSize, stream->send_window_size()));
}
}
void UnstallStreamSend(SpdyStream* stream, int32 delta_window_size) {
stream->IncreaseSendWindowSize(delta_window_size);
}
void RunResumeAfterUnstallTest(
const base::Callback<void(SpdySession*, SpdyStream*)>& stall_function,
const base::Callback<void(SpdySession*, SpdyStream*, int32)>&
unstall_function);
int old_max_group_sockets_;
int old_max_pool_sockets_;
SpdyTestUtil spdy_util_;
SpdySessionDependencies session_deps_;
scoped_refptr<HttpNetworkSession> http_session_;
SpdySessionPool* spdy_session_pool_;
GURL test_url_;
HostPortPair test_host_port_pair_;
SpdySessionKey key_;
};
INSTANTIATE_TEST_CASE_P(
NextProto,
SpdySessionTest,
testing::Values(kProtoDeprecatedSPDY2,
kProtoSPDY3, kProtoSPDY31, kProtoSPDY4a2,
kProtoHTTP2Draft04));
TEST_P(SpdySessionTest, InitialReadError) {
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session = TryCreateFakeSpdySessionExpectingFailure(
spdy_session_pool_, key_, ERR_FAILED);
EXPECT_TRUE(session);
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(session);
}
namespace {
class StreamRequestDestroyingCallback : public TestCompletionCallbackBase {
public:
StreamRequestDestroyingCallback() {}
virtual ~StreamRequestDestroyingCallback() {}
void SetRequestToDestroy(scoped_ptr<SpdyStreamRequest> request) {
request_ = request.Pass();
}
CompletionCallback MakeCallback() {
return base::Bind(&StreamRequestDestroyingCallback::OnComplete,
base::Unretained(this));
}
private:
void OnComplete(int result) {
request_.reset();
SetResult(result);
}
scoped_ptr<SpdyStreamRequest> request_;
};
}
TEST_P(SpdySessionTest, PendingStreamCancellingAnother) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockRead reads[] = {MockRead(ASYNC, 0, 0), };
DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
MockConnect connect_data(SYNCHRONOUS, OK);
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
for (size_t i = 0; i < kInitialMaxConcurrentStreams; ++i) {
base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
SPDY_BIDIRECTIONAL_STREAM, session, test_url_, MEDIUM, BoundNetLog());
ASSERT_TRUE(spdy_stream != NULL);
}
SpdyStreamRequest request1;
scoped_ptr<SpdyStreamRequest> request2(new SpdyStreamRequest);
StreamRequestDestroyingCallback callback1;
ASSERT_EQ(ERR_IO_PENDING,
request1.StartRequest(SPDY_BIDIRECTIONAL_STREAM,
session,
test_url_,
MEDIUM,
BoundNetLog(),
callback1.MakeCallback()));
TestCompletionCallback callback2;
ASSERT_EQ(ERR_IO_PENDING,
request2->StartRequest(SPDY_BIDIRECTIONAL_STREAM,
session,
test_url_,
MEDIUM,
BoundNetLog(),
callback2.callback()));
callback1.SetRequestToDestroy(request2.Pass());
session->CloseSessionOnError(ERR_ABORTED, "Aborting session");
EXPECT_EQ(ERR_ABORTED, callback1.WaitForResult());
}
TEST_P(SpdySessionTest, GoAwayWithNoActiveStreams) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
MockRead reads[] = {
CreateMockRead(*goaway, 0),
};
DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion());
EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
data.RunFor(1);
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
EXPECT_TRUE(session == NULL);
}
TEST_P(SpdySessionTest, GoAwayImmediatelyWithNoActiveStreams) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
MockRead reads[] = {
CreateMockRead(*goaway, 0, SYNCHRONOUS),
};
DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
data.StopAfter(1);
base::WeakPtr<SpdySession> session =
TryCreateInsecureSpdySessionExpectingFailure(
http_session_, key_, ERR_CONNECTION_CLOSED, BoundNetLog());
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(session);
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
}
TEST_P(SpdySessionTest, GoAwayWithActiveStreams) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
MockRead reads[] = {
CreateMockRead(*goaway, 2),
MockRead(ASYNC, 0, 3)
};
scoped_ptr<SpdyFrame> req1(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
scoped_ptr<SpdyFrame> req2(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, MEDIUM, true));
MockWrite writes[] = {
CreateMockWrite(*req1, 0),
CreateMockWrite(*req2, 1),
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion());
GURL url(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream1 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url, MEDIUM, BoundNetLog());
test::StreamDelegateDoNothing delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
base::WeakPtr<SpdyStream> spdy_stream2 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url, MEDIUM, BoundNetLog());
test::StreamDelegateDoNothing delegate2(spdy_stream2);
spdy_stream2->SetDelegate(&delegate2);
scoped_ptr<SpdyHeaderBlock> headers(
spdy_util_.ConstructGetHeaderBlock(url.spec()));
scoped_ptr<SpdyHeaderBlock> headers2(new SpdyHeaderBlock(*headers));
spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
data.RunFor(2);
EXPECT_EQ(1u, spdy_stream1->stream_id());
EXPECT_EQ(3u, spdy_stream2->stream_id());
EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
data.RunFor(1);
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
EXPECT_FALSE(session->IsStreamActive(3));
EXPECT_EQ(NULL, spdy_stream2.get());
EXPECT_TRUE(session->IsStreamActive(1));
EXPECT_FALSE(session->IsClosed());
spdy_stream1->Close();
EXPECT_EQ(NULL, spdy_stream1.get());
EXPECT_TRUE(session == NULL);
}
TEST_P(SpdySessionTest, GoAwayTwice) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
scoped_ptr<SpdyFrame> goaway1(spdy_util_.ConstructSpdyGoAway(1));
scoped_ptr<SpdyFrame> goaway2(spdy_util_.ConstructSpdyGoAway(0));
MockRead reads[] = {
CreateMockRead(*goaway1, 2),
CreateMockRead(*goaway2, 3),
MockRead(ASYNC, 0, 4)
};
scoped_ptr<SpdyFrame> req1(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
scoped_ptr<SpdyFrame> req2(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, MEDIUM, true));
MockWrite writes[] = {
CreateMockWrite(*req1, 0),
CreateMockWrite(*req2, 1),
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion());
GURL url(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream1 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url, MEDIUM, BoundNetLog());
test::StreamDelegateDoNothing delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
base::WeakPtr<SpdyStream> spdy_stream2 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url, MEDIUM, BoundNetLog());
test::StreamDelegateDoNothing delegate2(spdy_stream2);
spdy_stream2->SetDelegate(&delegate2);
scoped_ptr<SpdyHeaderBlock> headers(
spdy_util_.ConstructGetHeaderBlock(url.spec()));
scoped_ptr<SpdyHeaderBlock> headers2(new SpdyHeaderBlock(*headers));
spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
data.RunFor(2);
EXPECT_EQ(1u, spdy_stream1->stream_id());
EXPECT_EQ(3u, spdy_stream2->stream_id());
EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
data.RunFor(1);
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
EXPECT_FALSE(session->IsStreamActive(3));
EXPECT_EQ(NULL, spdy_stream2.get());
EXPECT_TRUE(session->IsStreamActive(1));
EXPECT_FALSE(session->IsClosed());
data.RunFor(1);
EXPECT_TRUE(session == NULL);
}
TEST_P(SpdySessionTest, GoAwayWithActiveStreamsThenClose) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
MockRead reads[] = {
CreateMockRead(*goaway, 2),
MockRead(ASYNC, 0, 3)
};
scoped_ptr<SpdyFrame> req1(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
scoped_ptr<SpdyFrame> req2(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, MEDIUM, true));
MockWrite writes[] = {
CreateMockWrite(*req1, 0),
CreateMockWrite(*req2, 1),
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion());
GURL url(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream1 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url, MEDIUM, BoundNetLog());
test::StreamDelegateDoNothing delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
base::WeakPtr<SpdyStream> spdy_stream2 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url, MEDIUM, BoundNetLog());
test::StreamDelegateDoNothing delegate2(spdy_stream2);
spdy_stream2->SetDelegate(&delegate2);
scoped_ptr<SpdyHeaderBlock> headers(
spdy_util_.ConstructGetHeaderBlock(url.spec()));
scoped_ptr<SpdyHeaderBlock> headers2(new SpdyHeaderBlock(*headers));
spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
data.RunFor(2);
EXPECT_EQ(1u, spdy_stream1->stream_id());
EXPECT_EQ(3u, spdy_stream2->stream_id());
EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
data.RunFor(1);
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
EXPECT_FALSE(session->IsStreamActive(3));
EXPECT_EQ(NULL, spdy_stream2.get());
EXPECT_TRUE(session->IsStreamActive(1));
EXPECT_FALSE(session->IsClosed());
session->CloseSessionOnError(ERR_ABORTED, "Aborting session");
EXPECT_EQ(NULL, spdy_stream1.get());
EXPECT_TRUE(session == NULL);
}
TEST_P(SpdySessionTest, CreateStreamAfterGoAway) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
MockRead reads[] = {
CreateMockRead(*goaway, 1),
MockRead(ASYNC, 0, 2)
};
scoped_ptr<SpdyFrame> req(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
MockWrite writes[] = {
CreateMockWrite(*req, 0),
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion());
GURL url(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url, MEDIUM, BoundNetLog());
test::StreamDelegateDoNothing delegate(spdy_stream);
spdy_stream->SetDelegate(&delegate);
scoped_ptr<SpdyHeaderBlock> headers(
spdy_util_.ConstructGetHeaderBlock(url.spec()));
spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
data.RunFor(1);
EXPECT_EQ(1u, spdy_stream->stream_id());
EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
data.RunFor(1);
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
EXPECT_TRUE(session->IsStreamActive(1));
SpdyStreamRequest stream_request;
int rv = stream_request.StartRequest(
SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog(),
CompletionCallback());
EXPECT_EQ(ERR_FAILED, rv);
data.RunFor(1);
EXPECT_TRUE(session == NULL);
}
TEST_P(SpdySessionTest, SynStreamAfterGoAway) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
scoped_ptr<SpdyFrame>
push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kDefaultURL));
MockRead reads[] = {
CreateMockRead(*goaway, 1),
CreateMockRead(*push, 2),
MockRead(ASYNC, 0, 4)
};
scoped_ptr<SpdyFrame> req(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
scoped_ptr<SpdyFrame> rst(
spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM));
MockWrite writes[] = {
CreateMockWrite(*req, 0),
CreateMockWrite(*rst, 3)
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion());
GURL url(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url, MEDIUM, BoundNetLog());
test::StreamDelegateDoNothing delegate(spdy_stream);
spdy_stream->SetDelegate(&delegate);
scoped_ptr<SpdyHeaderBlock> headers(
spdy_util_.ConstructGetHeaderBlock(url.spec()));
spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
data.RunFor(1);
EXPECT_EQ(1u, spdy_stream->stream_id());
EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
data.RunFor(1);
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
EXPECT_TRUE(session->IsStreamActive(1));
data.RunFor(3);
EXPECT_TRUE(session == NULL);
}
TEST_P(SpdySessionTest, NetworkChangeWithActiveStreams) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
MockRead reads[] = {
MockRead(ASYNC, 0, 1)
};
scoped_ptr<SpdyFrame> req1(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
MockWrite writes[] = {
CreateMockWrite(*req1, 0),
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
EXPECT_EQ(spdy_util_.spdy_version(), session->GetProtocolVersion());
base::WeakPtr<SpdyStream> spdy_stream =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session,
GURL(kDefaultURL), MEDIUM, BoundNetLog());
test::StreamDelegateDoNothing delegate(spdy_stream);
spdy_stream->SetDelegate(&delegate);
scoped_ptr<SpdyHeaderBlock> headers(
spdy_util_.ConstructGetHeaderBlock(kDefaultURL));
spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
data.RunFor(1);
EXPECT_EQ(1u, spdy_stream->stream_id());
EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
spdy_session_pool_->OnIPAddressChanged();
#if defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS)
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
EXPECT_FALSE(session->IsClosed());
EXPECT_TRUE(session->IsStreamActive(1));
spdy_stream->Close();
#endif
EXPECT_EQ(NULL, spdy_stream.get());
EXPECT_TRUE(session == NULL);
}
TEST_P(SpdySessionTest, ClientPing) {
session_deps_.enable_ping = true;
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
scoped_ptr<SpdyFrame> read_ping(spdy_util_.ConstructSpdyPing(1, true));
MockRead reads[] = {
CreateMockRead(*read_ping, 1),
MockRead(ASYNC, 0, 0, 2)
};
scoped_ptr<SpdyFrame> write_ping(spdy_util_.ConstructSpdyPing(1, false));
MockWrite writes[] = {
CreateMockWrite(*write_ping, 0),
};
DeterministicSocketData data(
reads, arraysize(reads), writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
base::WeakPtr<SpdyStream> spdy_stream1 =
CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
session, test_url_, MEDIUM, BoundNetLog());
ASSERT_TRUE(spdy_stream1.get() != NULL);
test::StreamDelegateSendImmediate delegate(spdy_stream1, NULL);
spdy_stream1->SetDelegate(&delegate);
base::TimeTicks before_ping_time = base::TimeTicks::Now();
session->set_connection_at_risk_of_loss_time(
base::TimeDelta::FromSeconds(-1));
session->set_hung_interval(base::TimeDelta::FromMilliseconds(50));
session->SendPrefacePingIfNoneInFlight();
data.RunFor(2);
session->CheckPingStatus(before_ping_time);
EXPECT_EQ(0, session->pings_in_flight());
EXPECT_GE(session->next_ping_id(), static_cast<uint32>(1));
EXPECT_FALSE(session->check_ping_status_pending());
EXPECT_GE(session->last_activity_time(), before_ping_time);
data.RunFor(1);
EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
EXPECT_TRUE(session == NULL);
}
TEST_P(SpdySessionTest, ServerPing) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
scoped_ptr<SpdyFrame> read_ping(spdy_util_.ConstructSpdyPing(2, false));
MockRead reads[] = {
CreateMockRead(*read_ping),
MockRead(SYNCHRONOUS, 0, 0)
};
scoped_ptr<SpdyFrame> write_ping(spdy_util_.ConstructSpdyPing(2, true));
MockWrite writes[] = {
CreateMockWrite(*write_ping),
};
StaticSocketDataProvider data(
reads, arraysize(reads), writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.socket_factory->AddSocketDataProvider(&data);
CreateNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
base::WeakPtr<SpdyStream> spdy_stream1 =
CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
session, test_url_, MEDIUM, BoundNetLog());
ASSERT_TRUE(spdy_stream1.get() != NULL);
test::StreamDelegateSendImmediate delegate(spdy_stream1, NULL);
spdy_stream1->SetDelegate(&delegate);
base::MessageLoop::current()->RunUntilIdle();
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
EXPECT_TRUE(session == NULL);
EXPECT_EQ(NULL, spdy_stream1.get());
}
TEST_P(SpdySessionTest, PingAndWriteLoop) {
session_deps_.enable_ping = true;
session_deps_.time_func = TheNearFuture;
MockConnect connect_data(SYNCHRONOUS, OK);
scoped_ptr<SpdyFrame> write_ping(spdy_util_.ConstructSpdyPing(1, false));
scoped_ptr<SpdyFrame> req(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
MockWrite writes[] = {
CreateMockWrite(*req, 0),
CreateMockWrite(*write_ping, 1),
};
MockRead reads[] = {
MockRead(ASYNC, 0, 2)
};
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);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
GURL url(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url, LOWEST, BoundNetLog());
test::StreamDelegateDoNothing delegate(spdy_stream);
spdy_stream->SetDelegate(&delegate);
scoped_ptr<SpdyHeaderBlock> headers(
spdy_util_.ConstructGetHeaderBlock(url.spec()));
spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
g_time_delta = base::TimeDelta::FromSeconds(11);
data.RunFor(2);
session->CloseSessionOnError(ERR_ABORTED, "Aborting");
}
TEST_P(SpdySessionTest, DeleteExpiredPushStreams) {
session_deps_.host_resolver->set_synchronous_mode(true);
session_deps_.time_func = TheNearFuture;
scoped_ptr<SpdyFrame> req(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
scoped_ptr<SpdyFrame> rst(
spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM));
scoped_ptr<SpdyFrame> push_a(spdy_util_.ConstructSpdyPush(
NULL, 0, 2, 1, "http://www.google.com/a.dat"));
scoped_ptr<SpdyFrame> push_a_body(
spdy_util_.ConstructSpdyBodyFrame(2, false));
scoped_ptr<SpdyFrame> push_b(spdy_util_.ConstructSpdyPush(
NULL, 0, 4, 1, "http://www.google.com/b.dat"));
MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4)};
MockRead reads[] = {
CreateMockRead(*push_a, 1), CreateMockRead(*push_a_body, 2),
CreateMockRead(*push_b, 3), MockRead(ASYNC, 0, 5),
};
DeterministicSocketData data(
reads, arraysize(reads), writes, arraysize(writes));
MockConnect connect_data(SYNCHRONOUS, OK);
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
GURL url(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog());
test::StreamDelegateDoNothing delegate(spdy_stream);
spdy_stream->SetDelegate(&delegate);
scoped_ptr<SpdyHeaderBlock> headers(
spdy_util_.ConstructGetHeaderBlock(url.spec()));
spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
data.RunFor(3);
EXPECT_EQ(1u, session->num_unclaimed_pushed_streams());
SpdySession::PushedStreamMap::iterator iter =
session->unclaimed_pushed_streams_.find(
GURL("http://www.google.com/a.dat"));
EXPECT_TRUE(session->unclaimed_pushed_streams_.end() != iter);
if (session->flow_control_state_ ==
SpdySession::FLOW_CONTROL_STREAM_AND_SESSION) {
EXPECT_EQ(kSpdySessionInitialWindowSize - kUploadDataSize,
session->session_recv_window_size_);
EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
}
g_time_delta = base::TimeDelta::FromSeconds(301);
data.RunFor(2);
EXPECT_EQ(1u, session->num_unclaimed_pushed_streams());
iter = session->unclaimed_pushed_streams_.find(
GURL("http://www.google.com/b.dat"));
EXPECT_TRUE(session->unclaimed_pushed_streams_.end() != iter);
if (session->flow_control_state_ ==
SpdySession::FLOW_CONTROL_STREAM_AND_SESSION) {
EXPECT_EQ(kSpdySessionInitialWindowSize,
session->session_recv_window_size_);
EXPECT_EQ(kUploadDataSize, session->session_unacked_recv_window_bytes_);
}
data.RunFor(1);
EXPECT_TRUE(session == NULL);
}
TEST_P(SpdySessionTest, FailedPing) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
MockRead reads[] = {
MockRead(ASYNC, 0, 0, 0)
};
scoped_ptr<SpdyFrame> write_ping(spdy_util_.ConstructSpdyPing(1, false));
DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
base::WeakPtr<SpdyStream> spdy_stream1 =
CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
session, test_url_, MEDIUM, BoundNetLog());
ASSERT_TRUE(spdy_stream1.get() != NULL);
test::StreamDelegateSendImmediate delegate(spdy_stream1, NULL);
spdy_stream1->SetDelegate(&delegate);
session->set_connection_at_risk_of_loss_time(base::TimeDelta::FromSeconds(0));
session->set_hung_interval(base::TimeDelta::FromSeconds(0));
session->WritePingFrame(1, false);
EXPECT_LT(0, session->pings_in_flight());
EXPECT_GE(session->next_ping_id(), static_cast<uint32>(1));
EXPECT_TRUE(session->check_ping_status_pending());
EXPECT_FALSE(session->IsClosed());
EXPECT_LT(0u, session->num_active_streams() + session->num_created_streams());
EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
base::TimeTicks now = base::TimeTicks::Now();
session->last_activity_time_ = now - base::TimeDelta::FromSeconds(1);
session->CheckPingStatus(now);
EXPECT_TRUE(session == NULL);
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
EXPECT_EQ(NULL, spdy_stream1.get());
}
TEST_P(SpdySessionTest, OnSettings) {
session_deps_.host_resolver->set_synchronous_mode(true);
const SpdySettingsIds kSpdySettingsIds = SETTINGS_MAX_CONCURRENT_STREAMS;
SettingsMap new_settings;
const uint32 max_concurrent_streams = kInitialMaxConcurrentStreams + 1;
new_settings[kSpdySettingsIds] =
SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
scoped_ptr<SpdyFrame> settings_frame(
spdy_util_.ConstructSpdySettings(new_settings));
MockRead reads[] = {
CreateMockRead(*settings_frame, 0),
MockRead(ASYNC, 0, 1),
};
DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
MockConnect connect_data(SYNCHRONOUS, OK);
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
for (size_t i = 0; i < kInitialMaxConcurrentStreams; ++i) {
base::WeakPtr<SpdyStream> spdy_stream =
CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
session, test_url_, MEDIUM, BoundNetLog());
ASSERT_TRUE(spdy_stream != NULL);
}
StreamReleaserCallback stream_releaser;
SpdyStreamRequest request;
ASSERT_EQ(ERR_IO_PENDING,
request.StartRequest(
SPDY_BIDIRECTIONAL_STREAM, session, test_url_, MEDIUM,
BoundNetLog(),
stream_releaser.MakeCallback(&request)));
data.RunFor(1);
EXPECT_EQ(OK, stream_releaser.WaitForResult());
data.RunFor(1);
EXPECT_TRUE(session == NULL);
}
TEST_P(SpdySessionTest, ClearSettings) {
if (spdy_util_.spdy_version() >= SPDY4) {
return;
}
session_deps_.host_resolver->set_synchronous_mode(true);
SettingsMap new_settings;
const uint32 max_concurrent_streams = kInitialMaxConcurrentStreams + 1;
new_settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
scoped_ptr<SpdyFrame> settings_frame(
spdy_util_.ConstructSpdySettings(new_settings));
uint8 flags = SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS;
test::SetFrameFlags(settings_frame.get(), flags, spdy_util_.spdy_version());
MockRead reads[] = {
CreateMockRead(*settings_frame, 0),
MockRead(ASYNC, 0, 1),
};
DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
MockConnect connect_data(SYNCHRONOUS, OK);
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
spdy_session_pool_->http_server_properties()->SetSpdySetting(
test_host_port_pair_,
SETTINGS_MAX_CONCURRENT_STREAMS,
SETTINGS_FLAG_PLEASE_PERSIST,
kInitialMaxConcurrentStreams);
EXPECT_FALSE(
spdy_session_pool_->http_server_properties()->GetSpdySettings(
test_host_port_pair_).empty());
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
for (size_t i = 0; i < kInitialMaxConcurrentStreams; ++i) {
base::WeakPtr<SpdyStream> spdy_stream =
CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
session, test_url_, MEDIUM, BoundNetLog());
ASSERT_TRUE(spdy_stream != NULL);
}
StreamReleaserCallback stream_releaser;
SpdyStreamRequest request;
ASSERT_EQ(ERR_IO_PENDING,
request.StartRequest(
SPDY_BIDIRECTIONAL_STREAM, session, test_url_, MEDIUM,
BoundNetLog(),
stream_releaser.MakeCallback(&request)));
data.RunFor(1);
EXPECT_EQ(OK, stream_releaser.WaitForResult());
EXPECT_TRUE(
spdy_session_pool_->http_server_properties()->GetSpdySettings(
test_host_port_pair_).empty());
EXPECT_EQ(kInitialMaxConcurrentStreams + 1,
session->max_concurrent_streams());
data.RunFor(1);
EXPECT_TRUE(session == NULL);
}
TEST_P(SpdySessionTest, CancelPendingCreateStream) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockRead reads[] = {
MockRead(SYNCHRONOUS, ERR_IO_PENDING)
};
StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
MockConnect connect_data(SYNCHRONOUS, OK);
data.set_connect_data(connect_data);
session_deps_.socket_factory->AddSocketDataProvider(&data);
CreateNetworkSession();
spdy_session_pool_->http_server_properties()->SetSpdySetting(
test_host_port_pair_,
SETTINGS_MAX_CONCURRENT_STREAMS,
SETTINGS_FLAG_PLEASE_PERSIST,
1);
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
for (size_t i = 0; i < kInitialMaxConcurrentStreams - 1; ++i) {
base::WeakPtr<SpdyStream> spdy_stream =
CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
session, test_url_, MEDIUM, BoundNetLog());
ASSERT_TRUE(spdy_stream != NULL);
}
base::WeakPtr<SpdyStream> spdy_stream1 =
CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
session, test_url_, MEDIUM, BoundNetLog());
ASSERT_TRUE(spdy_stream1.get() != NULL);
scoped_ptr<TestCompletionCallback> callback(new TestCompletionCallback);
SpdyStreamRequest request;
ASSERT_EQ(ERR_IO_PENDING,
request.StartRequest(
SPDY_BIDIRECTIONAL_STREAM, session, test_url_, MEDIUM,
BoundNetLog(),
callback->callback()));
spdy_stream1->Cancel();
EXPECT_EQ(NULL, spdy_stream1.get());
request.CancelRequest();
callback.reset();
base::MessageLoop::current()->RunUntilIdle();
}
TEST_P(SpdySessionTest, SendInitialDataOnNewSession) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockRead reads[] = {
MockRead(SYNCHRONOUS, ERR_IO_PENDING)
};
SettingsMap settings;
const SpdySettingsIds kSpdySettingsIds1 = SETTINGS_MAX_CONCURRENT_STREAMS;
const SpdySettingsIds kSpdySettingsIds2 = SETTINGS_INITIAL_WINDOW_SIZE;
const uint32 kInitialRecvWindowSize = 10 * 1024 * 1024;
settings[kSpdySettingsIds1] =
SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kMaxConcurrentPushedStreams);
if (spdy_util_.spdy_version() >= SPDY3) {
settings[kSpdySettingsIds2] =
SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kInitialRecvWindowSize);
}
MockConnect connect_data(SYNCHRONOUS, OK);
scoped_ptr<SpdyFrame> settings_frame(
spdy_util_.ConstructSpdySettings(settings));
scoped_ptr<SpdyFrame> initial_window_update(
spdy_util_.ConstructSpdyWindowUpdate(
kSessionFlowControlStreamId,
kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize));
std::vector<MockWrite> writes;
if (GetParam() == kProtoHTTP2Draft04) {
writes.push_back(
MockWrite(ASYNC,
kHttp2ConnectionHeaderPrefix,
kHttp2ConnectionHeaderPrefixSize));
}
writes.push_back(CreateMockWrite(*settings_frame));
if (GetParam() >= kProtoSPDY31) {
writes.push_back(CreateMockWrite(*initial_window_update));
};
SettingsMap server_settings;
const uint32 initial_max_concurrent_streams = 1;
server_settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
SettingsFlagsAndValue(SETTINGS_FLAG_PERSISTED,
initial_max_concurrent_streams);
scoped_ptr<SpdyFrame> server_settings_frame(
spdy_util_.ConstructSpdySettings(server_settings));
writes.push_back(CreateMockWrite(*server_settings_frame));
session_deps_.stream_initial_recv_window_size = kInitialRecvWindowSize;
StaticSocketDataProvider data(reads, arraysize(reads),
vector_as_array(&writes), writes.size());
data.set_connect_data(connect_data);
session_deps_.socket_factory->AddSocketDataProvider(&data);
CreateNetworkSession();
spdy_session_pool_->http_server_properties()->SetSpdySetting(
test_host_port_pair_,
SETTINGS_MAX_CONCURRENT_STREAMS,
SETTINGS_FLAG_PLEASE_PERSIST,
initial_max_concurrent_streams);
SpdySessionPoolPeer pool_peer(spdy_session_pool_);
pool_peer.SetEnableSendingInitialData(true);
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
base::MessageLoop::current()->RunUntilIdle();
EXPECT_TRUE(data.at_write_eof());
}
TEST_P(SpdySessionTest, ClearSettingsStorageOnIPAddressChanged) {
CreateNetworkSession();
base::WeakPtr<HttpServerProperties> test_http_server_properties =
spdy_session_pool_->http_server_properties();
SettingsFlagsAndValue flags_and_value1(SETTINGS_FLAG_PLEASE_PERSIST, 2);
test_http_server_properties->SetSpdySetting(
test_host_port_pair_,
SETTINGS_MAX_CONCURRENT_STREAMS,
SETTINGS_FLAG_PLEASE_PERSIST,
2);
EXPECT_NE(0u, test_http_server_properties->GetSpdySettings(
test_host_port_pair_).size());
spdy_session_pool_->OnIPAddressChanged();
EXPECT_EQ(0u, test_http_server_properties->GetSpdySettings(
test_host_port_pair_).size());
}
TEST_P(SpdySessionTest, Initialize) {
CapturingBoundNetLog log;
session_deps_.net_log = log.bound().net_log();
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
MockRead reads[] = {
MockRead(ASYNC, 0, 0)
};
StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
data.set_connect_data(connect_data);
session_deps_.socket_factory->AddSocketDataProvider(&data);
CreateNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, log.bound());
EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
base::MessageLoop::current()->RunUntilIdle();
net::CapturingNetLog::CapturedEntryList entries;
log.GetEntries(&entries);
EXPECT_LT(0u, entries.size());
int pos = net::ExpectLogContainsSomewhere(
entries, 0,
net::NetLog::TYPE_SPDY_SESSION_INITIALIZED,
net::NetLog::PHASE_NONE);
EXPECT_LT(0, pos);
CapturingNetLog::CapturedEntry entry = entries[pos];
NetLog::Source socket_source;
EXPECT_TRUE(NetLog::Source::FromEventParameters(entry.params.get(),
&socket_source));
EXPECT_TRUE(socket_source.IsValid());
EXPECT_NE(log.bound().source().id, socket_source.id);
}
TEST_P(SpdySessionTest, CloseSessionOnError) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway());
MockRead reads[] = {
CreateMockRead(*goaway),
MockRead(SYNCHRONOUS, 0, 0)
};
StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
data.set_connect_data(connect_data);
session_deps_.socket_factory->AddSocketDataProvider(&data);
CreateNetworkSession();
CapturingBoundNetLog log;
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, log.bound());
EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
base::MessageLoop::current()->RunUntilIdle();
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
EXPECT_TRUE(session == NULL);
net::CapturingNetLog::CapturedEntryList entries;
log.GetEntries(&entries);
EXPECT_LT(0u, entries.size());
int pos = net::ExpectLogContainsSomewhere(
entries, 0,
net::NetLog::TYPE_SPDY_SESSION_CLOSE,
net::NetLog::PHASE_NONE);
if (pos < static_cast<int>(entries.size())) {
CapturingNetLog::CapturedEntry entry = entries[pos];
int error_code = 0;
ASSERT_TRUE(entry.GetNetErrorCode(&error_code));
EXPECT_EQ(ERR_CONNECTION_CLOSED, error_code);
} else {
ADD_FAILURE();
}
}
TEST_P(SpdySessionTest, OutOfOrderSynStreams) {
MockConnect connect_data(SYNCHRONOUS, OK);
scoped_ptr<SpdyFrame> req_highest(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, HIGHEST, true));
scoped_ptr<SpdyFrame> req_lowest(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
MockWrite writes[] = {
CreateMockWrite(*req_highest, 0),
CreateMockWrite(*req_lowest, 1),
};
scoped_ptr<SpdyFrame> resp_highest(
spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
scoped_ptr<SpdyFrame> body_highest(
spdy_util_.ConstructSpdyBodyFrame(1, true));
scoped_ptr<SpdyFrame> resp_lowest(
spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
scoped_ptr<SpdyFrame> body_lowest(
spdy_util_.ConstructSpdyBodyFrame(3, true));
MockRead reads[] = {
CreateMockRead(*resp_highest, 2),
CreateMockRead(*body_highest, 3),
CreateMockRead(*resp_lowest, 4),
CreateMockRead(*body_lowest, 5),
MockRead(ASYNC, 0, 6)
};
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);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
GURL url(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream_lowest =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url, LOWEST, BoundNetLog());
ASSERT_TRUE(spdy_stream_lowest);
EXPECT_EQ(0u, spdy_stream_lowest->stream_id());
test::StreamDelegateDoNothing delegate_lowest(spdy_stream_lowest);
spdy_stream_lowest->SetDelegate(&delegate_lowest);
base::WeakPtr<SpdyStream> spdy_stream_highest =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url, HIGHEST, BoundNetLog());
ASSERT_TRUE(spdy_stream_highest);
EXPECT_EQ(0u, spdy_stream_highest->stream_id());
test::StreamDelegateDoNothing delegate_highest(spdy_stream_highest);
spdy_stream_highest->SetDelegate(&delegate_highest);
scoped_ptr<SpdyHeaderBlock> headers_lowest(
spdy_util_.ConstructGetHeaderBlock(url.spec()));
spdy_stream_lowest->SendRequestHeaders(
headers_lowest.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream_lowest->HasUrlFromHeaders());
scoped_ptr<SpdyHeaderBlock> headers_highest(
spdy_util_.ConstructGetHeaderBlock(url.spec()));
spdy_stream_highest->SendRequestHeaders(
headers_highest.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream_highest->HasUrlFromHeaders());
data.RunFor(7);
EXPECT_FALSE(spdy_stream_lowest);
EXPECT_FALSE(spdy_stream_highest);
EXPECT_EQ(3u, delegate_lowest.stream_id());
EXPECT_EQ(1u, delegate_highest.stream_id());
}
TEST_P(SpdySessionTest, CancelStream) {
MockConnect connect_data(SYNCHRONOUS, OK);
scoped_ptr<SpdyFrame> req2(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
MockWrite writes[] = {
CreateMockWrite(*req2, 0),
};
scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(1, true));
MockRead reads[] = {
CreateMockRead(*resp2, 1),
CreateMockRead(*body2, 2),
MockRead(ASYNC, 0, 3)
};
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);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
GURL url1(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream1 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url1, HIGHEST, BoundNetLog());
ASSERT_TRUE(spdy_stream1.get() != NULL);
EXPECT_EQ(0u, spdy_stream1->stream_id());
test::StreamDelegateDoNothing delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
GURL url2(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream2 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url2, LOWEST, BoundNetLog());
ASSERT_TRUE(spdy_stream2.get() != NULL);
EXPECT_EQ(0u, spdy_stream2->stream_id());
test::StreamDelegateDoNothing delegate2(spdy_stream2);
spdy_stream2->SetDelegate(&delegate2);
scoped_ptr<SpdyHeaderBlock> headers(
spdy_util_.ConstructGetHeaderBlock(url1.spec()));
spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
scoped_ptr<SpdyHeaderBlock> headers2(
spdy_util_.ConstructGetHeaderBlock(url2.spec()));
spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
EXPECT_EQ(0u, spdy_stream1->stream_id());
spdy_stream1->Cancel();
EXPECT_EQ(NULL, spdy_stream1.get());
EXPECT_EQ(0u, delegate1.stream_id());
data.RunFor(1);
EXPECT_EQ(0u, delegate1.stream_id());
EXPECT_EQ(1u, delegate2.stream_id());
spdy_stream2->Cancel();
EXPECT_EQ(NULL, spdy_stream2.get());
}
TEST_P(SpdySessionTest, CloseSessionWithTwoCreatedSelfClosingStreams) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
MockWrite writes[] = {
MockWrite(ASYNC, 0, 1)
};
MockRead reads[] = {
MockRead(ASYNC, 0, 0)
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
GURL url1(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream1 =
CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
session, url1, HIGHEST, BoundNetLog());
ASSERT_TRUE(spdy_stream1.get() != NULL);
EXPECT_EQ(0u, spdy_stream1->stream_id());
GURL url2(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream2 =
CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
session, url2, LOWEST, BoundNetLog());
ASSERT_TRUE(spdy_stream2.get() != NULL);
EXPECT_EQ(0u, spdy_stream2->stream_id());
test::ClosingDelegate delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
test::ClosingDelegate delegate2(spdy_stream2);
spdy_stream2->SetDelegate(&delegate2);
scoped_ptr<SpdyHeaderBlock> headers(
spdy_util_.ConstructGetHeaderBlock(url1.spec()));
spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
scoped_ptr<SpdyHeaderBlock> headers2(
spdy_util_.ConstructGetHeaderBlock(url2.spec()));
spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
EXPECT_EQ(0u, spdy_stream1->stream_id());
EXPECT_EQ(0u, spdy_stream2->stream_id());
session->CloseSessionOnError(ERR_ABORTED, std::string());
EXPECT_EQ(NULL, spdy_stream1.get());
EXPECT_EQ(NULL, spdy_stream2.get());
EXPECT_TRUE(delegate1.StreamIsClosed());
EXPECT_TRUE(delegate2.StreamIsClosed());
EXPECT_TRUE(session == NULL);
}
TEST_P(SpdySessionTest, CloseSessionWithTwoCreatedMutuallyClosingStreams) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
MockWrite writes[] = {
MockWrite(ASYNC, 0, 1)
};
MockRead reads[] = {
MockRead(ASYNC, 0, 0)
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
GURL url1(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream1 =
CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
session, url1, HIGHEST, BoundNetLog());
ASSERT_TRUE(spdy_stream1.get() != NULL);
EXPECT_EQ(0u, spdy_stream1->stream_id());
GURL url2(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream2 =
CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
session, url2, LOWEST, BoundNetLog());
ASSERT_TRUE(spdy_stream2.get() != NULL);
EXPECT_EQ(0u, spdy_stream2->stream_id());
test::ClosingDelegate delegate1(spdy_stream2);
spdy_stream1->SetDelegate(&delegate1);
test::ClosingDelegate delegate2(spdy_stream1);
spdy_stream2->SetDelegate(&delegate2);
scoped_ptr<SpdyHeaderBlock> headers(
spdy_util_.ConstructGetHeaderBlock(url1.spec()));
spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
scoped_ptr<SpdyHeaderBlock> headers2(
spdy_util_.ConstructGetHeaderBlock(url2.spec()));
spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
EXPECT_EQ(0u, spdy_stream1->stream_id());
EXPECT_EQ(0u, spdy_stream2->stream_id());
session->CloseSessionOnError(ERR_ABORTED, std::string());
EXPECT_EQ(NULL, spdy_stream1.get());
EXPECT_EQ(NULL, spdy_stream2.get());
EXPECT_TRUE(delegate1.StreamIsClosed());
EXPECT_TRUE(delegate2.StreamIsClosed());
EXPECT_TRUE(session == NULL);
}
TEST_P(SpdySessionTest, CloseSessionWithTwoActivatedSelfClosingStreams) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
scoped_ptr<SpdyFrame> req1(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
scoped_ptr<SpdyFrame> req2(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, MEDIUM, true));
MockWrite writes[] = {
CreateMockWrite(*req1, 0),
CreateMockWrite(*req2, 1),
};
MockRead reads[] = {
MockRead(ASYNC, 0, 2)
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
GURL url1(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream1 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url1, MEDIUM, BoundNetLog());
ASSERT_TRUE(spdy_stream1.get() != NULL);
EXPECT_EQ(0u, spdy_stream1->stream_id());
GURL url2(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream2 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url2, MEDIUM, BoundNetLog());
ASSERT_TRUE(spdy_stream2.get() != NULL);
EXPECT_EQ(0u, spdy_stream2->stream_id());
test::ClosingDelegate delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
test::ClosingDelegate delegate2(spdy_stream2);
spdy_stream2->SetDelegate(&delegate2);
scoped_ptr<SpdyHeaderBlock> headers(
spdy_util_.ConstructGetHeaderBlock(url1.spec()));
spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
scoped_ptr<SpdyHeaderBlock> headers2(
spdy_util_.ConstructGetHeaderBlock(url2.spec()));
spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
EXPECT_EQ(0u, spdy_stream1->stream_id());
EXPECT_EQ(0u, spdy_stream2->stream_id());
data.RunFor(2);
EXPECT_EQ(1u, spdy_stream1->stream_id());
EXPECT_EQ(3u, spdy_stream2->stream_id());
session->CloseSessionOnError(ERR_ABORTED, std::string());
EXPECT_EQ(NULL, spdy_stream1.get());
EXPECT_EQ(NULL, spdy_stream2.get());
EXPECT_TRUE(delegate1.StreamIsClosed());
EXPECT_TRUE(delegate2.StreamIsClosed());
EXPECT_TRUE(session == NULL);
}
TEST_P(SpdySessionTest, CloseSessionWithTwoActivatedMutuallyClosingStreams) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
scoped_ptr<SpdyFrame> req1(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
scoped_ptr<SpdyFrame> req2(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, MEDIUM, true));
MockWrite writes[] = {
CreateMockWrite(*req1, 0),
CreateMockWrite(*req2, 1),
};
MockRead reads[] = {
MockRead(ASYNC, 0, 2)
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
GURL url1(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream1 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url1, MEDIUM, BoundNetLog());
ASSERT_TRUE(spdy_stream1.get() != NULL);
EXPECT_EQ(0u, spdy_stream1->stream_id());
GURL url2(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream2 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url2, MEDIUM, BoundNetLog());
ASSERT_TRUE(spdy_stream2.get() != NULL);
EXPECT_EQ(0u, spdy_stream2->stream_id());
test::ClosingDelegate delegate1(spdy_stream2);
spdy_stream1->SetDelegate(&delegate1);
test::ClosingDelegate delegate2(spdy_stream1);
spdy_stream2->SetDelegate(&delegate2);
scoped_ptr<SpdyHeaderBlock> headers(
spdy_util_.ConstructGetHeaderBlock(url1.spec()));
spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
scoped_ptr<SpdyHeaderBlock> headers2(
spdy_util_.ConstructGetHeaderBlock(url2.spec()));
spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
EXPECT_EQ(0u, spdy_stream1->stream_id());
EXPECT_EQ(0u, spdy_stream2->stream_id());
data.RunFor(2);
EXPECT_EQ(1u, spdy_stream1->stream_id());
EXPECT_EQ(3u, spdy_stream2->stream_id());
session->CloseSessionOnError(ERR_ABORTED, std::string());
EXPECT_EQ(NULL, spdy_stream1.get());
EXPECT_EQ(NULL, spdy_stream2.get());
EXPECT_TRUE(delegate1.StreamIsClosed());
EXPECT_TRUE(delegate2.StreamIsClosed());
EXPECT_TRUE(session == NULL);
}
class SessionClosingDelegate : public test::StreamDelegateDoNothing {
public:
SessionClosingDelegate(const base::WeakPtr<SpdyStream>& stream,
const base::WeakPtr<SpdySession>& session_to_close)
: StreamDelegateDoNothing(stream),
session_to_close_(session_to_close) {}
virtual ~SessionClosingDelegate() {}
virtual void OnClose(int status) OVERRIDE {
session_to_close_->CloseSessionOnError(ERR_ABORTED, "Aborted");
}
private:
base::WeakPtr<SpdySession> session_to_close_;
};
TEST_P(SpdySessionTest, CloseActivatedStreamThatClosesSession) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
scoped_ptr<SpdyFrame> req(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
MockWrite writes[] = {
CreateMockWrite(*req, 0),
};
MockRead reads[] = {
MockRead(ASYNC, 0, 1)
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
GURL url(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url, MEDIUM, BoundNetLog());
ASSERT_TRUE(spdy_stream.get() != NULL);
EXPECT_EQ(0u, spdy_stream->stream_id());
SessionClosingDelegate delegate(spdy_stream, session);
spdy_stream->SetDelegate(&delegate);
scoped_ptr<SpdyHeaderBlock> headers(
spdy_util_.ConstructGetHeaderBlock(url.spec()));
spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
EXPECT_EQ(0u, spdy_stream->stream_id());
data.RunFor(1);
EXPECT_EQ(1u, spdy_stream->stream_id());
spdy_stream->Cancel();
EXPECT_EQ(NULL, spdy_stream.get());
EXPECT_TRUE(delegate.StreamIsClosed());
EXPECT_TRUE(session == NULL);
}
TEST_P(SpdySessionTest, VerifyDomainAuthentication) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
MockWrite writes[] = {
MockWrite(ASYNC, 0, 1)
};
MockRead reads[] = {
MockRead(ASYNC, 0, 0)
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
base::FilePath certs_dir = GetTestCertsDirectory();
scoped_refptr<X509Certificate> test_cert(
ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert);
SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
ssl.cert = test_cert;
session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateSecureSpdySession(http_session_, key_, BoundNetLog());
EXPECT_TRUE(session->VerifyDomainAuthentication("www.example.org"));
EXPECT_TRUE(session->VerifyDomainAuthentication("mail.example.org"));
EXPECT_TRUE(session->VerifyDomainAuthentication("mail.example.com"));
EXPECT_FALSE(session->VerifyDomainAuthentication("mail.google.com"));
}
TEST_P(SpdySessionTest, ConnectionPooledWithTlsChannelId) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
MockWrite writes[] = {
MockWrite(ASYNC, 0, 1)
};
MockRead reads[] = {
MockRead(ASYNC, 0, 0)
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
base::FilePath certs_dir = GetTestCertsDirectory();
scoped_refptr<X509Certificate> test_cert(
ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert);
SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
ssl.channel_id_sent = true;
ssl.cert = test_cert;
session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateSecureSpdySession(http_session_, key_, BoundNetLog());
EXPECT_TRUE(session->VerifyDomainAuthentication("www.example.org"));
EXPECT_TRUE(session->VerifyDomainAuthentication("mail.example.org"));
EXPECT_FALSE(session->VerifyDomainAuthentication("mail.example.com"));
EXPECT_FALSE(session->VerifyDomainAuthentication("mail.google.com"));
}
TEST_P(SpdySessionTest, CloseTwoStalledCreateStream) {
MockConnect connect_data(SYNCHRONOUS, OK);
SettingsMap new_settings;
const SpdySettingsIds kSpdySettingsIds1 = SETTINGS_MAX_CONCURRENT_STREAMS;
const uint32 max_concurrent_streams = 1;
new_settings[kSpdySettingsIds1] =
SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
scoped_ptr<SpdyFrame> req1(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
scoped_ptr<SpdyFrame> req2(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
scoped_ptr<SpdyFrame> req3(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, LOWEST, true));
MockWrite writes[] = {
CreateMockWrite(*req1, 1),
CreateMockWrite(*req2, 4),
CreateMockWrite(*req3, 7),
};
scoped_ptr<SpdyFrame> settings_frame(
spdy_util_.ConstructSpdySettings(new_settings));
scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
scoped_ptr<SpdyFrame> body1(spdy_util_.ConstructSpdyBodyFrame(1, true));
scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, true));
scoped_ptr<SpdyFrame> resp3(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5));
scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(5, true));
MockRead reads[] = {
CreateMockRead(*settings_frame),
CreateMockRead(*resp1, 2),
CreateMockRead(*body1, 3),
CreateMockRead(*resp2, 5),
CreateMockRead(*body2, 6),
CreateMockRead(*resp3, 8),
CreateMockRead(*body3, 9),
MockRead(ASYNC, 0, 10)
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
data.RunFor(1);
GURL url1(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream1 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url1, LOWEST, BoundNetLog());
ASSERT_TRUE(spdy_stream1.get() != NULL);
EXPECT_EQ(0u, spdy_stream1->stream_id());
test::StreamDelegateDoNothing delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
TestCompletionCallback callback2;
GURL url2(kDefaultURL);
SpdyStreamRequest request2;
ASSERT_EQ(ERR_IO_PENDING,
request2.StartRequest(
SPDY_REQUEST_RESPONSE_STREAM,
session, url2, LOWEST, BoundNetLog(), callback2.callback()));
TestCompletionCallback callback3;
GURL url3(kDefaultURL);
SpdyStreamRequest request3;
ASSERT_EQ(ERR_IO_PENDING,
request3.StartRequest(
SPDY_REQUEST_RESPONSE_STREAM,
session, url3, LOWEST, BoundNetLog(), callback3.callback()));
EXPECT_EQ(0u, session->num_active_streams());
EXPECT_EQ(1u, session->num_created_streams());
EXPECT_EQ(2u, session->pending_create_stream_queue_size(LOWEST));
scoped_ptr<SpdyHeaderBlock> headers(
spdy_util_.ConstructGetHeaderBlock(url1.spec()));
spdy_stream1->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
EXPECT_EQ(0u, delegate1.stream_id());
data.RunFor(3);
EXPECT_EQ(NULL, spdy_stream1.get());
EXPECT_EQ(1u, delegate1.stream_id());
EXPECT_EQ(0u, session->num_active_streams());
EXPECT_EQ(0u, session->num_created_streams());
EXPECT_EQ(1u, session->pending_create_stream_queue_size(LOWEST));
base::MessageLoop::current()->RunUntilIdle();
EXPECT_EQ(0u, session->num_active_streams());
EXPECT_EQ(1u, session->num_created_streams());
EXPECT_EQ(1u, session->pending_create_stream_queue_size(LOWEST));
base::WeakPtr<SpdyStream> stream2 = request2.ReleaseStream();
test::StreamDelegateDoNothing delegate2(stream2);
stream2->SetDelegate(&delegate2);
scoped_ptr<SpdyHeaderBlock> headers2(
spdy_util_.ConstructGetHeaderBlock(url2.spec()));
stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(stream2->HasUrlFromHeaders());
EXPECT_EQ(0u, delegate2.stream_id());
data.RunFor(3);
EXPECT_EQ(NULL, stream2.get());
EXPECT_EQ(3u, delegate2.stream_id());
EXPECT_EQ(0u, session->num_active_streams());
EXPECT_EQ(0u, session->num_created_streams());
EXPECT_EQ(0u, session->pending_create_stream_queue_size(LOWEST));
base::MessageLoop::current()->RunUntilIdle();
EXPECT_EQ(0u, session->num_active_streams());
EXPECT_EQ(1u, session->num_created_streams());
EXPECT_EQ(0u, session->pending_create_stream_queue_size(LOWEST));
base::WeakPtr<SpdyStream> stream3 = request3.ReleaseStream();
test::StreamDelegateDoNothing delegate3(stream3);
stream3->SetDelegate(&delegate3);
scoped_ptr<SpdyHeaderBlock> headers3(
spdy_util_.ConstructGetHeaderBlock(url3.spec()));
stream3->SendRequestHeaders(headers3.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(stream3->HasUrlFromHeaders());
EXPECT_EQ(0u, delegate3.stream_id());
data.RunFor(3);
EXPECT_EQ(NULL, stream3.get());
EXPECT_EQ(5u, delegate3.stream_id());
EXPECT_EQ(0u, session->num_active_streams());
EXPECT_EQ(0u, session->num_created_streams());
EXPECT_EQ(0u, session->pending_create_stream_queue_size(LOWEST));
data.RunFor(1);
}
TEST_P(SpdySessionTest, CancelTwoStalledCreateStream) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockRead reads[] = {
MockRead(SYNCHRONOUS, ERR_IO_PENDING)
};
StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
MockConnect connect_data(SYNCHRONOUS, OK);
data.set_connect_data(connect_data);
session_deps_.socket_factory->AddSocketDataProvider(&data);
CreateNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
for (size_t i = 0; i < kInitialMaxConcurrentStreams - 1; ++i) {
base::WeakPtr<SpdyStream> spdy_stream =
CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
session, test_url_, MEDIUM, BoundNetLog());
ASSERT_TRUE(spdy_stream != NULL);
}
GURL url1(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream1 =
CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
session, url1, LOWEST, BoundNetLog());
ASSERT_TRUE(spdy_stream1.get() != NULL);
EXPECT_EQ(0u, spdy_stream1->stream_id());
TestCompletionCallback callback2;
GURL url2(kDefaultURL);
SpdyStreamRequest request2;
ASSERT_EQ(ERR_IO_PENDING,
request2.StartRequest(
SPDY_BIDIRECTIONAL_STREAM, session, url2, LOWEST, BoundNetLog(),
callback2.callback()));
TestCompletionCallback callback3;
GURL url3(kDefaultURL);
SpdyStreamRequest request3;
ASSERT_EQ(ERR_IO_PENDING,
request3.StartRequest(
SPDY_BIDIRECTIONAL_STREAM, session, url3, LOWEST, BoundNetLog(),
callback3.callback()));
EXPECT_EQ(0u, session->num_active_streams());
EXPECT_EQ(kInitialMaxConcurrentStreams, session->num_created_streams());
EXPECT_EQ(2u, session->pending_create_stream_queue_size(LOWEST));
EXPECT_TRUE(spdy_stream1.get() != NULL);
spdy_stream1->Cancel();
EXPECT_EQ(NULL, spdy_stream1.get());
EXPECT_EQ(OK, callback2.WaitForResult());
EXPECT_EQ(0u, session->num_active_streams());
EXPECT_EQ(kInitialMaxConcurrentStreams, session->num_created_streams());
EXPECT_EQ(1u, session->pending_create_stream_queue_size(LOWEST));
base::WeakPtr<SpdyStream> spdy_stream2 = request2.ReleaseStream();
spdy_stream2->Cancel();
EXPECT_EQ(NULL, spdy_stream2.get());
EXPECT_EQ(OK, callback3.WaitForResult());
EXPECT_EQ(0u, session->num_active_streams());
EXPECT_EQ(kInitialMaxConcurrentStreams, session->num_created_streams());
EXPECT_EQ(0u, session->pending_create_stream_queue_size(LOWEST));
base::WeakPtr<SpdyStream> spdy_stream3 = request3.ReleaseStream();
spdy_stream3->Cancel();
EXPECT_EQ(NULL, spdy_stream3.get());
EXPECT_EQ(0u, session->num_active_streams());
EXPECT_EQ(kInitialMaxConcurrentStreams - 1, session->num_created_streams());
EXPECT_EQ(0u, session->pending_create_stream_queue_size(LOWEST));
}
TEST_P(SpdySessionTest, ReadDataWithoutYielding) {
MockConnect connect_data(SYNCHRONOUS, OK);
BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
scoped_ptr<SpdyFrame> req1(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
MockWrite writes[] = {
CreateMockWrite(*req1, 0),
};
ASSERT_EQ(32 * 1024, kMaxReadBytesWithoutYielding);
const int kPayloadSize =
kMaxReadBytesWithoutYielding / 4 - framer.GetControlFrameHeaderSize();
TestDataStream test_stream;
scoped_refptr<net::IOBuffer> payload(new net::IOBuffer(kPayloadSize));
char* payload_data = payload->data();
test_stream.GetBytes(payload_data, kPayloadSize);
scoped_ptr<SpdyFrame> partial_data_frame(
framer.CreateDataFrame(1, payload_data, kPayloadSize, DATA_FLAG_NONE));
scoped_ptr<SpdyFrame> finish_data_frame(
framer.CreateDataFrame(1, payload_data, kPayloadSize - 1, DATA_FLAG_FIN));
scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
MockRead reads[] = {
CreateMockRead(*resp1, 1),
CreateMockRead(*partial_data_frame, 2),
CreateMockRead(*partial_data_frame, 3, SYNCHRONOUS),
CreateMockRead(*partial_data_frame, 4, SYNCHRONOUS),
CreateMockRead(*finish_data_frame, 5, SYNCHRONOUS),
MockRead(ASYNC, 0, 6)
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.host_resolver->set_synchronous_mode(true);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
GURL url1(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream1 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url1, MEDIUM, BoundNetLog());
ASSERT_TRUE(spdy_stream1.get() != NULL);
EXPECT_EQ(0u, spdy_stream1->stream_id());
test::StreamDelegateDoNothing delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
scoped_ptr<SpdyHeaderBlock> headers1(
spdy_util_.ConstructGetHeaderBlock(url1.spec()));
spdy_stream1->SendRequestHeaders(headers1.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
SpdySessionTestTaskObserver observer("spdy_session.cc", "DoReadLoop");
EXPECT_EQ(0u, delegate1.stream_id());
data.RunFor(2);
EXPECT_EQ(1u, delegate1.stream_id());
EXPECT_EQ(0u, observer.executed_count());
data.RunFor(4);
EXPECT_EQ(NULL, spdy_stream1.get());
EXPECT_EQ(0u, observer.executed_count());
EXPECT_TRUE(data.at_write_eof());
EXPECT_TRUE(data.at_read_eof());
}
TEST_P(SpdySessionTest, TestYieldingDuringReadData) {
MockConnect connect_data(SYNCHRONOUS, OK);
BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
scoped_ptr<SpdyFrame> req1(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
MockWrite writes[] = {
CreateMockWrite(*req1, 0),
};
ASSERT_EQ(32 * 1024, kMaxReadBytesWithoutYielding);
const int kPayloadSize =
kMaxReadBytesWithoutYielding / 4 - framer.GetControlFrameHeaderSize();
TestDataStream test_stream;
scoped_refptr<net::IOBuffer> payload(new net::IOBuffer(kPayloadSize));
char* payload_data = payload->data();
test_stream.GetBytes(payload_data, kPayloadSize);
scoped_ptr<SpdyFrame> partial_data_frame(
framer.CreateDataFrame(1, payload_data, kPayloadSize, DATA_FLAG_NONE));
scoped_ptr<SpdyFrame> finish_data_frame(
framer.CreateDataFrame(1, "h", 1, DATA_FLAG_FIN));
scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
MockRead reads[] = {
CreateMockRead(*resp1, 1),
CreateMockRead(*partial_data_frame, 2),
CreateMockRead(*partial_data_frame, 3, SYNCHRONOUS),
CreateMockRead(*partial_data_frame, 4, SYNCHRONOUS),
CreateMockRead(*partial_data_frame, 5, SYNCHRONOUS),
CreateMockRead(*finish_data_frame, 6, SYNCHRONOUS),
MockRead(ASYNC, 0, 7)
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.host_resolver->set_synchronous_mode(true);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
GURL url1(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream1 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url1, MEDIUM, BoundNetLog());
ASSERT_TRUE(spdy_stream1.get() != NULL);
EXPECT_EQ(0u, spdy_stream1->stream_id());
test::StreamDelegateDoNothing delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
scoped_ptr<SpdyHeaderBlock> headers1(
spdy_util_.ConstructGetHeaderBlock(url1.spec()));
spdy_stream1->SendRequestHeaders(headers1.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
SpdySessionTestTaskObserver observer("spdy_session.cc", "DoReadLoop");
EXPECT_EQ(0u, delegate1.stream_id());
data.RunFor(2);
EXPECT_EQ(1u, delegate1.stream_id());
EXPECT_EQ(0u, observer.executed_count());
data.RunFor(6);
EXPECT_EQ(NULL, spdy_stream1.get());
EXPECT_EQ(1u, observer.executed_count());
EXPECT_TRUE(data.at_write_eof());
EXPECT_TRUE(data.at_read_eof());
}
TEST_P(SpdySessionTest, TestYieldingDuringAsyncReadData) {
MockConnect connect_data(SYNCHRONOUS, OK);
BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
scoped_ptr<SpdyFrame> req1(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
MockWrite writes[] = {
CreateMockWrite(*req1, 0),
};
ASSERT_EQ(32 * 1024, kMaxReadBytesWithoutYielding);
TestDataStream test_stream;
const int kEightKPayloadSize =
kMaxReadBytesWithoutYielding / 4 - framer.GetControlFrameHeaderSize();
scoped_refptr<net::IOBuffer> eightk_payload(
new net::IOBuffer(kEightKPayloadSize));
char* eightk_payload_data = eightk_payload->data();
test_stream.GetBytes(eightk_payload_data, kEightKPayloadSize);
TestDataStream test_stream2;
const int kTwoKPayloadSize = kEightKPayloadSize - 6 * 1024;
scoped_refptr<net::IOBuffer> twok_payload(
new net::IOBuffer(kTwoKPayloadSize));
char* twok_payload_data = twok_payload->data();
test_stream2.GetBytes(twok_payload_data, kTwoKPayloadSize);
scoped_ptr<SpdyFrame> eightk_data_frame(framer.CreateDataFrame(
1, eightk_payload_data, kEightKPayloadSize, DATA_FLAG_NONE));
scoped_ptr<SpdyFrame> twok_data_frame(framer.CreateDataFrame(
1, twok_payload_data, kTwoKPayloadSize, DATA_FLAG_NONE));
scoped_ptr<SpdyFrame> finish_data_frame(framer.CreateDataFrame(
1, "h", 1, DATA_FLAG_FIN));
scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
MockRead reads[] = {
CreateMockRead(*resp1, 1),
CreateMockRead(*eightk_data_frame, 2),
CreateMockRead(*eightk_data_frame, 3, SYNCHRONOUS),
CreateMockRead(*eightk_data_frame, 4, SYNCHRONOUS),
CreateMockRead(*twok_data_frame, 5, SYNCHRONOUS),
CreateMockRead(*eightk_data_frame, 6, ASYNC),
CreateMockRead(*eightk_data_frame, 7, SYNCHRONOUS),
CreateMockRead(*eightk_data_frame, 8, SYNCHRONOUS),
CreateMockRead(*eightk_data_frame, 9, SYNCHRONOUS),
CreateMockRead(*twok_data_frame, 10, SYNCHRONOUS),
CreateMockRead(*finish_data_frame, 11, SYNCHRONOUS),
MockRead(ASYNC, 0, 12)
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.host_resolver->set_synchronous_mode(true);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
GURL url1(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream1 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url1, MEDIUM, BoundNetLog());
ASSERT_TRUE(spdy_stream1.get() != NULL);
EXPECT_EQ(0u, spdy_stream1->stream_id());
test::StreamDelegateDoNothing delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
scoped_ptr<SpdyHeaderBlock> headers1(
spdy_util_.ConstructGetHeaderBlock(url1.spec()));
spdy_stream1->SendRequestHeaders(headers1.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
SpdySessionTestTaskObserver observer("spdy_session.cc", "DoReadLoop");
EXPECT_EQ(0u, delegate1.stream_id());
data.RunFor(2);
EXPECT_EQ(1u, delegate1.stream_id());
EXPECT_EQ(0u, observer.executed_count());
data.RunFor(12);
EXPECT_EQ(NULL, spdy_stream1.get());
EXPECT_EQ(1u, observer.executed_count());
EXPECT_TRUE(data.at_write_eof());
EXPECT_TRUE(data.at_read_eof());
}
TEST_P(SpdySessionTest, GoAwayWhileInDoReadLoop) {
MockConnect connect_data(SYNCHRONOUS, OK);
BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
scoped_ptr<SpdyFrame> req1(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
MockWrite writes[] = {
CreateMockWrite(*req1, 0),
};
scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
scoped_ptr<SpdyFrame> body1(spdy_util_.ConstructSpdyBodyFrame(1, true));
scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway());
MockRead reads[] = {
CreateMockRead(*resp1, 1),
CreateMockRead(*body1, 2),
CreateMockRead(*goaway, 3),
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.host_resolver->set_synchronous_mode(true);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
GURL url1(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream1 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url1, MEDIUM, BoundNetLog());
test::StreamDelegateDoNothing delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
ASSERT_TRUE(spdy_stream1.get() != NULL);
EXPECT_EQ(0u, spdy_stream1->stream_id());
scoped_ptr<SpdyHeaderBlock> headers1(
spdy_util_.ConstructGetHeaderBlock(url1.spec()));
spdy_stream1->SendRequestHeaders(headers1.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
EXPECT_EQ(0u, spdy_stream1->stream_id());
data.RunFor(1);
EXPECT_EQ(1u, spdy_stream1->stream_id());
data.RunFor(3);
EXPECT_EQ(NULL, spdy_stream1.get());
EXPECT_TRUE(data.at_write_eof());
EXPECT_TRUE(data.at_read_eof());
EXPECT_TRUE(session == NULL);
}
TEST_P(SpdySessionTest, ProtocolNegotiation) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
MockRead reads[] = {
MockRead(SYNCHRONOUS, 0, 0)
};
StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
data.set_connect_data(connect_data);
session_deps_.socket_factory->AddSocketDataProvider(&data);
CreateNetworkSession();
base::WeakPtr<SpdySession> session =
CreateFakeSpdySession(spdy_session_pool_, key_);
EXPECT_EQ(spdy_util_.spdy_version(),
session->buffered_spdy_framer_->protocol_version());
if (GetParam() == kProtoDeprecatedSPDY2) {
EXPECT_EQ(SpdySession::FLOW_CONTROL_NONE, session->flow_control_state());
EXPECT_EQ(0, session->session_send_window_size_);
EXPECT_EQ(0, session->session_recv_window_size_);
} else if (GetParam() == kProtoSPDY3) {
EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM, session->flow_control_state());
EXPECT_EQ(0, session->session_send_window_size_);
EXPECT_EQ(0, session->session_recv_window_size_);
} else {
EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
session->flow_control_state());
EXPECT_EQ(kSpdySessionInitialWindowSize,
session->session_send_window_size_);
EXPECT_EQ(kSpdySessionInitialWindowSize,
session->session_recv_window_size_);
}
EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
}
TEST_P(SpdySessionTest, CloseOneIdleConnection) {
ClientSocketPoolManager::set_max_sockets_per_group(
HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
ClientSocketPoolManager::set_max_sockets_per_pool(
HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
MockConnect connect_data(SYNCHRONOUS, OK);
MockRead reads[] = {
MockRead(SYNCHRONOUS, ERR_IO_PENDING)
};
StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
data.set_connect_data(connect_data);
session_deps_.socket_factory->AddSocketDataProvider(&data);
session_deps_.socket_factory->AddSocketDataProvider(&data);
CreateNetworkSession();
TransportClientSocketPool* pool =
http_session_->GetTransportSocketPool(
HttpNetworkSession::NORMAL_SOCKET_POOL);
SpdySessionKey key1(HostPortPair("1.com", 80), ProxyServer::Direct(),
PRIVACY_MODE_DISABLED);
base::WeakPtr<SpdySession> session1 =
CreateInsecureSpdySession(http_session_, key1, BoundNetLog());
EXPECT_FALSE(pool->IsStalled());
TestCompletionCallback callback2;
HostPortPair host_port2("2.com", 80);
scoped_refptr<TransportSocketParams> params2(
new TransportSocketParams(host_port2, false, false,
OnHostResolutionCallback()));
scoped_ptr<ClientSocketHandle> connection2(new ClientSocketHandle);
EXPECT_EQ(ERR_IO_PENDING,
connection2->Init(host_port2.ToString(), params2, DEFAULT_PRIORITY,
callback2.callback(), pool, BoundNetLog()));
EXPECT_TRUE(pool->IsStalled());
EXPECT_EQ(OK, callback2.WaitForResult());
EXPECT_FALSE(pool->IsStalled());
EXPECT_TRUE(session1 == NULL);
}
TEST_P(SpdySessionTest, CloseOneIdleConnectionWithAlias) {
ClientSocketPoolManager::set_max_sockets_per_group(
HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
ClientSocketPoolManager::set_max_sockets_per_pool(
HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
MockConnect connect_data(SYNCHRONOUS, OK);
MockRead reads[] = {
MockRead(SYNCHRONOUS, ERR_IO_PENDING)
};
StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
data.set_connect_data(connect_data);
session_deps_.socket_factory->AddSocketDataProvider(&data);
session_deps_.socket_factory->AddSocketDataProvider(&data);
session_deps_.host_resolver->set_synchronous_mode(true);
session_deps_.host_resolver->rules()->AddIPLiteralRule(
"1.com", "192.168.0.2", std::string());
session_deps_.host_resolver->rules()->AddIPLiteralRule(
"2.com", "192.168.0.2", std::string());
session_deps_.host_resolver->rules()->AddIPLiteralRule(
"3.com", "192.168.0.3", std::string());
CreateNetworkSession();
TransportClientSocketPool* pool =
http_session_->GetTransportSocketPool(
HttpNetworkSession::NORMAL_SOCKET_POOL);
SpdySessionKey key1(HostPortPair("1.com", 80), ProxyServer::Direct(),
PRIVACY_MODE_DISABLED);
base::WeakPtr<SpdySession> session1 =
CreateInsecureSpdySession(http_session_, key1, BoundNetLog());
EXPECT_FALSE(pool->IsStalled());
SpdySessionKey key2(HostPortPair("2.com", 80), ProxyServer::Direct(),
PRIVACY_MODE_DISABLED);
HostResolver::RequestInfo info(key2.host_port_pair());
AddressList addresses;
session_deps_.host_resolver->Resolve(info,
DEFAULT_PRIORITY,
&addresses,
CompletionCallback(),
NULL,
BoundNetLog());
base::WeakPtr<SpdySession> session2 =
spdy_session_pool_->FindAvailableSession(key2, BoundNetLog());
ASSERT_EQ(session1.get(), session2.get());
EXPECT_FALSE(pool->IsStalled());
TestCompletionCallback callback3;
HostPortPair host_port3("3.com", 80);
scoped_refptr<TransportSocketParams> params3(
new TransportSocketParams(host_port3, false, false,
OnHostResolutionCallback()));
scoped_ptr<ClientSocketHandle> connection3(new ClientSocketHandle);
EXPECT_EQ(ERR_IO_PENDING,
connection3->Init(host_port3.ToString(), params3, DEFAULT_PRIORITY,
callback3.callback(), pool, BoundNetLog()));
EXPECT_TRUE(pool->IsStalled());
EXPECT_EQ(OK, callback3.WaitForResult());
EXPECT_FALSE(pool->IsStalled());
EXPECT_TRUE(session1 == NULL);
EXPECT_TRUE(session2 == NULL);
}
TEST_P(SpdySessionTest, CloseSessionOnIdleWhenPoolStalled) {
ClientSocketPoolManager::set_max_sockets_per_group(
HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
ClientSocketPoolManager::set_max_sockets_per_pool(
HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
MockConnect connect_data(SYNCHRONOUS, OK);
MockRead reads[] = {
MockRead(SYNCHRONOUS, ERR_IO_PENDING)
};
scoped_ptr<SpdyFrame> req1(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
scoped_ptr<SpdyFrame> cancel1(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
MockWrite writes[] = {
CreateMockWrite(*req1, 1),
CreateMockWrite(*cancel1, 1),
};
StaticSocketDataProvider data(reads, arraysize(reads),
writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.socket_factory->AddSocketDataProvider(&data);
MockRead http_reads[] = {
MockRead(SYNCHRONOUS, ERR_IO_PENDING)
};
StaticSocketDataProvider http_data(http_reads, arraysize(http_reads),
NULL, 0);
http_data.set_connect_data(connect_data);
session_deps_.socket_factory->AddSocketDataProvider(&http_data);
CreateNetworkSession();
TransportClientSocketPool* pool =
http_session_->GetTransportSocketPool(
HttpNetworkSession::NORMAL_SOCKET_POOL);
GURL url1(kDefaultURL);
SpdySessionKey key1(HostPortPair(url1.host(), 80),
ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
base::WeakPtr<SpdySession> session1 =
CreateInsecureSpdySession(http_session_, key1, BoundNetLog());
EXPECT_FALSE(pool->IsStalled());
TestCompletionCallback callback1;
base::WeakPtr<SpdyStream> spdy_stream1 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session1, url1, DEFAULT_PRIORITY,
BoundNetLog());
ASSERT_TRUE(spdy_stream1.get());
test::StreamDelegateDoNothing delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
scoped_ptr<SpdyHeaderBlock> headers1(
spdy_util_.ConstructGetHeaderBlock(url1.spec()));
EXPECT_EQ(ERR_IO_PENDING,
spdy_stream1->SendRequestHeaders(
headers1.Pass(), NO_MORE_DATA_TO_SEND));
EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
base::MessageLoop::current()->RunUntilIdle();
TestCompletionCallback callback2;
HostPortPair host_port2("2.com", 80);
scoped_refptr<TransportSocketParams> params2(
new TransportSocketParams(host_port2, false, false,
OnHostResolutionCallback()));
scoped_ptr<ClientSocketHandle> connection2(new ClientSocketHandle);
EXPECT_EQ(ERR_IO_PENDING,
connection2->Init(host_port2.ToString(), params2, DEFAULT_PRIORITY,
callback2.callback(), pool, BoundNetLog()));
EXPECT_TRUE(pool->IsStalled());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(pool->IsStalled());
EXPECT_FALSE(callback2.have_result());
ASSERT_TRUE(spdy_stream1.get());
spdy_stream1->Cancel();
base::RunLoop().RunUntilIdle();
ASSERT_FALSE(pool->IsStalled());
EXPECT_EQ(OK, callback2.WaitForResult());
}
TEST_P(SpdySessionTest, SpdySessionKeyPrivacyMode) {
CreateDeterministicNetworkSession();
HostPortPair host_port_pair("www.google.com", 443);
SpdySessionKey key_privacy_enabled(host_port_pair, ProxyServer::Direct(),
PRIVACY_MODE_ENABLED);
SpdySessionKey key_privacy_disabled(host_port_pair, ProxyServer::Direct(),
PRIVACY_MODE_DISABLED);
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_enabled));
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_disabled));
base::WeakPtr<SpdySession> session_privacy_enabled =
CreateFakeSpdySession(spdy_session_pool_, key_privacy_enabled);
EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_privacy_enabled));
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_disabled));
base::WeakPtr<SpdySession> session_privacy_disabled =
CreateFakeSpdySession(spdy_session_pool_, key_privacy_disabled);
EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_privacy_enabled));
EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_privacy_disabled));
session_privacy_enabled->CloseSessionOnError(ERR_ABORTED, std::string());
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_enabled));
EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_privacy_disabled));
session_privacy_disabled->CloseSessionOnError(ERR_ABORTED, std::string());
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_enabled));
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_disabled));
}
class StreamCreatingDelegate : public test::StreamDelegateDoNothing {
public:
StreamCreatingDelegate(const base::WeakPtr<SpdyStream>& stream,
const base::WeakPtr<SpdySession>& session)
: StreamDelegateDoNothing(stream),
session_(session) {}
virtual ~StreamCreatingDelegate() {}
virtual void OnClose(int status) OVERRIDE {
GURL url(kDefaultURL);
ignore_result(
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session_, url, MEDIUM, BoundNetLog()));
}
private:
const base::WeakPtr<SpdySession> session_;
};
TEST_P(SpdySessionTest, CreateStreamOnStreamReset) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
scoped_ptr<SpdyFrame> req(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
MockWrite writes[] = {
CreateMockWrite(*req, 0),
};
scoped_ptr<SpdyFrame> rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_REFUSED_STREAM));
MockRead reads[] = {
CreateMockRead(*rst, 1),
MockRead(ASYNC, 0, 2)
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
GURL url(kDefaultURL);
base::WeakPtr<SpdyStream> spdy_stream =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url, MEDIUM, BoundNetLog());
ASSERT_TRUE(spdy_stream.get() != NULL);
EXPECT_EQ(0u, spdy_stream->stream_id());
StreamCreatingDelegate delegate(spdy_stream, session);
spdy_stream->SetDelegate(&delegate);
scoped_ptr<SpdyHeaderBlock> headers(
spdy_util_.ConstructGetHeaderBlock(url.spec()));
spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
EXPECT_EQ(0u, spdy_stream->stream_id());
data.RunFor(1);
EXPECT_EQ(1u, spdy_stream->stream_id());
data.RunFor(1);
EXPECT_EQ(NULL, spdy_stream.get());
EXPECT_TRUE(delegate.StreamIsClosed());
EXPECT_EQ(0u, session->num_active_streams());
EXPECT_EQ(1u, session->num_created_streams());
}
TEST_P(SpdySessionTest, UpdateStreamsSendWindowSize) {
if (GetParam() < kProtoSPDY3)
return;
SettingsMap new_settings;
int32 window_size = 1;
new_settings[SETTINGS_INITIAL_WINDOW_SIZE] =
SettingsFlagsAndValue(SETTINGS_FLAG_NONE, window_size);
MockConnect connect_data(SYNCHRONOUS, OK);
scoped_ptr<SpdyFrame> settings_frame(
spdy_util_.ConstructSpdySettings(new_settings));
MockRead reads[] = {
CreateMockRead(*settings_frame, 0),
MockRead(ASYNC, 0, 1)
};
session_deps_.host_resolver->set_synchronous_mode(true);
scoped_ptr<DeterministicSocketData> data(
new DeterministicSocketData(reads, arraysize(reads), NULL, 0));
data->set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(data.get());
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
base::WeakPtr<SpdyStream> spdy_stream1 =
CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
session, test_url_, MEDIUM, BoundNetLog());
ASSERT_TRUE(spdy_stream1.get() != NULL);
TestCompletionCallback callback1;
EXPECT_NE(spdy_stream1->send_window_size(), window_size);
data->RunFor(1);
base::MessageLoop::current()->RunUntilIdle();
EXPECT_EQ(session->stream_initial_send_window_size(), window_size);
EXPECT_EQ(spdy_stream1->send_window_size(), window_size);
spdy_stream1->Cancel();
EXPECT_EQ(NULL, spdy_stream1.get());
base::WeakPtr<SpdyStream> spdy_stream2 =
CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
session, test_url_, MEDIUM, BoundNetLog());
ASSERT_TRUE(spdy_stream2.get() != NULL);
EXPECT_EQ(spdy_stream2->send_window_size(), window_size);
spdy_stream2->Cancel();
EXPECT_EQ(NULL, spdy_stream2.get());
}
TEST_P(SpdySessionTest, AdjustRecvWindowSize) {
if (GetParam() < kProtoSPDY31)
return;
session_deps_.host_resolver->set_synchronous_mode(true);
const int32 delta_window_size = 100;
MockConnect connect_data(SYNCHRONOUS, OK);
MockRead reads[] = {
MockRead(ASYNC, 0, 1)
};
scoped_ptr<SpdyFrame> window_update(
spdy_util_.ConstructSpdyWindowUpdate(
kSessionFlowControlStreamId,
kSpdySessionInitialWindowSize + delta_window_size));
MockWrite writes[] = {
CreateMockWrite(*window_update, 0),
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
session->flow_control_state());
EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
session->IncreaseRecvWindowSize(delta_window_size);
EXPECT_EQ(kSpdySessionInitialWindowSize + delta_window_size,
session->session_recv_window_size_);
EXPECT_EQ(delta_window_size, session->session_unacked_recv_window_bytes_);
session->IncreaseRecvWindowSize(kSpdySessionInitialWindowSize);
EXPECT_EQ(kSpdySessionInitialWindowSize + delta_window_size +
kSpdySessionInitialWindowSize,
session->session_recv_window_size_);
EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
data.RunFor(1);
session->in_io_loop_ = true;
session->DecreaseRecvWindowSize(
kSpdySessionInitialWindowSize + delta_window_size +
kSpdySessionInitialWindowSize);
session->in_io_loop_ = false;
EXPECT_EQ(0, session->session_recv_window_size_);
EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
}
TEST_P(SpdySessionTest, AdjustSendWindowSize) {
if (GetParam() < kProtoSPDY31)
return;
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
MockRead reads[] = {
MockRead(SYNCHRONOUS, 0, 0)
};
StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
data.set_connect_data(connect_data);
session_deps_.socket_factory->AddSocketDataProvider(&data);
CreateNetworkSession();
base::WeakPtr<SpdySession> session =
CreateFakeSpdySession(spdy_session_pool_, key_);
EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
session->flow_control_state());
const int32 delta_window_size = 100;
EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
session->IncreaseSendWindowSize(delta_window_size);
EXPECT_EQ(kSpdySessionInitialWindowSize + delta_window_size,
session->session_send_window_size_);
session->DecreaseSendWindowSize(delta_window_size);
EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
}
TEST_P(SpdySessionTest, SessionFlowControlInactiveStream) {
if (GetParam() < kProtoSPDY31)
return;
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyBodyFrame(1, false));
MockRead reads[] = {
CreateMockRead(*resp, 0),
MockRead(ASYNC, 0, 1)
};
DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
session->flow_control_state());
EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
data.RunFor(1);
EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
EXPECT_EQ(kUploadDataSize, session->session_unacked_recv_window_bytes_);
data.RunFor(1);
}
class DropReceivedDataDelegate : public test::StreamDelegateSendImmediate {
public:
DropReceivedDataDelegate(const base::WeakPtr<SpdyStream>& stream,
base::StringPiece data)
: StreamDelegateSendImmediate(stream, data) {}
virtual ~DropReceivedDataDelegate() {}
virtual void OnDataReceived(scoped_ptr<SpdyBuffer> buffer) OVERRIDE {}
};
TEST_P(SpdySessionTest, SessionFlowControlNoReceiveLeaks) {
if (GetParam() < kProtoSPDY31)
return;
const char kStreamUrl[] = "http://www.google.com/";
const int32 msg_data_size = 100;
const std::string msg_data(msg_data_size, 'a');
MockConnect connect_data(SYNCHRONOUS, OK);
scoped_ptr<SpdyFrame> req(
spdy_util_.ConstructSpdyPost(
kStreamUrl, 1, msg_data_size, MEDIUM, NULL, 0));
scoped_ptr<SpdyFrame> msg(
spdy_util_.ConstructSpdyBodyFrame(
1, msg_data.data(), msg_data_size, false));
MockWrite writes[] = {
CreateMockWrite(*req, 0),
CreateMockWrite(*msg, 2),
};
scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
scoped_ptr<SpdyFrame> echo(
spdy_util_.ConstructSpdyBodyFrame(
1, msg_data.data(), msg_data_size, false));
scoped_ptr<SpdyFrame> window_update(
spdy_util_.ConstructSpdyWindowUpdate(
kSessionFlowControlStreamId, msg_data_size));
MockRead reads[] = {
CreateMockRead(*resp, 1),
CreateMockRead(*echo, 3),
MockRead(ASYNC, 0, 4)
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.host_resolver->set_synchronous_mode(true);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
GURL url(kStreamUrl);
base::WeakPtr<SpdyStream> stream =
CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
session, url, MEDIUM, BoundNetLog());
ASSERT_TRUE(stream.get() != NULL);
EXPECT_EQ(0u, stream->stream_id());
DropReceivedDataDelegate delegate(stream, msg_data);
stream->SetDelegate(&delegate);
scoped_ptr<SpdyHeaderBlock> headers(
spdy_util_.ConstructPostHeaderBlock(url.spec(), msg_data_size));
EXPECT_EQ(ERR_IO_PENDING,
stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
EXPECT_TRUE(stream->HasUrlFromHeaders());
EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
data.RunFor(4);
EXPECT_TRUE(data.at_write_eof());
EXPECT_TRUE(data.at_read_eof());
EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_);
stream->Close();
EXPECT_EQ(NULL, stream.get());
EXPECT_EQ(OK, delegate.WaitForClose());
EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_);
}
TEST_P(SpdySessionTest, SessionFlowControlNoSendLeaks) {
if (GetParam() < kProtoSPDY31)
return;
const char kStreamUrl[] = "http://www.google.com/";
const int32 msg_data_size = 100;
const std::string msg_data(msg_data_size, 'a');
MockConnect connect_data(SYNCHRONOUS, OK);
scoped_ptr<SpdyFrame> req(
spdy_util_.ConstructSpdyPost(
kStreamUrl, 1, msg_data_size, MEDIUM, NULL, 0));
MockWrite writes[] = {
CreateMockWrite(*req, 0),
};
scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
MockRead reads[] = {
CreateMockRead(*resp, 1),
MockRead(ASYNC, 0, 2)
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.host_resolver->set_synchronous_mode(true);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
GURL url(kStreamUrl);
base::WeakPtr<SpdyStream> stream =
CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
session, url, MEDIUM, BoundNetLog());
ASSERT_TRUE(stream.get() != NULL);
EXPECT_EQ(0u, stream->stream_id());
test::StreamDelegateSendImmediate delegate(stream, msg_data);
stream->SetDelegate(&delegate);
scoped_ptr<SpdyHeaderBlock> headers(
spdy_util_.ConstructPostHeaderBlock(url.spec(), msg_data_size));
EXPECT_EQ(ERR_IO_PENDING,
stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
EXPECT_TRUE(stream->HasUrlFromHeaders());
EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
data.RunFor(1);
EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
data.RunFor(1);
EXPECT_TRUE(data.at_write_eof());
EXPECT_TRUE(data.at_read_eof());
EXPECT_EQ(kSpdySessionInitialWindowSize - msg_data_size,
session->session_send_window_size_);
stream->Close();
EXPECT_EQ(NULL, stream.get());
EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
EXPECT_EQ(OK, delegate.WaitForClose());
}
TEST_P(SpdySessionTest, SessionFlowControlEndToEnd) {
if (GetParam() < kProtoSPDY31)
return;
const char kStreamUrl[] = "http://www.google.com/";
const int32 msg_data_size = 100;
const std::string msg_data(msg_data_size, 'a');
MockConnect connect_data(SYNCHRONOUS, OK);
scoped_ptr<SpdyFrame> req(
spdy_util_.ConstructSpdyPost(
kStreamUrl, 1, msg_data_size, MEDIUM, NULL, 0));
scoped_ptr<SpdyFrame> msg(
spdy_util_.ConstructSpdyBodyFrame(
1, msg_data.data(), msg_data_size, false));
MockWrite writes[] = {
CreateMockWrite(*req, 0),
CreateMockWrite(*msg, 2),
};
scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
scoped_ptr<SpdyFrame> echo(
spdy_util_.ConstructSpdyBodyFrame(
1, msg_data.data(), msg_data_size, false));
scoped_ptr<SpdyFrame> window_update(
spdy_util_.ConstructSpdyWindowUpdate(
kSessionFlowControlStreamId, msg_data_size));
MockRead reads[] = {
CreateMockRead(*resp, 1),
CreateMockRead(*echo, 3),
CreateMockRead(*window_update, 4),
MockRead(ASYNC, 0, 5)
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
data.set_connect_data(connect_data);
session_deps_.host_resolver->set_synchronous_mode(true);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
GURL url(kStreamUrl);
base::WeakPtr<SpdyStream> stream =
CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
session, url, MEDIUM, BoundNetLog());
ASSERT_TRUE(stream.get() != NULL);
EXPECT_EQ(0u, stream->stream_id());
test::StreamDelegateSendImmediate delegate(stream, msg_data);
stream->SetDelegate(&delegate);
scoped_ptr<SpdyHeaderBlock> headers(
spdy_util_.ConstructPostHeaderBlock(url.spec(), msg_data_size));
EXPECT_EQ(ERR_IO_PENDING,
stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
EXPECT_TRUE(stream->HasUrlFromHeaders());
EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
data.RunFor(1);
EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
data.RunFor(1);
EXPECT_EQ(kSpdySessionInitialWindowSize - msg_data_size,
session->session_send_window_size_);
EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
data.RunFor(1);
EXPECT_EQ(kSpdySessionInitialWindowSize - msg_data_size,
session->session_send_window_size_);
EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
data.RunFor(1);
EXPECT_EQ(kSpdySessionInitialWindowSize - msg_data_size,
session->session_send_window_size_);
EXPECT_EQ(kSpdySessionInitialWindowSize - msg_data_size,
session->session_recv_window_size_);
EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
data.RunFor(1);
EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
EXPECT_EQ(kSpdySessionInitialWindowSize - msg_data_size,
session->session_recv_window_size_);
EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
EXPECT_TRUE(data.at_write_eof());
EXPECT_TRUE(data.at_read_eof());
EXPECT_EQ(msg_data, delegate.TakeReceivedData());
EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_);
stream->Close();
EXPECT_EQ(NULL, stream.get());
EXPECT_EQ(OK, delegate.WaitForClose());
EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_);
EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_);
EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_);
}
void SpdySessionTest::RunResumeAfterUnstallTest(
const base::Callback<void(SpdySession*, SpdyStream*)>& stall_function,
const base::Callback<void(SpdySession*, SpdyStream*, int32)>&
unstall_function) {
const char kStreamUrl[] = "http://www.google.com/";
GURL url(kStreamUrl);
session_deps_.host_resolver->set_synchronous_mode(true);
scoped_ptr<SpdyFrame> req(
spdy_util_.ConstructSpdyPost(
kStreamUrl, 1, kBodyDataSize, LOWEST, NULL, 0));
scoped_ptr<SpdyFrame> body(
spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, true));
MockWrite writes[] = {
CreateMockWrite(*req, 0),
CreateMockWrite(*body, 1),
};
scoped_ptr<SpdyFrame> resp(
spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
scoped_ptr<SpdyFrame> echo(
spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, false));
MockRead reads[] = {
CreateMockRead(*resp, 2),
MockRead(ASYNC, 0, 0, 3),
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
MockConnect connect_data(SYNCHRONOUS, OK);
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
session->flow_control_state());
base::WeakPtr<SpdyStream> stream =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url, LOWEST, BoundNetLog());
ASSERT_TRUE(stream.get() != NULL);
test::StreamDelegateWithBody delegate(stream, kBodyDataStringPiece);
stream->SetDelegate(&delegate);
EXPECT_FALSE(stream->HasUrlFromHeaders());
EXPECT_FALSE(stream->send_stalled_by_flow_control());
scoped_ptr<SpdyHeaderBlock> headers(
spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize));
EXPECT_EQ(ERR_IO_PENDING,
stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
EXPECT_TRUE(stream->HasUrlFromHeaders());
EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
stall_function.Run(session.get(), stream.get());
data.RunFor(1);
EXPECT_TRUE(stream->send_stalled_by_flow_control());
unstall_function.Run(session.get(), stream.get(), kBodyDataSize);
EXPECT_FALSE(stream->send_stalled_by_flow_control());
data.RunFor(3);
EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
EXPECT_TRUE(delegate.send_headers_completed());
EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
EXPECT_EQ("HTTP/1.1", delegate.GetResponseHeaderValue(":version"));
EXPECT_EQ(std::string(), delegate.TakeReceivedData());
EXPECT_TRUE(data.at_write_eof());
}
TEST_P(SpdySessionTest, ResumeAfterUnstallSession) {
if (GetParam() < kProtoSPDY31)
return;
RunResumeAfterUnstallTest(
base::Bind(&SpdySessionTest::StallSessionOnly,
base::Unretained(this)),
base::Bind(&SpdySessionTest::UnstallSessionOnly,
base::Unretained(this)));
}
TEST_P(SpdySessionTest, ResumeAfterUnstallStream) {
if (GetParam() < kProtoSPDY31)
return;
RunResumeAfterUnstallTest(
base::Bind(&SpdySessionTest::StallStreamOnly,
base::Unretained(this)),
base::Bind(&SpdySessionTest::UnstallStreamOnly,
base::Unretained(this)));
}
TEST_P(SpdySessionTest, StallSessionStreamResumeAfterUnstallSessionStream) {
if (GetParam() < kProtoSPDY31)
return;
RunResumeAfterUnstallTest(
base::Bind(&SpdySessionTest::StallSessionStream,
base::Unretained(this)),
base::Bind(&SpdySessionTest::UnstallSessionStream,
base::Unretained(this)));
}
TEST_P(SpdySessionTest, StallStreamSessionResumeAfterUnstallSessionStream) {
if (GetParam() < kProtoSPDY31)
return;
RunResumeAfterUnstallTest(
base::Bind(&SpdySessionTest::StallStreamSession,
base::Unretained(this)),
base::Bind(&SpdySessionTest::UnstallSessionStream,
base::Unretained(this)));
}
TEST_P(SpdySessionTest, StallStreamSessionResumeAfterUnstallStreamSession) {
if (GetParam() < kProtoSPDY31)
return;
RunResumeAfterUnstallTest(
base::Bind(&SpdySessionTest::StallStreamSession,
base::Unretained(this)),
base::Bind(&SpdySessionTest::UnstallStreamSession,
base::Unretained(this)));
}
TEST_P(SpdySessionTest, StallSessionStreamResumeAfterUnstallStreamSession) {
if (GetParam() < kProtoSPDY31)
return;
RunResumeAfterUnstallTest(
base::Bind(&SpdySessionTest::StallSessionStream,
base::Unretained(this)),
base::Bind(&SpdySessionTest::UnstallStreamSession,
base::Unretained(this)));
}
TEST_P(SpdySessionTest, ResumeByPriorityAfterSendWindowSizeIncrease) {
if (GetParam() < kProtoSPDY31)
return;
const char kStreamUrl[] = "http://www.google.com/";
GURL url(kStreamUrl);
session_deps_.host_resolver->set_synchronous_mode(true);
scoped_ptr<SpdyFrame> req1(
spdy_util_.ConstructSpdyPost(
kStreamUrl, 1, kBodyDataSize, LOWEST, NULL, 0));
scoped_ptr<SpdyFrame> req2(
spdy_util_.ConstructSpdyPost(
kStreamUrl, 3, kBodyDataSize, MEDIUM, NULL, 0));
scoped_ptr<SpdyFrame> body1(
spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, true));
scoped_ptr<SpdyFrame> body2(
spdy_util_.ConstructSpdyBodyFrame(3, kBodyData, kBodyDataSize, true));
MockWrite writes[] = {
CreateMockWrite(*req1, 0),
CreateMockWrite(*req2, 1),
CreateMockWrite(*body2, 2),
CreateMockWrite(*body1, 3),
};
scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
MockRead reads[] = {
CreateMockRead(*resp1, 4),
CreateMockRead(*resp2, 5),
MockRead(ASYNC, 0, 0, 6),
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
MockConnect connect_data(SYNCHRONOUS, OK);
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
session->flow_control_state());
base::WeakPtr<SpdyStream> stream1 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url, LOWEST, BoundNetLog());
ASSERT_TRUE(stream1.get() != NULL);
test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece);
stream1->SetDelegate(&delegate1);
EXPECT_FALSE(stream1->HasUrlFromHeaders());
base::WeakPtr<SpdyStream> stream2 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url, MEDIUM, BoundNetLog());
ASSERT_TRUE(stream2.get() != NULL);
test::StreamDelegateWithBody delegate2(stream2, kBodyDataStringPiece);
stream2->SetDelegate(&delegate2);
EXPECT_FALSE(stream2->HasUrlFromHeaders());
EXPECT_FALSE(stream1->send_stalled_by_flow_control());
EXPECT_FALSE(stream2->send_stalled_by_flow_control());
StallSessionSend(session.get());
scoped_ptr<SpdyHeaderBlock> headers1(
spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize));
EXPECT_EQ(ERR_IO_PENDING,
stream1->SendRequestHeaders(headers1.Pass(), MORE_DATA_TO_SEND));
EXPECT_TRUE(stream1->HasUrlFromHeaders());
EXPECT_EQ(kStreamUrl, stream1->GetUrlFromHeaders().spec());
data.RunFor(1);
EXPECT_EQ(1u, stream1->stream_id());
EXPECT_TRUE(stream1->send_stalled_by_flow_control());
scoped_ptr<SpdyHeaderBlock> headers2(
spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize));
EXPECT_EQ(ERR_IO_PENDING,
stream2->SendRequestHeaders(headers2.Pass(), MORE_DATA_TO_SEND));
EXPECT_TRUE(stream2->HasUrlFromHeaders());
EXPECT_EQ(kStreamUrl, stream2->GetUrlFromHeaders().spec());
data.RunFor(1);
EXPECT_EQ(3u, stream2->stream_id());
EXPECT_TRUE(stream2->send_stalled_by_flow_control());
UnstallSessionSend(session.get(), kBodyDataSize);
EXPECT_TRUE(stream1->send_stalled_by_flow_control());
EXPECT_FALSE(stream2->send_stalled_by_flow_control());
data.RunFor(1);
EXPECT_TRUE(stream1->send_stalled_by_flow_control());
EXPECT_FALSE(stream2->send_stalled_by_flow_control());
UnstallSessionSend(session.get(), kBodyDataSize);
EXPECT_FALSE(stream1->send_stalled_by_flow_control());
EXPECT_FALSE(stream2->send_stalled_by_flow_control());
data.RunFor(4);
EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose());
EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose());
EXPECT_TRUE(delegate1.send_headers_completed());
EXPECT_EQ("200", delegate1.GetResponseHeaderValue(":status"));
EXPECT_EQ("HTTP/1.1", delegate1.GetResponseHeaderValue(":version"));
EXPECT_EQ(std::string(), delegate1.TakeReceivedData());
EXPECT_TRUE(delegate2.send_headers_completed());
EXPECT_EQ("200", delegate2.GetResponseHeaderValue(":status"));
EXPECT_EQ("HTTP/1.1", delegate2.GetResponseHeaderValue(":version"));
EXPECT_EQ(std::string(), delegate2.TakeReceivedData());
EXPECT_TRUE(data.at_write_eof());
}
class StreamClosingDelegate : public test::StreamDelegateWithBody {
public:
StreamClosingDelegate(const base::WeakPtr<SpdyStream>& stream,
base::StringPiece data)
: StreamDelegateWithBody(stream, data) {}
virtual ~StreamClosingDelegate() {}
void set_stream_to_close(const base::WeakPtr<SpdyStream>& stream_to_close) {
stream_to_close_ = stream_to_close;
}
virtual void OnDataSent() OVERRIDE {
test::StreamDelegateWithBody::OnDataSent();
if (stream_to_close_.get()) {
stream_to_close_->Close();
EXPECT_EQ(NULL, stream_to_close_.get());
}
}
private:
base::WeakPtr<SpdyStream> stream_to_close_;
};
TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedStreams) {
if (GetParam() < kProtoSPDY31)
return;
const char kStreamUrl[] = "http://www.google.com/";
GURL url(kStreamUrl);
session_deps_.host_resolver->set_synchronous_mode(true);
scoped_ptr<SpdyFrame> req1(
spdy_util_.ConstructSpdyPost(
kStreamUrl, 1, kBodyDataSize, LOWEST, NULL, 0));
scoped_ptr<SpdyFrame> req2(
spdy_util_.ConstructSpdyPost(
kStreamUrl, 3, kBodyDataSize, LOWEST, NULL, 0));
scoped_ptr<SpdyFrame> req3(
spdy_util_.ConstructSpdyPost(
kStreamUrl, 5, kBodyDataSize, LOWEST, NULL, 0));
scoped_ptr<SpdyFrame> body2(
spdy_util_.ConstructSpdyBodyFrame(3, kBodyData, kBodyDataSize, true));
MockWrite writes[] = {
CreateMockWrite(*req1, 0),
CreateMockWrite(*req2, 1),
CreateMockWrite(*req3, 2),
CreateMockWrite(*body2, 3),
};
scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
MockRead reads[] = {
CreateMockRead(*resp2, 4),
MockRead(ASYNC, 0, 0, 5),
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
MockConnect connect_data(SYNCHRONOUS, OK);
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
session->flow_control_state());
base::WeakPtr<SpdyStream> stream1 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url, LOWEST, BoundNetLog());
ASSERT_TRUE(stream1.get() != NULL);
test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece);
stream1->SetDelegate(&delegate1);
EXPECT_FALSE(stream1->HasUrlFromHeaders());
base::WeakPtr<SpdyStream> stream2 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url, LOWEST, BoundNetLog());
ASSERT_TRUE(stream2.get() != NULL);
StreamClosingDelegate delegate2(stream2, kBodyDataStringPiece);
stream2->SetDelegate(&delegate2);
EXPECT_FALSE(stream2->HasUrlFromHeaders());
base::WeakPtr<SpdyStream> stream3 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url, LOWEST, BoundNetLog());
ASSERT_TRUE(stream3.get() != NULL);
test::StreamDelegateWithBody delegate3(stream3, kBodyDataStringPiece);
stream3->SetDelegate(&delegate3);
EXPECT_FALSE(stream3->HasUrlFromHeaders());
EXPECT_FALSE(stream1->send_stalled_by_flow_control());
EXPECT_FALSE(stream2->send_stalled_by_flow_control());
EXPECT_FALSE(stream3->send_stalled_by_flow_control());
StallSessionSend(session.get());
scoped_ptr<SpdyHeaderBlock> headers1(
spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize));
EXPECT_EQ(ERR_IO_PENDING,
stream1->SendRequestHeaders(headers1.Pass(), MORE_DATA_TO_SEND));
EXPECT_TRUE(stream1->HasUrlFromHeaders());
EXPECT_EQ(kStreamUrl, stream1->GetUrlFromHeaders().spec());
data.RunFor(1);
EXPECT_EQ(1u, stream1->stream_id());
EXPECT_TRUE(stream1->send_stalled_by_flow_control());
scoped_ptr<SpdyHeaderBlock> headers2(
spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize));
EXPECT_EQ(ERR_IO_PENDING,
stream2->SendRequestHeaders(headers2.Pass(), MORE_DATA_TO_SEND));
EXPECT_TRUE(stream2->HasUrlFromHeaders());
EXPECT_EQ(kStreamUrl, stream2->GetUrlFromHeaders().spec());
data.RunFor(1);
EXPECT_EQ(3u, stream2->stream_id());
EXPECT_TRUE(stream2->send_stalled_by_flow_control());
scoped_ptr<SpdyHeaderBlock> headers3(
spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize));
EXPECT_EQ(ERR_IO_PENDING,
stream3->SendRequestHeaders(headers3.Pass(), MORE_DATA_TO_SEND));
EXPECT_TRUE(stream3->HasUrlFromHeaders());
EXPECT_EQ(kStreamUrl, stream3->GetUrlFromHeaders().spec());
data.RunFor(1);
EXPECT_EQ(5u, stream3->stream_id());
EXPECT_TRUE(stream3->send_stalled_by_flow_control());
SpdyStreamId stream_id1 = stream1->stream_id();
SpdyStreamId stream_id2 = stream2->stream_id();
SpdyStreamId stream_id3 = stream3->stream_id();
session->CloseActiveStream(stream_id1, ERR_CONNECTION_CLOSED);
EXPECT_EQ(NULL, stream1.get());
EXPECT_FALSE(session->IsStreamActive(stream_id1));
EXPECT_TRUE(session->IsStreamActive(stream_id2));
EXPECT_TRUE(session->IsStreamActive(stream_id3));
delegate2.set_stream_to_close(stream3);
UnstallSessionSend(session.get(), kBodyDataSize);
data.RunFor(1);
EXPECT_EQ(NULL, stream3.get());
EXPECT_FALSE(stream2->send_stalled_by_flow_control());
EXPECT_FALSE(session->IsStreamActive(stream_id1));
EXPECT_TRUE(session->IsStreamActive(stream_id2));
EXPECT_FALSE(session->IsStreamActive(stream_id3));
data.RunFor(2);
EXPECT_EQ(NULL, stream2.get());
EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose());
EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose());
EXPECT_EQ(OK, delegate3.WaitForClose());
EXPECT_TRUE(delegate1.send_headers_completed());
EXPECT_EQ(std::string(), delegate1.TakeReceivedData());
EXPECT_TRUE(delegate2.send_headers_completed());
EXPECT_EQ("200", delegate2.GetResponseHeaderValue(":status"));
EXPECT_EQ("HTTP/1.1", delegate2.GetResponseHeaderValue(":version"));
EXPECT_EQ(std::string(), delegate2.TakeReceivedData());
EXPECT_TRUE(delegate3.send_headers_completed());
EXPECT_EQ(std::string(), delegate3.TakeReceivedData());
EXPECT_TRUE(data.at_write_eof());
}
TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedSession) {
if (GetParam() < kProtoSPDY31)
return;
const char kStreamUrl[] = "http://www.google.com/";
GURL url(kStreamUrl);
session_deps_.host_resolver->set_synchronous_mode(true);
scoped_ptr<SpdyFrame> req1(
spdy_util_.ConstructSpdyPost(
kStreamUrl, 1, kBodyDataSize, LOWEST, NULL, 0));
scoped_ptr<SpdyFrame> req2(
spdy_util_.ConstructSpdyPost(
kStreamUrl, 3, kBodyDataSize, LOWEST, NULL, 0));
scoped_ptr<SpdyFrame> body1(
spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, false));
MockWrite writes[] = {
CreateMockWrite(*req1, 0),
CreateMockWrite(*req2, 1),
};
MockRead reads[] = {
MockRead(ASYNC, 0, 0, 2),
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
MockConnect connect_data(SYNCHRONOUS, OK);
data.set_connect_data(connect_data);
session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
CreateDeterministicNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
session->flow_control_state());
base::WeakPtr<SpdyStream> stream1 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url, LOWEST, BoundNetLog());
ASSERT_TRUE(stream1.get() != NULL);
test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece);
stream1->SetDelegate(&delegate1);
EXPECT_FALSE(stream1->HasUrlFromHeaders());
base::WeakPtr<SpdyStream> stream2 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
session, url, LOWEST, BoundNetLog());
ASSERT_TRUE(stream2.get() != NULL);
test::StreamDelegateWithBody delegate2(stream2, kBodyDataStringPiece);
stream2->SetDelegate(&delegate2);
EXPECT_FALSE(stream2->HasUrlFromHeaders());
EXPECT_FALSE(stream1->send_stalled_by_flow_control());
EXPECT_FALSE(stream2->send_stalled_by_flow_control());
StallSessionSend(session.get());
scoped_ptr<SpdyHeaderBlock> headers1(
spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize));
EXPECT_EQ(ERR_IO_PENDING,
stream1->SendRequestHeaders(headers1.Pass(), MORE_DATA_TO_SEND));
EXPECT_TRUE(stream1->HasUrlFromHeaders());
EXPECT_EQ(kStreamUrl, stream1->GetUrlFromHeaders().spec());
data.RunFor(1);
EXPECT_EQ(1u, stream1->stream_id());
EXPECT_TRUE(stream1->send_stalled_by_flow_control());
scoped_ptr<SpdyHeaderBlock> headers2(
spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kBodyDataSize));
EXPECT_EQ(ERR_IO_PENDING,
stream2->SendRequestHeaders(headers2.Pass(), MORE_DATA_TO_SEND));
EXPECT_TRUE(stream2->HasUrlFromHeaders());
EXPECT_EQ(kStreamUrl, stream2->GetUrlFromHeaders().spec());
data.RunFor(1);
EXPECT_EQ(3u, stream2->stream_id());
EXPECT_TRUE(stream2->send_stalled_by_flow_control());
EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
UnstallSessionSend(session.get(), kBodyDataSize);
session->CloseSessionOnError(ERR_CONNECTION_CLOSED, "Closing session");
EXPECT_TRUE(session == NULL);
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose());
EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose());
EXPECT_TRUE(delegate1.send_headers_completed());
EXPECT_EQ(std::string(), delegate1.TakeReceivedData());
EXPECT_TRUE(delegate2.send_headers_completed());
EXPECT_EQ(std::string(), delegate2.TakeReceivedData());
EXPECT_TRUE(data.at_write_eof());
}
TEST(MapFramerErrorToProtocolError, MapsValues) {
CHECK_EQ(SPDY_ERROR_INVALID_CONTROL_FRAME,
MapFramerErrorToProtocolError(
SpdyFramer::SPDY_INVALID_CONTROL_FRAME));
CHECK_EQ(SPDY_ERROR_INVALID_DATA_FRAME_FLAGS,
MapFramerErrorToProtocolError(
SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS));
CHECK_EQ(SPDY_ERROR_GOAWAY_FRAME_CORRUPT,
MapFramerErrorToProtocolError(
SpdyFramer::SPDY_GOAWAY_FRAME_CORRUPT));
CHECK_EQ(SPDY_ERROR_UNEXPECTED_FRAME,
MapFramerErrorToProtocolError(
SpdyFramer::SPDY_UNEXPECTED_FRAME));
}
TEST(MapRstStreamStatusToProtocolError, MapsValues) {
CHECK_EQ(STATUS_CODE_PROTOCOL_ERROR,
MapRstStreamStatusToProtocolError(
RST_STREAM_PROTOCOL_ERROR));
CHECK_EQ(STATUS_CODE_FRAME_TOO_LARGE,
MapRstStreamStatusToProtocolError(
RST_STREAM_FRAME_TOO_LARGE));
}
}