Refactor QpackEncoder to do two-pass encoding. gfe-relnote: n/a, change in QUIC v99-only code. PiperOrigin-RevId: 258561443 Change-Id: If03ac2f76064d2b462646bcda07a9e6e98655482
diff --git a/quic/core/qpack/qpack_encoder.cc b/quic/core/qpack/qpack_encoder.cc index 412b7af..3ffe9d0 100644 --- a/quic/core/qpack/qpack_encoder.cc +++ b/quic/core/qpack/qpack_encoder.cc
@@ -4,7 +4,7 @@ #include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h" -#include <string> +#include <list> #include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h" #include "net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.h" @@ -29,18 +29,10 @@ std::string QpackEncoder::EncodeHeaderList( QuicStreamId /* stream_id */, const spdy::SpdyHeaderBlock* header_list) { - QpackInstructionEncoder instruction_encoder; - std::string encoded_headers; + // First pass. - // TODO(bnc): Implement dynamic entries and set Required Insert Count and - // Delta Base accordingly. - QpackInstructionEncoder::Values values; - values.varint = 0; - values.varint2 = 0; - values.s_bit = false; - - instruction_encoder.Encode(QpackPrefixInstruction(), values, - &encoded_headers); + // Encode into |instructions| which will be serialized during the second pass. + std::list<InstructionWithValues> instructions; for (const auto& header : ValueSplittingHeaderList(header_list)) { QuicStringPiece name = header.first; @@ -56,36 +48,50 @@ case QpackHeaderTable::MatchType::kNameAndValue: DCHECK(is_static) << "Dynamic table entries not supported yet."; - values.s_bit = is_static; - values.varint = index; - - instruction_encoder.Encode(QpackIndexedHeaderFieldInstruction(), values, - &encoded_headers); + instructions.push_back({QpackIndexedHeaderFieldInstruction(), {}}); + instructions.back().values.s_bit = is_static; + instructions.back().values.varint = index; break; case QpackHeaderTable::MatchType::kName: DCHECK(is_static) << "Dynamic table entries not supported yet."; - values.s_bit = is_static; - values.varint = index; - values.value = value; - - instruction_encoder.Encode( - QpackLiteralHeaderFieldNameReferenceInstruction(), values, - &encoded_headers); + instructions.push_back( + {QpackLiteralHeaderFieldNameReferenceInstruction(), {}}); + instructions.back().values.s_bit = is_static; + instructions.back().values.varint = index; + instructions.back().values.value = value; break; case QpackHeaderTable::MatchType::kNoMatch: - values.name = name; - values.value = value; - - instruction_encoder.Encode(QpackLiteralHeaderFieldInstruction(), values, - &encoded_headers); + instructions.push_back({QpackLiteralHeaderFieldInstruction(), {}}); + instructions.back().values.name = name; + instructions.back().values.value = value; break; } } + // Second pass. + QpackInstructionEncoder instruction_encoder; + std::string encoded_headers; + + // Header block prefix. + // TODO(bnc): Implement dynamic entries and set Required Insert Count and + // Delta Base accordingly. + QpackInstructionEncoder::Values values; + values.varint = 0; // Encoded required insert count. + values.varint2 = 0; // Delta Base. + values.s_bit = false; // Delta Base sign. + + instruction_encoder.Encode(QpackPrefixInstruction(), values, + &encoded_headers); + + for (const auto& instruction : instructions) { + instruction_encoder.Encode(instruction.instruction, instruction.values, + &encoded_headers); + } + return encoded_headers; }
diff --git a/quic/core/qpack/qpack_encoder.h b/quic/core/qpack/qpack_encoder.h index 7ed5808..39600e8 100644 --- a/quic/core/qpack/qpack_encoder.h +++ b/quic/core/qpack/qpack_encoder.h
@@ -56,6 +56,17 @@ void OnErrorDetected(QuicStringPiece error_message) override; private: + // TODO(bnc): Consider moving this class to QpackInstructionEncoder or + // qpack_constants, adding factory methods, one for each instruction, and + // changing QpackInstructionEncoder::Encoder() to take an + // InstructionWithValues struct instead of separate |instruction| and |values| + // arguments. + struct InstructionWithValues { + // |instruction| is not owned. + const QpackInstruction* instruction; + QpackInstructionEncoder::Values values; + }; + DecoderStreamErrorDelegate* const decoder_stream_error_delegate_; QpackDecoderStreamReceiver decoder_stream_receiver_; QpackEncoderStreamSender encoder_stream_sender_;