• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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