-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
internal/http3: QPACK encoding and decoding
Basic support for encoding/decoding QPACK headers. QPACK supports three forms of header compression: Huffman-encoding of literal strings, a static table of well-known header values, and a dynamic table of header values negotiated between encoder and decoder at runtime. Right now, we support Huffman compression and the static table, but not the dynamic table. This is a supported mode for a QPACK encoder or decoder, so we can leave dynamic table support for after the rest of HTTP/3 is working. For golang/go#70914 Change-Id: Ib694199b99c752a220d43f3a309169b16020b474 Reviewed-on: https://go-review.googlesource.com/c/net/+/642599 LUCI-TryBot-Result: Go LUCI <[email protected]> Auto-Submit: Damien Neil <[email protected]> Reviewed-by: Jonathan Amsterdam <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]>
- Loading branch information
Showing
8 changed files
with
795 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
// 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 | ||
} |
Oops, something went wrong.