route/vendor/github.com/lucas-clemente/quic-go/internal/wire/connection_close_frame.go

97 lines
2.6 KiB
Go

package wire
import (
"bytes"
"errors"
"io"
"math"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/qerr"
)
// A ConnectionCloseFrame in QUIC
type ConnectionCloseFrame struct {
ErrorCode qerr.ErrorCode
ReasonPhrase string
}
// ParseConnectionCloseFrame reads a CONNECTION_CLOSE frame
func ParseConnectionCloseFrame(r *bytes.Reader, version protocol.VersionNumber) (*ConnectionCloseFrame, error) {
if _, err := r.ReadByte(); err != nil { // read the TypeByte
return nil, err
}
var errorCode qerr.ErrorCode
var reasonPhraseLen uint64
if version.UsesIETFFrameFormat() {
ec, err := utils.BigEndian.ReadUint16(r)
if err != nil {
return nil, err
}
errorCode = qerr.ErrorCode(ec)
reasonPhraseLen, err = utils.ReadVarInt(r)
if err != nil {
return nil, err
}
} else {
ec, err := utils.BigEndian.ReadUint32(r)
if err != nil {
return nil, err
}
errorCode = qerr.ErrorCode(ec)
length, err := utils.BigEndian.ReadUint16(r)
if err != nil {
return nil, err
}
reasonPhraseLen = uint64(length)
}
// shortcut to prevent the unneccessary allocation of dataLen bytes
// if the dataLen is larger than the remaining length of the packet
// reading the whole reason phrase would result in EOF when attempting to READ
if int(reasonPhraseLen) > r.Len() {
return nil, io.EOF
}
reasonPhrase := make([]byte, reasonPhraseLen)
if _, err := io.ReadFull(r, reasonPhrase); err != nil {
// this should never happen, since we already checked the reasonPhraseLen earlier
return nil, err
}
return &ConnectionCloseFrame{
ErrorCode: qerr.ErrorCode(errorCode),
ReasonPhrase: string(reasonPhrase),
}, nil
}
// MinLength of a written frame
func (f *ConnectionCloseFrame) MinLength(version protocol.VersionNumber) protocol.ByteCount {
if version.UsesIETFFrameFormat() {
return 1 + 2 + utils.VarIntLen(uint64(len(f.ReasonPhrase))) + protocol.ByteCount(len(f.ReasonPhrase))
}
return 1 + 4 + 2 + protocol.ByteCount(len(f.ReasonPhrase))
}
// Write writes an CONNECTION_CLOSE frame.
func (f *ConnectionCloseFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
b.WriteByte(0x02)
if len(f.ReasonPhrase) > math.MaxUint16 {
return errors.New("ConnectionFrame: ReasonPhrase too long")
}
if version.UsesIETFFrameFormat() {
utils.BigEndian.WriteUint16(b, uint16(f.ErrorCode))
utils.WriteVarInt(b, uint64(len(f.ReasonPhrase)))
} else {
utils.BigEndian.WriteUint32(b, uint32(f.ErrorCode))
utils.BigEndian.WriteUint16(b, uint16(len(f.ReasonPhrase)))
}
b.WriteString(f.ReasonPhrase)
return nil
}