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/quic/quic_headers_stream.h"
      6 
      7 #include "net/quic/quic_utils.h"
      8 #include "net/quic/spdy_utils.h"
      9 #include "net/quic/test_tools/quic_connection_peer.h"
     10 #include "net/quic/test_tools/quic_session_peer.h"
     11 #include "net/quic/test_tools/quic_test_utils.h"
     12 #include "net/quic/test_tools/reliable_quic_stream_peer.h"
     13 #include "net/spdy/spdy_protocol.h"
     14 #include "testing/gtest/include/gtest/gtest.h"
     15 
     16 using base::StringPiece;
     17 using std::string;
     18 using testing::Invoke;
     19 using testing::StrictMock;
     20 using testing::WithArgs;
     21 using testing::_;
     22 
     23 namespace net {
     24 namespace test {
     25 namespace {
     26 
     27 class MockVisitor : public SpdyFramerVisitorInterface {
     28  public:
     29   MOCK_METHOD1(OnError, void(SpdyFramer* framer));
     30   MOCK_METHOD3(OnDataFrameHeader, void(SpdyStreamId stream_id,
     31                                        size_t length,
     32                                        bool fin));
     33   MOCK_METHOD4(OnStreamFrameData, void(SpdyStreamId stream_id,
     34                                        const char* data,
     35                                        size_t len,
     36                                        bool fin));
     37   MOCK_METHOD3(OnControlFrameHeaderData, bool(SpdyStreamId stream_id,
     38                                               const char* header_data,
     39                                               size_t len));
     40   MOCK_METHOD5(OnSynStream, void(SpdyStreamId stream_id,
     41                                  SpdyStreamId associated_stream_id,
     42                                  SpdyPriority priority,
     43                                  bool fin,
     44                                  bool unidirectional));
     45   MOCK_METHOD2(OnSynReply, void(SpdyStreamId stream_id, bool fin));
     46   MOCK_METHOD2(OnRstStream, void(SpdyStreamId stream_id,
     47                                  SpdyRstStreamStatus status));
     48   MOCK_METHOD1(OnSettings, void(bool clear_persisted));
     49   MOCK_METHOD3(OnSetting, void(SpdySettingsIds id, uint8 flags, uint32 value));
     50   MOCK_METHOD0(OnSettingsAck, void());
     51   MOCK_METHOD0(OnSettingsEnd, void());
     52   MOCK_METHOD2(OnPing, void(SpdyPingId unique_id, bool is_ack));
     53   MOCK_METHOD2(OnGoAway, void(SpdyStreamId last_accepted_stream_id,
     54                               SpdyGoAwayStatus status));
     55   MOCK_METHOD3(OnHeaders, void(SpdyStreamId stream_id, bool fin, bool end));
     56   MOCK_METHOD2(OnWindowUpdate, void(SpdyStreamId stream_id,
     57                                     uint32 delta_window_size));
     58   MOCK_METHOD2(OnCredentialFrameData, bool(const char* credential_data,
     59                                            size_t len));
     60   MOCK_METHOD1(OnBlocked, void(SpdyStreamId stream_id));
     61   MOCK_METHOD3(OnPushPromise, void(SpdyStreamId stream_id,
     62                                    SpdyStreamId promised_stream_id,
     63                                    bool end));
     64   MOCK_METHOD2(OnContinuation, void(SpdyStreamId stream_id, bool end));
     65   MOCK_METHOD6(OnAltSvc, void(SpdyStreamId stream_id,
     66                               uint32 max_age,
     67                               uint16 port,
     68                               StringPiece protocol_id,
     69                               StringPiece host,
     70                               StringPiece origin));
     71   MOCK_METHOD2(OnUnknownFrame, bool(SpdyStreamId stream_id, int frame_type));
     72 };
     73 
     74 class QuicHeadersStreamTest : public ::testing::TestWithParam<bool> {
     75  public:
     76   static QuicVersionVector GetVersions() {
     77     QuicVersionVector versions;
     78     versions.push_back(QuicVersionMax());
     79     return versions;
     80   }
     81 
     82   QuicHeadersStreamTest()
     83       : connection_(new StrictMock<MockConnection>(is_server(), GetVersions())),
     84         session_(connection_),
     85         headers_stream_(QuicSessionPeer::GetHeadersStream(&session_)),
     86         body_("hello world"),
     87         framer_(SPDY3) {
     88     headers_[":version"]  = "HTTP/1.1";
     89     headers_[":status"] = "200 Ok";
     90     headers_["content-length"] = "11";
     91     framer_.set_visitor(&visitor_);
     92     EXPECT_EQ(QuicVersionMax(), session_.connection()->version());
     93     EXPECT_TRUE(headers_stream_ != NULL);
     94   }
     95 
     96   QuicConsumedData SaveIov(const IOVector& data) {
     97     const iovec* iov = data.iovec();
     98     int count = data.Capacity();
     99     for (int i = 0 ; i < count; ++i) {
    100       saved_data_.append(static_cast<char*>(iov[i].iov_base), iov[i].iov_len);
    101     }
    102     return QuicConsumedData(saved_data_.length(), false);
    103   }
    104 
    105   bool SaveHeaderData(const char* data, int len) {
    106     saved_header_data_.append(data, len);
    107     return true;
    108   }
    109 
    110   void SaveHeaderDataStringPiece(StringPiece data) {
    111     saved_header_data_.append(data.data(), data.length());
    112   }
    113 
    114   void WriteHeadersAndExpectSynStream(QuicStreamId stream_id,
    115                                       bool fin,
    116                                       QuicPriority priority) {
    117     WriteHeadersAndCheckData(stream_id, fin, priority, SYN_STREAM);
    118   }
    119 
    120   void WriteHeadersAndExpectSynReply(QuicStreamId stream_id,
    121                                      bool fin) {
    122     WriteHeadersAndCheckData(stream_id, fin, 0, SYN_REPLY);
    123   }
    124 
    125   void WriteHeadersAndCheckData(QuicStreamId stream_id,
    126                                 bool fin,
    127                                 QuicPriority priority,
    128                                 SpdyFrameType type) {
    129     // Write the headers and capture the outgoing data
    130     EXPECT_CALL(session_, WritevData(kHeadersStreamId, _, _, false, _, NULL))
    131         .WillOnce(WithArgs<1>(Invoke(this, &QuicHeadersStreamTest::SaveIov)));
    132     headers_stream_->WriteHeaders(stream_id, headers_, fin, NULL);
    133 
    134     // Parse the outgoing data and check that it matches was was written.
    135     if (type == SYN_STREAM) {
    136       EXPECT_CALL(visitor_, OnSynStream(stream_id, kNoAssociatedStream, 0,
    137                                         // priority,
    138                                         fin, kNotUnidirectional));
    139     } else {
    140       EXPECT_CALL(visitor_, OnSynReply(stream_id, fin));
    141     }
    142     EXPECT_CALL(visitor_, OnControlFrameHeaderData(stream_id, _, _))
    143         .WillRepeatedly(WithArgs<1, 2>(
    144             Invoke(this, &QuicHeadersStreamTest::SaveHeaderData)));
    145     if (fin) {
    146       EXPECT_CALL(visitor_, OnStreamFrameData(stream_id, NULL, 0, true));
    147     }
    148     framer_.ProcessInput(saved_data_.data(), saved_data_.length());
    149     EXPECT_FALSE(framer_.HasError()) << framer_.error_code();
    150 
    151     CheckHeaders();
    152     saved_data_.clear();
    153   }
    154 
    155   void CheckHeaders() {
    156     SpdyHeaderBlock headers;
    157     EXPECT_EQ(saved_header_data_.length(),
    158               framer_.ParseHeaderBlockInBuffer(saved_header_data_.data(),
    159                                                saved_header_data_.length(),
    160                                                &headers));
    161     EXPECT_EQ(headers_, headers);
    162     saved_header_data_.clear();
    163   }
    164 
    165   bool is_server() {
    166     return GetParam();
    167   }
    168 
    169   void CloseConnection() {
    170     QuicConnectionPeer::CloseConnection(connection_);
    171   }
    172 
    173   static const bool kNotUnidirectional = false;
    174   static const bool kNoAssociatedStream = false;
    175 
    176   StrictMock<MockConnection>* connection_;
    177   StrictMock<MockSession> session_;
    178   QuicHeadersStream* headers_stream_;
    179   SpdyHeaderBlock headers_;
    180   string body_;
    181   string saved_data_;
    182   string saved_header_data_;
    183   SpdyFramer framer_;
    184   StrictMock<MockVisitor> visitor_;
    185 };
    186 
    187 INSTANTIATE_TEST_CASE_P(Tests, QuicHeadersStreamTest, testing::Bool());
    188 
    189 TEST_P(QuicHeadersStreamTest, StreamId) {
    190   EXPECT_EQ(3u, headers_stream_->id());
    191 }
    192 
    193 TEST_P(QuicHeadersStreamTest, EffectivePriority) {
    194   EXPECT_EQ(0u, headers_stream_->EffectivePriority());
    195 }
    196 
    197 TEST_P(QuicHeadersStreamTest, WriteHeaders) {
    198   for (QuicStreamId stream_id = kClientDataStreamId1;
    199        stream_id < kClientDataStreamId3; stream_id += 2) {
    200     for (int count = 0; count < 2; ++count) {
    201       bool fin = (count == 0);
    202       if (is_server()) {
    203         WriteHeadersAndExpectSynReply(stream_id, fin);
    204       } else {
    205         for (QuicPriority priority = 0; priority < 7; ++priority) {
    206           WriteHeadersAndExpectSynStream(stream_id, fin, priority);
    207         }
    208       }
    209     }
    210   }
    211 }
    212 
    213 TEST_P(QuicHeadersStreamTest, ProcessRawData) {
    214   for (QuicStreamId stream_id = kClientDataStreamId1;
    215        stream_id < kClientDataStreamId3; stream_id += 2) {
    216     for (int count = 0; count < 2; ++count) {
    217       bool fin = (count == 0);
    218       for (QuicPriority priority = 0; priority < 7; ++priority) {
    219         // Replace with "WriteHeadersAndSaveData"
    220         scoped_ptr<SpdySerializedFrame> frame;
    221         if (is_server()) {
    222           SpdySynStreamIR syn_stream(stream_id);
    223           syn_stream.set_name_value_block(headers_);
    224           syn_stream.set_fin(fin);
    225           frame.reset(framer_.SerializeSynStream(syn_stream));
    226           EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0));
    227         } else {
    228           SpdySynReplyIR syn_reply(stream_id);
    229           syn_reply.set_name_value_block(headers_);
    230           syn_reply.set_fin(fin);
    231           frame.reset(framer_.SerializeSynReply(syn_reply));
    232         }
    233         EXPECT_CALL(session_, OnStreamHeaders(stream_id, _))
    234             .WillRepeatedly(WithArgs<1>(
    235                 Invoke(this,
    236                        &QuicHeadersStreamTest::SaveHeaderDataStringPiece)));
    237         EXPECT_CALL(session_,
    238                     OnStreamHeadersComplete(stream_id, fin, frame->size()));
    239         headers_stream_->ProcessRawData(frame->data(), frame->size());
    240 
    241         CheckHeaders();
    242       }
    243     }
    244   }
    245 }
    246 
    247 TEST_P(QuicHeadersStreamTest, ProcessSpdyDataFrame) {
    248   SpdyDataIR data(2, "");
    249   scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
    250   EXPECT_CALL(*connection_,
    251               SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
    252                                              "SPDY DATA frame received."))
    253       .WillOnce(InvokeWithoutArgs(this,
    254                                   &QuicHeadersStreamTest::CloseConnection));
    255   headers_stream_->ProcessRawData(frame->data(), frame->size());
    256 }
    257 
    258 TEST_P(QuicHeadersStreamTest, ProcessSpdyRstStreamFrame) {
    259   SpdyRstStreamIR data(2, RST_STREAM_PROTOCOL_ERROR, "");
    260   scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
    261   EXPECT_CALL(*connection_,
    262               SendConnectionCloseWithDetails(
    263                   QUIC_INVALID_HEADERS_STREAM_DATA,
    264                   "SPDY RST_STREAM frame received."))
    265       .WillOnce(InvokeWithoutArgs(this,
    266                                   &QuicHeadersStreamTest::CloseConnection));
    267   headers_stream_->ProcessRawData(frame->data(), frame->size());
    268 }
    269 
    270 TEST_P(QuicHeadersStreamTest, ProcessSpdySettingsFrame) {
    271   SpdySettingsIR data;
    272   data.AddSetting(SETTINGS_UPLOAD_BANDWIDTH, true, true, 0);
    273   scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
    274   EXPECT_CALL(*connection_,
    275               SendConnectionCloseWithDetails(
    276                   QUIC_INVALID_HEADERS_STREAM_DATA,
    277                   "SPDY SETTINGS frame received."))
    278       .WillOnce(InvokeWithoutArgs(this,
    279                                   &QuicHeadersStreamTest::CloseConnection));
    280   headers_stream_->ProcessRawData(frame->data(), frame->size());
    281 }
    282 
    283 TEST_P(QuicHeadersStreamTest, ProcessSpdyPingFrame) {
    284   SpdyPingIR data(1);
    285   scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
    286   EXPECT_CALL(*connection_,
    287               SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
    288                                              "SPDY PING frame received."))
    289       .WillOnce(InvokeWithoutArgs(this,
    290                                   &QuicHeadersStreamTest::CloseConnection));
    291   headers_stream_->ProcessRawData(frame->data(), frame->size());
    292 }
    293 
    294 TEST_P(QuicHeadersStreamTest, ProcessSpdyGoAwayFrame) {
    295   SpdyGoAwayIR data(1, GOAWAY_PROTOCOL_ERROR, "go away");
    296   scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
    297   EXPECT_CALL(*connection_,
    298               SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
    299                                              "SPDY GOAWAY frame received."))
    300       .WillOnce(InvokeWithoutArgs(this,
    301                                   &QuicHeadersStreamTest::CloseConnection));
    302   headers_stream_->ProcessRawData(frame->data(), frame->size());
    303 }
    304 
    305 TEST_P(QuicHeadersStreamTest, ProcessSpdyHeadersFrame) {
    306   SpdyHeadersIR data(1);
    307   scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
    308   EXPECT_CALL(*connection_,
    309               SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
    310                                              "SPDY HEADERS frame received."))
    311       .WillOnce(InvokeWithoutArgs(this,
    312                                   &QuicHeadersStreamTest::CloseConnection));
    313   headers_stream_->ProcessRawData(frame->data(), frame->size());
    314 }
    315 
    316 TEST_P(QuicHeadersStreamTest, ProcessSpdyWindowUpdateFrame) {
    317   SpdyWindowUpdateIR data(1, 1);
    318   scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
    319   EXPECT_CALL(*connection_,
    320               SendConnectionCloseWithDetails(
    321                   QUIC_INVALID_HEADERS_STREAM_DATA,
    322                   "SPDY WINDOW_UPDATE frame received."))
    323       .WillOnce(InvokeWithoutArgs(this,
    324                                   &QuicHeadersStreamTest::CloseConnection));
    325   headers_stream_->ProcessRawData(frame->data(), frame->size());
    326 }
    327 
    328 TEST_P(QuicHeadersStreamTest, NoConnectionLevelFlowControl) {
    329   if (connection_->version() < QUIC_VERSION_21) {
    330     EXPECT_FALSE(headers_stream_->flow_controller()->IsEnabled());
    331   } else {
    332     EXPECT_TRUE(headers_stream_->flow_controller()->IsEnabled());
    333   }
    334   EXPECT_FALSE(ReliableQuicStreamPeer::StreamContributesToConnectionFlowControl(
    335       headers_stream_));
    336 }
    337 
    338 }  // namespace
    339 }  // namespace test
    340 }  // namespace net
    341