| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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/quic_data_stream.h" | 5 #include "net/quic/quic_data_stream.h" |
| 6 | 6 |
| 7 #include "net/quic/quic_ack_notifier.h" | 7 #include "net/quic/quic_ack_notifier.h" |
| 8 #include "net/quic/quic_connection.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" | 9 #include "net/quic/quic_utils.h" |
| 12 #include "net/quic/quic_write_blocked_list.h" | 10 #include "net/quic/quic_write_blocked_list.h" |
| 13 #include "net/quic/spdy_utils.h" | 11 #include "net/quic/spdy_utils.h" |
| 14 #include "net/quic/test_tools/quic_session_peer.h" | 12 #include "net/quic/test_tools/quic_session_peer.h" |
| 15 #include "net/quic/test_tools/quic_test_utils.h" | 13 #include "net/quic/test_tools/quic_test_utils.h" |
| 16 #include "testing/gmock/include/gmock/gmock.h" | 14 #include "testing/gmock/include/gmock/gmock.h" |
| 17 | 15 |
| 18 using base::StringPiece; | 16 using base::StringPiece; |
| 19 using std::min; | 17 using std::min; |
| 20 using testing::_; | 18 using testing::_; |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 91 } | 89 } |
| 92 | 90 |
| 93 void Initialize(bool stream_should_process_data) { | 91 void Initialize(bool stream_should_process_data) { |
| 94 connection_ = new testing::StrictMock<MockConnection>( | 92 connection_ = new testing::StrictMock<MockConnection>( |
| 95 kIsServer, SupportedVersions(GetParam())); | 93 kIsServer, SupportedVersions(GetParam())); |
| 96 session_.reset(new testing::StrictMock<MockSession>(connection_)); | 94 session_.reset(new testing::StrictMock<MockSession>(connection_)); |
| 97 stream_.reset(new TestStream(kStreamId, session_.get(), | 95 stream_.reset(new TestStream(kStreamId, session_.get(), |
| 98 stream_should_process_data)); | 96 stream_should_process_data)); |
| 99 stream2_.reset(new TestStream(kStreamId + 2, session_.get(), | 97 stream2_.reset(new TestStream(kStreamId + 2, session_.get(), |
| 100 stream_should_process_data)); | 98 stream_should_process_data)); |
| 101 compressor_.reset(new QuicSpdyCompressor()); | |
| 102 decompressor_.reset(new QuicSpdyDecompressor); | |
| 103 write_blocked_list_ = | 99 write_blocked_list_ = |
| 104 QuicSessionPeer::GetWriteblockedStreams(session_.get()); | 100 QuicSessionPeer::GetWriteblockedStreams(session_.get()); |
| 105 } | 101 } |
| 106 | 102 |
| 107 string CompressHeaders(QuicPriority priority) { | |
| 108 return compressor_->CompressHeadersWithPriority(priority, headers_); | |
| 109 } | |
| 110 | |
| 111 size_t CompressedHeadersSize() { | |
| 112 return CompressHeaders(QuicUtils::HighestPriority()).size(); | |
| 113 } | |
| 114 | |
| 115 protected: | 103 protected: |
| 116 MockConnection* connection_; | 104 MockConnection* connection_; |
| 117 scoped_ptr<MockSession> session_; | 105 scoped_ptr<MockSession> session_; |
| 118 scoped_ptr<TestStream> stream_; | 106 scoped_ptr<TestStream> stream_; |
| 119 scoped_ptr<TestStream> stream2_; | 107 scoped_ptr<TestStream> stream2_; |
| 120 scoped_ptr<QuicSpdyCompressor> compressor_; | |
| 121 scoped_ptr<QuicSpdyDecompressor> decompressor_; | |
| 122 SpdyHeaderBlock headers_; | 108 SpdyHeaderBlock headers_; |
| 123 QuicWriteBlockedList* write_blocked_list_; | 109 QuicWriteBlockedList* write_blocked_list_; |
| 124 }; | 110 }; |
| 125 | 111 |
| 126 INSTANTIATE_TEST_CASE_P(Tests, QuicDataStreamTest, | 112 INSTANTIATE_TEST_CASE_P(Tests, QuicDataStreamTest, |
| 127 ::testing::ValuesIn(QuicSupportedVersions())); | 113 ::testing::ValuesIn(QuicSupportedVersions())); |
| 128 | 114 |
| 129 TEST_P(QuicDataStreamTest, ProcessHeaders) { | 115 TEST_P(QuicDataStreamTest, ProcessHeaders) { |
| 130 Initialize(kShouldProcessData); | 116 Initialize(kShouldProcessData); |
| 131 | 117 |
| 132 string headers = SpdyUtils::SerializeUncompressedHeaders(headers_); | 118 string headers = SpdyUtils::SerializeUncompressedHeaders(headers_); |
| 133 if (GetParam() > QUIC_VERSION_12) { | 119 stream_->OnStreamHeadersPriority(QuicUtils::HighestPriority()); |
| 134 stream_->OnStreamHeadersPriority(QuicUtils::HighestPriority()); | 120 stream_->OnStreamHeaders(headers); |
| 135 stream_->OnStreamHeaders(headers); | 121 EXPECT_EQ(headers, stream_->data()); |
| 136 EXPECT_EQ(headers, stream_->data()); | 122 stream_->OnStreamHeadersComplete(false, headers.size()); |
| 137 stream_->OnStreamHeadersComplete(false, CompressedHeadersSize()); | |
| 138 } else { | |
| 139 string compressed_headers = CompressHeaders(QuicUtils::HighestPriority()); | |
| 140 QuicStreamFrame frame(kStreamId, false, 0, | |
| 141 MakeIOVector(compressed_headers)); | |
| 142 | |
| 143 stream_->OnStreamFrame(frame); | |
| 144 } | |
| 145 EXPECT_EQ(QuicUtils::HighestPriority(), stream_->EffectivePriority()); | 123 EXPECT_EQ(QuicUtils::HighestPriority(), stream_->EffectivePriority()); |
| 146 EXPECT_EQ(headers, stream_->data()); | 124 EXPECT_EQ(headers, stream_->data()); |
| 147 EXPECT_FALSE(stream_->IsDoneReading()); | 125 EXPECT_FALSE(stream_->IsDoneReading()); |
| 148 } | 126 } |
| 149 | 127 |
| 150 TEST_P(QuicDataStreamTest, ProcessHeadersWithInvalidHeaderId) { | |
| 151 if (GetParam() > QUIC_VERSION_12) { | |
| 152 // Header ID is v12 specific. | |
| 153 return; | |
| 154 } | |
| 155 Initialize(kShouldProcessData); | |
| 156 | |
| 157 string compressed_headers = CompressHeaders(QuicUtils::HighestPriority()); | |
| 158 compressed_headers[4] = '\xFF'; // Illegal header id. | |
| 159 QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(compressed_headers)); | |
| 160 | |
| 161 EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_HEADER_ID)); | |
| 162 stream_->OnStreamFrame(frame); | |
| 163 } | |
| 164 | |
| 165 TEST_P(QuicDataStreamTest, ProcessHeadersWithInvalidPriority) { | |
| 166 if (GetParam() > QUIC_VERSION_12) { | |
| 167 // Invalid priority is handled in QuicHeadersStream. | |
| 168 return; | |
| 169 } | |
| 170 Initialize(kShouldProcessData); | |
| 171 | |
| 172 string compressed_headers = CompressHeaders(QuicUtils::HighestPriority()); | |
| 173 compressed_headers[0] = '\xFF'; // Illegal priority. | |
| 174 QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(compressed_headers)); | |
| 175 | |
| 176 EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_PRIORITY)); | |
| 177 stream_->OnStreamFrame(frame); | |
| 178 } | |
| 179 | |
| 180 TEST_P(QuicDataStreamTest, ProcessHeadersAndBody) { | 128 TEST_P(QuicDataStreamTest, ProcessHeadersAndBody) { |
| 181 Initialize(kShouldProcessData); | 129 Initialize(kShouldProcessData); |
| 182 | 130 |
| 183 string headers = SpdyUtils::SerializeUncompressedHeaders(headers_); | 131 string headers = SpdyUtils::SerializeUncompressedHeaders(headers_); |
| 184 string body = "this is the body"; | 132 string body = "this is the body"; |
| 185 | 133 |
| 186 if (GetParam() > QUIC_VERSION_12) { | 134 stream_->OnStreamHeaders(headers); |
| 187 stream_->OnStreamHeaders(headers); | 135 EXPECT_EQ(headers, stream_->data()); |
| 188 EXPECT_EQ(headers, stream_->data()); | 136 stream_->OnStreamHeadersComplete(false, headers.size()); |
| 189 stream_->OnStreamHeadersComplete(false, CompressedHeadersSize()); | 137 QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(body)); |
| 190 QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(body)); | 138 stream_->OnStreamFrame(frame); |
| 191 stream_->OnStreamFrame(frame); | |
| 192 } else { | |
| 193 string compressed_headers = CompressHeaders(QuicUtils::HighestPriority()); | |
| 194 string data = compressed_headers + body; | |
| 195 QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(data)); | |
| 196 stream_->OnStreamFrame(frame); | |
| 197 } | |
| 198 | 139 |
| 199 EXPECT_EQ(headers + body, stream_->data()); | 140 EXPECT_EQ(headers + body, stream_->data()); |
| 200 } | 141 } |
| 201 | 142 |
| 202 TEST_P(QuicDataStreamTest, ProcessHeadersAndBodyFragments) { | 143 TEST_P(QuicDataStreamTest, ProcessHeadersAndBodyFragments) { |
| 203 string headers = SpdyUtils::SerializeUncompressedHeaders(headers_); | 144 string headers = SpdyUtils::SerializeUncompressedHeaders(headers_); |
| 204 string body = "this is the body"; | 145 string body = "this is the body"; |
| 205 | 146 |
| 206 if (GetParam() > QUIC_VERSION_12) { | 147 for (size_t fragment_size = 1; fragment_size < body.size(); |
| 207 for (size_t fragment_size = 1; fragment_size < body.size(); | 148 ++fragment_size) { |
| 208 ++fragment_size) { | 149 Initialize(kShouldProcessData); |
| 209 Initialize(kShouldProcessData); | 150 for (size_t offset = 0; offset < headers.size(); |
| 210 for (size_t offset = 0; offset < headers.size(); | 151 offset += fragment_size) { |
| 211 offset += fragment_size) { | 152 size_t remaining_data = headers.size() - offset; |
| 212 size_t remaining_data = headers.size() - offset; | 153 StringPiece fragment(headers.data() + offset, |
| 213 StringPiece fragment(headers.data() + offset, | 154 min(fragment_size, remaining_data)); |
| 214 min(fragment_size, remaining_data)); | 155 stream_->OnStreamHeaders(fragment); |
| 215 stream_->OnStreamHeaders(fragment); | |
| 216 } | |
| 217 stream_->OnStreamHeadersComplete(false, CompressedHeadersSize()); | |
| 218 for (size_t offset = 0; offset < body.size(); offset += fragment_size) { | |
| 219 size_t remaining_data = body.size() - offset; | |
| 220 StringPiece fragment(body.data() + offset, | |
| 221 min(fragment_size, remaining_data)); | |
| 222 QuicStreamFrame frame(kStreamId, false, offset, MakeIOVector(fragment)); | |
| 223 stream_->OnStreamFrame(frame); | |
| 224 } | |
| 225 ASSERT_EQ(headers + body, | |
| 226 stream_->data()) << "fragment_size: " << fragment_size; | |
| 227 } | 156 } |
| 228 } else { | 157 stream_->OnStreamHeadersComplete(false, headers.size()); |
| 229 Initialize(kShouldProcessData); | 158 for (size_t offset = 0; offset < body.size(); offset += fragment_size) { |
| 230 string compressed_headers = CompressHeaders(QuicUtils::HighestPriority()); | 159 size_t remaining_data = body.size() - offset; |
| 231 string data = compressed_headers + body; | 160 StringPiece fragment(body.data() + offset, |
| 232 for (size_t fragment_size = 1; fragment_size < data.size(); | 161 min(fragment_size, remaining_data)); |
| 233 ++fragment_size) { | 162 QuicStreamFrame frame(kStreamId, false, offset, MakeIOVector(fragment)); |
| 234 Initialize(kShouldProcessData); | 163 stream_->OnStreamFrame(frame); |
| 235 for (size_t offset = 0; offset < data.size(); offset += fragment_size) { | |
| 236 size_t remaining_data = data.size() - offset; | |
| 237 StringPiece fragment(data.data() + offset, | |
| 238 min(fragment_size, remaining_data)); | |
| 239 QuicStreamFrame frame(kStreamId, false, offset, MakeIOVector(fragment)); | |
| 240 stream_->OnStreamFrame(frame); | |
| 241 } | |
| 242 ASSERT_EQ(headers + body, | |
| 243 stream_->data()) << "fragment_size: " << fragment_size; | |
| 244 } | 164 } |
| 165 ASSERT_EQ(headers + body, |
| 166 stream_->data()) << "fragment_size: " << fragment_size; |
| 245 } | 167 } |
| 246 } | 168 } |
| 247 | 169 |
| 248 TEST_P(QuicDataStreamTest, ProcessHeadersAndBodyFragmentsSplit) { | 170 TEST_P(QuicDataStreamTest, ProcessHeadersAndBodyFragmentsSplit) { |
| 249 string headers = SpdyUtils::SerializeUncompressedHeaders(headers_); | 171 string headers = SpdyUtils::SerializeUncompressedHeaders(headers_); |
| 250 string body = "this is the body"; | 172 string body = "this is the body"; |
| 251 | 173 |
| 252 if (GetParam() > QUIC_VERSION_12) { | 174 for (size_t split_point = 1; split_point < body.size() - 1; ++split_point) { |
| 253 for (size_t split_point = 1; split_point < body.size() - 1; ++split_point) { | 175 Initialize(kShouldProcessData); |
| 254 Initialize(kShouldProcessData); | 176 StringPiece headers1(headers.data(), split_point); |
| 255 StringPiece headers1(headers.data(), split_point); | 177 stream_->OnStreamHeaders(headers1); |
| 256 stream_->OnStreamHeaders(headers1); | |
| 257 | 178 |
| 258 StringPiece headers2(headers.data() + split_point, | 179 StringPiece headers2(headers.data() + split_point, |
| 259 headers.size() - split_point); | 180 headers.size() - split_point); |
| 260 stream_->OnStreamHeaders(headers2); | 181 stream_->OnStreamHeaders(headers2); |
| 261 stream_->OnStreamHeadersComplete(false, CompressedHeadersSize()); | 182 stream_->OnStreamHeadersComplete(false, headers.size()); |
| 262 | 183 |
| 263 StringPiece fragment1(body.data(), split_point); | 184 StringPiece fragment1(body.data(), split_point); |
| 264 QuicStreamFrame frame1(kStreamId, false, 0, MakeIOVector(fragment1)); | 185 QuicStreamFrame frame1(kStreamId, false, 0, MakeIOVector(fragment1)); |
| 265 stream_->OnStreamFrame(frame1); | 186 stream_->OnStreamFrame(frame1); |
| 266 | 187 |
| 267 StringPiece fragment2(body.data() + split_point, | 188 StringPiece fragment2(body.data() + split_point, |
| 268 body.size() - split_point); | 189 body.size() - split_point); |
| 269 QuicStreamFrame frame2( | 190 QuicStreamFrame frame2( |
| 270 kStreamId, false, split_point, MakeIOVector(fragment2)); | 191 kStreamId, false, split_point, MakeIOVector(fragment2)); |
| 271 stream_->OnStreamFrame(frame2); | 192 stream_->OnStreamFrame(frame2); |
| 272 | 193 |
| 273 ASSERT_EQ(headers + body, | 194 ASSERT_EQ(headers + body, |
| 274 stream_->data()) << "split_point: " << split_point; | 195 stream_->data()) << "split_point: " << split_point; |
| 275 } | |
| 276 } else { | |
| 277 Initialize(kShouldProcessData); | |
| 278 string compressed_headers = CompressHeaders(QuicUtils::LowestPriority()); | |
| 279 string data = compressed_headers + body; | |
| 280 | |
| 281 for (size_t split_point = 1; split_point < data.size() - 1; ++split_point) { | |
| 282 Initialize(kShouldProcessData); | |
| 283 | |
| 284 StringPiece fragment1(data.data(), split_point); | |
| 285 QuicStreamFrame frame1(kStreamId, false, 0, MakeIOVector(fragment1)); | |
| 286 stream_->OnStreamFrame(frame1); | |
| 287 | |
| 288 StringPiece fragment2(data.data() + split_point, | |
| 289 data.size() - split_point); | |
| 290 QuicStreamFrame frame2( | |
| 291 kStreamId, false, split_point, MakeIOVector(fragment2)); | |
| 292 stream_->OnStreamFrame(frame2); | |
| 293 | |
| 294 ASSERT_EQ(SpdyUtils::SerializeUncompressedHeaders(headers_) + body, | |
| 295 stream_->data()) << "split_point: " << split_point; | |
| 296 } | |
| 297 EXPECT_EQ(QuicUtils::LowestPriority(), stream_->EffectivePriority()); | |
| 298 } | 196 } |
| 299 } | 197 } |
| 300 | 198 |
| 301 TEST_P(QuicDataStreamTest, ProcessHeadersAndBodyReadv) { | 199 TEST_P(QuicDataStreamTest, ProcessHeadersAndBodyReadv) { |
| 302 Initialize(!kShouldProcessData); | 200 Initialize(!kShouldProcessData); |
| 303 | 201 |
| 304 string headers = SpdyUtils::SerializeUncompressedHeaders(headers_); | 202 string headers = SpdyUtils::SerializeUncompressedHeaders(headers_); |
| 305 string body = "this is the body"; | 203 string body = "this is the body"; |
| 306 | 204 |
| 307 if (GetParam() > QUIC_VERSION_12) { | 205 stream_->OnStreamHeaders(headers); |
| 308 stream_->OnStreamHeaders(headers); | 206 EXPECT_EQ(headers, stream_->data()); |
| 309 EXPECT_EQ(headers, stream_->data()); | 207 stream_->OnStreamHeadersComplete(false, headers.size()); |
| 310 stream_->OnStreamHeadersComplete(false, CompressedHeadersSize()); | 208 QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(body)); |
| 311 QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(body)); | 209 stream_->OnStreamFrame(frame); |
| 312 stream_->OnStreamFrame(frame); | |
| 313 } else { | |
| 314 string compressed_headers = CompressHeaders(QuicUtils::HighestPriority()); | |
| 315 string data = compressed_headers + body; | |
| 316 QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(data)); | |
| 317 stream_->OnStreamFrame(frame); | |
| 318 EXPECT_EQ(headers, stream_->data()); | |
| 319 } | |
| 320 | 210 |
| 321 char buffer[2048]; | 211 char buffer[2048]; |
| 322 ASSERT_LT(headers.length() + body.length(), arraysize(buffer)); | 212 ASSERT_LT(headers.length() + body.length(), arraysize(buffer)); |
| 323 struct iovec vec; | 213 struct iovec vec; |
| 324 vec.iov_base = buffer; | 214 vec.iov_base = buffer; |
| 325 vec.iov_len = arraysize(buffer); | 215 vec.iov_len = arraysize(buffer); |
| 326 | 216 |
| 327 size_t bytes_read = stream_->Readv(&vec, 1); | 217 size_t bytes_read = stream_->Readv(&vec, 1); |
| 328 EXPECT_EQ(headers.length(), bytes_read); | 218 EXPECT_EQ(headers.length(), bytes_read); |
| 329 EXPECT_EQ(headers, string(buffer, bytes_read)); | 219 EXPECT_EQ(headers, string(buffer, bytes_read)); |
| 330 | 220 |
| 331 bytes_read = stream_->Readv(&vec, 1); | 221 bytes_read = stream_->Readv(&vec, 1); |
| 332 EXPECT_EQ(body.length(), bytes_read); | 222 EXPECT_EQ(body.length(), bytes_read); |
| 333 EXPECT_EQ(body, string(buffer, bytes_read)); | 223 EXPECT_EQ(body, string(buffer, bytes_read)); |
| 334 } | 224 } |
| 335 | 225 |
| 336 TEST_P(QuicDataStreamTest, ProcessHeadersAndBodyIncrementalReadv) { | 226 TEST_P(QuicDataStreamTest, ProcessHeadersAndBodyIncrementalReadv) { |
| 337 Initialize(!kShouldProcessData); | 227 Initialize(!kShouldProcessData); |
| 338 | 228 |
| 339 string headers = SpdyUtils::SerializeUncompressedHeaders(headers_); | 229 string headers = SpdyUtils::SerializeUncompressedHeaders(headers_); |
| 340 string body = "this is the body"; | 230 string body = "this is the body"; |
| 341 if (GetParam() > QUIC_VERSION_12) { | 231 stream_->OnStreamHeaders(headers); |
| 342 stream_->OnStreamHeaders(headers); | 232 EXPECT_EQ(headers, stream_->data()); |
| 343 EXPECT_EQ(headers, stream_->data()); | 233 stream_->OnStreamHeadersComplete(false, headers.size()); |
| 344 stream_->OnStreamHeadersComplete(false, CompressedHeadersSize()); | 234 QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(body)); |
| 345 QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(body)); | 235 stream_->OnStreamFrame(frame); |
| 346 stream_->OnStreamFrame(frame); | 236 |
| 347 } else { | |
| 348 string compressed_headers = CompressHeaders(QuicUtils::HighestPriority()); | |
| 349 string data = compressed_headers + body; | |
| 350 QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(data)); | |
| 351 stream_->OnStreamFrame(frame); | |
| 352 EXPECT_EQ(headers, stream_->data()); | |
| 353 } | |
| 354 | 237 |
| 355 char buffer[1]; | 238 char buffer[1]; |
| 356 struct iovec vec; | 239 struct iovec vec; |
| 357 vec.iov_base = buffer; | 240 vec.iov_base = buffer; |
| 358 vec.iov_len = arraysize(buffer); | 241 vec.iov_len = arraysize(buffer); |
| 359 | 242 |
| 360 string data = headers + body; | 243 string data = headers + body; |
| 361 for (size_t i = 0; i < data.length(); ++i) { | 244 for (size_t i = 0; i < data.length(); ++i) { |
| 362 size_t bytes_read = stream_->Readv(&vec, 1); | 245 size_t bytes_read = stream_->Readv(&vec, 1); |
| 363 ASSERT_EQ(1u, bytes_read); | 246 ASSERT_EQ(1u, bytes_read); |
| 364 EXPECT_EQ(data.data()[i], buffer[0]); | 247 EXPECT_EQ(data.data()[i], buffer[0]); |
| 365 } | 248 } |
| 366 } | 249 } |
| 367 | 250 |
| 368 TEST_P(QuicDataStreamTest, ProcessHeadersUsingReadvWithMultipleIovecs) { | 251 TEST_P(QuicDataStreamTest, ProcessHeadersUsingReadvWithMultipleIovecs) { |
| 369 Initialize(!kShouldProcessData); | 252 Initialize(!kShouldProcessData); |
| 370 | 253 |
| 371 string headers = SpdyUtils::SerializeUncompressedHeaders(headers_); | 254 string headers = SpdyUtils::SerializeUncompressedHeaders(headers_); |
| 372 string body = "this is the body"; | 255 string body = "this is the body"; |
| 373 if (GetParam() > QUIC_VERSION_12) { | 256 stream_->OnStreamHeaders(headers); |
| 374 stream_->OnStreamHeaders(headers); | 257 EXPECT_EQ(headers, stream_->data()); |
| 375 EXPECT_EQ(headers, stream_->data()); | 258 stream_->OnStreamHeadersComplete(false, headers.size()); |
| 376 stream_->OnStreamHeadersComplete(false, CompressedHeadersSize()); | 259 QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(body)); |
| 377 QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(body)); | 260 stream_->OnStreamFrame(frame); |
| 378 stream_->OnStreamFrame(frame); | 261 |
| 379 } else { | |
| 380 string compressed_headers = CompressHeaders(QuicUtils::HighestPriority()); | |
| 381 string data = compressed_headers + body; | |
| 382 QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(data)); | |
| 383 stream_->OnStreamFrame(frame); | |
| 384 EXPECT_EQ(headers, stream_->data()); | |
| 385 } | |
| 386 | 262 |
| 387 char buffer1[1]; | 263 char buffer1[1]; |
| 388 char buffer2[1]; | 264 char buffer2[1]; |
| 389 struct iovec vec[2]; | 265 struct iovec vec[2]; |
| 390 vec[0].iov_base = buffer1; | 266 vec[0].iov_base = buffer1; |
| 391 vec[0].iov_len = arraysize(buffer1); | 267 vec[0].iov_len = arraysize(buffer1); |
| 392 vec[1].iov_base = buffer2; | 268 vec[1].iov_base = buffer2; |
| 393 vec[1].iov_len = arraysize(buffer2); | 269 vec[1].iov_len = arraysize(buffer2); |
| 394 string data = headers + body; | 270 string data = headers + body; |
| 395 for (size_t i = 0; i < data.length(); i += 2) { | 271 for (size_t i = 0; i < data.length(); i += 2) { |
| 396 size_t bytes_read = stream_->Readv(vec, 2); | 272 size_t bytes_read = stream_->Readv(vec, 2); |
| 397 ASSERT_EQ(2u, bytes_read) << i; | 273 ASSERT_EQ(2u, bytes_read) << i; |
| 398 ASSERT_EQ(data.data()[i], buffer1[0]) << i; | 274 ASSERT_EQ(data.data()[i], buffer1[0]) << i; |
| 399 ASSERT_EQ(data.data()[i + 1], buffer2[0]) << i; | 275 ASSERT_EQ(data.data()[i + 1], buffer2[0]) << i; |
| 400 } | 276 } |
| 401 } | 277 } |
| 402 | 278 |
| 403 TEST_P(QuicDataStreamTest, ProcessCorruptHeadersEarly) { | |
| 404 if (GetParam() > QUIC_VERSION_12) { | |
| 405 return; | |
| 406 } | |
| 407 Initialize(kShouldProcessData); | |
| 408 | |
| 409 string compressed_headers1 = CompressHeaders(QuicUtils::HighestPriority()); | |
| 410 QuicStreamFrame frame1( | |
| 411 stream_->id(), false, 0, MakeIOVector(compressed_headers1)); | |
| 412 string decompressed_headers1 = | |
| 413 SpdyUtils::SerializeUncompressedHeaders(headers_); | |
| 414 | |
| 415 headers_["content-type"] = "text/plain"; | |
| 416 string compressed_headers2 = CompressHeaders(QuicUtils::HighestPriority()); | |
| 417 // Corrupt the compressed data. | |
| 418 compressed_headers2[compressed_headers2.length() - 1] ^= 0xA1; | |
| 419 QuicStreamFrame frame2( | |
| 420 stream2_->id(), false, 0, MakeIOVector(compressed_headers2)); | |
| 421 string decompressed_headers2 = | |
| 422 SpdyUtils::SerializeUncompressedHeaders(headers_); | |
| 423 | |
| 424 // Deliver frame2 to stream2 out of order. The decompressor is not | |
| 425 // available yet, so no data will be processed. The compressed data | |
| 426 // will be buffered until OnDecompressorAvailable() is called | |
| 427 // to process it. | |
| 428 stream2_->OnStreamFrame(frame2); | |
| 429 EXPECT_EQ("", stream2_->data()); | |
| 430 | |
| 431 // Now deliver frame1 to stream1. The decompressor is available so | |
| 432 // the data will be processed, and the decompressor will become | |
| 433 // available for stream2. | |
| 434 stream_->OnStreamFrame(frame1); | |
| 435 EXPECT_EQ(decompressed_headers1, stream_->data()); | |
| 436 | |
| 437 // Verify that the decompressor is available, and inform stream2 | |
| 438 // that it can now decompress the buffered compressed data. Since | |
| 439 // the compressed data is corrupt, the stream will shutdown the session. | |
| 440 EXPECT_EQ(2u, session_->decompressor()->current_header_id()); | |
| 441 EXPECT_CALL(*connection_, SendConnectionClose(QUIC_DECOMPRESSION_FAILURE)); | |
| 442 stream2_->OnDecompressorAvailable(); | |
| 443 EXPECT_EQ("", stream2_->data()); | |
| 444 } | |
| 445 | |
| 446 TEST_P(QuicDataStreamTest, ProcessPartialHeadersEarly) { | |
| 447 if (GetParam() > QUIC_VERSION_12) { | |
| 448 return; | |
| 449 } | |
| 450 Initialize(kShouldProcessData); | |
| 451 | |
| 452 string compressed_headers1 = CompressHeaders(QuicUtils::HighestPriority()); | |
| 453 QuicStreamFrame frame1( | |
| 454 stream_->id(), false, 0, MakeIOVector(compressed_headers1)); | |
| 455 string decompressed_headers1 = | |
| 456 SpdyUtils::SerializeUncompressedHeaders(headers_); | |
| 457 | |
| 458 headers_["content-type"] = "text/plain"; | |
| 459 string compressed_headers2 = CompressHeaders(QuicUtils::HighestPriority()); | |
| 460 string partial_compressed_headers = | |
| 461 compressed_headers2.substr(0, compressed_headers2.length() / 2); | |
| 462 QuicStreamFrame frame2( | |
| 463 stream2_->id(), false, 0, MakeIOVector(partial_compressed_headers)); | |
| 464 string decompressed_headers2 = | |
| 465 SpdyUtils::SerializeUncompressedHeaders(headers_); | |
| 466 | |
| 467 // Deliver frame2 to stream2 out of order. The decompressor is not | |
| 468 // available yet, so no data will be processed. The compressed data | |
| 469 // will be buffered until OnDecompressorAvailable() is called | |
| 470 // to process it. | |
| 471 stream2_->OnStreamFrame(frame2); | |
| 472 EXPECT_EQ("", stream2_->data()); | |
| 473 | |
| 474 // Now deliver frame1 to stream1. The decompressor is available so | |
| 475 // the data will be processed, and the decompressor will become | |
| 476 // available for stream2. | |
| 477 stream_->OnStreamFrame(frame1); | |
| 478 EXPECT_EQ(decompressed_headers1, stream_->data()); | |
| 479 | |
| 480 // Verify that the decompressor is available, and inform stream2 | |
| 481 // that it can now decompress the buffered compressed data. Since | |
| 482 // the compressed data is incomplete it will not be passed to | |
| 483 // the stream. | |
| 484 EXPECT_EQ(2u, session_->decompressor()->current_header_id()); | |
| 485 stream2_->OnDecompressorAvailable(); | |
| 486 EXPECT_EQ("", stream2_->data()); | |
| 487 | |
| 488 // Now send remaining data and verify that we have now received the | |
| 489 // compressed headers. | |
| 490 string remaining_compressed_headers = | |
| 491 compressed_headers2.substr(partial_compressed_headers.length()); | |
| 492 | |
| 493 QuicStreamFrame frame3(stream2_->id(), false, | |
| 494 partial_compressed_headers.length(), | |
| 495 MakeIOVector(remaining_compressed_headers)); | |
| 496 stream2_->OnStreamFrame(frame3); | |
| 497 EXPECT_EQ(decompressed_headers2, stream2_->data()); | |
| 498 } | |
| 499 | |
| 500 TEST_P(QuicDataStreamTest, ProcessHeadersEarly) { | |
| 501 if (GetParam() > QUIC_VERSION_12) { | |
| 502 return; | |
| 503 } | |
| 504 Initialize(kShouldProcessData); | |
| 505 | |
| 506 string compressed_headers1 = CompressHeaders(QuicUtils::HighestPriority()); | |
| 507 QuicStreamFrame frame1( | |
| 508 stream_->id(), false, 0, MakeIOVector(compressed_headers1)); | |
| 509 string decompressed_headers1 = | |
| 510 SpdyUtils::SerializeUncompressedHeaders(headers_); | |
| 511 | |
| 512 headers_["content-type"] = "text/plain"; | |
| 513 string compressed_headers2 = CompressHeaders(QuicUtils::HighestPriority()); | |
| 514 QuicStreamFrame frame2( | |
| 515 stream2_->id(), false, 0, MakeIOVector(compressed_headers2)); | |
| 516 string decompressed_headers2 = | |
| 517 SpdyUtils::SerializeUncompressedHeaders(headers_); | |
| 518 | |
| 519 // Deliver frame2 to stream2 out of order. The decompressor is not | |
| 520 // available yet, so no data will be processed. The compressed data | |
| 521 // will be buffered until OnDecompressorAvailable() is called | |
| 522 // to process it. | |
| 523 stream2_->OnStreamFrame(frame2); | |
| 524 EXPECT_EQ("", stream2_->data()); | |
| 525 | |
| 526 // Now deliver frame1 to stream1. The decompressor is available so | |
| 527 // the data will be processed, and the decompressor will become | |
| 528 // available for stream2. | |
| 529 stream_->OnStreamFrame(frame1); | |
| 530 EXPECT_EQ(decompressed_headers1, stream_->data()); | |
| 531 | |
| 532 // Verify that the decompressor is available, and inform stream2 | |
| 533 // that it can now decompress the buffered compressed data. | |
| 534 EXPECT_EQ(2u, session_->decompressor()->current_header_id()); | |
| 535 stream2_->OnDecompressorAvailable(); | |
| 536 EXPECT_EQ(decompressed_headers2, stream2_->data()); | |
| 537 } | |
| 538 | |
| 539 TEST_P(QuicDataStreamTest, ProcessHeadersDelay) { | |
| 540 if (GetParam() > QUIC_VERSION_12) { | |
| 541 return; | |
| 542 } | |
| 543 Initialize(!kShouldProcessData); | |
| 544 | |
| 545 string compressed_headers = CompressHeaders(QuicUtils::HighestPriority()); | |
| 546 QuicStreamFrame frame1( | |
| 547 stream_->id(), false, 0, MakeIOVector(compressed_headers)); | |
| 548 string decompressed_headers = | |
| 549 SpdyUtils::SerializeUncompressedHeaders(headers_); | |
| 550 | |
| 551 // Send the headers to the stream and verify they were decompressed. | |
| 552 stream_->OnStreamFrame(frame1); | |
| 553 EXPECT_EQ(2u, session_->decompressor()->current_header_id()); | |
| 554 | |
| 555 // Verify that we are now able to handle the body data, | |
| 556 // even though the stream has not processed the headers. | |
| 557 EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_HEADER_ID)) | |
| 558 .Times(0); | |
| 559 QuicStreamFrame frame2(stream_->id(), false, compressed_headers.length(), | |
| 560 MakeIOVector("body data")); | |
| 561 stream_->OnStreamFrame(frame2); | |
| 562 } | |
| 563 | |
| 564 } // namespace | 279 } // namespace |
| 565 } // namespace test | 280 } // namespace test |
| 566 } // namespace net | 281 } // namespace net |
| OLD | NEW |