Skip to content

Commit bde0036

Browse files
authored
Merge pull request #2234 from AkihiroSuda/cherry-pick-2221
[release/1.0] services/content: fix reading a blob which is smaller than the read buffer
2 parents 21e89eb + eaee9f5 commit bde0036

2 files changed

Lines changed: 47 additions & 5 deletions

File tree

content/testsuite/testsuite.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ func ContentSuite(t *testing.T, name string, storeFn func(ctx context.Context, r
3131
t.Run("ResumeCopy", makeTest(t, name, storeFn, checkResume(resumeCopy)))
3232
t.Run("ResumeCopySeeker", makeTest(t, name, storeFn, checkResume(resumeCopySeeker)))
3333
t.Run("ResumeCopyReaderAt", makeTest(t, name, storeFn, checkResume(resumeCopyReaderAt)))
34+
t.Run("SmallBlob", makeTest(t, name, storeFn, checkSmallBlob))
3435
t.Run("Labels", makeTest(t, name, storeFn, checkLabels))
3536
}
3637

@@ -467,6 +468,45 @@ func resumeCopyReaderAt(ctx context.Context, w content.Writer, b []byte, _, size
467468
return errors.Wrap(content.Copy(ctx, w, r, size, dgst), "copy failed")
468469
}
469470

471+
// checkSmallBlob tests reading a blob which is smaller than the read size.
472+
func checkSmallBlob(ctx context.Context, t *testing.T, store content.Store) {
473+
blob := []byte(`foobar`)
474+
blobSize := int64(len(blob))
475+
blobDigest := digest.FromBytes(blob)
476+
// test write
477+
w, err := store.Writer(ctx, t.Name(), blobSize, blobDigest)
478+
if err != nil {
479+
t.Fatal(err)
480+
}
481+
if _, err := w.Write(blob); err != nil {
482+
t.Fatal(err)
483+
}
484+
if err := w.Commit(ctx, blobSize, blobDigest); err != nil {
485+
t.Fatal(err)
486+
}
487+
if err := w.Close(); err != nil {
488+
t.Fatal(err)
489+
}
490+
// test read.
491+
readSize := blobSize + 1
492+
ra, err := store.ReaderAt(ctx, blobDigest)
493+
if err != nil {
494+
t.Fatal(err)
495+
}
496+
r := io.NewSectionReader(ra, 0, readSize)
497+
b, err := ioutil.ReadAll(r)
498+
if err != nil {
499+
t.Fatal(err)
500+
}
501+
if err := ra.Close(); err != nil {
502+
t.Fatal(err)
503+
}
504+
d := digest.FromBytes(b)
505+
if blobDigest != d {
506+
t.Fatalf("expected %s (%q), got %s (%q)", blobDigest, string(blob),
507+
d, string(b))
508+
}
509+
}
470510
func checkStatus(t *testing.T, w content.Writer, expected content.Status, d digest.Digest, preStart, postStart, preUpdate, postUpdate time.Time) {
471511
t.Helper()
472512
st, err := w.Status()

services/content/service.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,9 @@ func (s *service) Read(req *api.ReadContentRequest, session api.Content_ReadServ
177177

178178
var (
179179
offset = req.Offset
180-
size = req.Size_
180+
// size is read size, not the expected size of the blob (oi.Size), which the caller might not be aware of.
181+
// offset+size can be larger than oi.Size.
182+
size = req.Size_
181183

182184
// TODO(stevvooe): Using the global buffer pool. At 32KB, it is probably
183185
// little inefficient for work over a fast network. We can tune this later.
@@ -189,12 +191,12 @@ func (s *service) Read(req *api.ReadContentRequest, session api.Content_ReadServ
189191
offset = 0
190192
}
191193

192-
if size <= 0 {
193-
size = oi.Size - offset
194+
if offset > oi.Size {
195+
return status.Errorf(codes.OutOfRange, "read past object length %v bytes", oi.Size)
194196
}
195197

196-
if offset+size > oi.Size {
197-
return status.Errorf(codes.OutOfRange, "read past object length %v bytes", oi.Size)
198+
if size <= 0 || offset+size > oi.Size {
199+
size = oi.Size - offset
198200
}
199201

200202
_, err = io.CopyBuffer(

0 commit comments

Comments
 (0)