Introduce HttpDecoder::DecodeSettings(). In IETF QUIC, the client will cache a serialized SETTINGS frame (done in QuicSpdyClientSessionBase::OnSettingsFrame). Later when 0-rtt is attempted, the client session needs to decode the settings and apply to itself. Unused code. not protected. PiperOrigin-RevId: 310039639 Change-Id: I634670c019286ebe24e20f86b44da5a834e82066
diff --git a/quic/core/http/http_decoder.cc b/quic/core/http/http_decoder.cc index 87f9919..7c3b81b 100644 --- a/quic/core/http/http_decoder.cc +++ b/quic/core/http/http_decoder.cc
@@ -11,6 +11,7 @@ #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" #include "net/third_party/quiche/src/quic/platform/api/quic_fallthrough.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" namespace quic { @@ -34,6 +35,55 @@ HttpDecoder::~HttpDecoder() {} +// static +bool HttpDecoder::DecodeSettings(const char* data, + QuicByteCount len, + SettingsFrame* frame) { + QuicDataReader reader(data, len); + uint64_t frame_type; + if (!reader.ReadVarInt62(&frame_type)) { + QUIC_DLOG(ERROR) << "Unable to read frame type."; + return false; + } + + if (frame_type != static_cast<uint64_t>(HttpFrameType::SETTINGS)) { + QUIC_DLOG(ERROR) << "Invalid frame type " << frame_type; + return false; + } + uint64_t frame_length; + if (!reader.ReadVarInt62(&frame_length)) { + QUIC_DLOG(ERROR) << "Unable to read frame length."; + return false; + } + + std::string buffer; + if (!reader.ReadBytes(buffer.data(), frame_length)) { + QUIC_DLOG(ERROR) << "Unable to read frame payload."; + return false; + } + + QuicDataReader frame_reader(buffer.data(), frame_length); + + while (!frame_reader.IsDoneReading()) { + uint64_t id; + if (!frame_reader.ReadVarInt62(&id)) { + QUIC_DLOG(ERROR) << "Unable to read setting identifier."; + return false; + } + uint64_t content; + if (!frame_reader.ReadVarInt62(&content)) { + QUIC_DLOG(ERROR) << "Unable to read setting value."; + return false; + } + auto result = frame->values.insert({id, content}); + if (!result.second) { + QUIC_DLOG(ERROR) << "Duplicate setting identifier."; + return false; + } + } + return true; +} + QuicByteCount HttpDecoder::ProcessInput(const char* data, QuicByteCount len) { DCHECK_EQ(QUIC_NO_ERROR, error_); DCHECK_NE(STATE_ERROR, state_);
diff --git a/quic/core/http/http_decoder.h b/quic/core/http/http_decoder.h index 3650bef..1551aa7 100644 --- a/quic/core/http/http_decoder.h +++ b/quic/core/http/http_decoder.h
@@ -131,6 +131,13 @@ // occurred. QuicByteCount ProcessInput(const char* data, QuicByteCount len); + // Decode settings frame from |data|. + // Upon successful decoding, |frame| will be populated, and returns true. + // This method is not used for regular processing of incoming data. + static bool DecodeSettings(const char* data, + QuicByteCount len, + SettingsFrame* frame); + // Returns an error code other than QUIC_NO_ERROR if and only if // Visitor::OnError() has been called. QuicErrorCode error() const { return error_; }
diff --git a/quic/core/http/http_decoder_test.cc b/quic/core/http/http_decoder_test.cc index 27f0990..86a1b69 100644 --- a/quic/core/http/http_decoder_test.cc +++ b/quic/core/http/http_decoder_test.cc
@@ -1072,6 +1072,43 @@ } } +TEST_F(HttpDecoderTest, DecodeSettings) { + std::string input = quiche::QuicheTextUtils::HexDecode( + "04" // type (SETTINGS) + "07" // length + "01" // identifier (SETTINGS_QPACK_MAX_TABLE_CAPACITY) + "02" // content + "06" // identifier (SETTINGS_MAX_HEADER_LIST_SIZE) + "05" // content + "4100" // identifier, encoded on 2 bytes (0x40), value is 256 (0x100) + "04"); // content + + SettingsFrame frame; + frame.values[1] = 2; + frame.values[6] = 5; + frame.values[256] = 4; + + SettingsFrame out; + EXPECT_TRUE(HttpDecoder::DecodeSettings(input.data(), input.size(), &out)); + EXPECT_EQ(frame, out); + + // non-settings frame. + input = quiche::QuicheTextUtils::HexDecode( + "0D" // type (MAX_PUSH_ID) + "01" // length + "01"); // Push Id + + EXPECT_FALSE(HttpDecoder::DecodeSettings(input.data(), input.size(), &out)); + + // Corrupt SETTINGS. + input = quiche::QuicheTextUtils::HexDecode( + "04" // type (SETTINGS) + "01" // length + "42"); // First byte of setting identifier, indicating a 2-byte varint62. + + EXPECT_FALSE(HttpDecoder::DecodeSettings(input.data(), input.size(), &out)); +} + } // namespace test } // namespace quic