chore: migrate to gitea
This commit is contained in:
183
vendor/github.com/quic-go/qpack/decoder.go
generated
vendored
Normal file
183
vendor/github.com/quic-go/qpack/decoder.go
generated
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
package qpack
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"golang.org/x/net/http2/hpack"
|
||||
)
|
||||
|
||||
// An invalidIndexError is returned when decoding encounters an invalid index
|
||||
// (e.g., an index that is out of bounds for the static table).
|
||||
type invalidIndexError int
|
||||
|
||||
func (e invalidIndexError) Error() string {
|
||||
return fmt.Sprintf("invalid indexed representation index %d", int(e))
|
||||
}
|
||||
|
||||
var errNoDynamicTable = errors.New("no dynamic table")
|
||||
|
||||
// A Decoder decodes QPACK header blocks.
|
||||
// A Decoder can be reused to decode multiple header blocks on different streams
|
||||
// on the same connection (e.g., headers then trailers).
|
||||
// This will be useful when dynamic table support is added.
|
||||
type Decoder struct{}
|
||||
|
||||
// DecodeFunc is a function that decodes the next header field from a header block.
|
||||
// It should be called repeatedly until it returns io.EOF.
|
||||
// It returns io.EOF when all header fields have been decoded.
|
||||
// Any error other than io.EOF indicates a decoding error.
|
||||
type DecodeFunc func() (HeaderField, error)
|
||||
|
||||
// NewDecoder returns a new Decoder.
|
||||
func NewDecoder() *Decoder {
|
||||
return &Decoder{}
|
||||
}
|
||||
|
||||
// Decode returns a function that decodes header fields from the given header block.
|
||||
// It does not copy the slice; the caller must ensure it remains valid during decoding.
|
||||
func (d *Decoder) Decode(p []byte) DecodeFunc {
|
||||
var readRequiredInsertCount bool
|
||||
var readDeltaBase bool
|
||||
|
||||
return func() (HeaderField, error) {
|
||||
if !readRequiredInsertCount {
|
||||
requiredInsertCount, rest, err := readVarInt(8, p)
|
||||
if err != nil {
|
||||
return HeaderField{}, err
|
||||
}
|
||||
p = rest
|
||||
readRequiredInsertCount = true
|
||||
if requiredInsertCount != 0 {
|
||||
return HeaderField{}, errors.New("expected Required Insert Count to be zero")
|
||||
}
|
||||
}
|
||||
|
||||
if !readDeltaBase {
|
||||
base, rest, err := readVarInt(7, p)
|
||||
if err != nil {
|
||||
return HeaderField{}, err
|
||||
}
|
||||
p = rest
|
||||
readDeltaBase = true
|
||||
if base != 0 {
|
||||
return HeaderField{}, errors.New("expected Base to be zero")
|
||||
}
|
||||
}
|
||||
|
||||
if len(p) == 0 {
|
||||
return HeaderField{}, io.EOF
|
||||
}
|
||||
|
||||
b := p[0]
|
||||
var hf HeaderField
|
||||
var rest []byte
|
||||
var err error
|
||||
switch {
|
||||
case (b & 0x80) > 0: // 1xxxxxxx
|
||||
hf, rest, err = d.parseIndexedHeaderField(p)
|
||||
case (b & 0xc0) == 0x40: // 01xxxxxx
|
||||
hf, rest, err = d.parseLiteralHeaderField(p)
|
||||
case (b & 0xe0) == 0x20: // 001xxxxx
|
||||
hf, rest, err = d.parseLiteralHeaderFieldWithoutNameReference(p)
|
||||
default:
|
||||
err = fmt.Errorf("unexpected type byte: %#x", b)
|
||||
}
|
||||
p = rest
|
||||
if err != nil {
|
||||
return HeaderField{}, err
|
||||
}
|
||||
return hf, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Decoder) parseIndexedHeaderField(buf []byte) (_ HeaderField, rest []byte, _ error) {
|
||||
if buf[0]&0x40 == 0 {
|
||||
return HeaderField{}, buf, errNoDynamicTable
|
||||
}
|
||||
index, rest, err := readVarInt(6, buf)
|
||||
if err != nil {
|
||||
return HeaderField{}, buf, err
|
||||
}
|
||||
hf, ok := d.at(index)
|
||||
if !ok {
|
||||
return HeaderField{}, buf, invalidIndexError(index)
|
||||
}
|
||||
return hf, rest, nil
|
||||
}
|
||||
|
||||
func (d *Decoder) parseLiteralHeaderField(buf []byte) (_ HeaderField, rest []byte, _ error) {
|
||||
if buf[0]&0x10 == 0 {
|
||||
return HeaderField{}, buf, errNoDynamicTable
|
||||
}
|
||||
// We don't need to check the value of the N-bit here.
|
||||
// It's only relevant when re-encoding header fields,
|
||||
// and determines whether the header field can be added to the dynamic table.
|
||||
// Since we don't support the dynamic table, we can ignore it.
|
||||
index, rest, err := readVarInt(4, buf)
|
||||
if err != nil {
|
||||
return HeaderField{}, buf, err
|
||||
}
|
||||
hf, ok := d.at(index)
|
||||
if !ok {
|
||||
return HeaderField{}, buf, invalidIndexError(index)
|
||||
}
|
||||
buf = rest
|
||||
if len(buf) == 0 {
|
||||
return HeaderField{}, buf, io.ErrUnexpectedEOF
|
||||
}
|
||||
usesHuffman := buf[0]&0x80 > 0
|
||||
val, rest, err := d.readString(rest, 7, usesHuffman)
|
||||
if err != nil {
|
||||
return HeaderField{}, rest, err
|
||||
}
|
||||
hf.Value = val
|
||||
return hf, rest, nil
|
||||
}
|
||||
|
||||
func (d *Decoder) parseLiteralHeaderFieldWithoutNameReference(buf []byte) (_ HeaderField, rest []byte, _ error) {
|
||||
usesHuffmanForName := buf[0]&0x8 > 0
|
||||
name, rest, err := d.readString(buf, 3, usesHuffmanForName)
|
||||
if err != nil {
|
||||
return HeaderField{}, rest, err
|
||||
}
|
||||
buf = rest
|
||||
if len(buf) == 0 {
|
||||
return HeaderField{}, rest, io.ErrUnexpectedEOF
|
||||
}
|
||||
usesHuffmanForVal := buf[0]&0x80 > 0
|
||||
val, rest, err := d.readString(buf, 7, usesHuffmanForVal)
|
||||
if err != nil {
|
||||
return HeaderField{}, rest, err
|
||||
}
|
||||
return HeaderField{Name: name, Value: val}, rest, nil
|
||||
}
|
||||
|
||||
func (d *Decoder) readString(buf []byte, n uint8, usesHuffman bool) (string, []byte, error) {
|
||||
l, buf, err := readVarInt(n, buf)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if uint64(len(buf)) < l {
|
||||
return "", nil, io.ErrUnexpectedEOF
|
||||
}
|
||||
var val string
|
||||
if usesHuffman {
|
||||
val, err = hpack.HuffmanDecodeToString(buf[:l])
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
} else {
|
||||
val = string(buf[:l])
|
||||
}
|
||||
buf = buf[l:]
|
||||
return val, buf, nil
|
||||
}
|
||||
|
||||
func (d *Decoder) at(i uint64) (hf HeaderField, ok bool) {
|
||||
if i >= uint64(len(staticTableEntries)) {
|
||||
return
|
||||
}
|
||||
return staticTableEntries[i], true
|
||||
}
|
||||
Reference in New Issue
Block a user