Home | History | Annotate | Download | only in quic
      1 // Copyright (c) 2012 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/quic/quic_session.h"
      6 
      7 #include <set>
      8 #include <vector>
      9 
     10 #include "base/containers/hash_tables.h"
     11 #include "net/quic/crypto/crypto_handshake.h"
     12 #include "net/quic/quic_connection.h"
     13 #include "net/quic/quic_protocol.h"
     14 #include "net/quic/test_tools/quic_connection_peer.h"
     15 #include "net/quic/test_tools/quic_test_utils.h"
     16 #include "net/spdy/spdy_framer.h"
     17 #include "testing/gmock/include/gmock/gmock.h"
     18 #include "testing/gtest/include/gtest/gtest.h"
     19 
     20 using base::hash_map;
     21 using std::set;
     22 using std::vector;
     23 using testing::_;
     24 using testing::InSequence;
     25 
     26 namespace net {
     27 namespace test {
     28 namespace {
     29 
     30 class TestCryptoStream : public QuicCryptoStream {
     31  public:
     32   explicit TestCryptoStream(QuicSession* session)
     33       : QuicCryptoStream(session) {
     34   }
     35 
     36   virtual void OnHandshakeMessage(
     37       const CryptoHandshakeMessage& message) OVERRIDE {
     38     encryption_established_ = true;
     39     handshake_confirmed_ = true;
     40     CryptoHandshakeMessage msg;
     41     string error_details;
     42     session()->config()->ToHandshakeMessage(&msg);
     43     const QuicErrorCode error = session()->config()->ProcessClientHello(
     44         msg, &error_details);
     45     EXPECT_EQ(QUIC_NO_ERROR, error);
     46     session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
     47   }
     48 };
     49 
     50 class TestStream : public ReliableQuicStream {
     51  public:
     52   TestStream(QuicStreamId id, QuicSession* session)
     53       : ReliableQuicStream(id, session) {
     54   }
     55 
     56   using ReliableQuicStream::CloseWriteSide;
     57 
     58   virtual uint32 ProcessData(const char* data, uint32 data_len) {
     59     return data_len;
     60   }
     61 
     62   MOCK_METHOD0(OnCanWrite, void());
     63 };
     64 
     65 class TestSession : public QuicSession {
     66  public:
     67   TestSession(QuicConnection* connection, bool is_server)
     68       : QuicSession(connection, DefaultQuicConfig(), is_server),
     69         crypto_stream_(this) {
     70   }
     71 
     72   virtual QuicCryptoStream* GetCryptoStream() OVERRIDE {
     73     return &crypto_stream_;
     74   }
     75 
     76   virtual TestStream* CreateOutgoingReliableStream() OVERRIDE {
     77     TestStream* stream = new TestStream(GetNextStreamId(), this);
     78     ActivateStream(stream);
     79     return stream;
     80   }
     81 
     82   virtual TestStream* CreateIncomingReliableStream(QuicStreamId id) OVERRIDE {
     83     return new TestStream(id, this);
     84   }
     85 
     86   bool IsClosedStream(QuicStreamId id) {
     87     return QuicSession::IsClosedStream(id);
     88   }
     89 
     90   ReliableQuicStream* GetIncomingReliableStream(QuicStreamId stream_id) {
     91     return QuicSession::GetIncomingReliableStream(stream_id);
     92   }
     93 
     94   // Helper method for gmock
     95   void MarkTwoWriteBlocked() {
     96     this->MarkWriteBlocked(2);
     97   }
     98 
     99   TestCryptoStream crypto_stream_;
    100 };
    101 
    102 class QuicSessionTest : public ::testing::Test {
    103  protected:
    104   QuicSessionTest()
    105       : guid_(1),
    106         connection_(new MockConnection(guid_, IPEndPoint(), false)),
    107         session_(connection_, true) {
    108   }
    109 
    110   void CheckClosedStreams() {
    111     for (int i = kCryptoStreamId; i < 100; i++) {
    112       if (closed_streams_.count(i) == 0) {
    113         EXPECT_FALSE(session_.IsClosedStream(i)) << " stream id: " << i;
    114       } else {
    115         EXPECT_TRUE(session_.IsClosedStream(i)) << " stream id: " << i;
    116       }
    117     }
    118   }
    119 
    120   void CloseStream(QuicStreamId id) {
    121     session_.CloseStream(id);
    122     closed_streams_.insert(id);
    123   }
    124 
    125   QuicGuid guid_;
    126   MockConnection* connection_;
    127   TestSession session_;
    128   QuicConnectionVisitorInterface* visitor_;
    129   hash_map<QuicStreamId, ReliableQuicStream*>* streams_;
    130   set<QuicStreamId> closed_streams_;
    131 };
    132 
    133 TEST_F(QuicSessionTest, IsCryptoHandshakeConfirmed) {
    134   EXPECT_FALSE(session_.IsCryptoHandshakeConfirmed());
    135   CryptoHandshakeMessage message;
    136   session_.crypto_stream_.OnHandshakeMessage(message);
    137   EXPECT_TRUE(session_.IsCryptoHandshakeConfirmed());
    138 }
    139 
    140 TEST_F(QuicSessionTest, IsClosedStreamDefault) {
    141   // Ensure that no streams are initially closed.
    142   for (int i = kCryptoStreamId; i < 100; i++) {
    143     EXPECT_FALSE(session_.IsClosedStream(i));
    144   }
    145 }
    146 
    147 TEST_F(QuicSessionTest, IsClosedStreamLocallyCreated) {
    148   TestStream* stream2 = session_.CreateOutgoingReliableStream();
    149   EXPECT_EQ(2u, stream2->id());
    150   TestStream* stream4 = session_.CreateOutgoingReliableStream();
    151   EXPECT_EQ(4u, stream4->id());
    152 
    153   CheckClosedStreams();
    154   CloseStream(4);
    155   CheckClosedStreams();
    156   CloseStream(2);
    157   CheckClosedStreams();
    158 }
    159 
    160 TEST_F(QuicSessionTest, IsClosedStreamPeerCreated) {
    161   session_.GetIncomingReliableStream(3);
    162   session_.GetIncomingReliableStream(5);
    163 
    164   CheckClosedStreams();
    165   CloseStream(3);
    166   CheckClosedStreams();
    167   CloseStream(5);
    168   // Create stream id 9, and implicitly 7
    169   session_.GetIncomingReliableStream(9);
    170   CheckClosedStreams();
    171   // Close 9, but make sure 7 is still not closed
    172   CloseStream(9);
    173   CheckClosedStreams();
    174 }
    175 
    176 TEST_F(QuicSessionTest, StreamIdTooLarge) {
    177   session_.GetIncomingReliableStream(3);
    178   EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_STREAM_ID));
    179   session_.GetIncomingReliableStream(105);
    180 }
    181 
    182 TEST_F(QuicSessionTest, DecompressionError) {
    183   ReliableQuicStream* stream = session_.GetIncomingReliableStream(3);
    184   EXPECT_CALL(*connection_, SendConnectionClose(QUIC_DECOMPRESSION_FAILURE));
    185   const char data[] =
    186       "\1\0\0\0"   // headers id
    187       "\0\0\0\4"   // length
    188       "abcd";      // invalid compressed data
    189   stream->ProcessRawData(data, arraysize(data));
    190 }
    191 
    192 TEST_F(QuicSessionTest, OnCanWrite) {
    193   TestStream* stream2 = session_.CreateOutgoingReliableStream();
    194   TestStream* stream4 = session_.CreateOutgoingReliableStream();
    195   TestStream* stream6 = session_.CreateOutgoingReliableStream();
    196 
    197   session_.MarkWriteBlocked(2);
    198   session_.MarkWriteBlocked(6);
    199   session_.MarkWriteBlocked(4);
    200 
    201   InSequence s;
    202   EXPECT_CALL(*stream2, OnCanWrite()).WillOnce(
    203       // Reregister, to test the loop limit.
    204       testing::InvokeWithoutArgs(&session_, &TestSession::MarkTwoWriteBlocked));
    205   EXPECT_CALL(*stream6, OnCanWrite());
    206   EXPECT_CALL(*stream4, OnCanWrite());
    207 
    208   EXPECT_FALSE(session_.OnCanWrite());
    209 }
    210 
    211 TEST_F(QuicSessionTest, OnCanWriteWithClosedStream) {
    212   TestStream* stream2 = session_.CreateOutgoingReliableStream();
    213   TestStream* stream4 = session_.CreateOutgoingReliableStream();
    214   session_.CreateOutgoingReliableStream();  // stream 6
    215 
    216   session_.MarkWriteBlocked(2);
    217   session_.MarkWriteBlocked(6);
    218   session_.MarkWriteBlocked(4);
    219   CloseStream(6);
    220 
    221   InSequence s;
    222   EXPECT_CALL(*stream2, OnCanWrite());
    223   EXPECT_CALL(*stream4, OnCanWrite());
    224   EXPECT_TRUE(session_.OnCanWrite());
    225 }
    226 
    227 // Regression test for http://crbug.com/248737
    228 TEST_F(QuicSessionTest, OutOfOrderHeaders) {
    229   QuicSpdyCompressor compressor;
    230   SpdyHeaderBlock headers;
    231   headers[":host"] = "www.google.com";
    232   headers[":path"] = "/index.hml";
    233   headers[":scheme"] = "http";
    234   vector<QuicStreamFrame> frames;
    235   QuicPacketHeader header;
    236   header.public_header.guid = session_.guid();
    237 
    238   TestStream* stream2 = session_.CreateOutgoingReliableStream();
    239   TestStream* stream4 = session_.CreateOutgoingReliableStream();
    240   stream2->CloseWriteSide();
    241   stream4->CloseWriteSide();
    242 
    243   // Create frame with headers for stream2.
    244   string compressed_headers1 = compressor.CompressHeaders(headers);
    245   QuicStreamFrame frame1(stream2->id(), false, 0, compressed_headers1);
    246 
    247   // Create frame with headers for stream4.
    248   string compressed_headers2 = compressor.CompressHeaders(headers);
    249   QuicStreamFrame frame2(stream4->id(), true, 0, compressed_headers2);
    250 
    251   // Process the second frame first.  This will cause the headers to
    252   // be queued up and processed after the first frame is processed.
    253   frames.push_back(frame2);
    254   session_.OnPacket(IPEndPoint(), IPEndPoint(), header, frames);
    255 
    256   // Process the first frame, and un-cork the buffered headers.
    257   frames[0] = frame1;
    258   session_.OnPacket(IPEndPoint(), IPEndPoint(), header, frames);
    259 
    260   // Ensure that the streams actually close and we don't DCHECK.
    261   session_.ConnectionClose(QUIC_CONNECTION_TIMED_OUT, true);
    262 }
    263 
    264 TEST_F(QuicSessionTest, SendGoAway) {
    265   // After sending a GoAway, ensure new incoming streams cannot be created and
    266   // result in a RST being sent.
    267   EXPECT_CALL(*connection_,
    268               SendGoAway(QUIC_PEER_GOING_AWAY, 0u, "Going Away."));
    269   session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away.");
    270   EXPECT_TRUE(session_.goaway_sent());
    271 
    272   EXPECT_CALL(*connection_, SendRstStream(3u, QUIC_STREAM_PEER_GOING_AWAY));
    273   EXPECT_FALSE(session_.GetIncomingReliableStream(3u));
    274 }
    275 
    276 TEST_F(QuicSessionTest, IncreasedTimeoutAfterCryptoHandshake) {
    277   EXPECT_EQ(kDefaultInitialTimeoutSecs,
    278             QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds());
    279   CryptoHandshakeMessage msg;
    280   session_.crypto_stream_.OnHandshakeMessage(msg);
    281   EXPECT_EQ(kDefaultTimeoutSecs,
    282             QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds());
    283 }
    284 
    285 }  // namespace
    286 }  // namespace test
    287 }  // namespace net
    288