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