Home | History | Annotate | Download | only in quic
      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:
     32   static QuicDataStream* GetIncomingReliableStream(
     33       QuicServerSession* s, QuicStreamId id) {
     34     return s->GetIncomingReliableStream(id);
     35   }
     36   static QuicDataStream* GetDataStream(QuicServerSession* s, QuicStreamId id) {
     37     return s->GetDataStream(id);
     38   }
     39 };
     40 
     41 class CloseOnDataStream : public QuicDataStream {
     42  public:
     43   CloseOnDataStream(QuicStreamId id, QuicSession* session)
     44       : QuicDataStream(id, session) {
     45   }
     46 
     47   virtual bool OnStreamFrame(const QuicStreamFrame& frame) OVERRIDE {
     48     session()->MarkDecompressionBlocked(1, id());
     49     session()->CloseStream(id());
     50     return true;
     51   }
     52 
     53   virtual uint32 ProcessData(const char* data, uint32 data_len) OVERRIDE {
     54     return 0;
     55   }
     56 };
     57 
     58 class TestQuicQuicServerSession : public QuicServerSession {
     59  public:
     60   TestQuicQuicServerSession(const QuicConfig& config,
     61                             QuicConnection* connection,
     62                             QuicSessionOwner* owner)
     63       : QuicServerSession(config, connection, owner),
     64         close_stream_on_data_(false) {
     65   }
     66 
     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 
     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:
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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