Skip to content

Commit

Permalink
use a single bytes.Reader for frame parsing (#3536)
Browse files Browse the repository at this point in the history
  • Loading branch information
marten-seemann committed Sep 1, 2022
1 parent 93e1d03 commit dfd35cb
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 61 deletions.
6 changes: 3 additions & 3 deletions connection.go
Expand Up @@ -1286,12 +1286,12 @@ func (s *connection) handleFrames(
// Only used for tracing.
// If we're not tracing, this slice will always remain empty.
var frames []wire.Frame
r := bytes.NewReader(data)
for {
frame, err := s.frameParser.ParseNext(r, encLevel)
for len(data) > 0 {
l, frame, err := s.frameParser.ParseNext(data, encLevel)
if err != nil {
return false, err
}
data = data[l:]
if frame == nil {
break
}
Expand Down
11 changes: 5 additions & 6 deletions fuzzing/frames/fuzz.go
@@ -1,7 +1,6 @@
package frames

import (
"bytes"
"fmt"

"github.com/lucas-clemente/quic-go/internal/protocol"
Expand Down Expand Up @@ -37,19 +36,19 @@ func Fuzz(data []byte) int {
parser := wire.NewFrameParser(true, version)
parser.SetAckDelayExponent(protocol.DefaultAckDelayExponent)

r := bytes.NewReader(data)
initialLen := r.Len()
initialLen := len(data)

var frames []wire.Frame

for r.Len() > 0 {
f, err := parser.ParseNext(r, encLevel)
for len(data) > 0 {
l, f, err := parser.ParseNext(data, encLevel)
if err != nil {
break
}
data = data[l:]
frames = append(frames, f)
}
parsedLen := initialLen - r.Len()
parsedLen := initialLen - len(data)

if len(frames) == 0 {
return 0
Expand Down
16 changes: 14 additions & 2 deletions internal/wire/frame_parser.go
Expand Up @@ -11,6 +11,8 @@ import (
)

type frameParser struct {
r bytes.Reader // cached bytes.Reader, so we don't have to repeatedly allocate them

ackDelayExponent uint8

supportsDatagrams bool
Expand All @@ -21,16 +23,26 @@ type frameParser struct {
// NewFrameParser creates a new frame parser.
func NewFrameParser(supportsDatagrams bool, v protocol.VersionNumber) FrameParser {
return &frameParser{
r: *bytes.NewReader(nil),
supportsDatagrams: supportsDatagrams,
version: v,
}
}

// ParseNext parses the next frame.
// It skips PADDING frames.
func (p *frameParser) ParseNext(r *bytes.Reader, encLevel protocol.EncryptionLevel) (Frame, error) {
func (p *frameParser) ParseNext(data []byte, encLevel protocol.EncryptionLevel) (int, Frame, error) {
startLen := len(data)
p.r.Reset(data)
frame, err := p.parseNext(&p.r, encLevel)
n := startLen - p.r.Len()
p.r.Reset(nil)
return n, frame, err
}

func (p *frameParser) parseNext(r *bytes.Reader, encLevel protocol.EncryptionLevel) (Frame, error) {
for r.Len() != 0 {
typeByte, _ := r.ReadByte()
typeByte, _ := p.r.ReadByte()
if typeByte == 0x0 { // PADDING frame
continue
}
Expand Down

0 comments on commit dfd35cb

Please sign in to comment.