blob: 018867afb1d01d36b40c00ab51080897b41cdb88 [file] [log] [blame]
// Copyright 2025 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24
package http3
import (
"errors"
"math/bits"
)
type qpackDecoder struct {
// The decoder has no state for now,
// but that'll change once we add dynamic table support.
//
// TODO: dynamic table support.
}
func (qd *qpackDecoder) decode(st *stream, f func(itype indexType, name, value string) error) error {
// Encoded Field Section prefix.
// We set SETTINGS_QPACK_MAX_TABLE_CAPACITY to 0,
// so the Required Insert Count must be 0.
_, requiredInsertCount, err := st.readPrefixedInt(8)
if err != nil {
return err
}
if requiredInsertCount != 0 {
return errQPACKDecompressionFailed
}
// Delta Base. We don't use the dynamic table yet, so this may be ignored.
_, _, err = st.readPrefixedInt(7)
if err != nil {
return err
}
sawNonPseudo := false
for st.lim > 0 {
firstByte, err := st.ReadByte()
if err != nil {
return err
}
var name, value string
var itype indexType
switch bits.LeadingZeros8(firstByte) {
case 0:
// Indexed Field Line
itype, name, value, err = st.decodeIndexedFieldLine(firstByte)
case 1:
// Literal Field Line With Name Reference
itype, name, value, err = st.decodeLiteralFieldLineWithNameReference(firstByte)
case 2:
// Literal Field Line with Literal Name
itype, name, value, err = st.decodeLiteralFieldLineWithLiteralName(firstByte)
case 3:
// Indexed Field Line With Post-Base Index
err = errors.New("dynamic table is not supported yet")
case 4:
// Indexed Field Line With Post-Base Name Reference
err = errors.New("dynamic table is not supported yet")
}
if err != nil {
return err
}
if len(name) == 0 {
return errH3MessageError
}
if name[0] == ':' {
if sawNonPseudo {
return errH3MessageError
}
} else {
sawNonPseudo = true
}
if err := f(itype, name, value); err != nil {
return err
}
}
return nil
}