Files
Felis/internal/submit/digest.go
T

42 lines
1.2 KiB
Go

package submit
import (
"bytes"
"crypto/sha256"
"errors"
"fmt"
"hash"
"io"
)
// ErrDigestMismatch reports bytes that do not hash to the SHA-256 their sender
// computed over them (the request's Content-Digest): they changed on the way.
// The API answers 400 digest_mismatch, and the client sends them again.
var ErrDigestMismatch = errors.New("submit: the bytes that arrived do not match the digest they were sent with")
// VerifyDigest passes r through and, where it ends, answers ErrDigestMismatch in
// place of io.EOF unless what went by hashes to want, a SHA-256. The stores
// treat that like any read that breaks off: UploadPart cuts the part back off,
// and UploadContext never lets the blob replace the one before it. So bytes
// changed on the way are never kept.
func VerifyDigest(r io.Reader, want []byte) io.Reader {
return &digestReader{r: r, h: sha256.New(), want: want}
}
type digestReader struct {
r io.Reader
h hash.Hash
want []byte
}
func (d *digestReader) Read(p []byte) (int, error) {
n, err := d.r.Read(p)
d.h.Write(p[:n])
if err == io.EOF {
if got := d.h.Sum(nil); !bytes.Equal(got, d.want) {
return n, fmt.Errorf("%w: they hash to %x, sent as %x", ErrDigestMismatch, got, d.want)
}
}
return n, err
}