Introduce Control streams for HTTP/3. gfe-relnote: n/a --unused code. PiperOrigin-RevId: 242161401 Change-Id: I29928112a479348ef66636b442ea6065bd832194
diff --git a/quic/core/http/quic_receive_control_stream.cc b/quic/core/http/quic_receive_control_stream.cc new file mode 100644 index 0000000..972dfc8 --- /dev/null +++ b/quic/core/http/quic_receive_control_stream.cc
@@ -0,0 +1,165 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.h" + +#include "net/third_party/quiche/src/quic/core/http/quic_spdy_session.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" + +namespace quic { + +const uint16_t kSettingsMaxHeaderListSize = 6; +const uint16_t kSettingsNumPlaceholders = 8; + +// Visitor of HttpDecoder that passes data frame to QuicSpdyStream and closes +// the connection on unexpected frames. +class QuicReceiveControlStream::HttpDecoderVisitor + : public HttpDecoder::Visitor { + public: + explicit HttpDecoderVisitor(QuicReceiveControlStream* stream) + : stream_(stream) {} + HttpDecoderVisitor(const HttpDecoderVisitor&) = delete; + HttpDecoderVisitor& operator=(const HttpDecoderVisitor&) = delete; + + void OnError(HttpDecoder* decoder) override { + stream_->session()->connection()->CloseConnection( + QUIC_HTTP_DECODER_ERROR, "Http decoder internal error", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + } + + void OnPriorityFrame(const PriorityFrame& frame) override { + CloseConnectionOnWrongFrame("Priority"); + } + + void OnCancelPushFrame(const CancelPushFrame& frame) override { + CloseConnectionOnWrongFrame("Cancel Push"); + } + + void OnMaxPushIdFrame(const MaxPushIdFrame& frame) override { + CloseConnectionOnWrongFrame("Max Push Id"); + } + + void OnGoAwayFrame(const GoAwayFrame& frame) override { + CloseConnectionOnWrongFrame("Goaway"); + } + + void OnSettingsFrameStart(Http3FrameLengths frame_lengths) override { + stream_->OnSettingsFrameStart(frame_lengths); + } + + void OnSettingsFrame(const SettingsFrame& frame) override { + stream_->OnSettingsFrame(frame); + } + + void OnDuplicatePushFrame(const DuplicatePushFrame& frame) override { + CloseConnectionOnWrongFrame("Duplicate Push"); + } + + void OnDataFrameStart(Http3FrameLengths frame_lengths) override { + CloseConnectionOnWrongFrame("Data"); + } + + void OnDataFramePayload(QuicStringPiece payload) override { + CloseConnectionOnWrongFrame("Data"); + } + + void OnDataFrameEnd() override { CloseConnectionOnWrongFrame("Data"); } + + void OnHeadersFrameStart(Http3FrameLengths frame_length) override { + CloseConnectionOnWrongFrame("Headers"); + } + + void OnHeadersFramePayload(QuicStringPiece payload) override { + CloseConnectionOnWrongFrame("Headers"); + } + + void OnHeadersFrameEnd(QuicByteCount frame_len) override { + CloseConnectionOnWrongFrame("Headers"); + } + + void OnPushPromiseFrameStart(PushId push_id) override { + CloseConnectionOnWrongFrame("Push Promise"); + } + + void OnPushPromiseFramePayload(QuicStringPiece payload) override { + CloseConnectionOnWrongFrame("Push Promise"); + } + + void OnPushPromiseFrameEnd() override { + CloseConnectionOnWrongFrame("Push Promise"); + } + + private: + void CloseConnectionOnWrongFrame(std::string frame_type) { + // TODO(renjietang): Change to HTTP/3 error type. + stream_->session()->connection()->CloseConnection( + QUIC_HTTP_DECODER_ERROR, + frame_type + " frame received on control stream", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + } + + QuicReceiveControlStream* stream_; +}; + +QuicReceiveControlStream::QuicReceiveControlStream(QuicStreamId id, + QuicSpdySession* session) + : QuicStream(id, session, /*is_static = */ true, READ_UNIDIRECTIONAL), + received_settings_length_(0), + http_decoder_visitor_(new HttpDecoderVisitor(this)) { + decoder_.set_visitor(http_decoder_visitor_.get()); + sequencer()->set_level_triggered(true); +} + +QuicReceiveControlStream::~QuicReceiveControlStream() {} + +void QuicReceiveControlStream::OnStreamReset(const QuicRstStreamFrame& frame) { + // TODO(renjietang) Change the error code to H/3 specific + // HTTP_CLOSED_CRITICAL_STREAM. + session()->connection()->CloseConnection( + QUIC_INVALID_STREAM_ID, "Attempt to reset receive control stream", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); +} + +void QuicReceiveControlStream::OnDataAvailable() { + iovec iov; + while (!reading_stopped() && sequencer()->PrefetchNextRegion(&iov)) { + decoder_.ProcessInput(reinterpret_cast<const char*>(iov.iov_base), + iov.iov_len); + } +} + +void QuicReceiveControlStream::OnSettingsFrameStart( + Http3FrameLengths frame_lengths) { + if (received_settings_length_ != 0) { + // TODO(renjietang): Change error code to HTTP_UNEXPECTED_FRAME. + session()->connection()->CloseConnection( + QUIC_INVALID_STREAM_ID, "Settings frames are received twice.", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return; + } + received_settings_length_ += + frame_lengths.header_length + frame_lengths.payload_length; +} + +void QuicReceiveControlStream::OnSettingsFrame(const SettingsFrame& settings) { + QuicSpdySession* spdy_session = static_cast<QuicSpdySession*>(session()); + for (auto& it : settings.values) { + uint16_t setting_id = it.first; + switch (setting_id) { + case kSettingsMaxHeaderListSize: + spdy_session->set_max_inbound_header_list_size(it.second); + break; + case kSettingsNumPlaceholders: + // TODO: Support placeholder setting + break; + default: + break; + } + } + sequencer()->MarkConsumed(received_settings_length_); +} + +} // namespace quic
diff --git a/quic/core/http/quic_receive_control_stream.h b/quic/core/http/quic_receive_control_stream.h new file mode 100644 index 0000000..1805d6c --- /dev/null +++ b/quic/core/http/quic_receive_control_stream.h
@@ -0,0 +1,53 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_HTTP_QUIC_RECEIVE_CONTROL_STREAM_H_ +#define QUICHE_QUIC_CORE_HTTP_QUIC_RECEIVE_CONTROL_STREAM_H_ + +#include "net/third_party/quiche/src/quic/core/http/http_decoder.h" +#include "net/third_party/quiche/src/quic/core/quic_stream.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +class QuicSpdySession; + +// 3.2.1 Control Stream. +// The receive control stream is peer initiated and is read only. +class QUIC_EXPORT_PRIVATE QuicReceiveControlStream : public QuicStream { + public: + // |session| can't be nullptr, and the ownership is not passed. The stream can + // only be accessed through the session. + explicit QuicReceiveControlStream(QuicStreamId id, QuicSpdySession* session); + QuicReceiveControlStream(const QuicReceiveControlStream&) = delete; + QuicReceiveControlStream& operator=(const QuicReceiveControlStream&) = delete; + ~QuicReceiveControlStream() override; + + // Overriding QuicStream::OnStreamReset to make sure control stream is never + // closed before connection. + void OnStreamReset(const QuicRstStreamFrame& frame) override; + + // Implementation of QuicStream. + void OnDataAvailable() override; + + protected: + // Called from HttpDecoderVisitor. + void OnSettingsFrameStart(Http3FrameLengths frame_lengths); + void OnSettingsFrame(const SettingsFrame& settings); + + private: + class HttpDecoderVisitor; + + HttpDecoder decoder_; + + // Track the number of settings bytes received. + size_t received_settings_length_; + + // HttpDecoder's visitor. + std::unique_ptr<HttpDecoderVisitor> http_decoder_visitor_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_HTTP_QUIC_RECEIVE_CONTROL_STREAM_H_
diff --git a/quic/core/http/quic_receive_control_stream_test.cc b/quic/core/http/quic_receive_control_stream_test.cc new file mode 100644 index 0000000..1861d17 --- /dev/null +++ b/quic/core/http/quic_receive_control_stream_test.cc
@@ -0,0 +1,172 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.h" + +#include <cstdint> +#include <ostream> +#include <utility> +#include <vector> + +#include "net/third_party/quiche/src/quic/core/http/http_decoder.h" +#include "net/third_party/quiche/src/quic/core/http/http_encoder.h" +#include "net/third_party/quiche/src/quic/core/http/spdy_utils.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +namespace quic { +namespace test { + +namespace { +using testing::_; +using testing::StrictMock; + +struct TestParams { + TestParams(const ParsedQuicVersion& version, Perspective perspective) + : version(version), perspective(perspective) { + QUIC_LOG(INFO) << "TestParams: version: " + << ParsedQuicVersionToString(version) + << ", perspective: " << perspective; + } + + TestParams(const TestParams& other) + : version(other.version), perspective(other.perspective) {} + + ParsedQuicVersion version; + Perspective perspective; +}; + +std::vector<TestParams> GetTestParams() { + std::vector<TestParams> params; + ParsedQuicVersionVector all_supported_versions = AllSupportedVersions(); + for (const auto& version : AllSupportedVersions()) { + if (!VersionHasControlStreams(version.transport_version)) { + continue; + } + for (Perspective p : {Perspective::IS_SERVER, Perspective::IS_CLIENT}) { + params.emplace_back(version, p); + } + } + return params; +} + +class QuicReceiveControlStreamTest : public QuicTestWithParam<TestParams> { + public: + QuicReceiveControlStreamTest() + : connection_(new StrictMock<MockQuicConnection>( + &helper_, + &alarm_factory_, + perspective(), + SupportedVersions(GetParam().version))), + session_(connection_) { + session_.Initialize(); + receive_control_stream_ = QuicMakeUnique<QuicReceiveControlStream>( + QuicUtils::GetFirstUnidirectionalStreamId( + GetParam().version.transport_version, + perspective() == Perspective::IS_CLIENT ? Perspective::IS_SERVER + : Perspective::IS_CLIENT), + &session_); + } + + Perspective perspective() const { return GetParam().perspective; } + + std::string EncodeSettings(const SettingsFrame& settings) { + HttpEncoder encoder; + std::unique_ptr<char[]> buffer; + auto header_length = encoder.SerializeSettingsFrame(settings, &buffer); + return std::string(buffer.get(), header_length); + } + + MockQuicConnectionHelper helper_; + MockAlarmFactory alarm_factory_; + StrictMock<MockQuicConnection>* connection_; + StrictMock<MockQuicSpdySession> session_; + HttpDecoder decoder_; + std::unique_ptr<QuicReceiveControlStream> receive_control_stream_; +}; + +INSTANTIATE_TEST_SUITE_P(Tests, + QuicReceiveControlStreamTest, + ::testing::ValuesIn(GetTestParams())); + +TEST_P(QuicReceiveControlStreamTest, ResetControlStream) { + QuicRstStreamFrame rst_frame(kInvalidControlFrameId, + receive_control_stream_->id(), + QUIC_STREAM_CANCELLED, 1234); + EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, _, _)); + receive_control_stream_->OnStreamReset(rst_frame); +} + +TEST_P(QuicReceiveControlStreamTest, ReceiveSettings) { + SettingsFrame settings; + settings.values[3] = 2; + settings.values[6] = 5; + std::string data = EncodeSettings(settings); + QuicStreamFrame frame(receive_control_stream_->id(), false, 0, + QuicStringPiece(data)); + EXPECT_NE(5u, session_.max_inbound_header_list_size()); + receive_control_stream_->OnStreamFrame(frame); + EXPECT_EQ(5u, session_.max_inbound_header_list_size()); +} + +TEST_P(QuicReceiveControlStreamTest, ReceiveSettingsTwice) { + SettingsFrame settings; + settings.values[3] = 2; + settings.values[6] = 5; + std::string data = EncodeSettings(settings); + QuicStreamFrame frame(receive_control_stream_->id(), false, 0, + QuicStringPiece(data)); + QuicStreamFrame frame2(receive_control_stream_->id(), false, data.length(), + QuicStringPiece(data)); + receive_control_stream_->OnStreamFrame(frame); + EXPECT_CALL(*connection_, + CloseConnection(QUIC_INVALID_STREAM_ID, + "Settings frames are received twice.", _)); + receive_control_stream_->OnStreamFrame(frame2); +} + +TEST_P(QuicReceiveControlStreamTest, ReceiveSettingsFragments) { + SettingsFrame settings; + settings.values[3] = 2; + settings.values[6] = 5; + std::string data = EncodeSettings(settings); + std::string data1 = data.substr(0, 1); + std::string data2 = data.substr(1, data.length() - 1); + + QuicStreamFrame frame(receive_control_stream_->id(), false, 0, + QuicStringPiece(data.data(), 1)); + QuicStreamFrame frame2(receive_control_stream_->id(), false, 1, + QuicStringPiece(data.data() + 1, data.length() - 1)); + EXPECT_NE(5u, session_.max_inbound_header_list_size()); + receive_control_stream_->OnStreamFrame(frame); + receive_control_stream_->OnStreamFrame(frame2); + EXPECT_EQ(5u, session_.max_inbound_header_list_size()); +} + +TEST_P(QuicReceiveControlStreamTest, ReceiveWrongFrame) { + GoAwayFrame goaway; + goaway.stream_id = 0x1; + HttpEncoder encoder; + std::unique_ptr<char[]> buffer; + QuicByteCount header_length = encoder.SerializeGoAwayFrame(goaway, &buffer); + std::string data = std::string(buffer.get(), header_length); + + QuicStreamFrame frame(receive_control_stream_->id(), false, 0, + QuicStringPiece(data)); + EXPECT_CALL(*connection_, CloseConnection(QUIC_HTTP_DECODER_ERROR, _, _)); + receive_control_stream_->OnStreamFrame(frame); +} + +} // namespace +} // namespace test +} // namespace quic
diff --git a/quic/core/http/quic_send_control_stream.cc b/quic/core/http/quic_send_control_stream.cc new file mode 100644 index 0000000..40b6111 --- /dev/null +++ b/quic/core/http/quic_send_control_stream.cc
@@ -0,0 +1,37 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h" + +#include "net/third_party/quiche/src/quic/core/http/quic_spdy_session.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" + +namespace quic { + +QuicSendControlStream::QuicSendControlStream(QuicStreamId id, + QuicSpdySession* session) + : QuicStream(id, session, /*is_static = */ true, WRITE_UNIDIRECTIONAL), + settings_sent_(false) {} + +void QuicSendControlStream::OnStreamReset(const QuicRstStreamFrame& frame) { + // TODO(renjietang) Change the error code to H/3 specific + // HTTP_CLOSED_CRITICAL_STREAM. + session()->connection()->CloseConnection( + QUIC_INVALID_STREAM_ID, "Attempt to reset send control stream", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); +} + +void QuicSendControlStream::SendSettingsFrame(const SettingsFrame& settings) { + DCHECK(!settings_sent_); + std::unique_ptr<char[]> buffer; + QuicByteCount frame_length = + encoder_.SerializeSettingsFrame(settings, &buffer); + WriteOrBufferData(QuicStringPiece(buffer.get(), frame_length), + /*fin = */ false, nullptr); + settings_sent_ = true; +} + +} // namespace quic
diff --git a/quic/core/http/quic_send_control_stream.h b/quic/core/http/quic_send_control_stream.h new file mode 100644 index 0000000..09bdafb --- /dev/null +++ b/quic/core/http/quic_send_control_stream.h
@@ -0,0 +1,47 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_HTTP_QUIC_SEND_CONTROL_STREAM_H_ +#define QUICHE_QUIC_CORE_HTTP_QUIC_SEND_CONTROL_STREAM_H_ + +#include "net/third_party/quiche/src/quic/core/http/http_encoder.h" +#include "net/third_party/quiche/src/quic/core/quic_stream.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +class QuicSpdySession; + +// 3.2.1 Control Stream. +// The send control stream is self initiated and is write only. +class QUIC_EXPORT_PRIVATE QuicSendControlStream : public QuicStream { + public: + // |session| can't be nullptr, and the ownership is not passed. The stream can + // only be accessed through the session. + explicit QuicSendControlStream(QuicStreamId id, QuicSpdySession* session); + QuicSendControlStream(const QuicSendControlStream&) = delete; + QuicSendControlStream& operator=(const QuicSendControlStream&) = delete; + ~QuicSendControlStream() override = default; + + // Overriding QuicStream::OnStreamReset to make sure control stream is never + // closed before connection. + void OnStreamReset(const QuicRstStreamFrame& frame) override; + + // Send |settings| on this stream. + // Settings frame must be the first frame sent on this stream. + void SendSettingsFrame(const SettingsFrame& settings); + + // The send control stream is write unidirectional, so this method should + // never be called. + void OnDataAvailable() override { QUIC_NOTREACHED(); } + + private: + HttpEncoder encoder_; + // Track if a settings frame is already sent. + bool settings_sent_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_HTTP_QUIC_SEND_CONTROL_STREAM_H_
diff --git a/quic/core/http/quic_send_control_stream_test.cc b/quic/core/http/quic_send_control_stream_test.cc new file mode 100644 index 0000000..980cdf5 --- /dev/null +++ b/quic/core/http/quic_send_control_stream_test.cc
@@ -0,0 +1,124 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h" + +#include <cstdint> +#include <ostream> +#include <utility> +#include <vector> + +#include "net/third_party/quiche/src/quic/core/http/http_encoder.h" +#include "net/third_party/quiche/src/quic/core/http/spdy_utils.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +namespace quic { +namespace test { + +namespace { +using testing::_; +using testing::Invoke; +using testing::StrictMock; + +struct TestParams { + TestParams(const ParsedQuicVersion& version, Perspective perspective) + : version(version), perspective(perspective) { + QUIC_LOG(INFO) << "TestParams: version: " + << ParsedQuicVersionToString(version) + << ", perspective: " << perspective; + } + + TestParams(const TestParams& other) + : version(other.version), perspective(other.perspective) {} + + ParsedQuicVersion version; + Perspective perspective; +}; + +std::vector<TestParams> GetTestParams() { + std::vector<TestParams> params; + ParsedQuicVersionVector all_supported_versions = AllSupportedVersions(); + for (const auto& version : AllSupportedVersions()) { + if (!VersionHasControlStreams(version.transport_version)) { + continue; + } + for (Perspective p : {Perspective::IS_SERVER, Perspective::IS_CLIENT}) { + params.emplace_back(version, p); + } + } + return params; +} + +class QuicSendControlStreamTest : public QuicTestWithParam<TestParams> { + public: + QuicSendControlStreamTest() + : connection_(new StrictMock<MockQuicConnection>( + &helper_, + &alarm_factory_, + perspective(), + SupportedVersions(GetParam().version))), + session_(connection_) { + session_.Initialize(); + send_control_stream_ = QuicMakeUnique<QuicSendControlStream>( + QuicSpdySessionPeer::GetNextOutgoingUnidirectionalStreamId(&session_), + &session_); + ON_CALL(session_, WritevData(_, _, _, _, _)) + .WillByDefault(Invoke(MockQuicSession::ConsumeData)); + } + + Perspective perspective() const { return GetParam().perspective; } + + MockQuicConnectionHelper helper_; + MockAlarmFactory alarm_factory_; + StrictMock<MockQuicConnection>* connection_; + StrictMock<MockQuicSpdySession> session_; + HttpEncoder encoder_; + std::unique_ptr<QuicSendControlStream> send_control_stream_; +}; + +INSTANTIATE_TEST_SUITE_P(Tests, + QuicSendControlStreamTest, + ::testing::ValuesIn(GetTestParams())); + +TEST_P(QuicSendControlStreamTest, WriteSettingsOnStartUp) { + SettingsFrame settings; + settings.values[3] = 2; + settings.values[6] = 5; + std::unique_ptr<char[]> buffer; + QuicByteCount frame_length = + encoder_.SerializeSettingsFrame(settings, &buffer); + + EXPECT_CALL(session_, WritevData(_, _, frame_length, _, _)); + send_control_stream_->SendSettingsFrame(settings); +} + +TEST_P(QuicSendControlStreamTest, ResetControlStream) { + QuicRstStreamFrame rst_frame(kInvalidControlFrameId, + send_control_stream_->id(), + QUIC_STREAM_CANCELLED, 1234); + EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, _, _)); + send_control_stream_->OnStreamReset(rst_frame); +} + +TEST_P(QuicSendControlStreamTest, ReceiveDataOnSendControlStream) { + QuicStreamFrame frame(send_control_stream_->id(), false, 0, "test"); + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_DATA_RECEIVED_ON_WRITE_UNIDIRECTIONAL_STREAM, _, _)); + send_control_stream_->OnStreamFrame(frame); +} + +} // namespace +} // namespace test +} // namespace quic
diff --git a/quic/core/http/quic_spdy_session.h b/quic/core/http/quic_spdy_session.h index c968284..0ff1150 100644 --- a/quic/core/http/quic_spdy_session.h +++ b/quic/core/http/quic_spdy_session.h
@@ -158,6 +158,10 @@ max_inbound_header_list_size_ = max_inbound_header_list_size; } + size_t max_inbound_header_list_size() const { + return max_inbound_header_list_size_; + } + // Returns true if the session has active request streams. bool HasActiveRequestStreams() const;
diff --git a/quic/core/quic_versions.h b/quic/core/quic_versions.h index 2c78760..c270f95 100644 --- a/quic/core/quic_versions.h +++ b/quic/core/quic_versions.h
@@ -353,6 +353,12 @@ return transport_version == QUIC_VERSION_99; } +// Returns whether |transport_version| has HTTP/3 Control stream. +QUIC_EXPORT_PRIVATE inline bool VersionHasControlStreams( + QuicTransportVersion transport_version) { + return transport_version == QUIC_VERSION_99; +} + // Initializes support for the provided IETF draft version by setting flags // and the version label. QUIC_EXPORT_PRIVATE void QuicVersionInitializeSupportForIetfDraft(
diff --git a/quic/core/quic_write_blocked_list.h b/quic/core/quic_write_blocked_list.h index df6b27d..83c2e20 100644 --- a/quic/core/quic_write_blocked_list.h +++ b/quic/core/quic_write_blocked_list.h
@@ -189,9 +189,6 @@ // Add |id| to the collection in unblocked state. void Register(QuicStreamId id) { DCHECK(!IsRegistered(id)); - DCHECK(streams_.empty() || id > streams_.back().id) - << "stream_id: " << id - << " last static stream: " << streams_.back().id; streams_.push_back({id, false}); }
diff --git a/quic/test_tools/quic_spdy_session_peer.cc b/quic/test_tools/quic_spdy_session_peer.cc index b739fa1..dcba12c 100644 --- a/quic/test_tools/quic_spdy_session_peer.cc +++ b/quic/test_tools/quic_spdy_session_peer.cc
@@ -61,5 +61,11 @@ id, std::move(headers), fin, priority, std::move(ack_listener)); } +// static +QuicStreamId QuicSpdySessionPeer::GetNextOutgoingUnidirectionalStreamId( + QuicSpdySession* session) { + return session->GetNextOutgoingUnidirectionalStreamId(); +} + } // namespace test } // namespace quic
diff --git a/quic/test_tools/quic_spdy_session_peer.h b/quic/test_tools/quic_spdy_session_peer.h index 58a864d..83e8b0c 100644 --- a/quic/test_tools/quic_spdy_session_peer.h +++ b/quic/test_tools/quic_spdy_session_peer.h
@@ -41,6 +41,9 @@ bool fin, spdy::SpdyPriority priority, QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener); + // |session| can't be nullptr. + static QuicStreamId GetNextOutgoingUnidirectionalStreamId( + QuicSpdySession* session); }; } // namespace test