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