forked from quic-go/quic-go
193 lines
6.0 KiB
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
|
|
}
|