Update the kubernetes api to latest
Signed-off-by: Mrunal Patel <mrunalp@gmail.com>
This commit is contained in:
parent
f5f2ff63b2
commit
303a3929b2
56 changed files with 6885 additions and 2610 deletions
437
vendor/golang.org/x/net/http2/frame.go
generated
vendored
437
vendor/golang.org/x/net/http2/frame.go
generated
vendored
|
@ -10,7 +10,12 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/net/http2/hpack"
|
||||
"golang.org/x/net/lex/httplex"
|
||||
)
|
||||
|
||||
const frameHeaderLen = 9
|
||||
|
@ -171,6 +176,12 @@ func (h FrameHeader) Header() FrameHeader { return h }
|
|||
func (h FrameHeader) String() string {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString("[FrameHeader ")
|
||||
h.writeDebug(&buf)
|
||||
buf.WriteByte(']')
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func (h FrameHeader) writeDebug(buf *bytes.Buffer) {
|
||||
buf.WriteString(h.Type.String())
|
||||
if h.Flags != 0 {
|
||||
buf.WriteString(" flags=")
|
||||
|
@ -187,15 +198,14 @@ func (h FrameHeader) String() string {
|
|||
if name != "" {
|
||||
buf.WriteString(name)
|
||||
} else {
|
||||
fmt.Fprintf(&buf, "0x%x", 1<<i)
|
||||
fmt.Fprintf(buf, "0x%x", 1<<i)
|
||||
}
|
||||
}
|
||||
}
|
||||
if h.StreamID != 0 {
|
||||
fmt.Fprintf(&buf, " stream=%d", h.StreamID)
|
||||
fmt.Fprintf(buf, " stream=%d", h.StreamID)
|
||||
}
|
||||
fmt.Fprintf(&buf, " len=%d]", h.Length)
|
||||
return buf.String()
|
||||
fmt.Fprintf(buf, " len=%d", h.Length)
|
||||
}
|
||||
|
||||
func (h *FrameHeader) checkValid() {
|
||||
|
@ -255,6 +265,11 @@ type Frame interface {
|
|||
type Framer struct {
|
||||
r io.Reader
|
||||
lastFrame Frame
|
||||
errDetail error
|
||||
|
||||
// lastHeaderStream is non-zero if the last frame was an
|
||||
// unfinished HEADERS/CONTINUATION.
|
||||
lastHeaderStream uint32
|
||||
|
||||
maxReadSize uint32
|
||||
headerBuf [frameHeaderLen]byte
|
||||
|
@ -271,18 +286,48 @@ type Framer struct {
|
|||
wbuf []byte
|
||||
|
||||
// AllowIllegalWrites permits the Framer's Write methods to
|
||||
// write frames that do not conform to the HTTP/2 spec. This
|
||||
// write frames that do not conform to the HTTP/2 spec. This
|
||||
// permits using the Framer to test other HTTP/2
|
||||
// implementations' conformance to the spec.
|
||||
// If false, the Write methods will prefer to return an error
|
||||
// rather than comply.
|
||||
AllowIllegalWrites bool
|
||||
|
||||
// AllowIllegalReads permits the Framer's ReadFrame method
|
||||
// to return non-compliant frames or frame orders.
|
||||
// This is for testing and permits using the Framer to test
|
||||
// other HTTP/2 implementations' conformance to the spec.
|
||||
// It is not compatible with ReadMetaHeaders.
|
||||
AllowIllegalReads bool
|
||||
|
||||
// ReadMetaHeaders if non-nil causes ReadFrame to merge
|
||||
// HEADERS and CONTINUATION frames together and return
|
||||
// MetaHeadersFrame instead.
|
||||
ReadMetaHeaders *hpack.Decoder
|
||||
|
||||
// MaxHeaderListSize is the http2 MAX_HEADER_LIST_SIZE.
|
||||
// It's used only if ReadMetaHeaders is set; 0 means a sane default
|
||||
// (currently 16MB)
|
||||
// If the limit is hit, MetaHeadersFrame.Truncated is set true.
|
||||
MaxHeaderListSize uint32
|
||||
|
||||
// TODO: track which type of frame & with which flags was sent
|
||||
// last. Then return an error (unless AllowIllegalWrites) if
|
||||
// we're in the middle of a header block and a
|
||||
// non-Continuation or Continuation on a different stream is
|
||||
// attempted to be written.
|
||||
|
||||
logReads bool
|
||||
|
||||
debugFramer *Framer // only use for logging written writes
|
||||
debugFramerBuf *bytes.Buffer
|
||||
}
|
||||
|
||||
func (fr *Framer) maxHeaderListSize() uint32 {
|
||||
if fr.MaxHeaderListSize == 0 {
|
||||
return 16 << 20 // sane default, per docs
|
||||
}
|
||||
return fr.MaxHeaderListSize
|
||||
}
|
||||
|
||||
func (f *Framer) startWrite(ftype FrameType, flags Flags, streamID uint32) {
|
||||
|
@ -310,6 +355,10 @@ func (f *Framer) endWrite() error {
|
|||
byte(length>>16),
|
||||
byte(length>>8),
|
||||
byte(length))
|
||||
if logFrameWrites {
|
||||
f.logWrite()
|
||||
}
|
||||
|
||||
n, err := f.w.Write(f.wbuf)
|
||||
if err == nil && n != len(f.wbuf) {
|
||||
err = io.ErrShortWrite
|
||||
|
@ -317,6 +366,24 @@ func (f *Framer) endWrite() error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (f *Framer) logWrite() {
|
||||
if f.debugFramer == nil {
|
||||
f.debugFramerBuf = new(bytes.Buffer)
|
||||
f.debugFramer = NewFramer(nil, f.debugFramerBuf)
|
||||
f.debugFramer.logReads = false // we log it ourselves, saying "wrote" below
|
||||
// Let us read anything, even if we accidentally wrote it
|
||||
// in the wrong order:
|
||||
f.debugFramer.AllowIllegalReads = true
|
||||
}
|
||||
f.debugFramerBuf.Write(f.wbuf)
|
||||
fr, err := f.debugFramer.ReadFrame()
|
||||
if err != nil {
|
||||
log.Printf("http2: Framer %p: failed to decode just-written frame", f)
|
||||
return
|
||||
}
|
||||
log.Printf("http2: Framer %p: wrote %v", f, summarizeFrame(fr))
|
||||
}
|
||||
|
||||
func (f *Framer) writeByte(v byte) { f.wbuf = append(f.wbuf, v) }
|
||||
func (f *Framer) writeBytes(v []byte) { f.wbuf = append(f.wbuf, v...) }
|
||||
func (f *Framer) writeUint16(v uint16) { f.wbuf = append(f.wbuf, byte(v>>8), byte(v)) }
|
||||
|
@ -332,8 +399,9 @@ const (
|
|||
// NewFramer returns a Framer that writes frames to w and reads them from r.
|
||||
func NewFramer(w io.Writer, r io.Reader) *Framer {
|
||||
fr := &Framer{
|
||||
w: w,
|
||||
r: r,
|
||||
w: w,
|
||||
r: r,
|
||||
logReads: logFrameReads,
|
||||
}
|
||||
fr.getReadBuf = func(size uint32) []byte {
|
||||
if cap(fr.readBuf) >= int(size) {
|
||||
|
@ -357,15 +425,39 @@ func (fr *Framer) SetMaxReadFrameSize(v uint32) {
|
|||
fr.maxReadSize = v
|
||||
}
|
||||
|
||||
// ErrorDetail returns a more detailed error of the last error
|
||||
// returned by Framer.ReadFrame. For instance, if ReadFrame
|
||||
// returns a StreamError with code PROTOCOL_ERROR, ErrorDetail
|
||||
// will say exactly what was invalid. ErrorDetail is not guaranteed
|
||||
// to return a non-nil value and like the rest of the http2 package,
|
||||
// its return value is not protected by an API compatibility promise.
|
||||
// ErrorDetail is reset after the next call to ReadFrame.
|
||||
func (fr *Framer) ErrorDetail() error {
|
||||
return fr.errDetail
|
||||
}
|
||||
|
||||
// ErrFrameTooLarge is returned from Framer.ReadFrame when the peer
|
||||
// sends a frame that is larger than declared with SetMaxReadFrameSize.
|
||||
var ErrFrameTooLarge = errors.New("http2: frame too large")
|
||||
|
||||
// terminalReadFrameError reports whether err is an unrecoverable
|
||||
// error from ReadFrame and no other frames should be read.
|
||||
func terminalReadFrameError(err error) bool {
|
||||
if _, ok := err.(StreamError); ok {
|
||||
return false
|
||||
}
|
||||
return err != nil
|
||||
}
|
||||
|
||||
// ReadFrame reads a single frame. The returned Frame is only valid
|
||||
// until the next call to ReadFrame.
|
||||
// If the frame is larger than previously set with SetMaxReadFrameSize,
|
||||
// the returned error is ErrFrameTooLarge.
|
||||
//
|
||||
// If the frame is larger than previously set with SetMaxReadFrameSize, the
|
||||
// returned error is ErrFrameTooLarge. Other errors may be of type
|
||||
// ConnectionError, StreamError, or anything else from the underlying
|
||||
// reader.
|
||||
func (fr *Framer) ReadFrame() (Frame, error) {
|
||||
fr.errDetail = nil
|
||||
if fr.lastFrame != nil {
|
||||
fr.lastFrame.invalidate()
|
||||
}
|
||||
|
@ -382,12 +474,71 @@ func (fr *Framer) ReadFrame() (Frame, error) {
|
|||
}
|
||||
f, err := typeFrameParser(fh.Type)(fh, payload)
|
||||
if err != nil {
|
||||
if ce, ok := err.(connError); ok {
|
||||
return nil, fr.connError(ce.Code, ce.Reason)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
fr.lastFrame = f
|
||||
if err := fr.checkFrameOrder(f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if fr.logReads {
|
||||
log.Printf("http2: Framer %p: read %v", fr, summarizeFrame(f))
|
||||
}
|
||||
if fh.Type == FrameHeaders && fr.ReadMetaHeaders != nil {
|
||||
return fr.readMetaFrame(f.(*HeadersFrame))
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// connError returns ConnectionError(code) but first
|
||||
// stashes away a public reason to the caller can optionally relay it
|
||||
// to the peer before hanging up on them. This might help others debug
|
||||
// their implementations.
|
||||
func (fr *Framer) connError(code ErrCode, reason string) error {
|
||||
fr.errDetail = errors.New(reason)
|
||||
return ConnectionError(code)
|
||||
}
|
||||
|
||||
// checkFrameOrder reports an error if f is an invalid frame to return
|
||||
// next from ReadFrame. Mostly it checks whether HEADERS and
|
||||
// CONTINUATION frames are contiguous.
|
||||
func (fr *Framer) checkFrameOrder(f Frame) error {
|
||||
last := fr.lastFrame
|
||||
fr.lastFrame = f
|
||||
if fr.AllowIllegalReads {
|
||||
return nil
|
||||
}
|
||||
|
||||
fh := f.Header()
|
||||
if fr.lastHeaderStream != 0 {
|
||||
if fh.Type != FrameContinuation {
|
||||
return fr.connError(ErrCodeProtocol,
|
||||
fmt.Sprintf("got %s for stream %d; expected CONTINUATION following %s for stream %d",
|
||||
fh.Type, fh.StreamID,
|
||||
last.Header().Type, fr.lastHeaderStream))
|
||||
}
|
||||
if fh.StreamID != fr.lastHeaderStream {
|
||||
return fr.connError(ErrCodeProtocol,
|
||||
fmt.Sprintf("got CONTINUATION for stream %d; expected stream %d",
|
||||
fh.StreamID, fr.lastHeaderStream))
|
||||
}
|
||||
} else if fh.Type == FrameContinuation {
|
||||
return fr.connError(ErrCodeProtocol, fmt.Sprintf("unexpected CONTINUATION for stream %d", fh.StreamID))
|
||||
}
|
||||
|
||||
switch fh.Type {
|
||||
case FrameHeaders, FrameContinuation:
|
||||
if fh.Flags.Has(FlagHeadersEndHeaders) {
|
||||
fr.lastHeaderStream = 0
|
||||
} else {
|
||||
fr.lastHeaderStream = fh.StreamID
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// A DataFrame conveys arbitrary, variable-length sequences of octets
|
||||
// associated with a stream.
|
||||
// See http://http2.github.io/http2-spec/#rfc.section.6.1
|
||||
|
@ -416,7 +567,7 @@ func parseDataFrame(fh FrameHeader, payload []byte) (Frame, error) {
|
|||
// field is 0x0, the recipient MUST respond with a
|
||||
// connection error (Section 5.4.1) of type
|
||||
// PROTOCOL_ERROR.
|
||||
return nil, ConnectionError(ErrCodeProtocol)
|
||||
return nil, connError{ErrCodeProtocol, "DATA frame with stream ID 0"}
|
||||
}
|
||||
f := &DataFrame{
|
||||
FrameHeader: fh,
|
||||
|
@ -434,13 +585,20 @@ func parseDataFrame(fh FrameHeader, payload []byte) (Frame, error) {
|
|||
// length of the frame payload, the recipient MUST
|
||||
// treat this as a connection error.
|
||||
// Filed: https://github.com/http2/http2-spec/issues/610
|
||||
return nil, ConnectionError(ErrCodeProtocol)
|
||||
return nil, connError{ErrCodeProtocol, "pad size larger than data payload"}
|
||||
}
|
||||
f.data = payload[:len(payload)-int(padSize)]
|
||||
return f, nil
|
||||
}
|
||||
|
||||
var errStreamID = errors.New("invalid streamid")
|
||||
var (
|
||||
errStreamID = errors.New("invalid stream ID")
|
||||
errDepStreamID = errors.New("invalid dependent stream ID")
|
||||
)
|
||||
|
||||
func validStreamIDOrZero(streamID uint32) bool {
|
||||
return streamID&(1<<31) == 0
|
||||
}
|
||||
|
||||
func validStreamID(streamID uint32) bool {
|
||||
return streamID != 0 && streamID&(1<<31) == 0
|
||||
|
@ -741,7 +899,7 @@ func parseHeadersFrame(fh FrameHeader, p []byte) (_ Frame, err error) {
|
|||
// is received whose stream identifier field is 0x0, the recipient MUST
|
||||
// respond with a connection error (Section 5.4.1) of type
|
||||
// PROTOCOL_ERROR.
|
||||
return nil, ConnectionError(ErrCodeProtocol)
|
||||
return nil, connError{ErrCodeProtocol, "HEADERS frame with stream ID 0"}
|
||||
}
|
||||
var padLength uint8
|
||||
if fh.Flags.Has(FlagHeadersPadded) {
|
||||
|
@ -827,8 +985,8 @@ func (f *Framer) WriteHeaders(p HeadersFrameParam) error {
|
|||
}
|
||||
if !p.Priority.IsZero() {
|
||||
v := p.Priority.StreamDep
|
||||
if !validStreamID(v) && !f.AllowIllegalWrites {
|
||||
return errors.New("invalid dependent stream id")
|
||||
if !validStreamIDOrZero(v) && !f.AllowIllegalWrites {
|
||||
return errDepStreamID
|
||||
}
|
||||
if p.Priority.Exclusive {
|
||||
v |= 1 << 31
|
||||
|
@ -871,10 +1029,10 @@ func (p PriorityParam) IsZero() bool {
|
|||
|
||||
func parsePriorityFrame(fh FrameHeader, payload []byte) (Frame, error) {
|
||||
if fh.StreamID == 0 {
|
||||
return nil, ConnectionError(ErrCodeProtocol)
|
||||
return nil, connError{ErrCodeProtocol, "PRIORITY frame with stream ID 0"}
|
||||
}
|
||||
if len(payload) != 5 {
|
||||
return nil, ConnectionError(ErrCodeFrameSize)
|
||||
return nil, connError{ErrCodeFrameSize, fmt.Sprintf("PRIORITY frame payload size was %d; want 5", len(payload))}
|
||||
}
|
||||
v := binary.BigEndian.Uint32(payload[:4])
|
||||
streamID := v & 0x7fffffff // mask off high bit
|
||||
|
@ -896,6 +1054,9 @@ func (f *Framer) WritePriority(streamID uint32, p PriorityParam) error {
|
|||
if !validStreamID(streamID) && !f.AllowIllegalWrites {
|
||||
return errStreamID
|
||||
}
|
||||
if !validStreamIDOrZero(p.StreamDep) {
|
||||
return errDepStreamID
|
||||
}
|
||||
f.startWrite(FramePriority, 0, streamID)
|
||||
v := p.StreamDep
|
||||
if p.Exclusive {
|
||||
|
@ -944,13 +1105,12 @@ type ContinuationFrame struct {
|
|||
}
|
||||
|
||||
func parseContinuationFrame(fh FrameHeader, p []byte) (Frame, error) {
|
||||
if fh.StreamID == 0 {
|
||||
return nil, connError{ErrCodeProtocol, "CONTINUATION frame with stream ID 0"}
|
||||
}
|
||||
return &ContinuationFrame{fh, p}, nil
|
||||
}
|
||||
|
||||
func (f *ContinuationFrame) StreamEnded() bool {
|
||||
return f.FrameHeader.Flags.Has(FlagDataEndStream)
|
||||
}
|
||||
|
||||
func (f *ContinuationFrame) HeaderBlockFragment() []byte {
|
||||
f.checkValid()
|
||||
return f.headerFragBuf
|
||||
|
@ -1112,3 +1272,236 @@ type streamEnder interface {
|
|||
type headersEnder interface {
|
||||
HeadersEnded() bool
|
||||
}
|
||||
|
||||
type headersOrContinuation interface {
|
||||
headersEnder
|
||||
HeaderBlockFragment() []byte
|
||||
}
|
||||
|
||||
// A MetaHeadersFrame is the representation of one HEADERS frame and
|
||||
// zero or more contiguous CONTINUATION frames and the decoding of
|
||||
// their HPACK-encoded contents.
|
||||
//
|
||||
// This type of frame does not appear on the wire and is only returned
|
||||
// by the Framer when Framer.ReadMetaHeaders is set.
|
||||
type MetaHeadersFrame struct {
|
||||
*HeadersFrame
|
||||
|
||||
// Fields are the fields contained in the HEADERS and
|
||||
// CONTINUATION frames. The underlying slice is owned by the
|
||||
// Framer and must not be retained after the next call to
|
||||
// ReadFrame.
|
||||
//
|
||||
// Fields are guaranteed to be in the correct http2 order and
|
||||
// not have unknown pseudo header fields or invalid header
|
||||
// field names or values. Required pseudo header fields may be
|
||||
// missing, however. Use the MetaHeadersFrame.Pseudo accessor
|
||||
// method access pseudo headers.
|
||||
Fields []hpack.HeaderField
|
||||
|
||||
// Truncated is whether the max header list size limit was hit
|
||||
// and Fields is incomplete. The hpack decoder state is still
|
||||
// valid, however.
|
||||
Truncated bool
|
||||
}
|
||||
|
||||
// PseudoValue returns the given pseudo header field's value.
|
||||
// The provided pseudo field should not contain the leading colon.
|
||||
func (mh *MetaHeadersFrame) PseudoValue(pseudo string) string {
|
||||
for _, hf := range mh.Fields {
|
||||
if !hf.IsPseudo() {
|
||||
return ""
|
||||
}
|
||||
if hf.Name[1:] == pseudo {
|
||||
return hf.Value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// RegularFields returns the regular (non-pseudo) header fields of mh.
|
||||
// The caller does not own the returned slice.
|
||||
func (mh *MetaHeadersFrame) RegularFields() []hpack.HeaderField {
|
||||
for i, hf := range mh.Fields {
|
||||
if !hf.IsPseudo() {
|
||||
return mh.Fields[i:]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PseudoFields returns the pseudo header fields of mh.
|
||||
// The caller does not own the returned slice.
|
||||
func (mh *MetaHeadersFrame) PseudoFields() []hpack.HeaderField {
|
||||
for i, hf := range mh.Fields {
|
||||
if !hf.IsPseudo() {
|
||||
return mh.Fields[:i]
|
||||
}
|
||||
}
|
||||
return mh.Fields
|
||||
}
|
||||
|
||||
func (mh *MetaHeadersFrame) checkPseudos() error {
|
||||
var isRequest, isResponse bool
|
||||
pf := mh.PseudoFields()
|
||||
for i, hf := range pf {
|
||||
switch hf.Name {
|
||||
case ":method", ":path", ":scheme", ":authority":
|
||||
isRequest = true
|
||||
case ":status":
|
||||
isResponse = true
|
||||
default:
|
||||
return pseudoHeaderError(hf.Name)
|
||||
}
|
||||
// Check for duplicates.
|
||||
// This would be a bad algorithm, but N is 4.
|
||||
// And this doesn't allocate.
|
||||
for _, hf2 := range pf[:i] {
|
||||
if hf.Name == hf2.Name {
|
||||
return duplicatePseudoHeaderError(hf.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if isRequest && isResponse {
|
||||
return errMixPseudoHeaderTypes
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fr *Framer) maxHeaderStringLen() int {
|
||||
v := fr.maxHeaderListSize()
|
||||
if uint32(int(v)) == v {
|
||||
return int(v)
|
||||
}
|
||||
// They had a crazy big number for MaxHeaderBytes anyway,
|
||||
// so give them unlimited header lengths:
|
||||
return 0
|
||||
}
|
||||
|
||||
// readMetaFrame returns 0 or more CONTINUATION frames from fr and
|
||||
// merge them into into the provided hf and returns a MetaHeadersFrame
|
||||
// with the decoded hpack values.
|
||||
func (fr *Framer) readMetaFrame(hf *HeadersFrame) (*MetaHeadersFrame, error) {
|
||||
if fr.AllowIllegalReads {
|
||||
return nil, errors.New("illegal use of AllowIllegalReads with ReadMetaHeaders")
|
||||
}
|
||||
mh := &MetaHeadersFrame{
|
||||
HeadersFrame: hf,
|
||||
}
|
||||
var remainSize = fr.maxHeaderListSize()
|
||||
var sawRegular bool
|
||||
|
||||
var invalid error // pseudo header field errors
|
||||
hdec := fr.ReadMetaHeaders
|
||||
hdec.SetEmitEnabled(true)
|
||||
hdec.SetMaxStringLength(fr.maxHeaderStringLen())
|
||||
hdec.SetEmitFunc(func(hf hpack.HeaderField) {
|
||||
if !httplex.ValidHeaderFieldValue(hf.Value) {
|
||||
invalid = headerFieldValueError(hf.Value)
|
||||
}
|
||||
isPseudo := strings.HasPrefix(hf.Name, ":")
|
||||
if isPseudo {
|
||||
if sawRegular {
|
||||
invalid = errPseudoAfterRegular
|
||||
}
|
||||
} else {
|
||||
sawRegular = true
|
||||
if !validWireHeaderFieldName(hf.Name) {
|
||||
invalid = headerFieldNameError(hf.Name)
|
||||
}
|
||||
}
|
||||
|
||||
if invalid != nil {
|
||||
hdec.SetEmitEnabled(false)
|
||||
return
|
||||
}
|
||||
|
||||
size := hf.Size()
|
||||
if size > remainSize {
|
||||
hdec.SetEmitEnabled(false)
|
||||
mh.Truncated = true
|
||||
return
|
||||
}
|
||||
remainSize -= size
|
||||
|
||||
mh.Fields = append(mh.Fields, hf)
|
||||
})
|
||||
// Lose reference to MetaHeadersFrame:
|
||||
defer hdec.SetEmitFunc(func(hf hpack.HeaderField) {})
|
||||
|
||||
var hc headersOrContinuation = hf
|
||||
for {
|
||||
frag := hc.HeaderBlockFragment()
|
||||
if _, err := hdec.Write(frag); err != nil {
|
||||
return nil, ConnectionError(ErrCodeCompression)
|
||||
}
|
||||
|
||||
if hc.HeadersEnded() {
|
||||
break
|
||||
}
|
||||
if f, err := fr.ReadFrame(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
hc = f.(*ContinuationFrame) // guaranteed by checkFrameOrder
|
||||
}
|
||||
}
|
||||
|
||||
mh.HeadersFrame.headerFragBuf = nil
|
||||
mh.HeadersFrame.invalidate()
|
||||
|
||||
if err := hdec.Close(); err != nil {
|
||||
return nil, ConnectionError(ErrCodeCompression)
|
||||
}
|
||||
if invalid != nil {
|
||||
fr.errDetail = invalid
|
||||
return nil, StreamError{mh.StreamID, ErrCodeProtocol}
|
||||
}
|
||||
if err := mh.checkPseudos(); err != nil {
|
||||
fr.errDetail = err
|
||||
return nil, StreamError{mh.StreamID, ErrCodeProtocol}
|
||||
}
|
||||
return mh, nil
|
||||
}
|
||||
|
||||
func summarizeFrame(f Frame) string {
|
||||
var buf bytes.Buffer
|
||||
f.Header().writeDebug(&buf)
|
||||
switch f := f.(type) {
|
||||
case *SettingsFrame:
|
||||
n := 0
|
||||
f.ForeachSetting(func(s Setting) error {
|
||||
n++
|
||||
if n == 1 {
|
||||
buf.WriteString(", settings:")
|
||||
}
|
||||
fmt.Fprintf(&buf, " %v=%v,", s.ID, s.Val)
|
||||
return nil
|
||||
})
|
||||
if n > 0 {
|
||||
buf.Truncate(buf.Len() - 1) // remove trailing comma
|
||||
}
|
||||
case *DataFrame:
|
||||
data := f.Data()
|
||||
const max = 256
|
||||
if len(data) > max {
|
||||
data = data[:max]
|
||||
}
|
||||
fmt.Fprintf(&buf, " data=%q", data)
|
||||
if len(f.Data()) > max {
|
||||
fmt.Fprintf(&buf, " (%d bytes omitted)", len(f.Data())-max)
|
||||
}
|
||||
case *WindowUpdateFrame:
|
||||
if f.StreamID == 0 {
|
||||
buf.WriteString(" (conn)")
|
||||
}
|
||||
fmt.Fprintf(&buf, " incr=%v", f.Increment)
|
||||
case *PingFrame:
|
||||
fmt.Fprintf(&buf, " ping=%q", f.Data[:])
|
||||
case *GoAwayFrame:
|
||||
fmt.Fprintf(&buf, " LastStreamID=%v ErrCode=%v Debug=%q",
|
||||
f.LastStreamID, f.ErrCode, f.debugData)
|
||||
case *RSTStreamFrame:
|
||||
fmt.Fprintf(&buf, " ErrCode=%v", f.ErrCode)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue