updated vendor
This commit is contained in:
+153
-35
@@ -11,11 +11,13 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/net/http/httpguts"
|
||||
"golang.org/x/net/http2/hpack"
|
||||
"golang.org/x/net/internal/httpsfv"
|
||||
)
|
||||
|
||||
const frameHeaderLen = 9
|
||||
@@ -23,33 +25,36 @@ const frameHeaderLen = 9
|
||||
var padZeros = make([]byte, 255) // zeros for padding
|
||||
|
||||
// A FrameType is a registered frame type as defined in
|
||||
// https://httpwg.org/specs/rfc7540.html#rfc.section.11.2
|
||||
// https://httpwg.org/specs/rfc7540.html#rfc.section.11.2 and other future
|
||||
// RFCs.
|
||||
type FrameType uint8
|
||||
|
||||
const (
|
||||
FrameData FrameType = 0x0
|
||||
FrameHeaders FrameType = 0x1
|
||||
FramePriority FrameType = 0x2
|
||||
FrameRSTStream FrameType = 0x3
|
||||
FrameSettings FrameType = 0x4
|
||||
FramePushPromise FrameType = 0x5
|
||||
FramePing FrameType = 0x6
|
||||
FrameGoAway FrameType = 0x7
|
||||
FrameWindowUpdate FrameType = 0x8
|
||||
FrameContinuation FrameType = 0x9
|
||||
FrameData FrameType = 0x0
|
||||
FrameHeaders FrameType = 0x1
|
||||
FramePriority FrameType = 0x2
|
||||
FrameRSTStream FrameType = 0x3
|
||||
FrameSettings FrameType = 0x4
|
||||
FramePushPromise FrameType = 0x5
|
||||
FramePing FrameType = 0x6
|
||||
FrameGoAway FrameType = 0x7
|
||||
FrameWindowUpdate FrameType = 0x8
|
||||
FrameContinuation FrameType = 0x9
|
||||
FramePriorityUpdate FrameType = 0x10
|
||||
)
|
||||
|
||||
var frameNames = [...]string{
|
||||
FrameData: "DATA",
|
||||
FrameHeaders: "HEADERS",
|
||||
FramePriority: "PRIORITY",
|
||||
FrameRSTStream: "RST_STREAM",
|
||||
FrameSettings: "SETTINGS",
|
||||
FramePushPromise: "PUSH_PROMISE",
|
||||
FramePing: "PING",
|
||||
FrameGoAway: "GOAWAY",
|
||||
FrameWindowUpdate: "WINDOW_UPDATE",
|
||||
FrameContinuation: "CONTINUATION",
|
||||
FrameData: "DATA",
|
||||
FrameHeaders: "HEADERS",
|
||||
FramePriority: "PRIORITY",
|
||||
FrameRSTStream: "RST_STREAM",
|
||||
FrameSettings: "SETTINGS",
|
||||
FramePushPromise: "PUSH_PROMISE",
|
||||
FramePing: "PING",
|
||||
FrameGoAway: "GOAWAY",
|
||||
FrameWindowUpdate: "WINDOW_UPDATE",
|
||||
FrameContinuation: "CONTINUATION",
|
||||
FramePriorityUpdate: "PRIORITY_UPDATE",
|
||||
}
|
||||
|
||||
func (t FrameType) String() string {
|
||||
@@ -125,21 +130,24 @@ var flagName = map[FrameType]map[Flags]string{
|
||||
type frameParser func(fc *frameCache, fh FrameHeader, countError func(string), payload []byte) (Frame, error)
|
||||
|
||||
var frameParsers = [...]frameParser{
|
||||
FrameData: parseDataFrame,
|
||||
FrameHeaders: parseHeadersFrame,
|
||||
FramePriority: parsePriorityFrame,
|
||||
FrameRSTStream: parseRSTStreamFrame,
|
||||
FrameSettings: parseSettingsFrame,
|
||||
FramePushPromise: parsePushPromise,
|
||||
FramePing: parsePingFrame,
|
||||
FrameGoAway: parseGoAwayFrame,
|
||||
FrameWindowUpdate: parseWindowUpdateFrame,
|
||||
FrameContinuation: parseContinuationFrame,
|
||||
FrameData: parseDataFrame,
|
||||
FrameHeaders: parseHeadersFrame,
|
||||
FramePriority: parsePriorityFrame,
|
||||
FrameRSTStream: parseRSTStreamFrame,
|
||||
FrameSettings: parseSettingsFrame,
|
||||
FramePushPromise: parsePushPromise,
|
||||
FramePing: parsePingFrame,
|
||||
FrameGoAway: parseGoAwayFrame,
|
||||
FrameWindowUpdate: parseWindowUpdateFrame,
|
||||
FrameContinuation: parseContinuationFrame,
|
||||
FramePriorityUpdate: parsePriorityUpdateFrame,
|
||||
}
|
||||
|
||||
func typeFrameParser(t FrameType) frameParser {
|
||||
if int(t) < len(frameParsers) {
|
||||
return frameParsers[t]
|
||||
if f := frameParsers[t]; f != nil {
|
||||
return f
|
||||
}
|
||||
}
|
||||
return parseUnknownFrame
|
||||
}
|
||||
@@ -1180,9 +1188,34 @@ type PriorityFrame struct {
|
||||
PriorityParam
|
||||
}
|
||||
|
||||
var defaultRFC9218Priority = PriorityParam{
|
||||
incremental: 0,
|
||||
urgency: 3,
|
||||
// defaultRFC9218Priority determines what priority we should use as the default
|
||||
// value.
|
||||
//
|
||||
// According to RFC 9218, by default, streams should be given an urgency of 3
|
||||
// and should be non-incremental. However, making streams non-incremental by
|
||||
// default would be a huge change to our historical behavior where we would
|
||||
// round-robin writes across streams. When streams are non-incremental, we
|
||||
// would process streams of the same urgency one-by-one to completion instead.
|
||||
//
|
||||
// To avoid such a sudden change which might break some HTTP/2 users, this
|
||||
// function allows the caller to specify whether they can actually use the
|
||||
// default value as specified in RFC 9218. If not, this function will return a
|
||||
// priority value where streams are incremental by default instead: effectively
|
||||
// a round-robin between stream of the same urgency.
|
||||
//
|
||||
// As an example, a server might not be able to use the RFC 9218 default value
|
||||
// when it's not sure that the client it is serving is aware of RFC 9218.
|
||||
func defaultRFC9218Priority(canUseDefault bool) PriorityParam {
|
||||
if canUseDefault {
|
||||
return PriorityParam{
|
||||
urgency: 3,
|
||||
incremental: 0,
|
||||
}
|
||||
}
|
||||
return PriorityParam{
|
||||
urgency: 3,
|
||||
incremental: 1,
|
||||
}
|
||||
}
|
||||
|
||||
// Note that HTTP/2 has had two different prioritization schemes, and
|
||||
@@ -1266,6 +1299,74 @@ func (f *Framer) WritePriority(streamID uint32, p PriorityParam) error {
|
||||
return f.endWrite()
|
||||
}
|
||||
|
||||
// PriorityUpdateFrame is a PRIORITY_UPDATE frame as described in
|
||||
// https://www.rfc-editor.org/rfc/rfc9218.html#name-the-priority_update-frame.
|
||||
type PriorityUpdateFrame struct {
|
||||
FrameHeader
|
||||
Priority string
|
||||
PrioritizedStreamID uint32
|
||||
}
|
||||
|
||||
func parseRFC9218Priority(s string, canUseDefault bool) (p PriorityParam, ok bool) {
|
||||
p = defaultRFC9218Priority(canUseDefault)
|
||||
ok = httpsfv.ParseDictionary(s, func(key, val, _ string) {
|
||||
switch key {
|
||||
case "u":
|
||||
if u, ok := httpsfv.ParseInteger(val); ok && u >= 0 && u <= 7 {
|
||||
p.urgency = uint8(u)
|
||||
}
|
||||
case "i":
|
||||
if i, ok := httpsfv.ParseBoolean(val); ok {
|
||||
if i {
|
||||
p.incremental = 1
|
||||
} else {
|
||||
p.incremental = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
if !ok {
|
||||
return defaultRFC9218Priority(canUseDefault), ok
|
||||
}
|
||||
return p, true
|
||||
}
|
||||
|
||||
func parsePriorityUpdateFrame(_ *frameCache, fh FrameHeader, countError func(string), payload []byte) (Frame, error) {
|
||||
if fh.StreamID != 0 {
|
||||
countError("frame_priority_update_non_zero_stream")
|
||||
return nil, connError{ErrCodeProtocol, "PRIORITY_UPDATE frame with non-zero stream ID"}
|
||||
}
|
||||
if len(payload) < 4 {
|
||||
countError("frame_priority_update_bad_length")
|
||||
return nil, connError{ErrCodeFrameSize, fmt.Sprintf("PRIORITY_UPDATE frame payload size was %d; want at least 4", len(payload))}
|
||||
}
|
||||
v := binary.BigEndian.Uint32(payload[:4])
|
||||
streamID := v & 0x7fffffff // mask off high bit
|
||||
if streamID == 0 {
|
||||
countError("frame_priority_update_prioritizing_zero_stream")
|
||||
return nil, connError{ErrCodeProtocol, "PRIORITY_UPDATE frame with prioritized stream ID of zero"}
|
||||
}
|
||||
return &PriorityUpdateFrame{
|
||||
FrameHeader: fh,
|
||||
PrioritizedStreamID: streamID,
|
||||
Priority: string(payload[4:]),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// WritePriorityUpdate writes a PRIORITY_UPDATE frame.
|
||||
//
|
||||
// It will perform exactly one Write to the underlying Writer.
|
||||
// It is the caller's responsibility to not call other Write methods concurrently.
|
||||
func (f *Framer) WritePriorityUpdate(streamID uint32, priority string) error {
|
||||
if !validStreamID(streamID) && !f.AllowIllegalWrites {
|
||||
return errStreamID
|
||||
}
|
||||
f.startWrite(FramePriorityUpdate, 0, 0)
|
||||
f.writeUint32(streamID)
|
||||
f.writeBytes([]byte(priority))
|
||||
return f.endWrite()
|
||||
}
|
||||
|
||||
// A RSTStreamFrame allows for abnormal termination of a stream.
|
||||
// See https://httpwg.org/specs/rfc7540.html#rfc.section.6.4
|
||||
type RSTStreamFrame struct {
|
||||
@@ -1547,6 +1648,23 @@ func (mh *MetaHeadersFrame) PseudoFields() []hpack.HeaderField {
|
||||
return mh.Fields
|
||||
}
|
||||
|
||||
func (mh *MetaHeadersFrame) rfc9218Priority(priorityAware bool) (p PriorityParam, priorityAwareAfter, hasIntermediary bool) {
|
||||
var s string
|
||||
for _, field := range mh.Fields {
|
||||
if field.Name == "priority" {
|
||||
s = field.Value
|
||||
priorityAware = true
|
||||
}
|
||||
if slices.Contains([]string{"via", "forwarded", "x-forwarded-for"}, field.Name) {
|
||||
hasIntermediary = true
|
||||
}
|
||||
}
|
||||
// No need to check for ok. parseRFC9218Priority will return a default
|
||||
// value if there is no priority field or if the field cannot be parsed.
|
||||
p, _ = parseRFC9218Priority(s, priorityAware && !hasIntermediary)
|
||||
return p, priorityAware, hasIntermediary
|
||||
}
|
||||
|
||||
func (mh *MetaHeadersFrame) checkPseudos() error {
|
||||
var isRequest, isResponse bool
|
||||
pf := mh.PseudoFields()
|
||||
|
||||
Reference in New Issue
Block a user