| 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/core/quic_spdy_stream.h" | 5 #include "net/quic/core/quic_spdy_stream.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "net/quic/core/quic_connection.h" | 10 #include "net/quic/core/quic_connection.h" |
| 11 #include "net/quic/core/quic_utils.h" | 11 #include "net/quic/core/quic_utils.h" |
| 12 #include "net/quic/core/quic_write_blocked_list.h" | 12 #include "net/quic/core/quic_write_blocked_list.h" |
| 13 #include "net/quic/core/spdy_utils.h" | 13 #include "net/quic/core/spdy_utils.h" |
| 14 #include "net/quic/platform/api/quic_ptr_util.h" | 14 #include "net/quic/platform/api/quic_ptr_util.h" |
| 15 #include "net/quic/platform/api/quic_string_piece.h" | 15 #include "net/quic/platform/api/quic_string_piece.h" |
| 16 #include "net/quic/platform/api/quic_test.h" | 16 #include "net/quic/platform/api/quic_test.h" |
| 17 #include "net/quic/platform/api/quic_text_utils.h" | 17 #include "net/quic/platform/api/quic_text_utils.h" |
| 18 #include "net/quic/test_tools/quic_flow_controller_peer.h" | 18 #include "net/quic/test_tools/quic_flow_controller_peer.h" |
| 19 #include "net/quic/test_tools/quic_spdy_session_peer.h" | 19 #include "net/quic/test_tools/quic_session_peer.h" |
| 20 #include "net/quic/test_tools/quic_stream_peer.h" | 20 #include "net/quic/test_tools/quic_stream_peer.h" |
| 21 #include "net/quic/test_tools/quic_test_utils.h" | 21 #include "net/quic/test_tools/quic_test_utils.h" |
| 22 | 22 |
| 23 using std::string; | 23 using std::string; |
| 24 using testing::AnyNumber; | 24 using testing::AnyNumber; |
| 25 using testing::Invoke; | 25 using testing::Invoke; |
| 26 using testing::Return; | 26 using testing::Return; |
| 27 using testing::StrictMock; | 27 using testing::StrictMock; |
| 28 using testing::_; | 28 using testing::_; |
| 29 | 29 |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 93 "Fas6LMcVC6Q8QLlHYbXBpdNFuGbuZGUnav5C-2I_-46lL0NGg3GewxGKGHvHEfoyn" | 93 "Fas6LMcVC6Q8QLlHYbXBpdNFuGbuZGUnav5C-2I_-46lL0NGg3GewxGKGHvHEfoyn" |
| 94 "EFFlEYHsBQ98rXImL8ySDycdLEFvBPdtctPmWCfTxwmoSMLHU2SCVDhbqMWU5b0yr" | 94 "EFFlEYHsBQ98rXImL8ySDycdLEFvBPdtctPmWCfTxwmoSMLHU2SCVDhbqMWU5b0yr" |
| 95 "JBCScs_ejbKaqBDoB7ZGxTvqlrB__2ZmnHHjCr8RgMRtKNtIeuZAo "; | 95 "JBCScs_ejbKaqBDoB7ZGxTvqlrB__2ZmnHHjCr8RgMRtKNtIeuZAo "; |
| 96 } | 96 } |
| 97 | 97 |
| 98 void Initialize(bool stream_should_process_data) { | 98 void Initialize(bool stream_should_process_data) { |
| 99 connection_ = new testing::StrictMock<MockQuicConnection>( | 99 connection_ = new testing::StrictMock<MockQuicConnection>( |
| 100 &helper_, &alarm_factory_, Perspective::IS_SERVER, | 100 &helper_, &alarm_factory_, Perspective::IS_SERVER, |
| 101 SupportedVersions(GetParam())); | 101 SupportedVersions(GetParam())); |
| 102 session_.reset(new testing::StrictMock<MockQuicSpdySession>(connection_)); | 102 session_.reset(new testing::StrictMock<MockQuicSpdySession>(connection_)); |
| 103 stream_ = new TestStream(GetNthClientInitiatedId(0), session_.get(), | 103 stream_ = new TestStream(kClientDataStreamId1, session_.get(), |
| 104 stream_should_process_data); | 104 stream_should_process_data); |
| 105 session_->ActivateStream(QuicWrapUnique(stream_)); | 105 session_->ActivateStream(QuicWrapUnique(stream_)); |
| 106 stream2_ = new TestStream(GetNthClientInitiatedId(1), session_.get(), | 106 stream2_ = new TestStream(kClientDataStreamId2, session_.get(), |
| 107 stream_should_process_data); | 107 stream_should_process_data); |
| 108 session_->ActivateStream(QuicWrapUnique(stream2_)); | 108 session_->ActivateStream(QuicWrapUnique(stream2_)); |
| 109 } | 109 } |
| 110 | 110 |
| 111 QuicHeaderList ProcessHeaders(bool fin, const SpdyHeaderBlock& headers) { | 111 QuicHeaderList ProcessHeaders(bool fin, const SpdyHeaderBlock& headers) { |
| 112 QuicHeaderList h = AsHeaderList(headers); | 112 QuicHeaderList h = AsHeaderList(headers); |
| 113 stream_->OnStreamHeaderList(fin, h.uncompressed_header_bytes(), h); | 113 stream_->OnStreamHeaderList(fin, h.uncompressed_header_bytes(), h); |
| 114 return h; | 114 return h; |
| 115 } | 115 } |
| 116 | 116 |
| 117 QuicStreamId GetNthClientInitiatedId(int n) { | |
| 118 return QuicSpdySessionPeer::GetNthClientInitiatedStreamId(*session_, n); | |
| 119 } | |
| 120 | |
| 121 protected: | 117 protected: |
| 122 MockQuicConnectionHelper helper_; | 118 MockQuicConnectionHelper helper_; |
| 123 MockAlarmFactory alarm_factory_; | 119 MockAlarmFactory alarm_factory_; |
| 124 MockQuicConnection* connection_; | 120 MockQuicConnection* connection_; |
| 125 std::unique_ptr<MockQuicSpdySession> session_; | 121 std::unique_ptr<MockQuicSpdySession> session_; |
| 126 | 122 |
| 127 // Owned by the |session_|. | 123 // Owned by the |session_|. |
| 128 TestStream* stream_; | 124 TestStream* stream_; |
| 129 TestStream* stream2_; | 125 TestStream* stream2_; |
| 130 | 126 |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 245 | 241 |
| 246 TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBody) { | 242 TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBody) { |
| 247 Initialize(kShouldProcessData); | 243 Initialize(kShouldProcessData); |
| 248 | 244 |
| 249 string body = "this is the body"; | 245 string body = "this is the body"; |
| 250 | 246 |
| 251 EXPECT_EQ("", stream_->data()); | 247 EXPECT_EQ("", stream_->data()); |
| 252 QuicHeaderList headers = ProcessHeaders(false, headers_); | 248 QuicHeaderList headers = ProcessHeaders(false, headers_); |
| 253 EXPECT_EQ(headers, stream_->header_list()); | 249 EXPECT_EQ(headers, stream_->header_list()); |
| 254 stream_->ConsumeHeaderList(); | 250 stream_->ConsumeHeaderList(); |
| 255 QuicStreamFrame frame(GetNthClientInitiatedId(0), false, 0, | 251 QuicStreamFrame frame(kClientDataStreamId1, false, 0, QuicStringPiece(body)); |
| 256 QuicStringPiece(body)); | |
| 257 stream_->OnStreamFrame(frame); | 252 stream_->OnStreamFrame(frame); |
| 258 EXPECT_EQ(QuicHeaderList(), stream_->header_list()); | 253 EXPECT_EQ(QuicHeaderList(), stream_->header_list()); |
| 259 EXPECT_EQ(body, stream_->data()); | 254 EXPECT_EQ(body, stream_->data()); |
| 260 } | 255 } |
| 261 | 256 |
| 262 TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyFragments) { | 257 TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyFragments) { |
| 263 string body = "this is the body"; | 258 string body = "this is the body"; |
| 264 | 259 |
| 265 for (size_t fragment_size = 1; fragment_size < body.size(); ++fragment_size) { | 260 for (size_t fragment_size = 1; fragment_size < body.size(); ++fragment_size) { |
| 266 Initialize(kShouldProcessData); | 261 Initialize(kShouldProcessData); |
| 267 QuicHeaderList headers = ProcessHeaders(false, headers_); | 262 QuicHeaderList headers = ProcessHeaders(false, headers_); |
| 268 ASSERT_EQ(headers, stream_->header_list()); | 263 ASSERT_EQ(headers, stream_->header_list()); |
| 269 stream_->ConsumeHeaderList(); | 264 stream_->ConsumeHeaderList(); |
| 270 for (size_t offset = 0; offset < body.size(); offset += fragment_size) { | 265 for (size_t offset = 0; offset < body.size(); offset += fragment_size) { |
| 271 size_t remaining_data = body.size() - offset; | 266 size_t remaining_data = body.size() - offset; |
| 272 QuicStringPiece fragment(body.data() + offset, | 267 QuicStringPiece fragment(body.data() + offset, |
| 273 std::min(fragment_size, remaining_data)); | 268 std::min(fragment_size, remaining_data)); |
| 274 QuicStreamFrame frame(GetNthClientInitiatedId(0), false, offset, | 269 QuicStreamFrame frame(kClientDataStreamId1, false, offset, |
| 275 QuicStringPiece(fragment)); | 270 QuicStringPiece(fragment)); |
| 276 stream_->OnStreamFrame(frame); | 271 stream_->OnStreamFrame(frame); |
| 277 } | 272 } |
| 278 ASSERT_EQ(body, stream_->data()) << "fragment_size: " << fragment_size; | 273 ASSERT_EQ(body, stream_->data()) << "fragment_size: " << fragment_size; |
| 279 } | 274 } |
| 280 } | 275 } |
| 281 | 276 |
| 282 TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyFragmentsSplit) { | 277 TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyFragmentsSplit) { |
| 283 string body = "this is the body"; | 278 string body = "this is the body"; |
| 284 | 279 |
| 285 for (size_t split_point = 1; split_point < body.size() - 1; ++split_point) { | 280 for (size_t split_point = 1; split_point < body.size() - 1; ++split_point) { |
| 286 Initialize(kShouldProcessData); | 281 Initialize(kShouldProcessData); |
| 287 QuicHeaderList headers = ProcessHeaders(false, headers_); | 282 QuicHeaderList headers = ProcessHeaders(false, headers_); |
| 288 ASSERT_EQ(headers, stream_->header_list()); | 283 ASSERT_EQ(headers, stream_->header_list()); |
| 289 stream_->ConsumeHeaderList(); | 284 stream_->ConsumeHeaderList(); |
| 290 | 285 |
| 291 QuicStringPiece fragment1(body.data(), split_point); | 286 QuicStringPiece fragment1(body.data(), split_point); |
| 292 QuicStreamFrame frame1(GetNthClientInitiatedId(0), false, 0, | 287 QuicStreamFrame frame1(kClientDataStreamId1, false, 0, |
| 293 QuicStringPiece(fragment1)); | 288 QuicStringPiece(fragment1)); |
| 294 stream_->OnStreamFrame(frame1); | 289 stream_->OnStreamFrame(frame1); |
| 295 | 290 |
| 296 QuicStringPiece fragment2(body.data() + split_point, | 291 QuicStringPiece fragment2(body.data() + split_point, |
| 297 body.size() - split_point); | 292 body.size() - split_point); |
| 298 QuicStreamFrame frame2(GetNthClientInitiatedId(0), false, split_point, | 293 QuicStreamFrame frame2(kClientDataStreamId1, false, split_point, |
| 299 QuicStringPiece(fragment2)); | 294 QuicStringPiece(fragment2)); |
| 300 stream_->OnStreamFrame(frame2); | 295 stream_->OnStreamFrame(frame2); |
| 301 | 296 |
| 302 ASSERT_EQ(body, stream_->data()) << "split_point: " << split_point; | 297 ASSERT_EQ(body, stream_->data()) << "split_point: " << split_point; |
| 303 } | 298 } |
| 304 } | 299 } |
| 305 | 300 |
| 306 TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyReadv) { | 301 TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyReadv) { |
| 307 Initialize(!kShouldProcessData); | 302 Initialize(!kShouldProcessData); |
| 308 | 303 |
| 309 string body = "this is the body"; | 304 string body = "this is the body"; |
| 310 | 305 |
| 311 ProcessHeaders(false, headers_); | 306 ProcessHeaders(false, headers_); |
| 312 QuicStreamFrame frame(GetNthClientInitiatedId(0), false, 0, | 307 QuicStreamFrame frame(kClientDataStreamId1, false, 0, QuicStringPiece(body)); |
| 313 QuicStringPiece(body)); | |
| 314 stream_->OnStreamFrame(frame); | 308 stream_->OnStreamFrame(frame); |
| 315 stream_->ConsumeHeaderList(); | 309 stream_->ConsumeHeaderList(); |
| 316 | 310 |
| 317 char buffer[2048]; | 311 char buffer[2048]; |
| 318 ASSERT_LT(body.length(), arraysize(buffer)); | 312 ASSERT_LT(body.length(), arraysize(buffer)); |
| 319 struct iovec vec; | 313 struct iovec vec; |
| 320 vec.iov_base = buffer; | 314 vec.iov_base = buffer; |
| 321 vec.iov_len = arraysize(buffer); | 315 vec.iov_len = arraysize(buffer); |
| 322 | 316 |
| 323 size_t bytes_read = stream_->Readv(&vec, 1); | 317 size_t bytes_read = stream_->Readv(&vec, 1); |
| 324 EXPECT_EQ(body.length(), bytes_read); | 318 EXPECT_EQ(body.length(), bytes_read); |
| 325 EXPECT_EQ(body, string(buffer, bytes_read)); | 319 EXPECT_EQ(body, string(buffer, bytes_read)); |
| 326 } | 320 } |
| 327 | 321 |
| 328 TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyMarkConsumed) { | 322 TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyMarkConsumed) { |
| 329 Initialize(!kShouldProcessData); | 323 Initialize(!kShouldProcessData); |
| 330 | 324 |
| 331 string body = "this is the body"; | 325 string body = "this is the body"; |
| 332 | 326 |
| 333 ProcessHeaders(false, headers_); | 327 ProcessHeaders(false, headers_); |
| 334 QuicStreamFrame frame(GetNthClientInitiatedId(0), false, 0, | 328 QuicStreamFrame frame(kClientDataStreamId1, false, 0, QuicStringPiece(body)); |
| 335 QuicStringPiece(body)); | |
| 336 stream_->OnStreamFrame(frame); | 329 stream_->OnStreamFrame(frame); |
| 337 stream_->ConsumeHeaderList(); | 330 stream_->ConsumeHeaderList(); |
| 338 | 331 |
| 339 struct iovec vec; | 332 struct iovec vec; |
| 340 | 333 |
| 341 EXPECT_EQ(1, stream_->GetReadableRegions(&vec, 1)); | 334 EXPECT_EQ(1, stream_->GetReadableRegions(&vec, 1)); |
| 342 EXPECT_EQ(body.length(), vec.iov_len); | 335 EXPECT_EQ(body.length(), vec.iov_len); |
| 343 EXPECT_EQ(body, string(static_cast<char*>(vec.iov_base), vec.iov_len)); | 336 EXPECT_EQ(body, string(static_cast<char*>(vec.iov_base), vec.iov_len)); |
| 344 | 337 |
| 345 stream_->MarkConsumed(body.length()); | 338 stream_->MarkConsumed(body.length()); |
| 346 EXPECT_EQ(body.length(), stream_->flow_controller()->bytes_consumed()); | 339 EXPECT_EQ(body.length(), stream_->flow_controller()->bytes_consumed()); |
| 347 } | 340 } |
| 348 | 341 |
| 349 TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyIncrementalReadv) { | 342 TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyIncrementalReadv) { |
| 350 Initialize(!kShouldProcessData); | 343 Initialize(!kShouldProcessData); |
| 351 | 344 |
| 352 string body = "this is the body"; | 345 string body = "this is the body"; |
| 353 ProcessHeaders(false, headers_); | 346 ProcessHeaders(false, headers_); |
| 354 QuicStreamFrame frame(GetNthClientInitiatedId(0), false, 0, | 347 QuicStreamFrame frame(kClientDataStreamId1, false, 0, QuicStringPiece(body)); |
| 355 QuicStringPiece(body)); | |
| 356 stream_->OnStreamFrame(frame); | 348 stream_->OnStreamFrame(frame); |
| 357 stream_->ConsumeHeaderList(); | 349 stream_->ConsumeHeaderList(); |
| 358 | 350 |
| 359 char buffer[1]; | 351 char buffer[1]; |
| 360 struct iovec vec; | 352 struct iovec vec; |
| 361 vec.iov_base = buffer; | 353 vec.iov_base = buffer; |
| 362 vec.iov_len = arraysize(buffer); | 354 vec.iov_len = arraysize(buffer); |
| 363 | 355 |
| 364 for (size_t i = 0; i < body.length(); ++i) { | 356 for (size_t i = 0; i < body.length(); ++i) { |
| 365 size_t bytes_read = stream_->Readv(&vec, 1); | 357 size_t bytes_read = stream_->Readv(&vec, 1); |
| 366 ASSERT_EQ(1u, bytes_read); | 358 ASSERT_EQ(1u, bytes_read); |
| 367 EXPECT_EQ(body.data()[i], buffer[0]); | 359 EXPECT_EQ(body.data()[i], buffer[0]); |
| 368 } | 360 } |
| 369 } | 361 } |
| 370 | 362 |
| 371 TEST_P(QuicSpdyStreamTest, ProcessHeadersUsingReadvWithMultipleIovecs) { | 363 TEST_P(QuicSpdyStreamTest, ProcessHeadersUsingReadvWithMultipleIovecs) { |
| 372 Initialize(!kShouldProcessData); | 364 Initialize(!kShouldProcessData); |
| 373 | 365 |
| 374 string body = "this is the body"; | 366 string body = "this is the body"; |
| 375 ProcessHeaders(false, headers_); | 367 ProcessHeaders(false, headers_); |
| 376 QuicStreamFrame frame(GetNthClientInitiatedId(0), false, 0, | 368 QuicStreamFrame frame(kClientDataStreamId1, false, 0, QuicStringPiece(body)); |
| 377 QuicStringPiece(body)); | |
| 378 stream_->OnStreamFrame(frame); | 369 stream_->OnStreamFrame(frame); |
| 379 stream_->ConsumeHeaderList(); | 370 stream_->ConsumeHeaderList(); |
| 380 | 371 |
| 381 char buffer1[1]; | 372 char buffer1[1]; |
| 382 char buffer2[1]; | 373 char buffer2[1]; |
| 383 struct iovec vec[2]; | 374 struct iovec vec[2]; |
| 384 vec[0].iov_base = buffer1; | 375 vec[0].iov_base = buffer1; |
| 385 vec[0].iov_len = arraysize(buffer1); | 376 vec[0].iov_len = arraysize(buffer1); |
| 386 vec[1].iov_base = buffer2; | 377 vec[1].iov_base = buffer2; |
| 387 vec[1].iov_len = arraysize(buffer2); | 378 vec[1].iov_len = arraysize(buffer2); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 404 QuicFlowControllerPeer::SetSendWindowOffset(stream_->flow_controller(), | 395 QuicFlowControllerPeer::SetSendWindowOffset(stream_->flow_controller(), |
| 405 kWindow); | 396 kWindow); |
| 406 EXPECT_EQ(kWindow, QuicFlowControllerPeer::SendWindowOffset( | 397 EXPECT_EQ(kWindow, QuicFlowControllerPeer::SendWindowOffset( |
| 407 stream_->flow_controller())); | 398 stream_->flow_controller())); |
| 408 | 399 |
| 409 // Try to send more data than the flow control limit allows. | 400 // Try to send more data than the flow control limit allows. |
| 410 string headers = SpdyUtils::SerializeUncompressedHeaders(headers_); | 401 string headers = SpdyUtils::SerializeUncompressedHeaders(headers_); |
| 411 const uint64_t kOverflow = 15; | 402 const uint64_t kOverflow = 15; |
| 412 string body(kWindow + kOverflow, 'a'); | 403 string body(kWindow + kOverflow, 'a'); |
| 413 | 404 |
| 414 EXPECT_CALL(*connection_, SendBlocked(GetNthClientInitiatedId(0))); | 405 EXPECT_CALL(*connection_, SendBlocked(kClientDataStreamId1)); |
| 415 EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) | 406 EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) |
| 416 .WillOnce(Return(QuicConsumedData(kWindow, true))); | 407 .WillOnce(Return(QuicConsumedData(kWindow, true))); |
| 417 stream_->WriteOrBufferData(body, false, nullptr); | 408 stream_->WriteOrBufferData(body, false, nullptr); |
| 418 | 409 |
| 419 // Should have sent as much as possible, resulting in no send window left. | 410 // Should have sent as much as possible, resulting in no send window left. |
| 420 EXPECT_EQ(0u, | 411 EXPECT_EQ(0u, |
| 421 QuicFlowControllerPeer::SendWindowSize(stream_->flow_controller())); | 412 QuicFlowControllerPeer::SendWindowSize(stream_->flow_controller())); |
| 422 | 413 |
| 423 // And we should have queued the overflowed data. | 414 // And we should have queued the overflowed data. |
| 424 EXPECT_EQ(kOverflow, QuicStreamPeer::SizeOfQueuedData(stream_)); | 415 EXPECT_EQ(kOverflow, QuicStreamPeer::SizeOfQueuedData(stream_)); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 442 kWindow); | 433 kWindow); |
| 443 QuicFlowControllerPeer::SetMaxReceiveWindow(stream_->flow_controller(), | 434 QuicFlowControllerPeer::SetMaxReceiveWindow(stream_->flow_controller(), |
| 444 kWindow); | 435 kWindow); |
| 445 EXPECT_EQ(kWindow, QuicFlowControllerPeer::ReceiveWindowOffset( | 436 EXPECT_EQ(kWindow, QuicFlowControllerPeer::ReceiveWindowOffset( |
| 446 stream_->flow_controller())); | 437 stream_->flow_controller())); |
| 447 | 438 |
| 448 // Stream receives enough data to fill a fraction of the receive window. | 439 // Stream receives enough data to fill a fraction of the receive window. |
| 449 string body(kWindow / 3, 'a'); | 440 string body(kWindow / 3, 'a'); |
| 450 ProcessHeaders(false, headers_); | 441 ProcessHeaders(false, headers_); |
| 451 | 442 |
| 452 QuicStreamFrame frame1(GetNthClientInitiatedId(0), false, 0, | 443 QuicStreamFrame frame1(kClientDataStreamId1, false, 0, QuicStringPiece(body)); |
| 453 QuicStringPiece(body)); | |
| 454 stream_->OnStreamFrame(frame1); | 444 stream_->OnStreamFrame(frame1); |
| 455 EXPECT_EQ(kWindow - (kWindow / 3), QuicFlowControllerPeer::ReceiveWindowSize( | 445 EXPECT_EQ(kWindow - (kWindow / 3), QuicFlowControllerPeer::ReceiveWindowSize( |
| 456 stream_->flow_controller())); | 446 stream_->flow_controller())); |
| 457 | 447 |
| 458 // Now receive another frame which results in the receive window being over | 448 // Now receive another frame which results in the receive window being over |
| 459 // half full. This should all be buffered, decreasing the receive window but | 449 // half full. This should all be buffered, decreasing the receive window but |
| 460 // not sending WINDOW_UPDATE. | 450 // not sending WINDOW_UPDATE. |
| 461 QuicStreamFrame frame2(GetNthClientInitiatedId(0), false, kWindow / 3, | 451 QuicStreamFrame frame2(kClientDataStreamId1, false, kWindow / 3, |
| 462 QuicStringPiece(body)); | 452 QuicStringPiece(body)); |
| 463 stream_->OnStreamFrame(frame2); | 453 stream_->OnStreamFrame(frame2); |
| 464 EXPECT_EQ( | 454 EXPECT_EQ( |
| 465 kWindow - (2 * kWindow / 3), | 455 kWindow - (2 * kWindow / 3), |
| 466 QuicFlowControllerPeer::ReceiveWindowSize(stream_->flow_controller())); | 456 QuicFlowControllerPeer::ReceiveWindowSize(stream_->flow_controller())); |
| 467 } | 457 } |
| 468 | 458 |
| 469 TEST_P(QuicSpdyStreamTest, StreamFlowControlWindowUpdate) { | 459 TEST_P(QuicSpdyStreamTest, StreamFlowControlWindowUpdate) { |
| 470 // Tests that on receipt of data, the stream updates its receive window offset | 460 // Tests that on receipt of data, the stream updates its receive window offset |
| 471 // appropriately, and sends WINDOW_UPDATE frames when its receive window drops | 461 // appropriately, and sends WINDOW_UPDATE frames when its receive window drops |
| 472 // too low. | 462 // too low. |
| 473 Initialize(kShouldProcessData); | 463 Initialize(kShouldProcessData); |
| 474 | 464 |
| 475 // Set a small flow control limit. | 465 // Set a small flow control limit. |
| 476 const uint64_t kWindow = 36; | 466 const uint64_t kWindow = 36; |
| 477 QuicFlowControllerPeer::SetReceiveWindowOffset(stream_->flow_controller(), | 467 QuicFlowControllerPeer::SetReceiveWindowOffset(stream_->flow_controller(), |
| 478 kWindow); | 468 kWindow); |
| 479 QuicFlowControllerPeer::SetMaxReceiveWindow(stream_->flow_controller(), | 469 QuicFlowControllerPeer::SetMaxReceiveWindow(stream_->flow_controller(), |
| 480 kWindow); | 470 kWindow); |
| 481 EXPECT_EQ(kWindow, QuicFlowControllerPeer::ReceiveWindowOffset( | 471 EXPECT_EQ(kWindow, QuicFlowControllerPeer::ReceiveWindowOffset( |
| 482 stream_->flow_controller())); | 472 stream_->flow_controller())); |
| 483 | 473 |
| 484 // Stream receives enough data to fill a fraction of the receive window. | 474 // Stream receives enough data to fill a fraction of the receive window. |
| 485 string body(kWindow / 3, 'a'); | 475 string body(kWindow / 3, 'a'); |
| 486 ProcessHeaders(false, headers_); | 476 ProcessHeaders(false, headers_); |
| 487 stream_->ConsumeHeaderList(); | 477 stream_->ConsumeHeaderList(); |
| 488 | 478 |
| 489 QuicStreamFrame frame1(GetNthClientInitiatedId(0), false, 0, | 479 QuicStreamFrame frame1(kClientDataStreamId1, false, 0, QuicStringPiece(body)); |
| 490 QuicStringPiece(body)); | |
| 491 stream_->OnStreamFrame(frame1); | 480 stream_->OnStreamFrame(frame1); |
| 492 EXPECT_EQ(kWindow - (kWindow / 3), QuicFlowControllerPeer::ReceiveWindowSize( | 481 EXPECT_EQ(kWindow - (kWindow / 3), QuicFlowControllerPeer::ReceiveWindowSize( |
| 493 stream_->flow_controller())); | 482 stream_->flow_controller())); |
| 494 | 483 |
| 495 // Now receive another frame which results in the receive window being over | 484 // Now receive another frame which results in the receive window being over |
| 496 // half full. This will trigger the stream to increase its receive window | 485 // half full. This will trigger the stream to increase its receive window |
| 497 // offset and send a WINDOW_UPDATE. The result will be again an available | 486 // offset and send a WINDOW_UPDATE. The result will be again an available |
| 498 // window of kWindow bytes. | 487 // window of kWindow bytes. |
| 499 QuicStreamFrame frame2(GetNthClientInitiatedId(0), false, kWindow / 3, | 488 QuicStreamFrame frame2(kClientDataStreamId1, false, kWindow / 3, |
| 500 QuicStringPiece(body)); | 489 QuicStringPiece(body)); |
| 501 EXPECT_CALL(*connection_, | 490 EXPECT_CALL(*connection_, |
| 502 SendWindowUpdate(GetNthClientInitiatedId(0), | 491 SendWindowUpdate(kClientDataStreamId1, |
| 503 QuicFlowControllerPeer::ReceiveWindowOffset( | 492 QuicFlowControllerPeer::ReceiveWindowOffset( |
| 504 stream_->flow_controller()) + | 493 stream_->flow_controller()) + |
| 505 2 * kWindow / 3)); | 494 2 * kWindow / 3)); |
| 506 stream_->OnStreamFrame(frame2); | 495 stream_->OnStreamFrame(frame2); |
| 507 EXPECT_EQ(kWindow, QuicFlowControllerPeer::ReceiveWindowSize( | 496 EXPECT_EQ(kWindow, QuicFlowControllerPeer::ReceiveWindowSize( |
| 508 stream_->flow_controller())); | 497 stream_->flow_controller())); |
| 509 } | 498 } |
| 510 | 499 |
| 511 TEST_P(QuicSpdyStreamTest, ConnectionFlowControlWindowUpdate) { | 500 TEST_P(QuicSpdyStreamTest, ConnectionFlowControlWindowUpdate) { |
| 512 // Tests that on receipt of data, the connection updates its receive window | 501 // Tests that on receipt of data, the connection updates its receive window |
| (...skipping 21 matching lines...) Expand all Loading... |
| 534 stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(), | 523 stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(), |
| 535 headers); | 524 headers); |
| 536 stream_->ConsumeHeaderList(); | 525 stream_->ConsumeHeaderList(); |
| 537 stream2_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(), | 526 stream2_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(), |
| 538 headers); | 527 headers); |
| 539 stream2_->ConsumeHeaderList(); | 528 stream2_->ConsumeHeaderList(); |
| 540 | 529 |
| 541 // Each stream gets a quarter window of data. This should not trigger a | 530 // Each stream gets a quarter window of data. This should not trigger a |
| 542 // WINDOW_UPDATE for either stream, nor for the connection. | 531 // WINDOW_UPDATE for either stream, nor for the connection. |
| 543 string body(kWindow / 4, 'a'); | 532 string body(kWindow / 4, 'a'); |
| 544 QuicStreamFrame frame1(GetNthClientInitiatedId(0), false, 0, | 533 QuicStreamFrame frame1(kClientDataStreamId1, false, 0, QuicStringPiece(body)); |
| 545 QuicStringPiece(body)); | |
| 546 stream_->OnStreamFrame(frame1); | 534 stream_->OnStreamFrame(frame1); |
| 547 QuicStreamFrame frame2(GetNthClientInitiatedId(1), false, 0, | 535 QuicStreamFrame frame2(kClientDataStreamId2, false, 0, QuicStringPiece(body)); |
| 548 QuicStringPiece(body)); | |
| 549 stream2_->OnStreamFrame(frame2); | 536 stream2_->OnStreamFrame(frame2); |
| 550 | 537 |
| 551 // Now receive a further single byte on one stream - again this does not | 538 // Now receive a further single byte on one stream - again this does not |
| 552 // trigger a stream WINDOW_UPDATE, but now the connection flow control window | 539 // trigger a stream WINDOW_UPDATE, but now the connection flow control window |
| 553 // is over half full and thus a connection WINDOW_UPDATE is sent. | 540 // is over half full and thus a connection WINDOW_UPDATE is sent. |
| 554 EXPECT_CALL(*connection_, SendWindowUpdate(GetNthClientInitiatedId(0), _)) | 541 EXPECT_CALL(*connection_, SendWindowUpdate(kClientDataStreamId1, _)).Times(0); |
| 555 .Times(0); | 542 EXPECT_CALL(*connection_, SendWindowUpdate(kClientDataStreamId2, _)).Times(0); |
| 556 EXPECT_CALL(*connection_, SendWindowUpdate(GetNthClientInitiatedId(1), _)) | |
| 557 .Times(0); | |
| 558 EXPECT_CALL(*connection_, | 543 EXPECT_CALL(*connection_, |
| 559 SendWindowUpdate(0, QuicFlowControllerPeer::ReceiveWindowOffset( | 544 SendWindowUpdate(0, |
| 560 session_->flow_controller()) + | 545 QuicFlowControllerPeer::ReceiveWindowOffset( |
| 561 1 + kWindow / 2)); | 546 session_->flow_controller()) + |
| 562 QuicStreamFrame frame3(GetNthClientInitiatedId(0), false, (kWindow / 4), | 547 1 + kWindow / 2)); |
| 548 QuicStreamFrame frame3(kClientDataStreamId1, false, (kWindow / 4), |
| 563 QuicStringPiece("a")); | 549 QuicStringPiece("a")); |
| 564 stream_->OnStreamFrame(frame3); | 550 stream_->OnStreamFrame(frame3); |
| 565 } | 551 } |
| 566 | 552 |
| 567 TEST_P(QuicSpdyStreamTest, StreamFlowControlViolation) { | 553 TEST_P(QuicSpdyStreamTest, StreamFlowControlViolation) { |
| 568 // Tests that on if the peer sends too much data (i.e. violates the flow | 554 // Tests that on if the peer sends too much data (i.e. violates the flow |
| 569 // control protocol), then we terminate the connection. | 555 // control protocol), then we terminate the connection. |
| 570 | 556 |
| 571 // Stream should not process data, so that data gets buffered in the | 557 // Stream should not process data, so that data gets buffered in the |
| 572 // sequencer, triggering flow control limits. | 558 // sequencer, triggering flow control limits. |
| 573 Initialize(!kShouldProcessData); | 559 Initialize(!kShouldProcessData); |
| 574 | 560 |
| 575 // Set a small flow control limit. | 561 // Set a small flow control limit. |
| 576 const uint64_t kWindow = 50; | 562 const uint64_t kWindow = 50; |
| 577 QuicFlowControllerPeer::SetReceiveWindowOffset(stream_->flow_controller(), | 563 QuicFlowControllerPeer::SetReceiveWindowOffset(stream_->flow_controller(), |
| 578 kWindow); | 564 kWindow); |
| 579 | 565 |
| 580 ProcessHeaders(false, headers_); | 566 ProcessHeaders(false, headers_); |
| 581 | 567 |
| 582 // Receive data to overflow the window, violating flow control. | 568 // Receive data to overflow the window, violating flow control. |
| 583 string body(kWindow + 1, 'a'); | 569 string body(kWindow + 1, 'a'); |
| 584 QuicStreamFrame frame(GetNthClientInitiatedId(0), false, 0, | 570 QuicStreamFrame frame(kClientDataStreamId1, false, 0, QuicStringPiece(body)); |
| 585 QuicStringPiece(body)); | |
| 586 EXPECT_CALL(*connection_, | 571 EXPECT_CALL(*connection_, |
| 587 CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _)); | 572 CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _)); |
| 588 stream_->OnStreamFrame(frame); | 573 stream_->OnStreamFrame(frame); |
| 589 } | 574 } |
| 590 | 575 |
| 591 TEST_P(QuicSpdyStreamTest, TestHandlingQuicRstStreamNoError) { | 576 TEST_P(QuicSpdyStreamTest, TestHandlingQuicRstStreamNoError) { |
| 592 Initialize(kShouldProcessData); | 577 Initialize(kShouldProcessData); |
| 593 ProcessHeaders(false, headers_); | 578 ProcessHeaders(false, headers_); |
| 594 | 579 |
| 595 stream_->OnStreamReset( | 580 stream_->OnStreamReset( |
| (...skipping 17 matching lines...) Expand all Loading... |
| 613 QuicFlowControllerPeer::SetReceiveWindowOffset(stream_->flow_controller(), | 598 QuicFlowControllerPeer::SetReceiveWindowOffset(stream_->flow_controller(), |
| 614 kStreamWindow); | 599 kStreamWindow); |
| 615 QuicFlowControllerPeer::SetReceiveWindowOffset(session_->flow_controller(), | 600 QuicFlowControllerPeer::SetReceiveWindowOffset(session_->flow_controller(), |
| 616 kConnectionWindow); | 601 kConnectionWindow); |
| 617 | 602 |
| 618 ProcessHeaders(false, headers_); | 603 ProcessHeaders(false, headers_); |
| 619 | 604 |
| 620 // Send enough data to overflow the connection level flow control window. | 605 // Send enough data to overflow the connection level flow control window. |
| 621 string body(kConnectionWindow + 1, 'a'); | 606 string body(kConnectionWindow + 1, 'a'); |
| 622 EXPECT_LT(body.size(), kStreamWindow); | 607 EXPECT_LT(body.size(), kStreamWindow); |
| 623 QuicStreamFrame frame(GetNthClientInitiatedId(0), false, 0, | 608 QuicStreamFrame frame(kClientDataStreamId1, false, 0, QuicStringPiece(body)); |
| 624 QuicStringPiece(body)); | |
| 625 | 609 |
| 626 EXPECT_CALL(*connection_, | 610 EXPECT_CALL(*connection_, |
| 627 CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _)); | 611 CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _)); |
| 628 stream_->OnStreamFrame(frame); | 612 stream_->OnStreamFrame(frame); |
| 629 } | 613 } |
| 630 | 614 |
| 631 TEST_P(QuicSpdyStreamTest, StreamFlowControlFinNotBlocked) { | 615 TEST_P(QuicSpdyStreamTest, StreamFlowControlFinNotBlocked) { |
| 632 // An attempt to write a FIN with no data should not be flow control blocked, | 616 // An attempt to write a FIN with no data should not be flow control blocked, |
| 633 // even if the send window is 0. | 617 // even if the send window is 0. |
| 634 | 618 |
| 635 Initialize(kShouldProcessData); | 619 Initialize(kShouldProcessData); |
| 636 | 620 |
| 637 // Set a flow control limit of zero. | 621 // Set a flow control limit of zero. |
| 638 QuicFlowControllerPeer::SetReceiveWindowOffset(stream_->flow_controller(), 0); | 622 QuicFlowControllerPeer::SetReceiveWindowOffset(stream_->flow_controller(), 0); |
| 639 EXPECT_EQ(0u, QuicFlowControllerPeer::ReceiveWindowOffset( | 623 EXPECT_EQ(0u, QuicFlowControllerPeer::ReceiveWindowOffset( |
| 640 stream_->flow_controller())); | 624 stream_->flow_controller())); |
| 641 | 625 |
| 642 // Send a frame with a FIN but no data. This should not be blocked. | 626 // Send a frame with a FIN but no data. This should not be blocked. |
| 643 string body = ""; | 627 string body = ""; |
| 644 bool fin = true; | 628 bool fin = true; |
| 645 | 629 |
| 646 EXPECT_CALL(*connection_, SendBlocked(GetNthClientInitiatedId(0))).Times(0); | 630 EXPECT_CALL(*connection_, SendBlocked(kClientDataStreamId1)).Times(0); |
| 647 EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) | 631 EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) |
| 648 .WillOnce(Return(QuicConsumedData(0, fin))); | 632 .WillOnce(Return(QuicConsumedData(0, fin))); |
| 649 | 633 |
| 650 stream_->WriteOrBufferData(body, fin, nullptr); | 634 stream_->WriteOrBufferData(body, fin, nullptr); |
| 651 } | 635 } |
| 652 | 636 |
| 653 TEST_P(QuicSpdyStreamTest, ReceivingTrailersViaHeaderList) { | 637 TEST_P(QuicSpdyStreamTest, ReceivingTrailersViaHeaderList) { |
| 654 // Test that receiving trailing headers from the peer via | 638 // Test that receiving trailing headers from the peer via |
| 655 // OnStreamHeaderList() works, and can be read from the stream and consumed. | 639 // OnStreamHeaderList() works, and can be read from the stream and consumed. |
| 656 Initialize(kShouldProcessData); | 640 Initialize(kShouldProcessData); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 718 // The final offset trailer will be consumed by QUIC. | 702 // The final offset trailer will be consumed by QUIC. |
| 719 trailers_block.erase(kFinalOffsetHeaderKey); | 703 trailers_block.erase(kFinalOffsetHeaderKey); |
| 720 EXPECT_EQ(trailers_block, stream_->received_trailers()); | 704 EXPECT_EQ(trailers_block, stream_->received_trailers()); |
| 721 | 705 |
| 722 // Consuming the trailers erases them from the stream. | 706 // Consuming the trailers erases them from the stream. |
| 723 stream_->MarkTrailersConsumed(); | 707 stream_->MarkTrailersConsumed(); |
| 724 EXPECT_TRUE(stream_->FinishedReadingTrailers()); | 708 EXPECT_TRUE(stream_->FinishedReadingTrailers()); |
| 725 | 709 |
| 726 EXPECT_FALSE(stream_->IsDoneReading()); | 710 EXPECT_FALSE(stream_->IsDoneReading()); |
| 727 // Receive and consume body. | 711 // Receive and consume body. |
| 728 QuicStreamFrame frame(GetNthClientInitiatedId(0), /*fin=*/false, 0, body); | 712 QuicStreamFrame frame(kClientDataStreamId1, /*fin=*/false, 0, body); |
| 729 stream_->OnStreamFrame(frame); | 713 stream_->OnStreamFrame(frame); |
| 730 EXPECT_EQ(body, stream_->data()); | 714 EXPECT_EQ(body, stream_->data()); |
| 731 EXPECT_TRUE(stream_->IsDoneReading()); | 715 EXPECT_TRUE(stream_->IsDoneReading()); |
| 732 } | 716 } |
| 733 | 717 |
| 734 TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithoutOffset) { | 718 TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithoutOffset) { |
| 735 // Test that receiving trailers without a final offset field is an error. | 719 // Test that receiving trailers without a final offset field is an error. |
| 736 Initialize(kShouldProcessData); | 720 Initialize(kShouldProcessData); |
| 737 | 721 |
| 738 // Receive initial headers. | 722 // Receive initial headers. |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 799 | 783 |
| 800 TEST_P(QuicSpdyStreamTest, ReceivingTrailersAfterBodyWithFin) { | 784 TEST_P(QuicSpdyStreamTest, ReceivingTrailersAfterBodyWithFin) { |
| 801 // If body data are received with a FIN, no trailers should then arrive. | 785 // If body data are received with a FIN, no trailers should then arrive. |
| 802 Initialize(kShouldProcessData); | 786 Initialize(kShouldProcessData); |
| 803 | 787 |
| 804 // Receive initial headers without FIN set. | 788 // Receive initial headers without FIN set. |
| 805 ProcessHeaders(false, headers_); | 789 ProcessHeaders(false, headers_); |
| 806 stream_->ConsumeHeaderList(); | 790 stream_->ConsumeHeaderList(); |
| 807 | 791 |
| 808 // Receive body data, with FIN. | 792 // Receive body data, with FIN. |
| 809 QuicStreamFrame frame(GetNthClientInitiatedId(0), /*fin=*/true, 0, "body"); | 793 QuicStreamFrame frame(kClientDataStreamId1, /*fin=*/true, 0, "body"); |
| 810 stream_->OnStreamFrame(frame); | 794 stream_->OnStreamFrame(frame); |
| 811 | 795 |
| 812 // Receive trailing headers after FIN already received. | 796 // Receive trailing headers after FIN already received. |
| 813 SpdyHeaderBlock trailers_block; | 797 SpdyHeaderBlock trailers_block; |
| 814 trailers_block["foo"] = "bar"; | 798 trailers_block["foo"] = "bar"; |
| 815 EXPECT_CALL(*connection_, | 799 EXPECT_CALL(*connection_, |
| 816 CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, _, _)) | 800 CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, _, _)) |
| 817 .Times(1); | 801 .Times(1); |
| 818 ProcessHeaders(true, trailers_block); | 802 ProcessHeaders(true, trailers_block); |
| 819 } | 803 } |
| 820 | 804 |
| 821 TEST_P(QuicSpdyStreamTest, ClosingStreamWithNoTrailers) { | 805 TEST_P(QuicSpdyStreamTest, ClosingStreamWithNoTrailers) { |
| 822 // Verify that a stream receiving headers, body, and no trailers is correctly | 806 // Verify that a stream receiving headers, body, and no trailers is correctly |
| 823 // marked as done reading on consumption of headers and body. | 807 // marked as done reading on consumption of headers and body. |
| 824 Initialize(kShouldProcessData); | 808 Initialize(kShouldProcessData); |
| 825 | 809 |
| 826 // Receive and consume initial headers with FIN not set. | 810 // Receive and consume initial headers with FIN not set. |
| 827 auto h = AsHeaderList(headers_); | 811 auto h = AsHeaderList(headers_); |
| 828 stream_->OnStreamHeaderList(/*fin=*/false, h.uncompressed_header_bytes(), h); | 812 stream_->OnStreamHeaderList(/*fin=*/false, h.uncompressed_header_bytes(), h); |
| 829 stream_->ConsumeHeaderList(); | 813 stream_->ConsumeHeaderList(); |
| 830 | 814 |
| 831 // Receive and consume body with FIN set, and no trailers. | 815 // Receive and consume body with FIN set, and no trailers. |
| 832 const string kBody = string(1024, 'x'); | 816 const string kBody = string(1024, 'x'); |
| 833 QuicStreamFrame frame(GetNthClientInitiatedId(0), /*fin=*/true, 0, kBody); | 817 QuicStreamFrame frame(kClientDataStreamId1, /*fin=*/true, 0, kBody); |
| 834 stream_->OnStreamFrame(frame); | 818 stream_->OnStreamFrame(frame); |
| 835 | 819 |
| 836 EXPECT_TRUE(stream_->IsDoneReading()); | 820 EXPECT_TRUE(stream_->IsDoneReading()); |
| 837 } | 821 } |
| 838 | 822 |
| 839 TEST_P(QuicSpdyStreamTest, WritingTrailersSendsAFin) { | 823 TEST_P(QuicSpdyStreamTest, WritingTrailersSendsAFin) { |
| 840 // Test that writing trailers will send a FIN, as Trailers are the last thing | 824 // Test that writing trailers will send a FIN, as Trailers are the last thing |
| 841 // to be sent on a stream. | 825 // to be sent on a stream. |
| 842 Initialize(kShouldProcessData); | 826 Initialize(kShouldProcessData); |
| 843 EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) | 827 EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 959 | 943 |
| 960 // Writing Trailers should fail, as the FIN has already been sent. | 944 // Writing Trailers should fail, as the FIN has already been sent. |
| 961 // populated with the number of body bytes written. | 945 // populated with the number of body bytes written. |
| 962 EXPECT_QUIC_BUG(stream_->WriteTrailers(SpdyHeaderBlock(), nullptr), | 946 EXPECT_QUIC_BUG(stream_->WriteTrailers(SpdyHeaderBlock(), nullptr), |
| 963 "Trailers cannot be sent after a FIN"); | 947 "Trailers cannot be sent after a FIN"); |
| 964 } | 948 } |
| 965 | 949 |
| 966 } // namespace | 950 } // namespace |
| 967 } // namespace test | 951 } // namespace test |
| 968 } // namespace net | 952 } // namespace net |
| OLD | NEW |