diff --git a/internal/git/pktline/pktline.go b/internal/git/pktline/pktline.go index 665d6cbde64d5a1d7e4843be2e7b5f2c5ed72e99..6ccb9d46475de0b886be0e4baeddc1149ef47e71 100644 --- a/internal/git/pktline/pktline.go +++ b/internal/git/pktline/pktline.go @@ -161,13 +161,17 @@ type errNotSideband struct{ pkt string } func (err *errNotSideband) Error() string { return fmt.Sprintf("invalid sideband packet: %q", err.pkt) } -// EachSidebandPacket iterates over a side-band-64k pktline stream. For -// each packet, it will call fn with the band ID and the packet. Fn must -// not retain the packet. +// EachSidebandPacket iterates over a side-band-64k pktline stream until +// it reaches a flush packet. For each packet, it will call fn with the +// band ID and the packet. Fn must not retain the packet. func EachSidebandPacket(r io.Reader, fn func(byte, []byte) error) error { scanner := NewScanner(r) for scanner.Scan() { + if IsFlush(scanner.Bytes()) { + return nil + } + data := Data(scanner.Bytes()) if len(data) == 0 { return &errNotSideband{scanner.Text()} @@ -177,5 +181,9 @@ func EachSidebandPacket(r io.Reader, fn func(byte, []byte) error) error { } } - return scanner.Err() + if err := scanner.Err(); err != nil { + return err + } + + return io.ErrUnexpectedEOF } diff --git a/internal/git/pktline/pkt_line_test.go b/internal/git/pktline/pktline_test.go similarity index 94% rename from internal/git/pktline/pkt_line_test.go rename to internal/git/pktline/pktline_test.go index 32694a7e0ab4eac1d122d50f873a0585fa2d9ae0..dc29d3b0e0f0d37f3c998b158484d011ba7d2d32 100644 --- a/internal/git/pktline/pkt_line_test.go +++ b/internal/git/pktline/pktline_test.go @@ -279,16 +279,23 @@ func TestEachSidebandPacket(t *testing.T) { }{ { desc: "empty", + in: "0000", out: map[byte]string{}, }, { desc: "empty with failing callback: callback does not run", + in: "0000", out: map[byte]string{}, callback: func(byte, []byte) error { panic("oh no") }, }, { desc: "valid stream", - in: "0008\x00foo0008\x01bar0008\xfequx0008\xffbaz", + in: "0008\x00foo0008\x01bar0008\xfequx0008\xffbaz0000", + out: map[byte]string{0: "foo", 1: "bar", 254: "qux", 255: "baz"}, + }, + { + desc: "valid stream trailing garbage", + in: "0008\x00foo0008\x01bar0008\xfequx0008\xffbaz0000 garbage!!", out: map[byte]string{0: "foo", 1: "bar", 254: "qux", 255: "baz"}, }, { @@ -297,6 +304,11 @@ func TestEachSidebandPacket(t *testing.T) { callback: func(byte, []byte) error { return callbackError }, err: callbackError, }, + { + desc: "valid stream except missing flush", + in: "0008\x00foo0008\x01bar0008\xfequx0008\xffbaz", + err: io.ErrUnexpectedEOF, + }, { desc: "interrupted stream", in: "ffff\x10hello world!!", diff --git a/internal/gitaly/service/hook/pack_objects.go b/internal/gitaly/service/hook/pack_objects.go index 112701c3332af945ce43e72cf25d41e550c4bacf..4972402f9f39000e315f2ae5c31fc4390a4fb85a 100644 --- a/internal/gitaly/service/hook/pack_objects.go +++ b/internal/gitaly/service/hook/pack_objects.go @@ -204,6 +204,10 @@ func (s *server) runPackObjects(ctx context.Context, w io.Writer, repo *gitalypb return fmt.Errorf("git-pack-objects: stderr: %q err: %w", stderrBuf.String(), err) } + if err := pktline.WriteFlush(w); err != nil { + return err + } + return nil }