From c2f1ff261ecf16720deb8e5ee9f772bd51c0e477 Mon Sep 17 00:00:00 2001 From: Rod Vagg Date: Thu, 5 Nov 2020 17:08:20 +1100 Subject: [PATCH] feat: handle mid-varint EOF case as UnexpectedEOF --- car_test.go | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++ util/util.go | 7 ++++++ 2 files changed, 72 insertions(+) diff --git a/car_test.go b/car_test.go index 53d59b36..e1e84240 100644 --- a/car_test.go +++ b/car_test.go @@ -3,6 +3,8 @@ package car import ( "bytes" "context" + "encoding/hex" + "io" "testing" cid "github.com/ipfs/go-cid" @@ -160,3 +162,66 @@ func TestRoundtripSelective(t *testing.T) { require.False(t, has) } } + +func TestEOFHandling(t *testing.T) { + // fixture is a clean single-block, single-root CAR + fixture, err := hex.DecodeString("3aa265726f6f747381d82a58250001711220151fe9e73c6267a7060c6f6c4cca943c236f4b196723489608edb42a8b8fa80b6776657273696f6e012c01711220151fe9e73c6267a7060c6f6c4cca943c236f4b196723489608edb42a8b8fa80ba165646f646779f5") + if err != nil { + t.Fatal(err) + } + + load := func(t *testing.T, byts []byte) *CarReader { + cr, err := NewCarReader(bytes.NewReader(byts)) + if err != nil { + t.Fatal(err) + } + + blk, err := cr.Next() + if err != nil { + t.Fatal(err) + } + if blk.Cid().String() != "bafyreiavd7u6opdcm6tqmddpnrgmvfb4enxuwglhenejmchnwqvixd5ibm" { + t.Fatal("unexpected CID") + } + + return cr + } + + t.Run("CleanEOF", func(t *testing.T) { + cr := load(t, fixture) + + blk, err := cr.Next() + if err != io.EOF { + t.Fatal("Didn't get expected EOF") + } + if blk != nil { + t.Fatal("EOF returned expected block") + } + }) + + t.Run("BadVarint", func(t *testing.T) { + fixtureBadVarint := append(fixture, 160) + cr := load(t, fixtureBadVarint) + + blk, err := cr.Next() + if err != io.ErrUnexpectedEOF { + t.Fatal("Didn't get unexpected EOF") + } + if blk != nil { + t.Fatal("EOF returned unexpected block") + } + }) + + t.Run("TruncatedBlock", func(t *testing.T) { + fixtureTruncatedBlock := append(fixture, 100, 0, 0) + cr := load(t, fixtureTruncatedBlock) + + blk, err := cr.Next() + if err != io.ErrUnexpectedEOF { + t.Fatal("Didn't get unexpected EOF") + } + if blk != nil { + t.Fatal("EOF returned unexpected block") + } + }) +} diff --git a/util/util.go b/util/util.go index 47c7e78d..08048f33 100644 --- a/util/util.go +++ b/util/util.go @@ -100,8 +100,15 @@ func LdSize(d ...[]byte) uint64 { } func LdRead(r *bufio.Reader) ([]byte, error) { + if _, err := r.Peek(1); err != nil { // no more blocks, likely clean io.EOF + return nil, err + } + l, err := binary.ReadUvarint(r) if err != nil { + if err == io.EOF { + return nil, io.ErrUnexpectedEOF // don't silently pretend this is a clean EOF + } return nil, err }