diff --git a/cos.go b/cos.go index c740648..422a7fe 100644 --- a/cos.go +++ b/cos.go @@ -22,7 +22,7 @@ import ( const ( // Version current go sdk version - Version = "0.7.20" + Version = "0.7.21" userAgent = "cos-go-sdk-v5/" + Version contentTypeXML = "application/xml" defaultServiceBaseURL = "http://service.cos.myqcloud.com" diff --git a/example/object/upload.go b/example/object/upload.go index 54a6f7d..81c2e64 100644 --- a/example/object/upload.go +++ b/example/object/upload.go @@ -51,7 +51,8 @@ func main() { // Case1 多线程上传对象 opt := &cos.MultiUploadOptions{ - ThreadPoolSize: 3, + EnableVerification: true, + ThreadPoolSize: 5, } v, _, err := c.Object.Upload( context.Background(), "gomulput1G", "./test1G", opt, @@ -71,4 +72,5 @@ func main() { ) log_status(err) fmt.Printf("Case2 done, %v\n", v) + } diff --git a/helper.go b/helper.go index 05d8e2b..bccacb8 100644 --- a/helper.go +++ b/helper.go @@ -6,6 +6,7 @@ import ( "crypto/sha1" "errors" "fmt" + "hash/crc64" "io" "net/http" "net/url" @@ -33,6 +34,17 @@ func calSHA1Digest(msg []byte) []byte { return m.Sum(nil) } +func calCRC64(fd io.Reader) (uint64, error) { + tb := crc64.MakeTable(crc64.ECMA) + hash := crc64.New(tb) + _, err := io.Copy(hash, fd) + if err != nil { + return 0, err + } + sum := hash.Sum64() + return sum, nil +} + // cloneRequest returns a clone of the provided *http.Request. The clone is a // shallow copy of the struct and its Header map. func cloneRequest(r *http.Request) *http.Request { diff --git a/object.go b/object.go index 673e1c0..585b554 100644 --- a/object.go +++ b/object.go @@ -524,10 +524,11 @@ type Object struct { // MultiUploadOptions is the option of the multiupload, // ThreadPoolSize default is one type MultiUploadOptions struct { - OptIni *InitiateMultipartUploadOptions - PartSize int64 - ThreadPoolSize int - CheckPoint bool + OptIni *InitiateMultipartUploadOptions + PartSize int64 + ThreadPoolSize int + CheckPoint bool + EnableVerification bool } type Chunk struct { @@ -738,11 +739,21 @@ func (s *ObjectService) Upload(ctx context.Context, name string, filepath string if opt == nil { opt = &MultiUploadOptions{} } + var localcrc uint64 // 1.Get the file chunk totalBytes, chunks, partNum, err := SplitFileIntoChunks(filepath, opt.PartSize) if err != nil { return nil, nil, err } + // 校验 + if opt.EnableVerification { + fd, err := os.Open(filepath) + if err != nil { + return nil, nil, err + } + defer fd.Close() + localcrc, err = calCRC64(fd) + } // filesize=0 , use simple upload if partNum == 0 { var opt0 *ObjectPutOptions @@ -881,8 +892,16 @@ func (s *ObjectService) Upload(ctx context.Context, name string, filepath string v, resp, err := s.CompleteMultipartUpload(context.Background(), name, uploadID, optcom) if err != nil { s.AbortMultipartUpload(ctx, name, uploadID) + return v, resp, err } + if resp != nil && opt.EnableVerification { + scoscrc := resp.Header.Get("x-cos-hash-crc64ecma") + icoscrc, _ := strconv.ParseUint(scoscrc, 10, 64) + if icoscrc != localcrc { + return v, resp, fmt.Errorf("verification failed, want:%v, return:%v", localcrc, icoscrc) + } + } return v, resp, err }