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_data_stream.h"
      6 
      7 #include "net/quic/quic_ack_notifier.h"
      8 #include "net/quic/quic_connection.h"
      9 #include "net/quic/quic_spdy_compressor.h"
     10 #include "net/quic/quic_spdy_decompressor.h"
     11 #include "net/quic/quic_utils.h"
     12 #include "net/quic/spdy_utils.h"
     13 #include "net/quic/test_tools/quic_session_peer.h"
     14 #include "net/quic/test_tools/quic_test_utils.h"
     15 #include "testing/gmock/include/gmock/gmock.h"
     16 
     17 using base::StringPiece;
     18 using std::min;
     19 using testing::_;
     20 using testing::InSequence;
     21 using testing::Return;
     22 using testing::SaveArg;
     23 using testing::StrEq;
     24 using testing::StrictMock;
     25 
     26 namespace net {
     27 namespace test {
     28 namespace {
     29 
     30 const QuicGuid kStreamId = 3;
     31 const bool kIsServer = true;
     32 const bool kShouldProcessData = true;
     33 
     34 class TestStream : public QuicDataStream {
     35  public:
     36   TestStream(QuicStreamId id,
     37              QuicSession* session,
     38              bool should_process_data)
     39       : QuicDataStream(id, session),
     40         should_process_data_(should_process_data) {}
     41 
     42   virtual uint32 ProcessData(const char* data, uint32 data_len) OVERRIDE {
     43     EXPECT_NE(0u, data_len);
     44     DVLOG(1) << "ProcessData data_len: " << data_len;
     45     data_ += string(data, data_len);
     46     return should_process_data_ ? data_len : 0;
     47   }
     48 
     49   using ReliableQuicStream::WriteOrBufferData;
     50   using ReliableQuicStream::CloseReadSide;
     51   using ReliableQuicStream::CloseWriteSide;
     52 
     53   const string& data() const { return data_; }
     54 
     55  private:
     56   bool should_process_data_;
     57   string data_;
     58 };
     59 
     60 class QuicDataStreamTest : public ::testing::TestWithParam<bool> {
     61  public:
     62   QuicDataStreamTest() {
     63     headers_[":host"] = "www.google.com";
     64     headers_[":path"] = "/index.hml";
     65     headers_[":scheme"] = "https";
     66     headers_["cookie"] =
     67         "__utma=208381060.1228362404.1372200928.1372200928.1372200928.1; "
     68         "__utmc=160408618; "
     69         "GX=DQAAAOEAAACWJYdewdE9rIrW6qw3PtVi2-d729qaa-74KqOsM1NVQblK4VhX"
     70         "hoALMsy6HOdDad2Sz0flUByv7etmo3mLMidGrBoljqO9hSVA40SLqpG_iuKKSHX"
     71         "RW3Np4bq0F0SDGDNsW0DSmTS9ufMRrlpARJDS7qAI6M3bghqJp4eABKZiRqebHT"
     72         "pMU-RXvTI5D5oCF1vYxYofH_l1Kviuiy3oQ1kS1enqWgbhJ2t61_SNdv-1XJIS0"
     73         "O3YeHLmVCs62O6zp89QwakfAWK9d3IDQvVSJzCQsvxvNIvaZFa567MawWlXg0Rh"
     74         "1zFMi5vzcns38-8_Sns; "
     75         "GA=v*2%2Fmem*57968640*47239936%2Fmem*57968640*47114716%2Fno-nm-"
     76         "yj*15%2Fno-cc-yj*5%2Fpc-ch*133685%2Fpc-s-cr*133947%2Fpc-s-t*1339"
     77         "47%2Fno-nm-yj*4%2Fno-cc-yj*1%2Fceft-as*1%2Fceft-nqas*0%2Fad-ra-c"
     78         "v_p%2Fad-nr-cv_p-f*1%2Fad-v-cv_p*859%2Fad-ns-cv_p-f*1%2Ffn-v-ad%"
     79         "2Fpc-t*250%2Fpc-cm*461%2Fpc-s-cr*722%2Fpc-s-t*722%2Fau_p*4"
     80         "SICAID=AJKiYcHdKgxum7KMXG0ei2t1-W4OD1uW-ecNsCqC0wDuAXiDGIcT_HA2o1"
     81         "3Rs1UKCuBAF9g8rWNOFbxt8PSNSHFuIhOo2t6bJAVpCsMU5Laa6lewuTMYI8MzdQP"
     82         "ARHKyW-koxuhMZHUnGBJAM1gJODe0cATO_KGoX4pbbFxxJ5IicRxOrWK_5rU3cdy6"
     83         "edlR9FsEdH6iujMcHkbE5l18ehJDwTWmBKBzVD87naobhMMrF6VvnDGxQVGp9Ir_b"
     84         "Rgj3RWUoPumQVCxtSOBdX0GlJOEcDTNCzQIm9BSfetog_eP_TfYubKudt5eMsXmN6"
     85         "QnyXHeGeK2UINUzJ-D30AFcpqYgH9_1BvYSpi7fc7_ydBU8TaD8ZRxvtnzXqj0RfG"
     86         "tuHghmv3aD-uzSYJ75XDdzKdizZ86IG6Fbn1XFhYZM-fbHhm3mVEXnyRW4ZuNOLFk"
     87         "Fas6LMcVC6Q8QLlHYbXBpdNFuGbuZGUnav5C-2I_-46lL0NGg3GewxGKGHvHEfoyn"
     88         "EFFlEYHsBQ98rXImL8ySDycdLEFvBPdtctPmWCfTxwmoSMLHU2SCVDhbqMWU5b0yr"
     89         "JBCScs_ejbKaqBDoB7ZGxTvqlrB__2ZmnHHjCr8RgMRtKNtIeuZAo ";
     90   }
     91 
     92   void Initialize(bool stream_should_process_data) {
     93     connection_ = new StrictMock<MockConnection>(kIsServer);
     94     session_.reset(new StrictMock<MockSession>(connection_));
     95     stream_.reset(new TestStream(kStreamId, session_.get(),
     96                                  stream_should_process_data));
     97     stream2_.reset(new TestStream(kStreamId + 2, session_.get(),
     98                                  stream_should_process_data));
     99     compressor_.reset(new QuicSpdyCompressor());
    100     decompressor_.reset(new QuicSpdyDecompressor);
    101     write_blocked_list_ =
    102         QuicSessionPeer::GetWriteblockedStreams(session_.get());
    103   }
    104 
    105  protected:
    106   MockConnection* connection_;
    107   scoped_ptr<MockSession> session_;
    108   scoped_ptr<TestStream> stream_;
    109   scoped_ptr<TestStream> stream2_;
    110   scoped_ptr<QuicSpdyCompressor> compressor_;
    111   scoped_ptr<QuicSpdyDecompressor> decompressor_;
    112   SpdyHeaderBlock headers_;
    113   WriteBlockedList<QuicStreamId>* write_blocked_list_;
    114 };
    115 
    116 TEST_F(QuicDataStreamTest, ProcessHeaders) {
    117   Initialize(kShouldProcessData);
    118 
    119   string compressed_headers = compressor_->CompressHeadersWithPriority(
    120       QuicUtils::HighestPriority(), headers_);
    121   QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(compressed_headers));
    122 
    123   stream_->OnStreamFrame(frame);
    124   EXPECT_EQ(SpdyUtils::SerializeUncompressedHeaders(headers_), stream_->data());
    125   EXPECT_EQ(QuicUtils::HighestPriority(), stream_->EffectivePriority());
    126 }
    127 
    128 TEST_F(QuicDataStreamTest, ProcessHeadersWithInvalidHeaderId) {
    129   Initialize(kShouldProcessData);
    130 
    131   string compressed_headers = compressor_->CompressHeadersWithPriority(
    132       QuicUtils::HighestPriority(), headers_);
    133   compressed_headers[4] = '\xFF';  // Illegal  header id.
    134   QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(compressed_headers));
    135 
    136   EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_HEADER_ID));
    137   stream_->OnStreamFrame(frame);
    138 }
    139 
    140 TEST_F(QuicDataStreamTest, ProcessHeadersWithInvalidPriority) {
    141   Initialize(kShouldProcessData);
    142 
    143   string compressed_headers = compressor_->CompressHeadersWithPriority(
    144       QuicUtils::HighestPriority(), headers_);
    145   compressed_headers[0] = '\xFF';  // Illegal priority.
    146   QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(compressed_headers));
    147 
    148   EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_PRIORITY));
    149   stream_->OnStreamFrame(frame);
    150 }
    151 
    152 TEST_F(QuicDataStreamTest, ProcessHeadersAndBody) {
    153   Initialize(kShouldProcessData);
    154 
    155   string compressed_headers = compressor_->CompressHeadersWithPriority(
    156       QuicUtils::HighestPriority(), headers_);
    157   string body = "this is the body";
    158   string data = compressed_headers + body;
    159   QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(data));
    160 
    161   stream_->OnStreamFrame(frame);
    162   EXPECT_EQ(SpdyUtils::SerializeUncompressedHeaders(headers_) + body,
    163             stream_->data());
    164 }
    165 
    166 TEST_F(QuicDataStreamTest, ProcessHeadersAndBodyFragments) {
    167   Initialize(kShouldProcessData);
    168 
    169   string compressed_headers = compressor_->CompressHeadersWithPriority(
    170       QuicUtils::LowestPriority(), headers_);
    171   string body = "this is the body";
    172   string data = compressed_headers + body;
    173 
    174   for (size_t fragment_size = 1; fragment_size < data.size(); ++fragment_size) {
    175     Initialize(kShouldProcessData);
    176     for (size_t offset = 0; offset < data.size(); offset += fragment_size) {
    177       size_t remaining_data = data.length() - offset;
    178       StringPiece fragment(data.data() + offset,
    179                            min(fragment_size, remaining_data));
    180       QuicStreamFrame frame(kStreamId, false, offset, MakeIOVector(fragment));
    181 
    182       stream_->OnStreamFrame(frame);
    183     }
    184     ASSERT_EQ(SpdyUtils::SerializeUncompressedHeaders(headers_) + body,
    185               stream_->data()) << "fragment_size: " << fragment_size;
    186   }
    187 
    188   for (size_t split_point = 1; split_point < data.size() - 1; ++split_point) {
    189     Initialize(kShouldProcessData);
    190 
    191     StringPiece fragment1(data.data(), split_point);
    192     QuicStreamFrame frame1(kStreamId, false, 0, MakeIOVector(fragment1));
    193     stream_->OnStreamFrame(frame1);
    194 
    195     StringPiece fragment2(data.data() + split_point, data.size() - split_point);
    196     QuicStreamFrame frame2(
    197         kStreamId, false, split_point, MakeIOVector(fragment2));
    198     stream_->OnStreamFrame(frame2);
    199 
    200     ASSERT_EQ(SpdyUtils::SerializeUncompressedHeaders(headers_) + body,
    201               stream_->data()) << "split_point: " << split_point;
    202   }
    203   EXPECT_EQ(QuicUtils::LowestPriority(), stream_->EffectivePriority());
    204 }
    205 
    206 TEST_F(QuicDataStreamTest, ProcessHeadersAndBodyReadv) {
    207   Initialize(!kShouldProcessData);
    208 
    209   string compressed_headers = compressor_->CompressHeadersWithPriority(
    210       QuicUtils::HighestPriority(), headers_);
    211   string body = "this is the body";
    212   string data = compressed_headers + body;
    213   QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(data));
    214   string uncompressed_headers =
    215       SpdyUtils::SerializeUncompressedHeaders(headers_);
    216   string uncompressed_data = uncompressed_headers + body;
    217 
    218   stream_->OnStreamFrame(frame);
    219   EXPECT_EQ(uncompressed_headers, stream_->data());
    220 
    221   char buffer[2048];
    222   ASSERT_LT(data.length(), arraysize(buffer));
    223   struct iovec vec;
    224   vec.iov_base = buffer;
    225   vec.iov_len = arraysize(buffer);
    226 
    227   size_t bytes_read = stream_->Readv(&vec, 1);
    228   EXPECT_EQ(uncompressed_headers.length(), bytes_read);
    229   EXPECT_EQ(uncompressed_headers, string(buffer, bytes_read));
    230 
    231   bytes_read = stream_->Readv(&vec, 1);
    232   EXPECT_EQ(body.length(), bytes_read);
    233   EXPECT_EQ(body, string(buffer, bytes_read));
    234 }
    235 
    236 TEST_F(QuicDataStreamTest, ProcessHeadersAndBodyIncrementalReadv) {
    237   Initialize(!kShouldProcessData);
    238 
    239   string compressed_headers = compressor_->CompressHeadersWithPriority(
    240       QuicUtils::HighestPriority(), headers_);
    241   string body = "this is the body";
    242   string data = compressed_headers + body;
    243   QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(data));
    244   string uncompressed_headers =
    245       SpdyUtils::SerializeUncompressedHeaders(headers_);
    246   string uncompressed_data = uncompressed_headers + body;
    247 
    248   stream_->OnStreamFrame(frame);
    249   EXPECT_EQ(uncompressed_headers, stream_->data());
    250 
    251   char buffer[1];
    252   struct iovec vec;
    253   vec.iov_base = buffer;
    254   vec.iov_len = arraysize(buffer);
    255   for (size_t i = 0; i < uncompressed_data.length(); ++i) {
    256     size_t bytes_read = stream_->Readv(&vec, 1);
    257     ASSERT_EQ(1u, bytes_read);
    258     EXPECT_EQ(uncompressed_data.data()[i], buffer[0]);
    259   }
    260 }
    261 
    262 TEST_F(QuicDataStreamTest, ProcessHeadersUsingReadvWithMultipleIovecs) {
    263   Initialize(!kShouldProcessData);
    264 
    265   string compressed_headers = compressor_->CompressHeadersWithPriority(
    266       QuicUtils::HighestPriority(), headers_);
    267   string body = "this is the body";
    268   string data = compressed_headers + body;
    269   QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(data));
    270   string uncompressed_headers =
    271       SpdyUtils::SerializeUncompressedHeaders(headers_);
    272   string uncompressed_data = uncompressed_headers + body;
    273 
    274   stream_->OnStreamFrame(frame);
    275   EXPECT_EQ(uncompressed_headers, stream_->data());
    276 
    277   char buffer1[1];
    278   char buffer2[1];
    279   struct iovec vec[2];
    280   vec[0].iov_base = buffer1;
    281   vec[0].iov_len = arraysize(buffer1);
    282   vec[1].iov_base = buffer2;
    283   vec[1].iov_len = arraysize(buffer2);
    284   for (size_t i = 0; i < uncompressed_data.length(); i += 2) {
    285     size_t bytes_read = stream_->Readv(vec, 2);
    286     ASSERT_EQ(2u, bytes_read) << i;
    287     ASSERT_EQ(uncompressed_data.data()[i], buffer1[0]) << i;
    288     ASSERT_EQ(uncompressed_data.data()[i + 1], buffer2[0]) << i;
    289   }
    290 }
    291 
    292 TEST_F(QuicDataStreamTest, ProcessCorruptHeadersEarly) {
    293   Initialize(kShouldProcessData);
    294 
    295   string compressed_headers1 = compressor_->CompressHeadersWithPriority(
    296       QuicUtils::HighestPriority(), headers_);
    297   QuicStreamFrame frame1(
    298       stream_->id(), false, 0, MakeIOVector(compressed_headers1));
    299   string decompressed_headers1 =
    300       SpdyUtils::SerializeUncompressedHeaders(headers_);
    301 
    302   headers_["content-type"] = "text/plain";
    303   string compressed_headers2 = compressor_->CompressHeadersWithPriority(
    304       QuicUtils::HighestPriority(), headers_);
    305   // Corrupt the compressed data.
    306   compressed_headers2[compressed_headers2.length() - 1] ^= 0xA1;
    307   QuicStreamFrame frame2(
    308       stream2_->id(), false, 0, MakeIOVector(compressed_headers2));
    309   string decompressed_headers2 =
    310       SpdyUtils::SerializeUncompressedHeaders(headers_);
    311 
    312   // Deliver frame2 to stream2 out of order.  The decompressor is not
    313   // available yet, so no data will be processed.  The compressed data
    314   // will be buffered until OnDecompressorAvailable() is called
    315   // to process it.
    316   stream2_->OnStreamFrame(frame2);
    317   EXPECT_EQ("", stream2_->data());
    318 
    319   // Now deliver frame1 to stream1.  The decompressor is available so
    320   // the data will be processed, and the decompressor will become
    321   // available for stream2.
    322   stream_->OnStreamFrame(frame1);
    323   EXPECT_EQ(decompressed_headers1, stream_->data());
    324 
    325   // Verify that the decompressor is available, and inform stream2
    326   // that it can now decompress the buffered compressed data.    Since
    327   // the compressed data is corrupt, the stream will shutdown the session.
    328   EXPECT_EQ(2u, session_->decompressor()->current_header_id());
    329   EXPECT_CALL(*connection_, SendConnectionClose(QUIC_DECOMPRESSION_FAILURE));
    330   stream2_->OnDecompressorAvailable();
    331   EXPECT_EQ("", stream2_->data());
    332 }
    333 
    334 TEST_F(QuicDataStreamTest, ProcessPartialHeadersEarly) {
    335   Initialize(kShouldProcessData);
    336 
    337   string compressed_headers1 = compressor_->CompressHeadersWithPriority(
    338       QuicUtils::HighestPriority(), headers_);
    339   QuicStreamFrame frame1(
    340       stream_->id(), false, 0, MakeIOVector(compressed_headers1));
    341   string decompressed_headers1 =
    342       SpdyUtils::SerializeUncompressedHeaders(headers_);
    343 
    344   headers_["content-type"] = "text/plain";
    345   string compressed_headers2 = compressor_->CompressHeadersWithPriority(
    346       QuicUtils::HighestPriority(), headers_);
    347   string partial_compressed_headers =
    348       compressed_headers2.substr(0, compressed_headers2.length() / 2);
    349   QuicStreamFrame frame2(
    350       stream2_->id(), false, 0, MakeIOVector(partial_compressed_headers));
    351   string decompressed_headers2 =
    352       SpdyUtils::SerializeUncompressedHeaders(headers_);
    353 
    354   // Deliver frame2 to stream2 out of order.  The decompressor is not
    355   // available yet, so no data will be processed.  The compressed data
    356   // will be buffered until OnDecompressorAvailable() is called
    357   // to process it.
    358   stream2_->OnStreamFrame(frame2);
    359   EXPECT_EQ("", stream2_->data());
    360 
    361   // Now deliver frame1 to stream1.  The decompressor is available so
    362   // the data will be processed, and the decompressor will become
    363   // available for stream2.
    364   stream_->OnStreamFrame(frame1);
    365   EXPECT_EQ(decompressed_headers1, stream_->data());
    366 
    367   // Verify that the decompressor is available, and inform stream2
    368   // that it can now decompress the buffered compressed data.  Since
    369   // the compressed data is incomplete it will not be passed to
    370   // the stream.
    371   EXPECT_EQ(2u, session_->decompressor()->current_header_id());
    372   stream2_->OnDecompressorAvailable();
    373   EXPECT_EQ("", stream2_->data());
    374 
    375   // Now send remaining data and verify that we have now received the
    376   // compressed headers.
    377   string remaining_compressed_headers =
    378       compressed_headers2.substr(partial_compressed_headers.length());
    379 
    380   QuicStreamFrame frame3(stream2_->id(), false,
    381                          partial_compressed_headers.length(),
    382                          MakeIOVector(remaining_compressed_headers));
    383   stream2_->OnStreamFrame(frame3);
    384   EXPECT_EQ(decompressed_headers2, stream2_->data());
    385 }
    386 
    387 TEST_F(QuicDataStreamTest, ProcessHeadersEarly) {
    388   Initialize(kShouldProcessData);
    389 
    390   string compressed_headers1 = compressor_->CompressHeadersWithPriority(
    391       QuicUtils::HighestPriority(), headers_);
    392   QuicStreamFrame frame1(
    393       stream_->id(), false, 0, MakeIOVector(compressed_headers1));
    394   string decompressed_headers1 =
    395       SpdyUtils::SerializeUncompressedHeaders(headers_);
    396 
    397   headers_["content-type"] = "text/plain";
    398   string compressed_headers2 = compressor_->CompressHeadersWithPriority(
    399       QuicUtils::HighestPriority(), headers_);
    400   QuicStreamFrame frame2(
    401       stream2_->id(), false, 0, MakeIOVector(compressed_headers2));
    402   string decompressed_headers2 =
    403       SpdyUtils::SerializeUncompressedHeaders(headers_);
    404 
    405   // Deliver frame2 to stream2 out of order.  The decompressor is not
    406   // available yet, so no data will be processed.  The compressed data
    407   // will be buffered until OnDecompressorAvailable() is called
    408   // to process it.
    409   stream2_->OnStreamFrame(frame2);
    410   EXPECT_EQ("", stream2_->data());
    411 
    412   // Now deliver frame1 to stream1.  The decompressor is available so
    413   // the data will be processed, and the decompressor will become
    414   // available for stream2.
    415   stream_->OnStreamFrame(frame1);
    416   EXPECT_EQ(decompressed_headers1, stream_->data());
    417 
    418   // Verify that the decompressor is available, and inform stream2
    419   // that it can now decompress the buffered compressed data.
    420   EXPECT_EQ(2u, session_->decompressor()->current_header_id());
    421   stream2_->OnDecompressorAvailable();
    422   EXPECT_EQ(decompressed_headers2, stream2_->data());
    423 }
    424 
    425 TEST_F(QuicDataStreamTest, ProcessHeadersDelay) {
    426   Initialize(!kShouldProcessData);
    427 
    428   string compressed_headers = compressor_->CompressHeadersWithPriority(
    429       QuicUtils::HighestPriority(), headers_);
    430   QuicStreamFrame frame1(
    431       stream_->id(), false, 0, MakeIOVector(compressed_headers));
    432   string decompressed_headers =
    433       SpdyUtils::SerializeUncompressedHeaders(headers_);
    434 
    435   // Send the headers to the stream and verify they were decompressed.
    436   stream_->OnStreamFrame(frame1);
    437   EXPECT_EQ(2u, session_->decompressor()->current_header_id());
    438 
    439   // Verify that we are now able to handle the body data,
    440   // even though the stream has not processed the headers.
    441   EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_HEADER_ID))
    442       .Times(0);
    443   QuicStreamFrame frame2(stream_->id(), false, compressed_headers.length(),
    444                          MakeIOVector("body data"));
    445   stream_->OnStreamFrame(frame2);
    446 }
    447 
    448 }  // namespace
    449 }  // namespace test
    450 }  // namespace net
    451