Files
quic-go/internal/wire/frame_parser.go

193 lines
6.0 KiB
Go

package wire
import (
"errors"
"fmt"
"io"
"github.com/quic-go/quic-go/internal/protocol"
"github.com/quic-go/quic-go/internal/qerr"
"github.com/quic-go/quic-go/quicvarint"
)
var errUnknownFrameType = errors.New("unknown frame type")
// The FrameParser parses QUIC frames, one by one.
type FrameParser struct {
ackDelayExponent uint8
supportsDatagrams bool
supportsResetStreamAt bool
supportsAckFrequency bool
// To avoid allocating when parsing, keep a single ACK frame struct.
// It is used over and over again.
ackFrame *AckFrame
}
// NewFrameParser creates a new frame parser.
func NewFrameParser(supportsDatagrams, supportsResetStreamAt, supportsAckFrequency bool) *FrameParser {
return &FrameParser{
supportsDatagrams: supportsDatagrams,
supportsResetStreamAt: supportsResetStreamAt,
supportsAckFrequency: supportsAckFrequency,
ackFrame: &AckFrame{},
}
}
// ParseType parses the frame type of the next frame.
// It skips over PADDING frames.
func (p *FrameParser) ParseType(b []byte, encLevel protocol.EncryptionLevel) (FrameType, int, error) {
var parsed int
for len(b) != 0 {
typ, l, err := quicvarint.Parse(b)
parsed += l
if err != nil {
return 0, parsed, &qerr.TransportError{
ErrorCode: qerr.FrameEncodingError,
ErrorMessage: err.Error(),
}
}
b = b[l:]
if typ == 0x0 { // skip PADDING frames
continue
}
ft := FrameType(typ)
valid := ft.isValidRFC9000() ||
(p.supportsDatagrams && ft.IsDatagramFrameType()) ||
(p.supportsResetStreamAt && ft == FrameTypeResetStreamAt) ||
(p.supportsAckFrequency && (ft == FrameTypeAckFrequency || ft == FrameTypeImmediateAck))
if !valid {
return 0, parsed, &qerr.TransportError{
ErrorCode: qerr.FrameEncodingError,
FrameType: typ,
ErrorMessage: errUnknownFrameType.Error(),
}
}
if !ft.isAllowedAtEncLevel(encLevel) {
return 0, parsed, &qerr.TransportError{
ErrorCode: qerr.FrameEncodingError,
FrameType: typ,
ErrorMessage: fmt.Sprintf("%d not allowed at encryption level %s", ft, encLevel),
}
}
return ft, parsed, nil
}
return 0, parsed, io.EOF
}
func (p *FrameParser) ParseStreamFrame(frameType FrameType, data []byte, v protocol.Version) (*StreamFrame, int, error) {
frame, n, err := ParseStreamFrame(data, frameType, v)
if err != nil {
return nil, n, &qerr.TransportError{
ErrorCode: qerr.FrameEncodingError,
FrameType: uint64(frameType),
ErrorMessage: err.Error(),
}
}
return frame, n, nil
}
func (p *FrameParser) ParseAckFrame(frameType FrameType, data []byte, encLevel protocol.EncryptionLevel, v protocol.Version) (*AckFrame, int, error) {
ackDelayExponent := p.ackDelayExponent
if encLevel != protocol.Encryption1RTT {
ackDelayExponent = protocol.DefaultAckDelayExponent
}
p.ackFrame.Reset()
l, err := parseAckFrame(p.ackFrame, data, frameType, ackDelayExponent, v)
if err != nil {
return nil, l, &qerr.TransportError{
ErrorCode: qerr.FrameEncodingError,
FrameType: uint64(frameType),
ErrorMessage: err.Error(),
}
}
return p.ackFrame, l, nil
}
func (p *FrameParser) ParseDatagramFrame(frameType FrameType, data []byte, v protocol.Version) (*DatagramFrame, int, error) {
f, l, err := parseDatagramFrame(data, frameType, v)
if err != nil {
return nil, 0, &qerr.TransportError{
ErrorCode: qerr.FrameEncodingError,
FrameType: uint64(frameType),
ErrorMessage: err.Error(),
}
}
return f, l, nil
}
// ParseLessCommonFrame parses everything except STREAM, ACK or DATAGRAM.
// These cases should be handled separately for performance reasons.
func (p *FrameParser) ParseLessCommonFrame(frameType FrameType, data []byte, v protocol.Version) (Frame, int, error) {
var frame Frame
var l int
var err error
//nolint:exhaustive // Common frames should already be handled.
switch frameType {
case FrameTypePing:
frame = &PingFrame{}
case FrameTypeResetStream:
frame, l, err = parseResetStreamFrame(data, false, v)
case FrameTypeStopSending:
frame, l, err = parseStopSendingFrame(data, v)
case FrameTypeCrypto:
frame, l, err = parseCryptoFrame(data, v)
case FrameTypeNewToken:
frame, l, err = parseNewTokenFrame(data, v)
case FrameTypeMaxData:
frame, l, err = parseMaxDataFrame(data, v)
case FrameTypeMaxStreamData:
frame, l, err = parseMaxStreamDataFrame(data, v)
case FrameTypeBidiMaxStreams, FrameTypeUniMaxStreams:
frame, l, err = parseMaxStreamsFrame(data, frameType, v)
case FrameTypeDataBlocked:
frame, l, err = parseDataBlockedFrame(data, v)
case FrameTypeStreamDataBlocked:
frame, l, err = parseStreamDataBlockedFrame(data, v)
case FrameTypeBidiStreamBlocked, FrameTypeUniStreamBlocked:
frame, l, err = parseStreamsBlockedFrame(data, frameType, v)
case FrameTypeNewConnectionID:
frame, l, err = parseNewConnectionIDFrame(data, v)
case FrameTypeRetireConnectionID:
frame, l, err = parseRetireConnectionIDFrame(data, v)
case FrameTypePathChallenge:
frame, l, err = parsePathChallengeFrame(data, v)
case FrameTypePathResponse:
frame, l, err = parsePathResponseFrame(data, v)
case FrameTypeConnectionClose, FrameTypeApplicationClose:
frame, l, err = parseConnectionCloseFrame(data, frameType, v)
case FrameTypeHandshakeDone:
frame = &HandshakeDoneFrame{}
case FrameTypeResetStreamAt:
frame, l, err = parseResetStreamFrame(data, true, v)
case FrameTypeAckFrequency:
frame, l, err = parseAckFrequencyFrame(data, v)
case FrameTypeImmediateAck:
frame = &ImmediateAckFrame{}
default:
err = errUnknownFrameType
}
if err != nil {
return frame, l, &qerr.TransportError{
ErrorCode: qerr.FrameEncodingError,
FrameType: uint64(frameType),
ErrorMessage: err.Error(),
}
}
return frame, l, err
}
// SetAckDelayExponent sets the acknowledgment delay exponent (sent in the transport parameters).
// This value is used to scale the ACK Delay field in the ACK frame.
func (p *FrameParser) SetAckDelayExponent(exp uint8) {
p.ackDelayExponent = exp
}
func replaceUnexpectedEOF(e error) error {
if e == io.ErrUnexpectedEOF {
return io.EOF
}
return e
}