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