Jelajahi Sumber

fix resume object options bug

taowei.wtw 6 tahun lalu
induk
melakukan
b21bbd0247
8 mengubah file dengan 406 tambahan dan 27 penghapusan
  1. 1 1
      oss/const.go
  2. 9 3
      oss/download.go
  3. 98 1
      oss/download_test.go
  4. 16 4
      oss/multicopy.go
  5. 59 1
      oss/multicopy_test.go
  6. 24 16
      oss/upload.go
  7. 85 1
      oss/upload_test.go
  8. 114 0
      oss/utils.go

+ 1 - 1
oss/const.go

@@ -182,5 +182,5 @@ const (
 
 	NullVersion = "null"
 
-	Version = "v2.0.3" // Go SDK version
+	Version = "v2.0.4" // Go SDK version
 )

+ 9 - 3
oss/download.go

@@ -38,8 +38,14 @@ func (bucket Bucket) DownloadFile(objectKey, filePath string, partSize int64, op
 	cpConf := getCpConfig(options)
 	routines := getRoutines(options)
 
+	var strVersionId string
+	versionId, _ := findOption(options, "versionId", nil)
+	if versionId != nil {
+		strVersionId = versionId.(string)
+	}
+
 	if cpConf != nil && cpConf.IsEnable {
-		cpFilePath := getDownloadCpFilePath(cpConf, bucket.BucketName, objectKey, filePath)
+		cpFilePath := getDownloadCpFilePath(cpConf, bucket.BucketName, objectKey, filePath, strVersionId)
 		if cpFilePath != "" {
 			return bucket.downloadFileWithCp(objectKey, filePath, partSize, options, cpFilePath, routines, uRange)
 		}
@@ -48,11 +54,11 @@ func (bucket Bucket) DownloadFile(objectKey, filePath string, partSize int64, op
 	return bucket.downloadFile(objectKey, filePath, partSize, options, routines, uRange)
 }
 
-func getDownloadCpFilePath(cpConf *cpConfig, srcBucket, srcObject, destFile string) string {
+func getDownloadCpFilePath(cpConf *cpConfig, srcBucket, srcObject, destFile, versionId string) string {
 	if cpConf.FilePath == "" && cpConf.DirPath != "" {
 		src := fmt.Sprintf("oss://%v/%v", srcBucket, srcObject)
 		absPath, _ := filepath.Abs(destFile)
-		cpFileName := getCpFileName(src, absPath)
+		cpFileName := getCpFileName(src, absPath, versionId)
 		cpConf.FilePath = cpConf.DirPath + string(os.PathSeparator) + cpFileName
 	}
 	return cpConf.FilePath

+ 98 - 1
oss/download_test.go

@@ -216,7 +216,7 @@ func (s *OssDownloadSuite) TestDownloadRoutineWithRecovery(c *C) {
 	// Check
 	dcp = downloadCheckpoint{}
 	cpConf := cpConfig{IsEnable: true, DirPath: "./"}
-	cpFilePath := getDownloadCpFilePath(&cpConf, s.bucket.BucketName, objectName, newFile)
+	cpFilePath := getDownloadCpFilePath(&cpConf, s.bucket.BucketName, objectName, newFile, "")
 	err = dcp.load(cpFilePath)
 	c.Assert(err, IsNil)
 	c.Assert(dcp.Magic, Equals, downloadCpMagic)
@@ -880,3 +880,100 @@ func (s *OssDownloadSuite) TestVersioningDownloadWithCheckPoint(c *C) {
 	c.Assert(err, IsNil)
 	forceDeleteBucket(client, bucketName, c)
 }
+
+func (s *OssDownloadSuite) TestdownloadFileChoiceOptions(c *C) {
+	// create a bucket with default proprety
+	client, err := New(endpoint, accessID, accessKey)
+	c.Assert(err, IsNil)
+
+	bucketName := bucketNamePrefix + randLowStr(6)
+	err = client.CreateBucket(bucketName)
+	c.Assert(err, IsNil)
+
+	bucket, err := client.Bucket(bucketName)
+
+	// begin test
+	objectName := objectNamePrefix + randStr(8)
+	fileName := "test-file-" + randStr(8)
+	fileData := randStr(500 * 1024)
+	createFile(fileName, fileData, c)
+	newFile := randStr(8) + ".jpg"
+
+	// Upload a file
+	var respHeader http.Header
+	options := []Option{Routines(3), GetResponseHeader(&respHeader)}
+	err = bucket.UploadFile(objectName, fileName, 100*1024, options...)
+	c.Assert(err, IsNil)
+
+	// Resumable download with checkpoint dir
+	os.Remove(newFile)
+
+	// downloadFile with properties
+	options = []Option{
+		ObjectACL(ACLPublicRead),
+		RequestPayer(Requester),
+		TrafficLimitHeader(1024 * 1024 * 8),
+	}
+
+	err = bucket.DownloadFile(objectName, newFile, 100*1024, options...)
+	c.Assert(err, IsNil)
+
+	eq, err := compareFiles(fileName, newFile)
+	c.Assert(err, IsNil)
+	c.Assert(eq, Equals, true)
+
+	os.Remove(fileName)
+	os.Remove(newFile)
+	err = bucket.DeleteObject(objectName)
+	c.Assert(err, IsNil)
+	forceDeleteBucket(client, bucketName, c)
+}
+
+func (s *OssDownloadSuite) TestdownloadFileWithCpChoiceOptions(c *C) {
+	// create a bucket with default proprety
+	client, err := New(endpoint, accessID, accessKey)
+	c.Assert(err, IsNil)
+
+	bucketName := bucketNamePrefix + randLowStr(6)
+	err = client.CreateBucket(bucketName)
+	c.Assert(err, IsNil)
+
+	bucket, err := client.Bucket(bucketName)
+
+	// begin test
+	objectName := objectNamePrefix + randStr(8)
+	fileName := "test-file-" + randStr(8)
+	fileData := randStr(500 * 1024)
+	createFile(fileName, fileData, c)
+	newFile := randStr(8) + ".jpg"
+
+	// Upload a file
+	var respHeader http.Header
+	options := []Option{Routines(3), GetResponseHeader(&respHeader)}
+	err = bucket.UploadFile(objectName, fileName, 100*1024, options...)
+	c.Assert(err, IsNil)
+
+	// Resumable download with checkpoint dir
+	os.Remove(newFile)
+
+	// DownloadFile with properties
+	options = []Option{
+		ObjectACL(ACLPublicRead),
+		RequestPayer(Requester),
+		TrafficLimitHeader(1024 * 1024 * 8),
+		CheckpointDir(true, "./"),
+	}
+
+	err = bucket.DownloadFile(objectName, newFile, 100*1024, options...)
+	c.Assert(err, IsNil)
+
+	eq, err := compareFiles(fileName, newFile)
+	c.Assert(err, IsNil)
+	c.Assert(eq, Equals, true)
+
+	os.Remove(fileName)
+	os.Remove(newFile)
+	err = bucket.DeleteObject(objectName)
+	c.Assert(err, IsNil)
+	forceDeleteBucket(client, bucketName, c)
+}

+ 16 - 4
oss/multicopy.go

@@ -31,8 +31,14 @@ func (bucket Bucket) CopyFile(srcBucketName, srcObjectKey, destObjectKey string,
 	cpConf := getCpConfig(options)
 	routines := getRoutines(options)
 
+	var strVersionId string
+	versionId, _ := findOption(options, "versionId", nil)
+	if versionId != nil {
+		strVersionId = versionId.(string)
+	}
+
 	if cpConf != nil && cpConf.IsEnable {
-		cpFilePath := getCopyCpFilePath(cpConf, srcBucketName, srcObjectKey, destBucketName, destObjectKey)
+		cpFilePath := getCopyCpFilePath(cpConf, srcBucketName, srcObjectKey, destBucketName, destObjectKey, strVersionId)
 		if cpFilePath != "" {
 			return bucket.copyFileWithCp(srcBucketName, srcObjectKey, destBucketName, destObjectKey, partSize, options, cpFilePath, routines)
 		}
@@ -42,11 +48,11 @@ func (bucket Bucket) CopyFile(srcBucketName, srcObjectKey, destObjectKey string,
 		partSize, options, routines)
 }
 
-func getCopyCpFilePath(cpConf *cpConfig, srcBucket, srcObject, destBucket, destObject string) string {
+func getCopyCpFilePath(cpConf *cpConfig, srcBucket, srcObject, destBucket, destObject, versionId string) string {
 	if cpConf.FilePath == "" && cpConf.DirPath != "" {
 		dest := fmt.Sprintf("oss://%v/%v", destBucket, destObject)
 		src := fmt.Sprintf("oss://%v/%v", srcBucket, srcObject)
-		cpFileName := getCpFileName(src, dest)
+		cpFileName := getCpFileName(src, dest, versionId)
 		cpConf.FilePath = cpConf.DirPath + string(os.PathSeparator) + cpFileName
 	}
 	return cpConf.FilePath
@@ -172,6 +178,9 @@ func (bucket Bucket) copyFile(srcBucketName, srcObjectKey, destBucketName, destO
 	event := newProgressEvent(TransferStartedEvent, 0, totalBytes, 0)
 	publishProgress(listener, event)
 
+	// oss server don't support x-oss-storage-class
+	options = deleteOption(options, HTTPHeaderOssStorageClass)
+
 	// Start to copy workers
 	arg := copyWorkerArg{descBucket, imur, srcBucketName, srcObjectKey, options, copyPartHooker}
 	for w := 1; w <= routines; w++ {
@@ -422,6 +431,9 @@ func (bucket Bucket) copyFileWithCp(srcBucketName, srcObjectKey, destBucketName,
 	event := newProgressEvent(TransferStartedEvent, completedBytes, ccp.ObjStat.Size, 0)
 	publishProgress(listener, event)
 
+	// oss server don't support x-oss-storage-class
+	options = deleteOption(options, HTTPHeaderOssStorageClass)
+
 	// Start the worker coroutines
 	arg := copyWorkerArg{descBucket, imur, srcBucketName, srcObjectKey, options, copyPartHooker}
 	for w := 1; w <= routines; w++ {
@@ -455,7 +467,7 @@ func (bucket Bucket) copyFileWithCp(srcBucketName, srcObjectKey, destBucketName,
 		}
 	}
 
-	event = newProgressEvent(TransferCompletedEvent, completedBytes, ccp.ObjStat.Size,0)
+	event = newProgressEvent(TransferCompletedEvent, completedBytes, ccp.ObjStat.Size, 0)
 	publishProgress(listener, event)
 
 	return ccp.complete(descBucket, ccp.CopyParts, cpFilePath, options)

+ 59 - 1
oss/multicopy_test.go

@@ -334,7 +334,7 @@ func (s *OssCopySuite) TestCopyRoutineWithRecovery(c *C) {
 	// Check CP
 	ccp = copyCheckpoint{}
 	cpConf := cpConfig{IsEnable: true, DirPath: "./"}
-	cpFilePath := getCopyCpFilePath(&cpConf, bucketName, srcObjectName, s.bucket.BucketName, destObjectName)
+	cpFilePath := getCopyCpFilePath(&cpConf, bucketName, srcObjectName, s.bucket.BucketName, destObjectName, "")
 	err = ccp.load(cpFilePath)
 	c.Assert(err, IsNil)
 	c.Assert(ccp.Magic, Equals, copyCpMagic)
@@ -588,3 +588,61 @@ func (s *OssCopySuite) TestVersioningCopyFileCrossBucket(c *C) {
 	forceDeleteBucket(client, bucketName, c)
 	forceDeleteBucket(client, destBucketName, c)
 }
+
+// TestCopyFileChoiceOptions
+func (s *OssCopySuite) TestCopyFileChoiceOptions(c *C) {
+	destBucketName := bucketName + "-desc"
+	srcObjectName := objectNamePrefix + randStr(8)
+	destObjectName := srcObjectName + "-dest"
+	fileName := "../sample/BingWallpaper-2015-11-07.jpg"
+	newFile := randStr(8) + ".jpg"
+
+	destBucket, err := s.client.Bucket(destBucketName)
+	c.Assert(err, IsNil)
+
+	// Create a target bucket
+	err = s.client.CreateBucket(destBucketName)
+
+	// Upload source file
+	err = s.bucket.UploadFile(srcObjectName, fileName, 100*1024, Routines(3))
+	c.Assert(err, IsNil)
+	os.Remove(newFile)
+
+	// copyfile with properties
+	options := []Option{
+		ObjectACL(ACLPublicRead),
+		RequestPayer(Requester),
+		TrafficLimitHeader(1024 * 1024 * 8),
+		ObjectStorageClass(StorageArchive),
+		Routines(5),
+	}
+
+	// Copy files
+	err = destBucket.CopyFile(bucketName, srcObjectName, destObjectName, 1024*100, options...)
+	c.Assert(err, IsNil)
+
+	err = destBucket.DeleteObject(destObjectName)
+	c.Assert(err, IsNil)
+	os.Remove(newFile)
+
+	// Copy file with options
+	options = []Option{
+		ObjectACL(ACLPublicRead),
+		RequestPayer(Requester),
+		TrafficLimitHeader(1024 * 1024 * 8),
+		ObjectStorageClass(StorageArchive),
+		Routines(10),
+		Checkpoint(true, "copy.cp"),
+	}
+
+	err = destBucket.CopyFile(bucketName, srcObjectName, destObjectName, 1024*100, options...)
+	c.Assert(err, IsNil)
+
+	err = destBucket.DeleteObject(destObjectName)
+	c.Assert(err, IsNil)
+	os.Remove(newFile)
+
+	// Delete target bucket
+	err = s.client.DeleteBucket(destBucketName)
+	c.Assert(err, IsNil)
+}

+ 24 - 16
oss/upload.go

@@ -44,7 +44,7 @@ func getUploadCpFilePath(cpConf *cpConfig, srcFile, destBucket, destObject strin
 	if cpConf.FilePath == "" && cpConf.DirPath != "" {
 		dest := fmt.Sprintf("oss://%v/%v", destBucket, destObject)
 		absPath, _ := filepath.Abs(srcFile)
-		cpFileName := getCpFileName(absPath, dest)
+		cpFileName := getCpFileName(absPath, dest, "")
 		cpConf.FilePath = cpConf.DirPath + string(os.PathSeparator) + cpFileName
 	}
 	return cpConf.FilePath
@@ -63,7 +63,7 @@ func getCpConfig(options []Option) *cpConfig {
 }
 
 // getCpFileName return the name of the checkpoint file
-func getCpFileName(src, dest string) string {
+func getCpFileName(src, dest, versionId string) string {
 	md5Ctx := md5.New()
 	md5Ctx.Write([]byte(src))
 	srcCheckSum := hex.EncodeToString(md5Ctx.Sum(nil))
@@ -72,7 +72,14 @@ func getCpFileName(src, dest string) string {
 	md5Ctx.Write([]byte(dest))
 	destCheckSum := hex.EncodeToString(md5Ctx.Sum(nil))
 
-	return fmt.Sprintf("%v-%v.cp", srcCheckSum, destCheckSum)
+	if versionId == "" {
+		return fmt.Sprintf("%v-%v.cp", srcCheckSum, destCheckSum)
+	}
+
+	md5Ctx.Reset()
+	md5Ctx.Write([]byte(versionId))
+	versionCheckSum := hex.EncodeToString(md5Ctx.Sum(nil))
+	return fmt.Sprintf("%v-%v-%v.cp", srcCheckSum, destCheckSum, versionCheckSum)
 }
 
 // getRoutines gets the routine count. by default it's 1.
@@ -175,6 +182,10 @@ func (bucket Bucket) uploadFile(objectKey, filePath string, partSize int64, opti
 		return err
 	}
 
+	partOptions := ChoiceTransferPartOption(options)
+	completeOptions := ChoiceCompletePartOption(options)
+	abortOptions := ChoiceAbortPartOption(options)
+
 	// Initialize the multipart upload
 	imur, err := bucket.InitiateMultipartUpload(objectKey, options...)
 	if err != nil {
@@ -191,11 +202,8 @@ func (bucket Bucket) uploadFile(objectKey, filePath string, partSize int64, opti
 	event := newProgressEvent(TransferStartedEvent, 0, totalBytes, 0)
 	publishProgress(listener, event)
 
-	// oss server don't support x-oss-storage-class
-	options = deleteOption(options, HTTPHeaderOssStorageClass)
-
 	// Start the worker coroutine
-	arg := workerArg{&bucket, filePath, imur, options, uploadPartHooker}
+	arg := workerArg{&bucket, filePath, imur, partOptions, uploadPartHooker}
 	for w := 1; w <= routines; w++ {
 		go worker(w, arg, jobs, results, failed, die)
 	}
@@ -221,7 +229,7 @@ func (bucket Bucket) uploadFile(objectKey, filePath string, partSize int64, opti
 			close(die)
 			event = newProgressEvent(TransferFailedEvent, completedBytes, totalBytes, 0)
 			publishProgress(listener, event)
-			bucket.AbortMultipartUpload(imur, options...)
+			bucket.AbortMultipartUpload(imur, abortOptions...)
 			return err
 		}
 
@@ -234,9 +242,9 @@ func (bucket Bucket) uploadFile(objectKey, filePath string, partSize int64, opti
 	publishProgress(listener, event)
 
 	// Complete the multpart upload
-	_, err = bucket.CompleteMultipartUpload(imur, parts, options...)
+	_, err = bucket.CompleteMultipartUpload(imur, parts, completeOptions...)
 	if err != nil {
-		bucket.AbortMultipartUpload(imur, options...)
+		bucket.AbortMultipartUpload(imur, abortOptions...)
 		return err
 	}
 	return nil
@@ -299,7 +307,7 @@ func (cp uploadCheckpoint) isValid(filePath string) (bool, error) {
 
 	// Compare the file size, file's last modified time and file's MD5
 	if cp.FileStat.Size != st.Size() ||
-		cp.FileStat.LastModified != st.ModTime() ||
+		!cp.FileStat.LastModified.Equal(st.ModTime()) ||
 		cp.FileStat.MD5 != md {
 		return false, nil
 	}
@@ -448,6 +456,9 @@ func complete(cp *uploadCheckpoint, bucket *Bucket, parts []UploadPart, cpFilePa
 func (bucket Bucket) uploadFileWithCp(objectKey, filePath string, partSize int64, options []Option, cpFilePath string, routines int) error {
 	listener := getProgressListener(options)
 
+	partOptions := ChoiceTransferPartOption(options)
+	completeOptions := ChoiceCompletePartOption(options)
+
 	// Load CP data
 	ucp := uploadCheckpoint{}
 	err := ucp.load(cpFilePath)
@@ -482,11 +493,8 @@ func (bucket Bucket) uploadFileWithCp(objectKey, filePath string, partSize int64
 	event := newProgressEvent(TransferStartedEvent, completedBytes, ucp.FileStat.Size, 0)
 	publishProgress(listener, event)
 
-	// oss server don't support x-oss-storage-class
-	options = deleteOption(options, HTTPHeaderOssStorageClass)
-
 	// Start the workers
-	arg := workerArg{&bucket, filePath, imur, options, uploadPartHooker}
+	arg := workerArg{&bucket, filePath, imur, partOptions, uploadPartHooker}
 	for w := 1; w <= routines; w++ {
 		go worker(w, arg, jobs, results, failed, die)
 	}
@@ -521,6 +529,6 @@ func (bucket Bucket) uploadFileWithCp(objectKey, filePath string, partSize int64
 	publishProgress(listener, event)
 
 	// Complete the multipart upload
-	err = complete(&ucp, &bucket, ucp.allParts(), cpFilePath, options)
+	err = complete(&ucp, &bucket, ucp.allParts(), cpFilePath, completeOptions)
 	return err
 }

+ 85 - 1
oss/upload_test.go

@@ -459,7 +459,7 @@ func (s *OssUploadSuite) TestUploadLocalFileChange(c *C) {
 	c.Assert(err, IsNil)
 }
 
-// TestUploadPartArchiveObject 
+// TestUploadPartArchiveObject
 func (s *OssUploadSuite) TestUploadPartArchiveObject(c *C) {
 	// create archive bucket
 	client, err := New(endpoint, accessID, accessKey)
@@ -561,3 +561,87 @@ func (s *OssUploadSuite) TestVersioningUploadRoutineWithRecovery(c *C) {
 	bucket.DeleteObject(objectName)
 	forceDeleteBucket(client, bucketName, c)
 }
+
+// TestUploadFileChoiceOptions
+func (s *OssUploadSuite) TestUploadFileChoiceOptions(c *C) {
+	// create a bucket with default proprety
+	client, err := New(endpoint, accessID, accessKey)
+	c.Assert(err, IsNil)
+
+	bucketName := bucketNamePrefix + randLowStr(6)
+	err = client.CreateBucket(bucketName)
+	c.Assert(err, IsNil)
+	bucket, err := client.Bucket(bucketName)
+
+	fileName := "../sample/BingWallpaper-2015-11-07.jpg"
+	fileInfo, err := os.Stat(fileName)
+	c.Assert(err, IsNil)
+
+	objectName := objectNamePrefix + randStr(8)
+
+	// UploadFile with properties
+	options := []Option{
+		ObjectACL(ACLPublicRead),
+		RequestPayer(Requester),
+		TrafficLimitHeader(1024 * 1024 * 8),
+		ServerSideEncryption("AES256"),
+		ObjectStorageClass(StorageArchive),
+	}
+
+	// Updating the file
+	err = bucket.UploadFile(objectName, fileName, fileInfo.Size()/2, options...)
+	c.Assert(err, IsNil)
+
+	// GetMetaDetail
+	headerResp, err := bucket.GetObjectDetailedMeta(objectName)
+	c.Assert(err, IsNil)
+
+	c.Assert(headerResp.Get("X-Oss-Server-Side-Encryption"), Equals, "AES256")
+	aclResult, err := bucket.GetObjectACL(objectName)
+	c.Assert(aclResult.ACL, Equals, "public-read")
+	c.Assert(err, IsNil)
+	forceDeleteBucket(client, bucketName, c)
+}
+
+// TestUploadFileWithCpChoiceOptions
+func (s *OssUploadSuite) TestUploadFileWithCpChoiceOptions(c *C) {
+	// create a bucket with default proprety
+	client, err := New(endpoint, accessID, accessKey)
+	c.Assert(err, IsNil)
+
+	bucketName := bucketNamePrefix + randLowStr(6)
+	err = client.CreateBucket(bucketName)
+	c.Assert(err, IsNil)
+	bucket, err := client.Bucket(bucketName)
+
+	fileName := "../sample/BingWallpaper-2015-11-07.jpg"
+	fileInfo, err := os.Stat(fileName)
+	c.Assert(err, IsNil)
+
+	objectName := objectNamePrefix + randStr(8)
+
+	// UploadFile with properties
+	options := []Option{
+		ObjectACL(ACLPublicRead),
+		RequestPayer(Requester),
+		TrafficLimitHeader(1024 * 1024 * 8),
+		ServerSideEncryption("AES256"),
+		ObjectStorageClass(StorageArchive),
+		Checkpoint(true, fileName+".cp"),
+	}
+
+	// Updating the file
+	err = bucket.UploadFile(objectName, fileName, fileInfo.Size()/2, options...)
+	c.Assert(err, IsNil)
+
+	// GetMetaDetail
+	headerResp, err := bucket.GetObjectDetailedMeta(objectName)
+	c.Assert(err, IsNil)
+
+	c.Assert(headerResp.Get("X-Oss-Server-Side-Encryption"), Equals, "AES256")
+	aclResult, err := bucket.GetObjectACL(objectName)
+	c.Assert(aclResult.ACL, Equals, "public-read")
+	c.Assert(err, IsNil)
+
+	forceDeleteBucket(client, bucketName, c)
+}

+ 114 - 0
oss/utils.go

@@ -4,6 +4,7 @@ import (
 	"bytes"
 	"errors"
 	"fmt"
+	"hash/crc32"
 	"hash/crc64"
 	"net/http"
 	"os"
@@ -263,3 +264,116 @@ func GetPartEnd(begin int64, total int64, per int64) int64 {
 var crcTable = func() *crc64.Table {
 	return crc64.MakeTable(crc64.ECMA)
 }
+
+// crcTable returns the table constructed from the specified polynomial
+var crc32Table = func() *crc32.Table {
+	return crc32.MakeTable(crc32.IEEE)
+}
+
+// choiceTransferPartOption choices valid option supported by Uploadpart or DownloadPart
+func ChoiceTransferPartOption(options []Option) []Option {
+	var outOption []Option
+
+	listener, _ := findOption(options, progressListener, nil)
+	if listener != nil {
+		outOption = append(outOption, Progress(listener.(ProgressListener)))
+	}
+
+	payer, _ := findOption(options, HTTPHeaderOssRequester, nil)
+	if payer != nil {
+		outOption = append(outOption, RequestPayer(PayerType(payer.(string))))
+	}
+
+	versionId, _ := findOption(options, "versionId", nil)
+	if versionId != nil {
+		outOption = append(outOption, VersionId(versionId.(string)))
+	}
+
+	trafficLimit, _ := findOption(options, HTTPHeaderOssTrafficLimit, nil)
+	if trafficLimit != nil {
+		speed, _ := strconv.ParseInt(trafficLimit.(string), 10, 64)
+		outOption = append(outOption, TrafficLimitHeader(speed))
+	}
+
+	respHeader, _ := findOption(options, responseHeader, nil)
+	if respHeader != nil {
+		outOption = append(outOption, GetResponseHeader(respHeader.(*http.Header)))
+	}
+
+	return outOption
+}
+
+// ChoiceCompletePartOption choices valid option supported by CompleteMulitiPart
+func ChoiceCompletePartOption(options []Option) []Option {
+	var outOption []Option
+
+	listener, _ := findOption(options, progressListener, nil)
+	if listener != nil {
+		outOption = append(outOption, Progress(listener.(ProgressListener)))
+	}
+
+	payer, _ := findOption(options, HTTPHeaderOssRequester, nil)
+	if payer != nil {
+		outOption = append(outOption, RequestPayer(PayerType(payer.(string))))
+	}
+
+	acl, _ := findOption(options, HTTPHeaderOssObjectACL, nil)
+	if acl != nil {
+		outOption = append(outOption, ObjectACL(ACLType(acl.(string))))
+	}
+
+	callback, _ := findOption(options, HTTPHeaderOssCallback, nil)
+	if callback != nil {
+		outOption = append(outOption, Callback(callback.(string)))
+	}
+
+	callbackVar, _ := findOption(options, HTTPHeaderOssCallbackVar, nil)
+	if callbackVar != nil {
+		outOption = append(outOption, CallbackVar(callbackVar.(string)))
+	}
+
+	respHeader, _ := findOption(options, responseHeader, nil)
+	if respHeader != nil {
+		outOption = append(outOption, GetResponseHeader(respHeader.(*http.Header)))
+	}
+
+	return outOption
+}
+
+// ChoiceAbortPartOption choices valid option supported by AbortMultipartUpload
+func ChoiceAbortPartOption(options []Option) []Option {
+	var outOption []Option
+	payer, _ := findOption(options, HTTPHeaderOssRequester, nil)
+	if payer != nil {
+		outOption = append(outOption, RequestPayer(PayerType(payer.(string))))
+	}
+
+	respHeader, _ := findOption(options, responseHeader, nil)
+	if respHeader != nil {
+		outOption = append(outOption, GetResponseHeader(respHeader.(*http.Header)))
+	}
+
+	return outOption
+}
+
+// ChoiceHeadObjectOption choices valid option supported by HeadObject
+func ChoiceHeadObjectOption(options []Option) []Option {
+	var outOption []Option
+
+	payer, _ := findOption(options, HTTPHeaderOssRequester, nil)
+	if payer != nil {
+		outOption = append(outOption, RequestPayer(PayerType(payer.(string))))
+	}
+
+	versionId, _ := findOption(options, "versionId", nil)
+	if versionId != nil {
+		outOption = append(outOption, VersionId(versionId.(string)))
+	}
+
+	respHeader, _ := findOption(options, responseHeader, nil)
+	if respHeader != nil {
+		outOption = append(outOption, GetResponseHeader(respHeader.(*http.Header)))
+	}
+
+	return outOption
+}