| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "net/quic/quic_headers_stream.h" | |
| 6 | |
| 7 #include <string> | |
| 8 | |
| 9 #include "base/strings/string_number_conversions.h" | |
| 10 #include "net/quic/quic_bug_tracker.h" | |
| 11 #include "net/quic/quic_utils.h" | |
| 12 #include "net/quic/spdy_utils.h" | |
| 13 #include "net/quic/test_tools/quic_connection_peer.h" | |
| 14 #include "net/quic/test_tools/quic_headers_stream_peer.h" | |
| 15 #include "net/quic/test_tools/quic_spdy_session_peer.h" | |
| 16 #include "net/quic/test_tools/quic_test_utils.h" | |
| 17 #include "net/quic/test_tools/reliable_quic_stream_peer.h" | |
| 18 #include "net/spdy/spdy_alt_svc_wire_format.h" | |
| 19 #include "net/spdy/spdy_flags.h" | |
| 20 #include "net/spdy/spdy_protocol.h" | |
| 21 #include "net/spdy/spdy_test_utils.h" | |
| 22 #include "net/test/gtest_util.h" | |
| 23 #include "testing/gtest/include/gtest/gtest.h" | |
| 24 | |
| 25 using base::StringPiece; | |
| 26 using std::ostream; | |
| 27 using std::string; | |
| 28 using std::vector; | |
| 29 using testing::ElementsAre; | |
| 30 using testing::_; | |
| 31 using testing::AtLeast; | |
| 32 using testing::HasSubstr; | |
| 33 using testing::InSequence; | |
| 34 using testing::Invoke; | |
| 35 using testing::Return; | |
| 36 using testing::StrictMock; | |
| 37 using testing::WithArgs; | |
| 38 using testing::_; | |
| 39 | |
| 40 // TODO(bnc): Merge these correctly. | |
| 41 bool FLAGS_use_http2_frame_decoder_adapter; | |
| 42 bool FLAGS_spdy_use_hpack_decoder2; | |
| 43 bool FLAGS_spdy_framer_use_new_methods2; | |
| 44 | |
| 45 namespace net { | |
| 46 namespace test { | |
| 47 | |
| 48 class MockHpackDebugVisitor : public QuicHeadersStream::HpackDebugVisitor { | |
| 49 public: | |
| 50 explicit MockHpackDebugVisitor() : HpackDebugVisitor() {} | |
| 51 | |
| 52 MOCK_METHOD1(OnUseEntry, void(QuicTime::Delta elapsed)); | |
| 53 | |
| 54 private: | |
| 55 DISALLOW_COPY_AND_ASSIGN(MockHpackDebugVisitor); | |
| 56 }; | |
| 57 | |
| 58 namespace { | |
| 59 | |
| 60 // TODO(ckrasic): this workaround is due to absence of std::initializer_list | |
| 61 const bool kFins[] = {false, true}; | |
| 62 | |
| 63 class MockVisitor : public SpdyFramerVisitorInterface { | |
| 64 public: | |
| 65 MOCK_METHOD1(OnError, void(SpdyFramer* framer)); | |
| 66 MOCK_METHOD3(OnDataFrameHeader, | |
| 67 void(SpdyStreamId stream_id, size_t length, bool fin)); | |
| 68 MOCK_METHOD3(OnStreamFrameData, | |
| 69 void(SpdyStreamId stream_id, const char* data, size_t len)); | |
| 70 MOCK_METHOD1(OnStreamEnd, void(SpdyStreamId stream_id)); | |
| 71 MOCK_METHOD2(OnStreamPadding, void(SpdyStreamId stream_id, size_t len)); | |
| 72 MOCK_METHOD1(OnHeaderFrameStart, | |
| 73 SpdyHeadersHandlerInterface*(SpdyStreamId stream_id)); | |
| 74 MOCK_METHOD2(OnHeaderFrameEnd, void(SpdyStreamId stream_id, bool end)); | |
| 75 MOCK_METHOD3(OnControlFrameHeaderData, | |
| 76 bool(SpdyStreamId stream_id, | |
| 77 const char* header_data, | |
| 78 size_t len)); | |
| 79 MOCK_METHOD5(OnSynStream, | |
| 80 void(SpdyStreamId stream_id, | |
| 81 SpdyStreamId associated_stream_id, | |
| 82 SpdyPriority priority, | |
| 83 bool fin, | |
| 84 bool unidirectional)); | |
| 85 MOCK_METHOD2(OnSynReply, void(SpdyStreamId stream_id, bool fin)); | |
| 86 MOCK_METHOD2(OnRstStream, | |
| 87 void(SpdyStreamId stream_id, SpdyRstStreamStatus status)); | |
| 88 MOCK_METHOD1(OnSettings, void(bool clear_persisted)); | |
| 89 MOCK_METHOD3(OnSetting, | |
| 90 void(SpdySettingsIds id, uint8_t flags, uint32_t value)); | |
| 91 MOCK_METHOD0(OnSettingsAck, void()); | |
| 92 MOCK_METHOD0(OnSettingsEnd, void()); | |
| 93 MOCK_METHOD2(OnPing, void(SpdyPingId unique_id, bool is_ack)); | |
| 94 MOCK_METHOD2(OnGoAway, | |
| 95 void(SpdyStreamId last_accepted_stream_id, | |
| 96 SpdyGoAwayStatus status)); | |
| 97 MOCK_METHOD7(OnHeaders, | |
| 98 void(SpdyStreamId stream_id, | |
| 99 bool has_priority, | |
| 100 int weight, | |
| 101 SpdyStreamId parent_stream_id, | |
| 102 bool exclusive, | |
| 103 bool fin, | |
| 104 bool end)); | |
| 105 MOCK_METHOD2(OnWindowUpdate, | |
| 106 void(SpdyStreamId stream_id, int delta_window_size)); | |
| 107 MOCK_METHOD1(OnBlocked, void(SpdyStreamId stream_id)); | |
| 108 MOCK_METHOD3(OnPushPromise, | |
| 109 void(SpdyStreamId stream_id, | |
| 110 SpdyStreamId promised_stream_id, | |
| 111 bool end)); | |
| 112 MOCK_METHOD2(OnContinuation, void(SpdyStreamId stream_id, bool end)); | |
| 113 MOCK_METHOD4(OnPriority, | |
| 114 void(SpdyStreamId stream_id, | |
| 115 SpdyStreamId parent_id, | |
| 116 int weight, | |
| 117 bool exclusive)); | |
| 118 MOCK_METHOD3(OnAltSvc, | |
| 119 void(SpdyStreamId stream_id, | |
| 120 StringPiece origin, | |
| 121 const SpdyAltSvcWireFormat::AlternativeServiceVector& | |
| 122 altsvc_vector)); | |
| 123 MOCK_METHOD2(OnUnknownFrame, bool(SpdyStreamId stream_id, int frame_type)); | |
| 124 }; | |
| 125 | |
| 126 class ForceHolAckListener : public QuicAckListenerInterface { | |
| 127 public: | |
| 128 ForceHolAckListener() : total_acked_bytes_(0) {} | |
| 129 | |
| 130 void OnPacketAcked(int acked_bytes, QuicTime::Delta ack_delay_time) override { | |
| 131 total_acked_bytes_ += acked_bytes; | |
| 132 } | |
| 133 | |
| 134 void OnPacketRetransmitted(int retransmitted_bytes) override {} | |
| 135 | |
| 136 size_t total_acked_bytes() { return total_acked_bytes_; } | |
| 137 | |
| 138 private: | |
| 139 ~ForceHolAckListener() override {} | |
| 140 | |
| 141 size_t total_acked_bytes_; | |
| 142 | |
| 143 DISALLOW_COPY_AND_ASSIGN(ForceHolAckListener); | |
| 144 }; | |
| 145 | |
| 146 enum Http2DecoderChoice { | |
| 147 HTTP2_DECODER_SPDY, | |
| 148 HTTP2_DECODER_NESTED_SPDY, | |
| 149 HTTP2_DECODER_NEW | |
| 150 }; | |
| 151 ostream& operator<<(ostream& os, Http2DecoderChoice v) { | |
| 152 switch (v) { | |
| 153 case HTTP2_DECODER_SPDY: | |
| 154 return os << "SPDY"; | |
| 155 case HTTP2_DECODER_NESTED_SPDY: | |
| 156 return os << "NESTED_SPDY"; | |
| 157 case HTTP2_DECODER_NEW: | |
| 158 return os << "NEW"; | |
| 159 } | |
| 160 return os; | |
| 161 } | |
| 162 | |
| 163 enum HpackDecoderChoice { HPACK_DECODER_SPDY, HPACK_DECODER_NEW }; | |
| 164 ostream& operator<<(ostream& os, HpackDecoderChoice v) { | |
| 165 switch (v) { | |
| 166 case HPACK_DECODER_SPDY: | |
| 167 return os << "SPDY"; | |
| 168 case HPACK_DECODER_NEW: | |
| 169 return os << "NEW"; | |
| 170 } | |
| 171 return os; | |
| 172 } | |
| 173 | |
| 174 typedef std:: | |
| 175 tuple<QuicVersion, Perspective, Http2DecoderChoice, HpackDecoderChoice> | |
| 176 TestParamsTuple; | |
| 177 | |
| 178 struct TestParams { | |
| 179 explicit TestParams(TestParamsTuple params) | |
| 180 : version(std::get<0>(params)), | |
| 181 perspective(std::get<1>(params)), | |
| 182 http2_decoder(std::get<2>(params)), | |
| 183 hpack_decoder(std::get<3>(params)) { | |
| 184 switch (http2_decoder) { | |
| 185 case HTTP2_DECODER_SPDY: | |
| 186 FLAGS_use_nested_spdy_framer_decoder = false; | |
| 187 FLAGS_use_http2_frame_decoder_adapter = false; | |
| 188 break; | |
| 189 case HTTP2_DECODER_NESTED_SPDY: | |
| 190 FLAGS_use_nested_spdy_framer_decoder = true; | |
| 191 FLAGS_use_http2_frame_decoder_adapter = false; | |
| 192 break; | |
| 193 case HTTP2_DECODER_NEW: | |
| 194 FLAGS_use_nested_spdy_framer_decoder = false; | |
| 195 FLAGS_use_http2_frame_decoder_adapter = true; | |
| 196 // Http2FrameDecoderAdapter needs the new header methods, else | |
| 197 // --use_http2_frame_decoder_adapter=true will be ignored. | |
| 198 FLAGS_spdy_framer_use_new_methods2 = true; | |
| 199 break; | |
| 200 } | |
| 201 switch (hpack_decoder) { | |
| 202 case HPACK_DECODER_SPDY: | |
| 203 FLAGS_spdy_use_hpack_decoder2 = false; | |
| 204 break; | |
| 205 case HPACK_DECODER_NEW: | |
| 206 FLAGS_spdy_use_hpack_decoder2 = true; | |
| 207 // Needs new header methods to be used. | |
| 208 FLAGS_spdy_framer_use_new_methods2 = true; | |
| 209 break; | |
| 210 } | |
| 211 FLAGS_quic_supports_push_promise = true; | |
| 212 FLAGS_quic_always_log_bugs_for_tests = true; | |
| 213 VLOG(1) << "TestParams: version: " << QuicVersionToString(version) | |
| 214 << ", perspective: " << perspective | |
| 215 << ", http2_decoder: " << http2_decoder | |
| 216 << ", hpack_decoder: " << hpack_decoder; | |
| 217 } | |
| 218 | |
| 219 QuicVersion version; | |
| 220 Perspective perspective; | |
| 221 Http2DecoderChoice http2_decoder; | |
| 222 HpackDecoderChoice hpack_decoder; | |
| 223 }; | |
| 224 | |
| 225 class QuicHeadersStreamTest : public ::testing::TestWithParam<TestParamsTuple> { | |
| 226 public: | |
| 227 // Constructing the test_params_ object will set the necessary flags before | |
| 228 // the MockQuicConnection is constructed, which we need because the latter | |
| 229 // will construct a SpdyFramer that will use those flags to decide whether | |
| 230 // to construct a decoder adapter. | |
| 231 QuicHeadersStreamTest() | |
| 232 : test_params_(GetParam()), | |
| 233 connection_(new StrictMock<MockQuicConnection>(&helper_, | |
| 234 &alarm_factory_, | |
| 235 perspective(), | |
| 236 GetVersion())), | |
| 237 session_(connection_), | |
| 238 headers_stream_(QuicSpdySessionPeer::GetHeadersStream(&session_)), | |
| 239 body_("hello world"), | |
| 240 hpack_encoder_visitor_(new StrictMock<MockHpackDebugVisitor>), | |
| 241 hpack_decoder_visitor_(new StrictMock<MockHpackDebugVisitor>), | |
| 242 stream_frame_(kHeadersStreamId, /*fin=*/false, /*offset=*/0, ""), | |
| 243 next_promised_stream_id_(2) { | |
| 244 headers_[":version"] = "HTTP/1.1"; | |
| 245 headers_[":status"] = "200 Ok"; | |
| 246 headers_["content-length"] = "11"; | |
| 247 framer_ = std::unique_ptr<SpdyFramer>(new SpdyFramer(HTTP2)); | |
| 248 framer_->set_visitor(&visitor_); | |
| 249 EXPECT_EQ(version(), session_.connection()->version()); | |
| 250 EXPECT_TRUE(headers_stream_ != nullptr); | |
| 251 connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); | |
| 252 } | |
| 253 | |
| 254 QuicConsumedData SaveIov(const QuicIOVector& data) { | |
| 255 const iovec* iov = data.iov; | |
| 256 int count = data.iov_count; | |
| 257 int consumed = 0; | |
| 258 for (int i = 0; i < count; ++i) { | |
| 259 saved_data_.append(static_cast<char*>(iov[i].iov_base), iov[i].iov_len); | |
| 260 consumed += iov[i].iov_len; | |
| 261 } | |
| 262 return QuicConsumedData(consumed, false); | |
| 263 } | |
| 264 | |
| 265 QuicConsumedData SaveIovAndNotifyAckListener( | |
| 266 const QuicIOVector& data, | |
| 267 QuicAckListenerInterface* ack_listener) { | |
| 268 QuicConsumedData result = SaveIov(data); | |
| 269 if (ack_listener) { | |
| 270 ack_listener->OnPacketAcked(result.bytes_consumed, | |
| 271 QuicTime::Delta::Zero()); | |
| 272 } | |
| 273 return result; | |
| 274 } | |
| 275 | |
| 276 void SavePayload(const char* data, size_t len) { | |
| 277 saved_payloads_.append(data, len); | |
| 278 } | |
| 279 | |
| 280 bool SaveHeaderData(const char* data, int len) { | |
| 281 saved_header_data_.append(data, len); | |
| 282 return true; | |
| 283 } | |
| 284 | |
| 285 void SaveHeaderDataStringPiece(StringPiece data) { | |
| 286 saved_header_data_.append(data.data(), data.length()); | |
| 287 } | |
| 288 | |
| 289 void SavePromiseHeaderList(QuicStreamId /* stream_id */, | |
| 290 QuicStreamId /* promised_stream_id */, | |
| 291 size_t size, | |
| 292 const QuicHeaderList& header_list) { | |
| 293 SaveToHandler(size, header_list); | |
| 294 } | |
| 295 | |
| 296 void SaveHeaderList(QuicStreamId /* stream_id */, | |
| 297 bool /* fin */, | |
| 298 size_t size, | |
| 299 const QuicHeaderList& header_list) { | |
| 300 SaveToHandler(size, header_list); | |
| 301 } | |
| 302 | |
| 303 void SaveToHandler(size_t size, const QuicHeaderList& header_list) { | |
| 304 headers_handler_.reset(new TestHeadersHandler); | |
| 305 headers_handler_->OnHeaderBlockStart(); | |
| 306 for (const auto& p : header_list) { | |
| 307 headers_handler_->OnHeader(p.first, p.second); | |
| 308 } | |
| 309 headers_handler_->OnHeaderBlockEnd(size); | |
| 310 } | |
| 311 | |
| 312 void WriteHeadersAndExpectSynStream(QuicStreamId stream_id, | |
| 313 bool fin, | |
| 314 SpdyPriority priority) { | |
| 315 WriteHeadersAndCheckData(stream_id, fin, priority, SYN_STREAM); | |
| 316 } | |
| 317 | |
| 318 void WriteHeadersAndExpectSynReply(QuicStreamId stream_id, bool fin) { | |
| 319 WriteHeadersAndCheckData(stream_id, fin, 0, SYN_REPLY); | |
| 320 } | |
| 321 | |
| 322 void WriteHeadersAndCheckData(QuicStreamId stream_id, | |
| 323 bool fin, | |
| 324 SpdyPriority priority, | |
| 325 SpdyFrameType type) { | |
| 326 // Write the headers and capture the outgoing data | |
| 327 EXPECT_CALL(session_, WritevData(headers_stream_, kHeadersStreamId, _, _, | |
| 328 false, nullptr)) | |
| 329 .WillOnce(WithArgs<2>(Invoke(this, &QuicHeadersStreamTest::SaveIov))); | |
| 330 headers_stream_->WriteHeaders(stream_id, headers_.Clone(), fin, priority, | |
| 331 nullptr); | |
| 332 | |
| 333 // Parse the outgoing data and check that it matches was was written. | |
| 334 if (type == SYN_STREAM) { | |
| 335 EXPECT_CALL(visitor_, | |
| 336 OnHeaders(stream_id, kHasPriority, | |
| 337 Spdy3PriorityToHttp2Weight(priority), | |
| 338 /*parent_stream_id=*/0, | |
| 339 /*exclusive=*/false, fin, kFrameComplete)); | |
| 340 } else { | |
| 341 EXPECT_CALL(visitor_, | |
| 342 OnHeaders(stream_id, !kHasPriority, | |
| 343 /*priority=*/0, | |
| 344 /*parent_stream_id=*/0, | |
| 345 /*exclusive=*/false, fin, kFrameComplete)); | |
| 346 } | |
| 347 headers_handler_.reset(new TestHeadersHandler); | |
| 348 EXPECT_CALL(visitor_, OnHeaderFrameStart(stream_id)) | |
| 349 .WillOnce(Return(headers_handler_.get())); | |
| 350 EXPECT_CALL(visitor_, OnHeaderFrameEnd(stream_id, true)).Times(1); | |
| 351 if (fin) { | |
| 352 EXPECT_CALL(visitor_, OnStreamEnd(stream_id)); | |
| 353 } | |
| 354 framer_->ProcessInput(saved_data_.data(), saved_data_.length()); | |
| 355 EXPECT_FALSE(framer_->HasError()) | |
| 356 << SpdyFramer::ErrorCodeToString(framer_->error_code()); | |
| 357 | |
| 358 CheckHeaders(); | |
| 359 saved_data_.clear(); | |
| 360 } | |
| 361 | |
| 362 void CheckHeaders() { | |
| 363 EXPECT_EQ(headers_, headers_handler_->decoded_block()); | |
| 364 headers_handler_.reset(); | |
| 365 } | |
| 366 | |
| 367 Perspective perspective() const { return test_params_.perspective; } | |
| 368 | |
| 369 QuicVersion version() const { return test_params_.version; } | |
| 370 | |
| 371 QuicVersionVector GetVersion() { | |
| 372 QuicVersionVector versions; | |
| 373 versions.push_back(version()); | |
| 374 return versions; | |
| 375 } | |
| 376 | |
| 377 void TearDownLocalConnectionState() { | |
| 378 QuicConnectionPeer::TearDownLocalConnectionState(connection_); | |
| 379 } | |
| 380 | |
| 381 QuicStreamId NextPromisedStreamId() { return next_promised_stream_id_ += 2; } | |
| 382 | |
| 383 static const bool kFrameComplete = true; | |
| 384 static const bool kHasPriority = true; | |
| 385 | |
| 386 const TestParams test_params_; | |
| 387 MockQuicConnectionHelper helper_; | |
| 388 MockAlarmFactory alarm_factory_; | |
| 389 StrictMock<MockQuicConnection>* connection_; | |
| 390 StrictMock<MockQuicSpdySession> session_; | |
| 391 QuicHeadersStream* headers_stream_; | |
| 392 SpdyHeaderBlock headers_; | |
| 393 std::unique_ptr<TestHeadersHandler> headers_handler_; | |
| 394 string body_; | |
| 395 string saved_data_; | |
| 396 string saved_header_data_; | |
| 397 string saved_payloads_; | |
| 398 std::unique_ptr<SpdyFramer> framer_; | |
| 399 StrictMock<MockVisitor> visitor_; | |
| 400 std::unique_ptr<StrictMock<MockHpackDebugVisitor>> hpack_encoder_visitor_; | |
| 401 std::unique_ptr<StrictMock<MockHpackDebugVisitor>> hpack_decoder_visitor_; | |
| 402 QuicStreamFrame stream_frame_; | |
| 403 QuicStreamId next_promised_stream_id_; | |
| 404 }; | |
| 405 | |
| 406 // Run all tests with each version, perspective (client or server), | |
| 407 // HTTP/2 and HPACK decoder. | |
| 408 INSTANTIATE_TEST_CASE_P( | |
| 409 Tests, | |
| 410 QuicHeadersStreamTest, | |
| 411 ::testing::Combine( | |
| 412 ::testing::ValuesIn(QuicSupportedVersions()), | |
| 413 ::testing::Values(Perspective::IS_CLIENT, Perspective::IS_SERVER), | |
| 414 ::testing::Values(HTTP2_DECODER_SPDY, | |
| 415 HTTP2_DECODER_NESTED_SPDY, | |
| 416 HTTP2_DECODER_NEW), | |
| 417 ::testing::Values(HPACK_DECODER_SPDY, HPACK_DECODER_NEW))); | |
| 418 | |
| 419 TEST_P(QuicHeadersStreamTest, StreamId) { | |
| 420 EXPECT_EQ(3u, headers_stream_->id()); | |
| 421 } | |
| 422 | |
| 423 TEST_P(QuicHeadersStreamTest, WriteHeaders) { | |
| 424 for (QuicStreamId stream_id = kClientDataStreamId1; | |
| 425 stream_id < kClientDataStreamId3; stream_id += 2) { | |
| 426 for (bool fin : kFins) { | |
| 427 if (perspective() == Perspective::IS_SERVER) { | |
| 428 WriteHeadersAndExpectSynReply(stream_id, fin); | |
| 429 } else { | |
| 430 for (SpdyPriority priority = 0; priority < 7; ++priority) { | |
| 431 // TODO(rch): implement priorities correctly. | |
| 432 WriteHeadersAndExpectSynStream(stream_id, fin, 0); | |
| 433 } | |
| 434 } | |
| 435 } | |
| 436 } | |
| 437 } | |
| 438 | |
| 439 TEST_P(QuicHeadersStreamTest, WritePushPromises) { | |
| 440 for (QuicStreamId stream_id = kClientDataStreamId1; | |
| 441 stream_id < kClientDataStreamId3; stream_id += 2) { | |
| 442 QuicStreamId promised_stream_id = NextPromisedStreamId(); | |
| 443 if (perspective() == Perspective::IS_SERVER) { | |
| 444 // Write the headers and capture the outgoing data | |
| 445 EXPECT_CALL(session_, WritevData(headers_stream_, kHeadersStreamId, _, _, | |
| 446 false, nullptr)) | |
| 447 .WillOnce(WithArgs<2>(Invoke(this, &QuicHeadersStreamTest::SaveIov))); | |
| 448 headers_stream_->WritePushPromise(stream_id, promised_stream_id, | |
| 449 headers_.Clone(), nullptr); | |
| 450 | |
| 451 // Parse the outgoing data and check that it matches was was written. | |
| 452 EXPECT_CALL(visitor_, | |
| 453 OnPushPromise(stream_id, promised_stream_id, kFrameComplete)); | |
| 454 headers_handler_.reset(new TestHeadersHandler); | |
| 455 EXPECT_CALL(visitor_, OnHeaderFrameStart(stream_id)) | |
| 456 .WillOnce(Return(headers_handler_.get())); | |
| 457 EXPECT_CALL(visitor_, OnHeaderFrameEnd(stream_id, true)).Times(1); | |
| 458 framer_->ProcessInput(saved_data_.data(), saved_data_.length()); | |
| 459 EXPECT_FALSE(framer_->HasError()) | |
| 460 << SpdyFramer::ErrorCodeToString(framer_->error_code()); | |
| 461 CheckHeaders(); | |
| 462 saved_data_.clear(); | |
| 463 } else { | |
| 464 EXPECT_DFATAL( | |
| 465 headers_stream_->WritePushPromise(stream_id, promised_stream_id, | |
| 466 headers_.Clone(), nullptr), | |
| 467 "Client shouldn't send PUSH_PROMISE"); | |
| 468 } | |
| 469 } | |
| 470 } | |
| 471 | |
| 472 TEST_P(QuicHeadersStreamTest, ProcessRawData) { | |
| 473 for (QuicStreamId stream_id = kClientDataStreamId1; | |
| 474 stream_id < kClientDataStreamId3; stream_id += 2) { | |
| 475 for (bool fin : {false, true}) { | |
| 476 for (SpdyPriority priority = 0; priority < 7; ++priority) { | |
| 477 // Replace with "WriteHeadersAndSaveData" | |
| 478 SpdySerializedFrame frame; | |
| 479 if (perspective() == Perspective::IS_SERVER) { | |
| 480 SpdyHeadersIR headers_frame(stream_id, headers_.Clone()); | |
| 481 headers_frame.set_fin(fin); | |
| 482 headers_frame.set_has_priority(true); | |
| 483 headers_frame.set_weight(Spdy3PriorityToHttp2Weight(0)); | |
| 484 frame = framer_->SerializeFrame(headers_frame); | |
| 485 EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0)); | |
| 486 } else { | |
| 487 SpdyHeadersIR headers_frame(stream_id, headers_.Clone()); | |
| 488 headers_frame.set_fin(fin); | |
| 489 frame = framer_->SerializeFrame(headers_frame); | |
| 490 } | |
| 491 EXPECT_CALL(session_, | |
| 492 OnStreamHeaderList(stream_id, fin, frame.size(), _)) | |
| 493 .WillOnce(Invoke(this, &QuicHeadersStreamTest::SaveHeaderList)); | |
| 494 stream_frame_.data_buffer = frame.data(); | |
| 495 stream_frame_.data_length = frame.size(); | |
| 496 headers_stream_->OnStreamFrame(stream_frame_); | |
| 497 stream_frame_.offset += frame.size(); | |
| 498 CheckHeaders(); | |
| 499 } | |
| 500 } | |
| 501 } | |
| 502 } | |
| 503 | |
| 504 TEST_P(QuicHeadersStreamTest, ProcessPushPromise) { | |
| 505 if (perspective() == Perspective::IS_SERVER) | |
| 506 return; | |
| 507 for (QuicStreamId stream_id = kClientDataStreamId1; | |
| 508 stream_id < kClientDataStreamId3; stream_id += 2) { | |
| 509 QuicStreamId promised_stream_id = NextPromisedStreamId(); | |
| 510 SpdyPushPromiseIR push_promise(stream_id, promised_stream_id, | |
| 511 headers_.Clone()); | |
| 512 SpdySerializedFrame frame(framer_->SerializeFrame(push_promise)); | |
| 513 if (perspective() == Perspective::IS_SERVER) { | |
| 514 EXPECT_CALL(*connection_, | |
| 515 CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, | |
| 516 "PUSH_PROMISE not supported.", _)) | |
| 517 .WillRepeatedly(InvokeWithoutArgs( | |
| 518 this, &QuicHeadersStreamTest::TearDownLocalConnectionState)); | |
| 519 } else { | |
| 520 EXPECT_CALL(session_, OnPromiseHeaderList(stream_id, promised_stream_id, | |
| 521 frame.size(), _)) | |
| 522 .WillOnce( | |
| 523 Invoke(this, &QuicHeadersStreamTest::SavePromiseHeaderList)); | |
| 524 } | |
| 525 stream_frame_.data_buffer = frame.data(); | |
| 526 stream_frame_.data_length = frame.size(); | |
| 527 headers_stream_->OnStreamFrame(stream_frame_); | |
| 528 if (perspective() == Perspective::IS_CLIENT) { | |
| 529 stream_frame_.offset += frame.size(); | |
| 530 CheckHeaders(); | |
| 531 } | |
| 532 } | |
| 533 } | |
| 534 | |
| 535 TEST_P(QuicHeadersStreamTest, EmptyHeaderHOLBlockedTime) { | |
| 536 if (!FLAGS_quic_measure_headers_hol_blocking_time) { | |
| 537 return; | |
| 538 } | |
| 539 EXPECT_CALL(session_, OnHeadersHeadOfLineBlocking(_)).Times(0); | |
| 540 testing::InSequence seq; | |
| 541 bool fin = true; | |
| 542 for (int stream_num = 0; stream_num < 10; stream_num++) { | |
| 543 QuicStreamId stream_id = QuicClientDataStreamId(stream_num); | |
| 544 // Replace with "WriteHeadersAndSaveData" | |
| 545 SpdySerializedFrame frame; | |
| 546 if (perspective() == Perspective::IS_SERVER) { | |
| 547 SpdyHeadersIR headers_frame(stream_id, headers_.Clone()); | |
| 548 headers_frame.set_fin(fin); | |
| 549 headers_frame.set_has_priority(true); | |
| 550 headers_frame.set_weight(Spdy3PriorityToHttp2Weight(0)); | |
| 551 frame = framer_->SerializeFrame(headers_frame); | |
| 552 EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0)); | |
| 553 } else { | |
| 554 SpdyHeadersIR headers_frame(stream_id, headers_.Clone()); | |
| 555 headers_frame.set_fin(fin); | |
| 556 frame = framer_->SerializeFrame(headers_frame); | |
| 557 } | |
| 558 EXPECT_CALL(session_, OnStreamHeaderList(stream_id, fin, frame.size(), _)) | |
| 559 .Times(1); | |
| 560 stream_frame_.data_buffer = frame.data(); | |
| 561 stream_frame_.data_length = frame.size(); | |
| 562 headers_stream_->OnStreamFrame(stream_frame_); | |
| 563 connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); | |
| 564 stream_frame_.offset += frame.size(); | |
| 565 } | |
| 566 } | |
| 567 | |
| 568 TEST_P(QuicHeadersStreamTest, NonEmptyHeaderHOLBlockedTime) { | |
| 569 QuicStreamId stream_id; | |
| 570 bool fin = true; | |
| 571 QuicStreamFrame stream_frames[10]; | |
| 572 SpdySerializedFrame frames[10]; | |
| 573 // First create all the frames in order | |
| 574 { | |
| 575 InSequence seq; | |
| 576 for (int stream_num = 0; stream_num < 10; ++stream_num) { | |
| 577 stream_id = QuicClientDataStreamId(stream_num); | |
| 578 if (perspective() == Perspective::IS_SERVER) { | |
| 579 SpdyHeadersIR headers_frame(stream_id, headers_.Clone()); | |
| 580 headers_frame.set_fin(fin); | |
| 581 headers_frame.set_has_priority(true); | |
| 582 headers_frame.set_weight(Spdy3PriorityToHttp2Weight(0)); | |
| 583 frames[stream_num] = framer_->SerializeFrame(headers_frame); | |
| 584 EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0)).Times(1); | |
| 585 } else { | |
| 586 SpdyHeadersIR headers_frame(stream_id, headers_.Clone()); | |
| 587 headers_frame.set_fin(fin); | |
| 588 frames[stream_num] = framer_->SerializeFrame(headers_frame); | |
| 589 } | |
| 590 stream_frames[stream_num].stream_id = stream_frame_.stream_id; | |
| 591 stream_frames[stream_num].offset = stream_frame_.offset; | |
| 592 stream_frames[stream_num].data_buffer = frames[stream_num].data(); | |
| 593 stream_frames[stream_num].data_length = frames[stream_num].size(); | |
| 594 DVLOG(1) << "make frame for stream " << stream_num << " offset " | |
| 595 << stream_frames[stream_num].offset; | |
| 596 stream_frame_.offset += frames[stream_num].size(); | |
| 597 EXPECT_CALL(session_, OnStreamHeaderList(stream_id, fin, _, _)).Times(1); | |
| 598 } | |
| 599 } | |
| 600 | |
| 601 // Actually writing the frames in reverse order will cause HOL blocking. | |
| 602 EXPECT_CALL(session_, OnHeadersHeadOfLineBlocking(_)).Times(9); | |
| 603 | |
| 604 for (int stream_num = 9; stream_num >= 0; --stream_num) { | |
| 605 DVLOG(1) << "OnStreamFrame for stream " << stream_num << " offset " | |
| 606 << stream_frames[stream_num].offset; | |
| 607 headers_stream_->OnStreamFrame(stream_frames[stream_num]); | |
| 608 connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); | |
| 609 } | |
| 610 } | |
| 611 | |
| 612 TEST_P(QuicHeadersStreamTest, ProcessLargeRawData) { | |
| 613 // We want to create a frame that is more than the SPDY Framer's max control | |
| 614 // frame size, which is 16K, but less than the HPACK decoders max decode | |
| 615 // buffer size, which is 32K. | |
| 616 headers_["key0"] = string(1 << 13, '.'); | |
| 617 headers_["key1"] = string(1 << 13, '.'); | |
| 618 headers_["key2"] = string(1 << 13, '.'); | |
| 619 for (QuicStreamId stream_id = kClientDataStreamId1; | |
| 620 stream_id < kClientDataStreamId3; stream_id += 2) { | |
| 621 for (bool fin : {false, true}) { | |
| 622 for (SpdyPriority priority = 0; priority < 7; ++priority) { | |
| 623 // Replace with "WriteHeadersAndSaveData" | |
| 624 SpdySerializedFrame frame; | |
| 625 if (perspective() == Perspective::IS_SERVER) { | |
| 626 SpdyHeadersIR headers_frame(stream_id, headers_.Clone()); | |
| 627 headers_frame.set_fin(fin); | |
| 628 headers_frame.set_has_priority(true); | |
| 629 headers_frame.set_weight(Spdy3PriorityToHttp2Weight(0)); | |
| 630 frame = framer_->SerializeFrame(headers_frame); | |
| 631 EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0)); | |
| 632 } else { | |
| 633 SpdyHeadersIR headers_frame(stream_id, headers_.Clone()); | |
| 634 headers_frame.set_fin(fin); | |
| 635 frame = framer_->SerializeFrame(headers_frame); | |
| 636 } | |
| 637 EXPECT_CALL(session_, | |
| 638 OnStreamHeaderList(stream_id, fin, frame.size(), _)) | |
| 639 .WillOnce(Invoke(this, &QuicHeadersStreamTest::SaveHeaderList)); | |
| 640 stream_frame_.data_buffer = frame.data(); | |
| 641 stream_frame_.data_length = frame.size(); | |
| 642 headers_stream_->OnStreamFrame(stream_frame_); | |
| 643 stream_frame_.offset += frame.size(); | |
| 644 CheckHeaders(); | |
| 645 } | |
| 646 } | |
| 647 } | |
| 648 } | |
| 649 | |
| 650 TEST_P(QuicHeadersStreamTest, ProcessBadData) { | |
| 651 const char kBadData[] = "blah blah blah"; | |
| 652 EXPECT_CALL(*connection_, | |
| 653 CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, _, _)) | |
| 654 .Times(::testing::AnyNumber()); | |
| 655 stream_frame_.data_buffer = kBadData; | |
| 656 stream_frame_.data_length = strlen(kBadData); | |
| 657 headers_stream_->OnStreamFrame(stream_frame_); | |
| 658 } | |
| 659 | |
| 660 TEST_P(QuicHeadersStreamTest, ProcessSpdyDataFrame) { | |
| 661 SpdyDataIR data(2, "ping"); | |
| 662 SpdySerializedFrame frame(framer_->SerializeFrame(data)); | |
| 663 | |
| 664 EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, | |
| 665 "SPDY DATA frame received.", _)) | |
| 666 .WillOnce(InvokeWithoutArgs( | |
| 667 this, &QuicHeadersStreamTest::TearDownLocalConnectionState)); | |
| 668 stream_frame_.data_buffer = frame.data(); | |
| 669 stream_frame_.data_length = frame.size(); | |
| 670 headers_stream_->OnStreamFrame(stream_frame_); | |
| 671 } | |
| 672 | |
| 673 TEST_P(QuicHeadersStreamTest, ProcessSpdyDataFrameForceHolBlocking) { | |
| 674 if (version() <= QUIC_VERSION_35) { | |
| 675 return; | |
| 676 } | |
| 677 QuicSpdySessionPeer::SetForceHolBlocking(&session_, true); | |
| 678 SpdyDataIR data(2, "ping"); | |
| 679 SpdySerializedFrame frame(framer_->SerializeFrame(data)); | |
| 680 EXPECT_CALL(session_, OnStreamFrameData(2, _, 4, false)); | |
| 681 stream_frame_.data_buffer = frame.data(); | |
| 682 stream_frame_.data_length = frame.size(); | |
| 683 headers_stream_->OnStreamFrame(stream_frame_); | |
| 684 } | |
| 685 | |
| 686 TEST_P(QuicHeadersStreamTest, ProcessSpdyDataFrameEmptyWithFin) { | |
| 687 if (version() <= QUIC_VERSION_35) { | |
| 688 return; | |
| 689 } | |
| 690 QuicSpdySessionPeer::SetForceHolBlocking(&session_, true); | |
| 691 SpdyDataIR data(2, ""); | |
| 692 data.set_fin(true); | |
| 693 SpdySerializedFrame frame(framer_->SerializeFrame(data)); | |
| 694 EXPECT_CALL(session_, OnStreamFrameData(2, _, 0, true)); | |
| 695 stream_frame_.data_buffer = frame.data(); | |
| 696 stream_frame_.data_length = frame.size(); | |
| 697 headers_stream_->OnStreamFrame(stream_frame_); | |
| 698 } | |
| 699 | |
| 700 TEST_P(QuicHeadersStreamTest, ProcessSpdyRstStreamFrame) { | |
| 701 SpdyRstStreamIR data(2, RST_STREAM_PROTOCOL_ERROR); | |
| 702 SpdySerializedFrame frame(framer_->SerializeFrame(data)); | |
| 703 EXPECT_CALL(*connection_, | |
| 704 CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, | |
| 705 "SPDY RST_STREAM frame received.", _)) | |
| 706 .WillOnce(InvokeWithoutArgs( | |
| 707 this, &QuicHeadersStreamTest::TearDownLocalConnectionState)); | |
| 708 stream_frame_.data_buffer = frame.data(); | |
| 709 stream_frame_.data_length = frame.size(); | |
| 710 headers_stream_->OnStreamFrame(stream_frame_); | |
| 711 } | |
| 712 | |
| 713 TEST_P(QuicHeadersStreamTest, ProcessSpdySettingsFrame) { | |
| 714 FLAGS_quic_respect_http2_settings_frame = false; | |
| 715 SpdySettingsIR data; | |
| 716 data.AddSetting(SETTINGS_HEADER_TABLE_SIZE, true, true, 0); | |
| 717 SpdySerializedFrame frame(framer_->SerializeFrame(data)); | |
| 718 EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, | |
| 719 "SPDY SETTINGS frame received.", _)) | |
| 720 .WillOnce(InvokeWithoutArgs( | |
| 721 this, &QuicHeadersStreamTest::TearDownLocalConnectionState)); | |
| 722 stream_frame_.data_buffer = frame.data(); | |
| 723 stream_frame_.data_length = frame.size(); | |
| 724 headers_stream_->OnStreamFrame(stream_frame_); | |
| 725 } | |
| 726 | |
| 727 TEST_P(QuicHeadersStreamTest, RespectHttp2SettingsFrameSupportedFields) { | |
| 728 FLAGS_quic_respect_http2_settings_frame = true; | |
| 729 const uint32_t kTestHeaderTableSize = 1000; | |
| 730 SpdySettingsIR data; | |
| 731 // Respect supported settings frames SETTINGS_HEADER_TABLE_SIZE. | |
| 732 data.AddSetting(SETTINGS_HEADER_TABLE_SIZE, true, true, kTestHeaderTableSize); | |
| 733 SpdySerializedFrame frame(framer_->SerializeFrame(data)); | |
| 734 stream_frame_.data_buffer = frame.data(); | |
| 735 stream_frame_.data_length = frame.size(); | |
| 736 headers_stream_->OnStreamFrame(stream_frame_); | |
| 737 EXPECT_EQ(kTestHeaderTableSize, | |
| 738 QuicHeadersStreamPeer::GetSpdyFramer(headers_stream_) | |
| 739 .header_encoder_table_size()); | |
| 740 } | |
| 741 | |
| 742 TEST_P(QuicHeadersStreamTest, RespectHttp2SettingsFrameUnsupportedFields) { | |
| 743 FLAGS_quic_respect_http2_settings_frame = true; | |
| 744 SpdySettingsIR data; | |
| 745 // Does not support SETTINGS_MAX_HEADER_LIST_SIZE, | |
| 746 // SETTINGS_MAX_CONCURRENT_STREAMS, SETTINGS_INITIAL_WINDOW_SIZE, | |
| 747 // SETTINGS_ENABLE_PUSH and SETTINGS_MAX_FRAME_SIZE. | |
| 748 data.AddSetting(SETTINGS_MAX_HEADER_LIST_SIZE, true, true, 2000); | |
| 749 data.AddSetting(SETTINGS_MAX_CONCURRENT_STREAMS, true, true, 100); | |
| 750 data.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, true, true, 100); | |
| 751 data.AddSetting(SETTINGS_ENABLE_PUSH, true, true, 1); | |
| 752 data.AddSetting(SETTINGS_MAX_FRAME_SIZE, true, true, 1250); | |
| 753 SpdySerializedFrame frame(framer_->SerializeFrame(data)); | |
| 754 EXPECT_CALL( | |
| 755 *connection_, | |
| 756 CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, | |
| 757 "Unsupported field of HTTP/2 SETTINGS frame: " + | |
| 758 base::IntToString(SETTINGS_MAX_HEADER_LIST_SIZE), | |
| 759 _)); | |
| 760 EXPECT_CALL( | |
| 761 *connection_, | |
| 762 CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, | |
| 763 "Unsupported field of HTTP/2 SETTINGS frame: " + | |
| 764 base::IntToString(SETTINGS_MAX_CONCURRENT_STREAMS), | |
| 765 _)); | |
| 766 EXPECT_CALL( | |
| 767 *connection_, | |
| 768 CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, | |
| 769 "Unsupported field of HTTP/2 SETTINGS frame: " + | |
| 770 base::IntToString(SETTINGS_INITIAL_WINDOW_SIZE), | |
| 771 _)); | |
| 772 EXPECT_CALL(*connection_, | |
| 773 CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, | |
| 774 "Unsupported field of HTTP/2 SETTINGS frame: " + | |
| 775 base::IntToString(SETTINGS_ENABLE_PUSH), | |
| 776 _)); | |
| 777 EXPECT_CALL(*connection_, | |
| 778 CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, | |
| 779 "Unsupported field of HTTP/2 SETTINGS frame: " + | |
| 780 base::IntToString(SETTINGS_MAX_FRAME_SIZE), | |
| 781 _)); | |
| 782 stream_frame_.data_buffer = frame.data(); | |
| 783 stream_frame_.data_length = frame.size(); | |
| 784 headers_stream_->OnStreamFrame(stream_frame_); | |
| 785 } | |
| 786 | |
| 787 TEST_P(QuicHeadersStreamTest, ProcessSpdyPingFrame) { | |
| 788 SpdyPingIR data(1); | |
| 789 SpdySerializedFrame frame(framer_->SerializeFrame(data)); | |
| 790 EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, | |
| 791 "SPDY PING frame received.", _)) | |
| 792 .WillOnce(InvokeWithoutArgs( | |
| 793 this, &QuicHeadersStreamTest::TearDownLocalConnectionState)); | |
| 794 stream_frame_.data_buffer = frame.data(); | |
| 795 stream_frame_.data_length = frame.size(); | |
| 796 headers_stream_->OnStreamFrame(stream_frame_); | |
| 797 } | |
| 798 | |
| 799 TEST_P(QuicHeadersStreamTest, ProcessSpdyGoAwayFrame) { | |
| 800 SpdyGoAwayIR data(1, GOAWAY_PROTOCOL_ERROR, "go away"); | |
| 801 SpdySerializedFrame frame(framer_->SerializeFrame(data)); | |
| 802 EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, | |
| 803 "SPDY GOAWAY frame received.", _)) | |
| 804 .WillOnce(InvokeWithoutArgs( | |
| 805 this, &QuicHeadersStreamTest::TearDownLocalConnectionState)); | |
| 806 stream_frame_.data_buffer = frame.data(); | |
| 807 stream_frame_.data_length = frame.size(); | |
| 808 headers_stream_->OnStreamFrame(stream_frame_); | |
| 809 } | |
| 810 | |
| 811 TEST_P(QuicHeadersStreamTest, ProcessSpdyWindowUpdateFrame) { | |
| 812 SpdyWindowUpdateIR data(1, 1); | |
| 813 SpdySerializedFrame frame(framer_->SerializeFrame(data)); | |
| 814 EXPECT_CALL(*connection_, | |
| 815 CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, | |
| 816 "SPDY WINDOW_UPDATE frame received.", _)) | |
| 817 .WillOnce(InvokeWithoutArgs( | |
| 818 this, &QuicHeadersStreamTest::TearDownLocalConnectionState)); | |
| 819 stream_frame_.data_buffer = frame.data(); | |
| 820 stream_frame_.data_length = frame.size(); | |
| 821 headers_stream_->OnStreamFrame(stream_frame_); | |
| 822 } | |
| 823 | |
| 824 TEST_P(QuicHeadersStreamTest, NoConnectionLevelFlowControl) { | |
| 825 EXPECT_FALSE(ReliableQuicStreamPeer::StreamContributesToConnectionFlowControl( | |
| 826 headers_stream_)); | |
| 827 } | |
| 828 | |
| 829 TEST_P(QuicHeadersStreamTest, HpackDecoderDebugVisitor) { | |
| 830 if (FLAGS_use_nested_spdy_framer_decoder) | |
| 831 return; | |
| 832 | |
| 833 StrictMock<MockHpackDebugVisitor>* hpack_decoder_visitor = | |
| 834 hpack_decoder_visitor_.get(); | |
| 835 headers_stream_->SetHpackDecoderDebugVisitor( | |
| 836 std::move(hpack_decoder_visitor_)); | |
| 837 | |
| 838 // Create some headers we expect to generate entries in HPACK's | |
| 839 // dynamic table, in addition to content-length. | |
| 840 headers_["key0"] = string(1 << 1, '.'); | |
| 841 headers_["key1"] = string(1 << 2, '.'); | |
| 842 headers_["key2"] = string(1 << 3, '.'); | |
| 843 { | |
| 844 testing::InSequence seq; | |
| 845 // Number of indexed representations generated in headers below. | |
| 846 for (int i = 1; i < 28; i++) { | |
| 847 EXPECT_CALL(*hpack_decoder_visitor, | |
| 848 OnUseEntry(QuicTime::Delta::FromMilliseconds(i))) | |
| 849 .Times(4); | |
| 850 } | |
| 851 } | |
| 852 for (QuicStreamId stream_id = kClientDataStreamId1; | |
| 853 stream_id < kClientDataStreamId3; stream_id += 2) { | |
| 854 for (bool fin : {false, true}) { | |
| 855 for (SpdyPriority priority = 0; priority < 7; ++priority) { | |
| 856 // Replace with "WriteHeadersAndSaveData" | |
| 857 SpdySerializedFrame frame; | |
| 858 if (perspective() == Perspective::IS_SERVER) { | |
| 859 SpdyHeadersIR headers_frame(stream_id, headers_.Clone()); | |
| 860 headers_frame.set_fin(fin); | |
| 861 headers_frame.set_has_priority(true); | |
| 862 headers_frame.set_weight(Spdy3PriorityToHttp2Weight(0)); | |
| 863 frame = framer_->SerializeFrame(headers_frame); | |
| 864 EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0)); | |
| 865 } else { | |
| 866 SpdyHeadersIR headers_frame(stream_id, headers_.Clone()); | |
| 867 headers_frame.set_fin(fin); | |
| 868 frame = framer_->SerializeFrame(headers_frame); | |
| 869 } | |
| 870 EXPECT_CALL(session_, | |
| 871 OnStreamHeaderList(stream_id, fin, frame.size(), _)) | |
| 872 .WillOnce(Invoke(this, &QuicHeadersStreamTest::SaveHeaderList)); | |
| 873 stream_frame_.data_buffer = frame.data(); | |
| 874 stream_frame_.data_length = frame.size(); | |
| 875 connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); | |
| 876 headers_stream_->OnStreamFrame(stream_frame_); | |
| 877 stream_frame_.offset += frame.size(); | |
| 878 CheckHeaders(); | |
| 879 } | |
| 880 } | |
| 881 } | |
| 882 } | |
| 883 | |
| 884 TEST_P(QuicHeadersStreamTest, HpackEncoderDebugVisitor) { | |
| 885 StrictMock<MockHpackDebugVisitor>* hpack_encoder_visitor = | |
| 886 hpack_encoder_visitor_.get(); | |
| 887 headers_stream_->SetHpackEncoderDebugVisitor( | |
| 888 std::move(hpack_encoder_visitor_)); | |
| 889 | |
| 890 if (perspective() == Perspective::IS_SERVER) { | |
| 891 testing::InSequence seq; | |
| 892 for (int i = 1; i < 4; i++) { | |
| 893 EXPECT_CALL(*hpack_encoder_visitor, | |
| 894 OnUseEntry(QuicTime::Delta::FromMilliseconds(i))); | |
| 895 } | |
| 896 } else { | |
| 897 testing::InSequence seq; | |
| 898 for (int i = 1; i < 28; i++) { | |
| 899 EXPECT_CALL(*hpack_encoder_visitor, | |
| 900 OnUseEntry(QuicTime::Delta::FromMilliseconds(i))); | |
| 901 } | |
| 902 } | |
| 903 for (QuicStreamId stream_id = kClientDataStreamId1; | |
| 904 stream_id < kClientDataStreamId3; stream_id += 2) { | |
| 905 for (bool fin : {false, true}) { | |
| 906 if (perspective() == Perspective::IS_SERVER) { | |
| 907 WriteHeadersAndExpectSynReply(stream_id, fin); | |
| 908 connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); | |
| 909 } else { | |
| 910 for (SpdyPriority priority = 0; priority < 7; ++priority) { | |
| 911 // TODO(rch): implement priorities correctly. | |
| 912 WriteHeadersAndExpectSynStream(stream_id, fin, 0); | |
| 913 connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); | |
| 914 } | |
| 915 } | |
| 916 } | |
| 917 } | |
| 918 } | |
| 919 | |
| 920 TEST_P(QuicHeadersStreamTest, WritevStreamData) { | |
| 921 QuicStreamId id = kClientDataStreamId1; | |
| 922 QuicStreamOffset offset = 0; | |
| 923 struct iovec iov; | |
| 924 string data; | |
| 925 | |
| 926 // This test will issue a write that will require fragmenting into | |
| 927 // multiple HTTP/2 DATA frames. | |
| 928 const int kMinDataFrames = 4; | |
| 929 const size_t data_len = | |
| 930 kSpdyInitialFrameSizeLimit * kMinDataFrames + 1024; | |
| 931 // Set headers stream send window large enough for data written below. | |
| 932 headers_stream_->flow_controller()->UpdateSendWindowOffset(data_len * 2 * 4); | |
| 933 test::GenerateBody(&data, data_len); | |
| 934 | |
| 935 for (bool fin : {true, false}) { | |
| 936 for (bool use_ack_listener : {true, false}) { | |
| 937 scoped_refptr<ForceHolAckListener> ack_listener; | |
| 938 if (use_ack_listener) { | |
| 939 ack_listener = new ForceHolAckListener(); | |
| 940 } | |
| 941 EXPECT_CALL(session_, | |
| 942 WritevData(headers_stream_, kHeadersStreamId, _, _, false, _)) | |
| 943 .WillRepeatedly(WithArgs<2, 5>(Invoke( | |
| 944 this, &QuicHeadersStreamTest::SaveIovAndNotifyAckListener))); | |
| 945 | |
| 946 QuicConsumedData consumed_data = headers_stream_->WritevStreamData( | |
| 947 id, MakeIOVector(data, &iov), offset, fin, ack_listener.get()); | |
| 948 | |
| 949 EXPECT_EQ(consumed_data.bytes_consumed, data_len); | |
| 950 EXPECT_EQ(consumed_data.fin_consumed, fin); | |
| 951 // Now process the written data with the SPDY framer, and verify | |
| 952 // that the original data is unchanged. | |
| 953 EXPECT_CALL(visitor_, OnDataFrameHeader(id, _, _)) | |
| 954 .Times(AtLeast(kMinDataFrames)); | |
| 955 EXPECT_CALL(visitor_, OnStreamFrameData(id, _, _)) | |
| 956 .WillRepeatedly(WithArgs<1, 2>( | |
| 957 Invoke(this, &QuicHeadersStreamTest::SavePayload))); | |
| 958 if (fin) { | |
| 959 EXPECT_CALL(visitor_, OnStreamEnd(id)); | |
| 960 } | |
| 961 framer_->ProcessInput(saved_data_.data(), saved_data_.length()); | |
| 962 EXPECT_EQ(saved_payloads_, data); | |
| 963 | |
| 964 if (use_ack_listener) { | |
| 965 // Notice, acked bytes doesn't include extra bytes used by | |
| 966 // HTTP/2 DATA frame headers. | |
| 967 EXPECT_EQ(ack_listener->total_acked_bytes(), data_len); | |
| 968 } | |
| 969 saved_data_.clear(); | |
| 970 saved_payloads_.clear(); | |
| 971 } | |
| 972 } | |
| 973 } | |
| 974 | |
| 975 } // namespace | |
| 976 } // namespace test | |
| 977 } // namespace net | |
| OLD | NEW |