checksum.go 1.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. package tos
  2. import (
  3. "crypto/md5"
  4. "encoding/hex"
  5. "errors"
  6. "hash"
  7. "io"
  8. "strings"
  9. )
  10. var (
  11. ErrETagMissMatch = errors.New("tos: ETag miss match")
  12. )
  13. // ETagCheckReadCloser checks ETag on read EOF
  14. type ETagCheckReadCloser struct {
  15. reader io.Reader
  16. closer io.Closer
  17. checksum hash.Hash
  18. eTag string
  19. requestID string
  20. }
  21. func NewETagCheckReadCloser(reader io.ReadCloser, eTag, requestID string) *ETagCheckReadCloser {
  22. checksum := md5.New()
  23. return &ETagCheckReadCloser{
  24. reader: io.TeeReader(reader, checksum),
  25. closer: reader,
  26. checksum: checksum,
  27. eTag: strings.Trim(eTag, `"`),
  28. requestID: requestID,
  29. }
  30. }
  31. func (ec *ETagCheckReadCloser) Read(p []byte) (n int, err error) {
  32. n, err = ec.reader.Read(p)
  33. if err == io.EOF && len(ec.eTag) > 0 {
  34. sum := ec.checksum.Sum(nil)
  35. if hexSum := hex.EncodeToString(sum); hexSum != ec.eTag {
  36. return n, &ChecksumError{
  37. RequestID: ec.requestID,
  38. ExpectedChecksum: ec.eTag,
  39. ActualChecksum: hexSum,
  40. }
  41. }
  42. }
  43. return n, err
  44. }
  45. func (ec *ETagCheckReadCloser) Close() error {
  46. return ec.closer.Close()
  47. }