1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/tools/quic/quic_server_session.h"
6
7 #include "net/quic/crypto/quic_crypto_server_config.h"
8 #include "net/quic/crypto/quic_random.h"
9 #include "net/quic/quic_connection.h"
10 #include "net/quic/test_tools/quic_connection_peer.h"
11 #include "net/quic/test_tools/quic_data_stream_peer.h"
12 #include "net/quic/test_tools/quic_test_utils.h"
13 #include "net/tools/epoll_server/epoll_server.h"
14 #include "net/tools/quic/quic_spdy_server_stream.h"
15 #include "net/tools/quic/test_tools/quic_test_utils.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18
19 using __gnu_cxx::vector;
20 using net::test::MockConnection;
21 using net::test::QuicConnectionPeer;
22 using net::test::QuicDataStreamPeer;
23 using testing::_;
24 using testing::StrictMock;
25
26 namespace net {
27 namespace tools {
28 namespace test {
29
30 class QuicServerSessionPeer {
31 public:
GetIncomingReliableStream(QuicServerSession * s,QuicStreamId id)32 static QuicDataStream* GetIncomingReliableStream(
33 QuicServerSession* s, QuicStreamId id) {
34 return s->GetIncomingReliableStream(id);
35 }
GetDataStream(QuicServerSession * s,QuicStreamId id)36 static QuicDataStream* GetDataStream(QuicServerSession* s, QuicStreamId id) {
37 return s->GetDataStream(id);
38 }
39 };
40
41 class CloseOnDataStream : public QuicDataStream {
42 public:
CloseOnDataStream(QuicStreamId id,QuicSession * session)43 CloseOnDataStream(QuicStreamId id, QuicSession* session)
44 : QuicDataStream(id, session) {
45 }
46
OnStreamFrame(const QuicStreamFrame & frame)47 virtual bool OnStreamFrame(const QuicStreamFrame& frame) OVERRIDE {
48 session()->MarkDecompressionBlocked(1, id());
49 session()->CloseStream(id());
50 return true;
51 }
52
ProcessData(const char * data,uint32 data_len)53 virtual uint32 ProcessData(const char* data, uint32 data_len) OVERRIDE {
54 return 0;
55 }
56 };
57
58 class TestQuicQuicServerSession : public QuicServerSession {
59 public:
TestQuicQuicServerSession(const QuicConfig & config,QuicConnection * connection,QuicSessionOwner * owner)60 TestQuicQuicServerSession(const QuicConfig& config,
61 QuicConnection* connection,
62 QuicSessionOwner* owner)
63 : QuicServerSession(config, connection, owner),
64 close_stream_on_data_(false) {
65 }
66
CreateIncomingDataStream(QuicStreamId id)67 virtual QuicDataStream* CreateIncomingDataStream(
68 QuicStreamId id) OVERRIDE {
69 if (!ShouldCreateIncomingDataStream(id)) {
70 return NULL;
71 }
72 if (close_stream_on_data_) {
73 return new CloseOnDataStream(id, this);
74 } else {
75 return new QuicSpdyServerStream(id, this);
76 }
77 }
78
CloseStreamOnData()79 void CloseStreamOnData() {
80 close_stream_on_data_ = true;
81 }
82
83 private:
84 bool close_stream_on_data_;
85 };
86
87 namespace {
88
89 class QuicServerSessionTest : public ::testing::Test {
90 protected:
QuicServerSessionTest()91 QuicServerSessionTest()
92 : crypto_config_(QuicCryptoServerConfig::TESTING,
93 QuicRandom::GetInstance()) {
94 config_.SetDefaults();
95 config_.set_max_streams_per_connection(3, 3);
96
97 connection_ = new MockConnection(true);
98 session_.reset(new TestQuicQuicServerSession(
99 config_, connection_, &owner_));
100 session_->InitializeSession(crypto_config_);
101 visitor_ = QuicConnectionPeer::GetVisitor(connection_);
102 }
103
MarkHeadersReadForStream(QuicStreamId id)104 void MarkHeadersReadForStream(QuicStreamId id) {
105 QuicDataStream* stream = QuicServerSessionPeer::GetDataStream(
106 session_.get(), id);
107 ASSERT_TRUE(stream != NULL);
108 QuicDataStreamPeer::SetHeadersDecompressed(stream, true);
109 }
110
111 StrictMock<MockQuicSessionOwner> owner_;
112 MockConnection* connection_;
113 QuicConfig config_;
114 QuicCryptoServerConfig crypto_config_;
115 scoped_ptr<TestQuicQuicServerSession> session_;
116 QuicConnectionVisitorInterface* visitor_;
117 };
118
TEST_F(QuicServerSessionTest,CloseStreamDueToReset)119 TEST_F(QuicServerSessionTest, CloseStreamDueToReset) {
120 // Open a stream, then reset it.
121 // Send two bytes of payload to open it.
122 QuicStreamFrame data1(3, false, 0, MakeIOVector("HT"));
123 vector<QuicStreamFrame> frames;
124 frames.push_back(data1);
125 EXPECT_TRUE(visitor_->OnStreamFrames(frames));
126 EXPECT_EQ(1u, session_->GetNumOpenStreams());
127
128 // Pretend we got full headers, so we won't trigger the 'unrecoverable
129 // compression context' state.
130 MarkHeadersReadForStream(3);
131
132 // Send a reset.
133 QuicRstStreamFrame rst1(3, QUIC_STREAM_NO_ERROR);
134 visitor_->OnRstStream(rst1);
135 EXPECT_EQ(0u, session_->GetNumOpenStreams());
136
137 // Send the same two bytes of payload in a new packet.
138 EXPECT_TRUE(visitor_->OnStreamFrames(frames));
139
140 // The stream should not be re-opened.
141 EXPECT_EQ(0u, session_->GetNumOpenStreams());
142 }
143
TEST_F(QuicServerSessionTest,NeverOpenStreamDueToReset)144 TEST_F(QuicServerSessionTest, NeverOpenStreamDueToReset) {
145 // Send a reset.
146 QuicRstStreamFrame rst1(3, QUIC_STREAM_NO_ERROR);
147 visitor_->OnRstStream(rst1);
148 EXPECT_EQ(0u, session_->GetNumOpenStreams());
149
150 // Send two bytes of payload.
151 QuicStreamFrame data1(3, false, 0, MakeIOVector("HT"));
152 vector<QuicStreamFrame> frames;
153 frames.push_back(data1);
154
155 // When we get data for the closed stream, it implies the far side has
156 // compressed some headers. As a result we're going to bail due to
157 // unrecoverable compression context state.
158 EXPECT_CALL(*connection_, SendConnectionClose(
159 QUIC_STREAM_RST_BEFORE_HEADERS_DECOMPRESSED));
160 EXPECT_FALSE(visitor_->OnStreamFrames(frames));
161
162 // The stream should never be opened, now that the reset is received.
163 EXPECT_EQ(0u, session_->GetNumOpenStreams());
164 }
165
TEST_F(QuicServerSessionTest,GoOverPrematureClosedStreamLimit)166 TEST_F(QuicServerSessionTest, GoOverPrematureClosedStreamLimit) {
167 QuicStreamFrame data1(3, false, 0, MakeIOVector("H"));
168 vector<QuicStreamFrame> frames;
169 frames.push_back(data1);
170
171 // Set up the stream such that it's open in OnPacket, but closes half way
172 // through while on the decompression blocked list.
173 session_->CloseStreamOnData();
174
175 EXPECT_CALL(*connection_, SendConnectionClose(
176 QUIC_STREAM_RST_BEFORE_HEADERS_DECOMPRESSED));
177 EXPECT_FALSE(visitor_->OnStreamFrames(frames));
178 }
179
TEST_F(QuicServerSessionTest,AcceptClosedStream)180 TEST_F(QuicServerSessionTest, AcceptClosedStream) {
181 vector<QuicStreamFrame> frames;
182 // Send (empty) compressed headers followed by two bytes of data.
183 frames.push_back(
184 QuicStreamFrame(3, false, 0, MakeIOVector("\1\0\0\0\0\0\0\0HT")));
185 frames.push_back(
186 QuicStreamFrame(5, false, 0, MakeIOVector("\2\0\0\0\0\0\0\0HT")));
187 EXPECT_TRUE(visitor_->OnStreamFrames(frames));
188
189 // Pretend we got full headers, so we won't trigger the 'unercoverable
190 // compression context' state.
191 MarkHeadersReadForStream(3);
192
193 // Send a reset.
194 QuicRstStreamFrame rst(3, QUIC_STREAM_NO_ERROR);
195 visitor_->OnRstStream(rst);
196
197 // If we were tracking, we'd probably want to reject this because it's data
198 // past the reset point of stream 3. As it's a closed stream we just drop the
199 // data on the floor, but accept the packet because it has data for stream 5.
200 frames.clear();
201 frames.push_back(QuicStreamFrame(3, false, 2, MakeIOVector("TP")));
202 frames.push_back(QuicStreamFrame(5, false, 2, MakeIOVector("TP")));
203 EXPECT_TRUE(visitor_->OnStreamFrames(frames));
204 }
205
TEST_F(QuicServerSessionTest,MaxNumConnections)206 TEST_F(QuicServerSessionTest, MaxNumConnections) {
207 EXPECT_EQ(0u, session_->GetNumOpenStreams());
208 EXPECT_TRUE(
209 QuicServerSessionPeer::GetIncomingReliableStream(session_.get(), 3));
210 EXPECT_TRUE(
211 QuicServerSessionPeer::GetIncomingReliableStream(session_.get(), 5));
212 EXPECT_TRUE(
213 QuicServerSessionPeer::GetIncomingReliableStream(session_.get(), 7));
214 EXPECT_FALSE(
215 QuicServerSessionPeer::GetIncomingReliableStream(session_.get(), 9));
216 }
217
TEST_F(QuicServerSessionTest,MaxNumConnectionsImplicit)218 TEST_F(QuicServerSessionTest, MaxNumConnectionsImplicit) {
219 EXPECT_EQ(0u, session_->GetNumOpenStreams());
220 EXPECT_TRUE(
221 QuicServerSessionPeer::GetIncomingReliableStream(session_.get(), 3));
222 // Implicitly opens two more streams before 9.
223 EXPECT_FALSE(
224 QuicServerSessionPeer::GetIncomingReliableStream(session_.get(), 9));
225 }
226
TEST_F(QuicServerSessionTest,GetEvenIncomingError)227 TEST_F(QuicServerSessionTest, GetEvenIncomingError) {
228 // Incoming streams on the server session must be odd.
229 EXPECT_EQ(NULL,
230 QuicServerSessionPeer::GetIncomingReliableStream(
231 session_.get(), 2));
232 }
233
234 } // namespace
235 } // namespace test
236 } // namespace tools
237 } // namespace net
238