| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/quic/reliable_quic_stream.h" | 5 #include "net/quic/reliable_quic_stream.h" |
| 6 | 6 |
| 7 #include "net/quic/quic_connection.h" | 7 #include "net/quic/quic_connection.h" |
| 8 #include "net/quic/quic_spdy_compressor.h" | |
| 9 #include "net/quic/quic_spdy_decompressor.h" | |
| 10 #include "net/quic/quic_utils.h" | 8 #include "net/quic/quic_utils.h" |
| 11 #include "net/quic/spdy_utils.h" | |
| 12 #include "net/quic/test_tools/quic_test_utils.h" | 9 #include "net/quic/test_tools/quic_test_utils.h" |
| 13 #include "testing/gmock/include/gmock/gmock.h" | 10 #include "testing/gmock/include/gmock/gmock.h" |
| 14 | 11 |
| 15 using base::StringPiece; | 12 using base::StringPiece; |
| 16 using std::min; | |
| 17 using testing::_; | 13 using testing::_; |
| 18 using testing::InSequence; | 14 using testing::InSequence; |
| 19 using testing::Return; | 15 using testing::Return; |
| 20 using testing::SaveArg; | |
| 21 using testing::StrEq; | 16 using testing::StrEq; |
| 22 using testing::StrictMock; | |
| 23 | 17 |
| 24 namespace net { | 18 namespace net { |
| 25 namespace test { | 19 namespace test { |
| 26 namespace { | 20 namespace { |
| 27 | 21 |
| 28 const char kData1[] = "FooAndBar"; | 22 const char kData1[] = "FooAndBar"; |
| 29 const char kData2[] = "EepAndBaz"; | 23 const char kData2[] = "EepAndBaz"; |
| 30 const size_t kDataLen = 9; | 24 const size_t kDataLen = 9; |
| 31 const QuicGuid kGuid = 42; | |
| 32 const QuicGuid kStreamId = 3; | |
| 33 const bool kIsServer = true; | |
| 34 const bool kShouldProcessData = true; | |
| 35 | 25 |
| 36 class TestStream : public ReliableQuicStream { | 26 class QuicReliableTestStream : public ReliableQuicStream { |
| 37 public: | 27 public: |
| 38 TestStream(QuicStreamId id, | 28 QuicReliableTestStream(QuicStreamId id, QuicSession* session) |
| 39 QuicSession* session, | 29 : ReliableQuicStream(id, session) { |
| 40 bool should_process_data) | |
| 41 : ReliableQuicStream(id, session), | |
| 42 should_process_data_(should_process_data) { | |
| 43 } | 30 } |
| 44 | |
| 45 virtual uint32 ProcessData(const char* data, uint32 data_len) OVERRIDE { | 31 virtual uint32 ProcessData(const char* data, uint32 data_len) OVERRIDE { |
| 46 LOG(INFO) << "data_len: " << data_len; | 32 return 0; |
| 47 data_ += string(data, data_len); | |
| 48 return should_process_data_ ? data_len : 0; | |
| 49 } | 33 } |
| 50 | |
| 51 using ReliableQuicStream::WriteData; | 34 using ReliableQuicStream::WriteData; |
| 52 using ReliableQuicStream::CloseReadSide; | 35 using ReliableQuicStream::CloseReadSide; |
| 53 using ReliableQuicStream::CloseWriteSide; | 36 using ReliableQuicStream::CloseWriteSide; |
| 54 | |
| 55 const string& data() const { return data_; } | |
| 56 | |
| 57 private: | |
| 58 bool should_process_data_; | |
| 59 string data_; | |
| 60 }; | 37 }; |
| 61 | 38 |
| 62 class ReliableQuicStreamTest : public ::testing::TestWithParam<bool> { | 39 class ReliableQuicStreamTest : public ::testing::TestWithParam<bool> { |
| 63 public: | 40 public: |
| 64 ReliableQuicStreamTest() { | 41 ReliableQuicStreamTest() |
| 65 headers_[":host"] = "www.google.com"; | 42 : connection_(new MockConnection(1, IPEndPoint(), false)), |
| 66 headers_[":path"] = "/index.hml"; | 43 session_(connection_, true), |
| 67 headers_[":scheme"] = "https"; | 44 stream_(1, &session_) { |
| 68 } | 45 } |
| 69 | 46 |
| 70 void Initialize(bool stream_should_process_data) { | |
| 71 connection_ = new MockConnection(kGuid, IPEndPoint(), kIsServer); | |
| 72 session_.reset(new MockSession(connection_, kIsServer)); | |
| 73 stream_.reset(new TestStream(kStreamId, session_.get(), | |
| 74 stream_should_process_data)); | |
| 75 stream2_.reset(new TestStream(kStreamId + 2, session_.get(), | |
| 76 stream_should_process_data)); | |
| 77 compressor_.reset(new QuicSpdyCompressor()); | |
| 78 decompressor_.reset(new QuicSpdyDecompressor); | |
| 79 } | |
| 80 | |
| 81 protected: | |
| 82 MockConnection* connection_; | 47 MockConnection* connection_; |
| 83 scoped_ptr<MockSession> session_; | 48 MockSession session_; |
| 84 scoped_ptr<TestStream> stream_; | 49 QuicReliableTestStream stream_; |
| 85 scoped_ptr<TestStream> stream2_; | |
| 86 scoped_ptr<QuicSpdyCompressor> compressor_; | |
| 87 scoped_ptr<QuicSpdyDecompressor> decompressor_; | |
| 88 SpdyHeaderBlock headers_; | |
| 89 }; | 50 }; |
| 90 | 51 |
| 91 TEST_F(ReliableQuicStreamTest, WriteAllData) { | 52 TEST_F(ReliableQuicStreamTest, WriteAllData) { |
| 92 Initialize(kShouldProcessData); | |
| 93 | |
| 94 connection_->options()->max_packet_length = | 53 connection_->options()->max_packet_length = |
| 95 1 + QuicPacketCreator::StreamFramePacketOverhead(1, !kIncludeVersion); | 54 1 + QuicPacketCreator::StreamFramePacketOverhead(1, !kIncludeVersion); |
| 96 // TODO(rch): figure out how to get StrEq working here. | 55 // TODO(rch): figure out how to get StrEq working here. |
| 97 //EXPECT_CALL(*session_, WriteData(kStreamId, StrEq(kData1), _, _)).WillOnce( | 56 //EXPECT_CALL(session_, WriteData(_, StrEq(kData1), _, _)).WillOnce( |
| 98 EXPECT_CALL(*session_, WriteData(kStreamId, _, _, _)).WillOnce( | 57 EXPECT_CALL(session_, WriteData(1, _, _, _)).WillOnce( |
| 99 Return(QuicConsumedData(kDataLen, true))); | 58 Return(QuicConsumedData(kDataLen, true))); |
| 100 EXPECT_EQ(kDataLen, stream_->WriteData(kData1, false).bytes_consumed); | 59 EXPECT_EQ(kDataLen, stream_.WriteData(kData1, false).bytes_consumed); |
| 101 } | 60 } |
| 102 | 61 |
| 103 TEST_F(ReliableQuicStreamTest, WriteData) { | 62 TEST_F(ReliableQuicStreamTest, WriteData) { |
| 104 Initialize(kShouldProcessData); | |
| 105 | |
| 106 connection_->options()->max_packet_length = | 63 connection_->options()->max_packet_length = |
| 107 1 + QuicPacketCreator::StreamFramePacketOverhead(1, !kIncludeVersion); | 64 1 + QuicPacketCreator::StreamFramePacketOverhead(1, !kIncludeVersion); |
| 108 // TODO(rch): figure out how to get StrEq working here. | 65 // TODO(rch): figure out how to get StrEq working here. |
| 109 //EXPECT_CALL(*session_, WriteData(_, StrEq(kData1), _, _)).WillOnce( | 66 //EXPECT_CALL(session_, WriteData(_, StrEq(kData1), _, _)).WillOnce( |
| 110 EXPECT_CALL(*session_, WriteData(_, _, _, _)).WillOnce( | 67 EXPECT_CALL(session_, WriteData(_, _, _, _)).WillOnce( |
| 111 Return(QuicConsumedData(kDataLen - 1, false))); | 68 Return(QuicConsumedData(kDataLen - 1, false))); |
| 112 // The return will be kDataLen, because the last byte gets buffered. | 69 // The return will be kDataLen, because the last byte gets buffered. |
| 113 EXPECT_EQ(kDataLen, stream_->WriteData(kData1, false).bytes_consumed); | 70 EXPECT_EQ(kDataLen, stream_.WriteData(kData1, false).bytes_consumed); |
| 114 | 71 |
| 115 // Queue a bytes_consumed write. | 72 // Queue a bytes_consumed write. |
| 116 EXPECT_EQ(kDataLen, stream_->WriteData(kData2, false).bytes_consumed); | 73 EXPECT_EQ(kDataLen, stream_.WriteData(kData2, false).bytes_consumed); |
| 117 | 74 |
| 118 // Make sure we get the tail of the first write followed by the bytes_consumed | 75 // Make sure we get the tail of the first write followed by the bytes_consumed |
| 119 InSequence s; | 76 InSequence s; |
| 120 //EXPECT_CALL(*session_, WriteData(_, StrEq(&kData1[kDataLen - 1]), _, _)). | 77 //EXPECT_CALL(session_, WriteData(_, StrEq(&kData2[kDataLen - 1]), _, _)). |
| 121 EXPECT_CALL(*session_, WriteData(_, _, _, _)). | 78 EXPECT_CALL(session_, WriteData(_, _, _, _)). |
| 122 WillOnce(Return(QuicConsumedData(1, false))); | 79 WillOnce(Return(QuicConsumedData(1, false))); |
| 123 //EXPECT_CALL(*session_, WriteData(_, StrEq(kData2), _, _)). | 80 //EXPECT_CALL(session_, WriteData(_, StrEq(kData2), _, _)). |
| 124 EXPECT_CALL(*session_, WriteData(_, _, _, _)). | 81 EXPECT_CALL(session_, WriteData(_, _, _, _)). |
| 125 WillOnce(Return(QuicConsumedData(kDataLen - 2, false))); | 82 WillOnce(Return(QuicConsumedData(kDataLen - 2, false))); |
| 126 stream_->OnCanWrite(); | 83 stream_.OnCanWrite(); |
| 127 | 84 |
| 128 // And finally the end of the bytes_consumed | 85 // And finally the end of the bytes_consumed |
| 129 //EXPECT_CALL(*session_, WriteData(_, StrEq(&kData2[kDataLen - 2]), _, _)). | 86 //EXPECT_CALL(session_, WriteData(_, StrEq(&kData2[kDataLen - 2]), _, _)). |
| 130 EXPECT_CALL(*session_, WriteData(_, _, _, _)). | 87 EXPECT_CALL(session_, WriteData(_, _, _, _)). |
| 131 WillOnce(Return(QuicConsumedData(2, true))); | 88 WillOnce(Return(QuicConsumedData(2, true))); |
| 132 stream_->OnCanWrite(); | 89 stream_.OnCanWrite(); |
| 133 } | 90 } |
| 134 | 91 |
| 135 TEST_F(ReliableQuicStreamTest, ConnectionCloseAfterStreamClose) { | 92 TEST_F(ReliableQuicStreamTest, ConnectionCloseAfterStreamClose) { |
| 136 Initialize(kShouldProcessData); | 93 stream_.CloseReadSide(); |
| 137 | 94 stream_.CloseWriteSide(); |
| 138 stream_->CloseReadSide(); | 95 EXPECT_EQ(QUIC_STREAM_NO_ERROR, stream_.stream_error()); |
| 139 stream_->CloseWriteSide(); | 96 EXPECT_EQ(QUIC_NO_ERROR, stream_.connection_error()); |
| 140 EXPECT_EQ(QUIC_STREAM_NO_ERROR, stream_->stream_error()); | 97 stream_.ConnectionClose(QUIC_INTERNAL_ERROR, false); |
| 141 EXPECT_EQ(QUIC_NO_ERROR, stream_->connection_error()); | 98 EXPECT_EQ(QUIC_STREAM_NO_ERROR, stream_.stream_error()); |
| 142 stream_->ConnectionClose(QUIC_INTERNAL_ERROR, false); | 99 EXPECT_EQ(QUIC_NO_ERROR, stream_.connection_error()); |
| 143 EXPECT_EQ(QUIC_STREAM_NO_ERROR, stream_->stream_error()); | |
| 144 EXPECT_EQ(QUIC_NO_ERROR, stream_->connection_error()); | |
| 145 } | |
| 146 | |
| 147 TEST_F(ReliableQuicStreamTest, ProcessHeaders) { | |
| 148 Initialize(kShouldProcessData); | |
| 149 | |
| 150 string compressed_headers = compressor_->CompressHeaders(headers_); | |
| 151 QuicStreamFrame frame(kStreamId, false, 0, compressed_headers); | |
| 152 | |
| 153 stream_->OnStreamFrame(frame); | |
| 154 EXPECT_EQ(SpdyUtils::SerializeUncompressedHeaders(headers_), stream_->data()); | |
| 155 } | |
| 156 | |
| 157 TEST_F(ReliableQuicStreamTest, ProcessHeadersWithInvalidHeaderId) { | |
| 158 Initialize(kShouldProcessData); | |
| 159 | |
| 160 string compressed_headers = compressor_->CompressHeaders(headers_); | |
| 161 compressed_headers.replace(0, 1, 1, '\xFF'); // Illegal header id. | |
| 162 QuicStreamFrame frame(kStreamId, false, 0, compressed_headers); | |
| 163 | |
| 164 EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_HEADER_ID)); | |
| 165 stream_->OnStreamFrame(frame); | |
| 166 } | |
| 167 | |
| 168 TEST_F(ReliableQuicStreamTest, ProcessHeadersAndBody) { | |
| 169 Initialize(kShouldProcessData); | |
| 170 | |
| 171 string compressed_headers = compressor_->CompressHeaders(headers_); | |
| 172 string body = "this is the body"; | |
| 173 string data = compressed_headers + body; | |
| 174 QuicStreamFrame frame(kStreamId, false, 0, data); | |
| 175 | |
| 176 stream_->OnStreamFrame(frame); | |
| 177 EXPECT_EQ(SpdyUtils::SerializeUncompressedHeaders(headers_) + body, | |
| 178 stream_->data()); | |
| 179 } | |
| 180 | |
| 181 TEST_F(ReliableQuicStreamTest, ProcessHeadersAndBodyFragments) { | |
| 182 Initialize(kShouldProcessData); | |
| 183 | |
| 184 string compressed_headers = compressor_->CompressHeaders(headers_); | |
| 185 string body = "this is the body"; | |
| 186 string data = compressed_headers + body; | |
| 187 | |
| 188 for (size_t fragment_size = 1; fragment_size < data.size(); ++fragment_size) { | |
| 189 Initialize(kShouldProcessData); | |
| 190 for (size_t offset = 0; offset < data.size(); offset += fragment_size) { | |
| 191 size_t remaining_data = data.length() - offset; | |
| 192 StringPiece fragment(data.data() + offset, | |
| 193 min(fragment_size, remaining_data)); | |
| 194 QuicStreamFrame frame(kStreamId, false, offset, fragment); | |
| 195 | |
| 196 stream_->OnStreamFrame(frame); | |
| 197 } | |
| 198 ASSERT_EQ(SpdyUtils::SerializeUncompressedHeaders(headers_) + body, | |
| 199 stream_->data()) << "fragment_size: " << fragment_size; | |
| 200 } | |
| 201 } | |
| 202 | |
| 203 TEST_F(ReliableQuicStreamTest, ProcessHeadersAndBodyReadv) { | |
| 204 Initialize(!kShouldProcessData); | |
| 205 | |
| 206 string compressed_headers = compressor_->CompressHeaders(headers_); | |
| 207 string body = "this is the body"; | |
| 208 string data = compressed_headers + body; | |
| 209 QuicStreamFrame frame(kStreamId, false, 0, data); | |
| 210 string uncompressed_headers = | |
| 211 SpdyUtils::SerializeUncompressedHeaders(headers_); | |
| 212 string uncompressed_data = uncompressed_headers + body; | |
| 213 | |
| 214 stream_->OnStreamFrame(frame); | |
| 215 EXPECT_EQ(uncompressed_data, stream_->data()); | |
| 216 | |
| 217 char buffer[1024]; | |
| 218 ASSERT_LT(data.length(), arraysize(buffer)); | |
| 219 struct iovec vec; | |
| 220 vec.iov_base = buffer; | |
| 221 vec.iov_len = arraysize(buffer); | |
| 222 | |
| 223 size_t bytes_read = stream_->Readv(&vec, 1); | |
| 224 EXPECT_EQ(uncompressed_headers.length(), bytes_read); | |
| 225 EXPECT_EQ(uncompressed_headers, string(buffer, bytes_read)); | |
| 226 | |
| 227 bytes_read = stream_->Readv(&vec, 1); | |
| 228 EXPECT_EQ(body.length(), bytes_read); | |
| 229 EXPECT_EQ(body, string(buffer, bytes_read)); | |
| 230 } | |
| 231 | |
| 232 TEST_F(ReliableQuicStreamTest, ProcessHeadersAndBodyIncrementalReadv) { | |
| 233 Initialize(!kShouldProcessData); | |
| 234 | |
| 235 string compressed_headers = compressor_->CompressHeaders(headers_); | |
| 236 string body = "this is the body"; | |
| 237 string data = compressed_headers + body; | |
| 238 QuicStreamFrame frame(kStreamId, false, 0, data); | |
| 239 string uncompressed_headers = | |
| 240 SpdyUtils::SerializeUncompressedHeaders(headers_); | |
| 241 string uncompressed_data = uncompressed_headers + body; | |
| 242 | |
| 243 stream_->OnStreamFrame(frame); | |
| 244 EXPECT_EQ(uncompressed_data, stream_->data()); | |
| 245 | |
| 246 char buffer[1]; | |
| 247 struct iovec vec; | |
| 248 vec.iov_base = buffer; | |
| 249 vec.iov_len = arraysize(buffer); | |
| 250 for (size_t i = 0; i < uncompressed_data.length(); ++i) { | |
| 251 size_t bytes_read = stream_->Readv(&vec, 1); | |
| 252 ASSERT_EQ(1u, bytes_read); | |
| 253 EXPECT_EQ(uncompressed_data.data()[i], buffer[0]); | |
| 254 } | |
| 255 } | |
| 256 | |
| 257 TEST_F(ReliableQuicStreamTest, ProcessHeadersUsingReadvWithMultipleIovecs) { | |
| 258 Initialize(!kShouldProcessData); | |
| 259 | |
| 260 string compressed_headers = compressor_->CompressHeaders(headers_); | |
| 261 string body = "this is the body"; | |
| 262 string data = compressed_headers + body; | |
| 263 QuicStreamFrame frame(kStreamId, false, 0, data); | |
| 264 string uncompressed_headers = | |
| 265 SpdyUtils::SerializeUncompressedHeaders(headers_); | |
| 266 string uncompressed_data = uncompressed_headers + body; | |
| 267 | |
| 268 stream_->OnStreamFrame(frame); | |
| 269 EXPECT_EQ(uncompressed_data, stream_->data()); | |
| 270 | |
| 271 char buffer1[1]; | |
| 272 char buffer2[1]; | |
| 273 struct iovec vec[2]; | |
| 274 vec[0].iov_base = buffer1; | |
| 275 vec[0].iov_len = arraysize(buffer1); | |
| 276 vec[1].iov_base = buffer2; | |
| 277 vec[1].iov_len = arraysize(buffer2); | |
| 278 for (size_t i = 0; i < uncompressed_data.length(); i += 2) { | |
| 279 size_t bytes_read = stream_->Readv(vec, 2); | |
| 280 ASSERT_EQ(2u, bytes_read) << i; | |
| 281 ASSERT_EQ(uncompressed_data.data()[i], buffer1[0]) << i; | |
| 282 ASSERT_EQ(uncompressed_data.data()[i + 1], buffer2[0]) << i; | |
| 283 } | |
| 284 } | |
| 285 | |
| 286 TEST_F(ReliableQuicStreamTest, ProcessHeadersEarly) { | |
| 287 Initialize(kShouldProcessData); | |
| 288 | |
| 289 string compressed_headers1 = compressor_->CompressHeaders(headers_); | |
| 290 QuicStreamFrame frame1(stream_->id(), false, 0, compressed_headers1); | |
| 291 string decompressed_headers1 = | |
| 292 SpdyUtils::SerializeUncompressedHeaders(headers_); | |
| 293 | |
| 294 headers_["content-type"] = "text/plain"; | |
| 295 string compressed_headers2 = compressor_->CompressHeaders(headers_); | |
| 296 QuicStreamFrame frame2(stream2_->id(), false, 0, compressed_headers2); | |
| 297 string decompressed_headers2 = | |
| 298 SpdyUtils::SerializeUncompressedHeaders(headers_); | |
| 299 | |
| 300 stream2_->OnStreamFrame(frame2); | |
| 301 EXPECT_EQ("", stream_->data()); | |
| 302 | |
| 303 stream_->OnStreamFrame(frame1); | |
| 304 EXPECT_EQ(decompressed_headers1, stream_->data()); | |
| 305 | |
| 306 EXPECT_EQ(2u, session_->decompressor()->current_header_id()); | |
| 307 stream2_->OnDecompressorAvailable(); | |
| 308 EXPECT_EQ(decompressed_headers2, stream2_->data()); | |
| 309 } | 100 } |
| 310 | 101 |
| 311 } // namespace | 102 } // namespace |
| 312 } // namespace test | 103 } // namespace test |
| 313 } // namespace net | 104 } // namespace net |
| OLD | NEW |