add sse-c and optional header for put object
This commit is contained in:
@@ -549,6 +549,85 @@ func (s *CosTestSuite) TestCreateCompleteMultipartUpload() {
|
|||||||
assert.Nil(s.T(), err, "CompleteMultipartUpload Failed")
|
assert.Nil(s.T(), err, "CompleteMultipartUpload Failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *CosTestSuite) TestSSE_C() {
|
||||||
|
name := "test/TestSSE_C"
|
||||||
|
content := "test sse-c " + time.Now().Format(time.RFC3339)
|
||||||
|
f := strings.NewReader(content)
|
||||||
|
putOpt := &cos.ObjectPutOptions{
|
||||||
|
ObjectPutHeaderOptions: &cos.ObjectPutHeaderOptions{
|
||||||
|
ContentType: "text/html",
|
||||||
|
//XCosServerSideEncryption: "AES256",
|
||||||
|
XCosSSECustomerAglo: "AES256",
|
||||||
|
XCosSSECustomerKey: "MDEyMzQ1Njc4OUFCQ0RFRjAxMjM0NTY3ODlBQkNERUY=",
|
||||||
|
XCosSSECustomerKeyMD5: "U5L61r7jcwdNvT7frmUG8g==",
|
||||||
|
},
|
||||||
|
ACLHeaderOptions: &cos.ACLHeaderOptions{
|
||||||
|
XCosACL: "public-read",
|
||||||
|
//XCosACL: "private",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, err := s.Client.Object.Put(context.Background(), name, f, putOpt)
|
||||||
|
assert.Nil(s.T(), err, "PutObject with SSE failed")
|
||||||
|
|
||||||
|
headOpt := &cos.ObjectHeadOptions{
|
||||||
|
XCosSSECustomerAglo: "AES256",
|
||||||
|
XCosSSECustomerKey: "MDEyMzQ1Njc4OUFCQ0RFRjAxMjM0NTY3ODlBQkNERUY=",
|
||||||
|
XCosSSECustomerKeyMD5: "U5L61r7jcwdNvT7frmUG8g==",
|
||||||
|
}
|
||||||
|
_, err = s.Client.Object.Head(context.Background(), name, headOpt)
|
||||||
|
assert.Nil(s.T(), err, "HeadObject with SSE failed")
|
||||||
|
|
||||||
|
getOpt := &cos.ObjectGetOptions{
|
||||||
|
XCosSSECustomerAglo: "AES256",
|
||||||
|
XCosSSECustomerKey: "MDEyMzQ1Njc4OUFCQ0RFRjAxMjM0NTY3ODlBQkNERUY=",
|
||||||
|
XCosSSECustomerKeyMD5: "U5L61r7jcwdNvT7frmUG8g==",
|
||||||
|
}
|
||||||
|
var resp *cos.Response
|
||||||
|
resp, err = s.Client.Object.Get(context.Background(), name, getOpt)
|
||||||
|
assert.Nil(s.T(), err, "GetObject with SSE failed")
|
||||||
|
|
||||||
|
bodyBytes, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
bodyContent := string(bodyBytes)
|
||||||
|
assert.Equal(s.T(), content, bodyContent, "GetObject with SSE failed, want: %+v, res: %+v", content, bodyContent)
|
||||||
|
|
||||||
|
copyOpt := &cos.ObjectCopyOptions{
|
||||||
|
&cos.ObjectCopyHeaderOptions{
|
||||||
|
XCosCopySourceSSECustomerAglo: "AES256",
|
||||||
|
XCosCopySourceSSECustomerKey: "MDEyMzQ1Njc4OUFCQ0RFRjAxMjM0NTY3ODlBQkNERUY=",
|
||||||
|
XCosCopySourceSSECustomerKeyMD5: "U5L61r7jcwdNvT7frmUG8g==",
|
||||||
|
},
|
||||||
|
&cos.ACLHeaderOptions{},
|
||||||
|
}
|
||||||
|
copySource := s.Bucket + "-" + s.Appid + ".cos." + s.Region + ".myqcloud.com/" + name
|
||||||
|
_, _, err = s.Client.Object.Copy(context.Background(), "test/TestSSE_C_Copy", copySource, copyOpt)
|
||||||
|
assert.Nil(s.T(), err, "CopyObject with SSE failed")
|
||||||
|
|
||||||
|
partIni := &cos.MultiUploadOptions{
|
||||||
|
OptIni: &cos.InitiateMultipartUploadOptions{
|
||||||
|
&cos.ACLHeaderOptions{},
|
||||||
|
&cos.ObjectPutHeaderOptions{
|
||||||
|
XCosSSECustomerAglo: "AES256",
|
||||||
|
XCosSSECustomerKey: "MDEyMzQ1Njc4OUFCQ0RFRjAxMjM0NTY3ODlBQkNERUY=",
|
||||||
|
XCosSSECustomerKeyMD5: "U5L61r7jcwdNvT7frmUG8g==",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PartSize: 1,
|
||||||
|
}
|
||||||
|
filePath := "tmpfile" + time.Now().Format(time.RFC3339)
|
||||||
|
newFile, err := os.Create(filePath)
|
||||||
|
assert.Nil(s.T(), err, "create tmp file Failed")
|
||||||
|
defer newFile.Close()
|
||||||
|
b := make([]byte, 1024*10)
|
||||||
|
_, err = rand.Read(b)
|
||||||
|
newFile.Write(b)
|
||||||
|
|
||||||
|
_, _, err = s.Client.Object.MultiUpload(context.Background(), "test/TestSSE_C_MultiUpload", filePath, partIni)
|
||||||
|
assert.Nil(s.T(), err, "MultiUpload with SSE failed")
|
||||||
|
|
||||||
|
err = os.Remove(filePath)
|
||||||
|
assert.Nil(s.T(), err, "remove local file Failed")
|
||||||
|
}
|
||||||
|
|
||||||
// End of api test
|
// End of api test
|
||||||
|
|
||||||
// All methods that begin with "Test" are run as tests within a
|
// All methods that begin with "Test" are run as tests within a
|
||||||
|
|||||||
34
object.go
34
object.go
@@ -26,6 +26,10 @@ type ObjectGetOptions struct {
|
|||||||
ResponseContentEncoding string `url:"response-content-encoding,omitempty" header:"-"`
|
ResponseContentEncoding string `url:"response-content-encoding,omitempty" header:"-"`
|
||||||
Range string `url:"-" header:"Range,omitempty"`
|
Range string `url:"-" header:"Range,omitempty"`
|
||||||
IfModifiedSince string `url:"-" header:"If-Modified-Since,omitempty"`
|
IfModifiedSince string `url:"-" header:"If-Modified-Since,omitempty"`
|
||||||
|
// SSE-C
|
||||||
|
XCosSSECustomerAglo string `header:"x-cos-server-side-encryption-customer-algorithm,omitempty" url:"-" xml:"-"`
|
||||||
|
XCosSSECustomerKey string `header:"x-cos-server-side-encryption-customer-key,omitempty" url:"-" xml:"-"`
|
||||||
|
XCosSSECustomerKeyMD5 string `header:"x-cos-server-side-encryption-customer-key-MD5,omitempty" url:"-" xml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// presignedURLTestingOptions is the opt of presigned url
|
// presignedURLTestingOptions is the opt of presigned url
|
||||||
@@ -135,6 +139,12 @@ type ObjectPutHeaderOptions struct {
|
|||||||
//XCosObjectType string `header:"x-cos-object-type,omitempty" url:"-"`
|
//XCosObjectType string `header:"x-cos-object-type,omitempty" url:"-"`
|
||||||
// Enable Server Side Encryption, Only supported: AES256
|
// Enable Server Side Encryption, Only supported: AES256
|
||||||
XCosServerSideEncryption string `header:"x-cos-server-side-encryption,omitempty" url:"-" xml:"-"`
|
XCosServerSideEncryption string `header:"x-cos-server-side-encryption,omitempty" url:"-" xml:"-"`
|
||||||
|
// SSE-C
|
||||||
|
XCosSSECustomerAglo string `header:"x-cos-server-side-encryption-customer-algorithm,omitempty" url:"-" xml:"-"`
|
||||||
|
XCosSSECustomerKey string `header:"x-cos-server-side-encryption-customer-key,omitempty" url:"-" xml:"-"`
|
||||||
|
XCosSSECustomerKeyMD5 string `header:"x-cos-server-side-encryption-customer-key-MD5,omitempty" url:"-" xml:"-"`
|
||||||
|
//兼容其他自定义头部
|
||||||
|
XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ObjectPutOptions the options of put object
|
// ObjectPutOptions the options of put object
|
||||||
@@ -191,6 +201,13 @@ type ObjectCopyHeaderOptions struct {
|
|||||||
XCosMetaXXX *http.Header `header:"x-cos-meta-*,omitempty" url:"-"`
|
XCosMetaXXX *http.Header `header:"x-cos-meta-*,omitempty" url:"-"`
|
||||||
XCosCopySource string `header:"x-cos-copy-source" url:"-" xml:"-"`
|
XCosCopySource string `header:"x-cos-copy-source" url:"-" xml:"-"`
|
||||||
XCosServerSideEncryption string `header:"x-cos-server-side-encryption,omitempty" url:"-" xml:"-"`
|
XCosServerSideEncryption string `header:"x-cos-server-side-encryption,omitempty" url:"-" xml:"-"`
|
||||||
|
// SSE-C
|
||||||
|
XCosSSECustomerAglo string `header:"x-cos-server-side-encryption-customer-algorithm,omitempty" url:"-" xml:"-"`
|
||||||
|
XCosSSECustomerKey string `header:"x-cos-server-side-encryption-customer-key,omitempty" url:"-" xml:"-"`
|
||||||
|
XCosSSECustomerKeyMD5 string `header:"x-cos-server-side-encryption-customer-key-MD5,omitempty" url:"-" xml:"-"`
|
||||||
|
XCosCopySourceSSECustomerAglo string `header:"x-cos-copy-source-server-side-encryption-customer-algorithm,omitempty" url:"-" xml:"-"`
|
||||||
|
XCosCopySourceSSECustomerKey string `header:"x-cos-copy-source-server-side-encryption-customer-key,omitempty" url:"-" xml:"-"`
|
||||||
|
XCosCopySourceSSECustomerKeyMD5 string `header:"x-cos-copy-source-server-side-encryption-customer-key-MD5,omitempty" url:"-" xml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ObjectCopyOptions is the option of Copy, choose header or body
|
// ObjectCopyOptions is the option of Copy, choose header or body
|
||||||
@@ -272,6 +289,10 @@ func (s *ObjectService) Delete(ctx context.Context, name string) (*Response, err
|
|||||||
// ObjectHeadOptions is the option of HeadObject
|
// ObjectHeadOptions is the option of HeadObject
|
||||||
type ObjectHeadOptions struct {
|
type ObjectHeadOptions struct {
|
||||||
IfModifiedSince string `url:"-" header:"If-Modified-Since,omitempty"`
|
IfModifiedSince string `url:"-" header:"If-Modified-Since,omitempty"`
|
||||||
|
// SSE-C
|
||||||
|
XCosSSECustomerAglo string `header:"x-cos-server-side-encryption-customer-algorithm,omitempty" url:"-" xml:"-"`
|
||||||
|
XCosSSECustomerKey string `header:"x-cos-server-side-encryption-customer-key,omitempty" url:"-" xml:"-"`
|
||||||
|
XCosSSECustomerKeyMD5 string `header:"x-cos-server-side-encryption-customer-key-MD5,omitempty" url:"-" xml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Head Object请求可以取回对应Object的元数据,Head的权限与Get的权限一致
|
// Head Object请求可以取回对应Object的元数据,Head的权限与Get的权限一致
|
||||||
@@ -472,14 +493,12 @@ func worker(s *ObjectService, jobs <-chan *Jobs, results chan<- *Results) {
|
|||||||
|
|
||||||
fd.Seek(j.Chunk.OffSet, os.SEEK_SET)
|
fd.Seek(j.Chunk.OffSet, os.SEEK_SET)
|
||||||
// UploadPart do not support the chunk trsf, so need to add the content-length
|
// UploadPart do not support the chunk trsf, so need to add the content-length
|
||||||
opt := &ObjectUploadPartOptions{
|
j.Opt.ContentLength = int(j.Chunk.Size)
|
||||||
ContentLength: int(j.Chunk.Size),
|
|
||||||
}
|
|
||||||
|
|
||||||
rt := j.RetryTimes
|
rt := j.RetryTimes
|
||||||
for {
|
for {
|
||||||
resp, err := s.UploadPart(context.Background(), j.Name, j.UploadId, j.Chunk.Number,
|
resp, err := s.UploadPart(context.Background(), j.Name, j.UploadId, j.Chunk.Number,
|
||||||
&io.LimitedReader{R: fd, N: j.Chunk.Size}, opt)
|
&io.LimitedReader{R: fd, N: j.Chunk.Size}, j.Opt)
|
||||||
res.PartNumber = j.Chunk.Number
|
res.PartNumber = j.Chunk.Number
|
||||||
res.Resp = resp
|
res.Resp = resp
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -581,12 +600,19 @@ func (s *ObjectService) MultiUpload(ctx context.Context, name string, filepath s
|
|||||||
|
|
||||||
// 4.Push jobs
|
// 4.Push jobs
|
||||||
for _, chunk := range chunks {
|
for _, chunk := range chunks {
|
||||||
|
partOpt := &ObjectUploadPartOptions{}
|
||||||
|
if optini != nil && optini.ObjectPutHeaderOptions != nil {
|
||||||
|
partOpt.XCosSSECustomerAglo = optini.XCosSSECustomerAglo
|
||||||
|
partOpt.XCosSSECustomerKey = optini.XCosSSECustomerKey
|
||||||
|
partOpt.XCosSSECustomerKeyMD5 = optini.XCosSSECustomerKeyMD5
|
||||||
|
}
|
||||||
job := &Jobs{
|
job := &Jobs{
|
||||||
Name: name,
|
Name: name,
|
||||||
RetryTimes: 3,
|
RetryTimes: 3,
|
||||||
FilePath: filepath,
|
FilePath: filepath,
|
||||||
UploadId: uploadID,
|
UploadId: uploadID,
|
||||||
Chunk: chunk,
|
Chunk: chunk,
|
||||||
|
Opt: partOpt,
|
||||||
}
|
}
|
||||||
chjobs <- job
|
chjobs <- job
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,10 @@ type ObjectUploadPartOptions struct {
|
|||||||
Expect string `header:"Expect,omitempty" url:"-"`
|
Expect string `header:"Expect,omitempty" url:"-"`
|
||||||
XCosContentSHA1 string `header:"x-cos-content-sha1" url:"-"`
|
XCosContentSHA1 string `header:"x-cos-content-sha1" url:"-"`
|
||||||
ContentLength int `header:"Content-Length,omitempty" url:"-"`
|
ContentLength int `header:"Content-Length,omitempty" url:"-"`
|
||||||
|
|
||||||
|
XCosSSECustomerAglo string `header:"x-cos-server-side-encryption-customer-algorithm,omitempty" url:"-" xml:"-"`
|
||||||
|
XCosSSECustomerKey string `header:"x-cos-server-side-encryption-customer-key,omitempty" url:"-" xml:"-"`
|
||||||
|
XCosSSECustomerKeyMD5 string `header:"x-cos-server-side-encryption-customer-key-MD5,omitempty" url:"-" xml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UploadPart 请求实现在初始化以后的分块上传,支持的块的数量为1到10000,块的大小为1 MB 到5 GB。
|
// UploadPart 请求实现在初始化以后的分块上传,支持的块的数量为1到10000,块的大小为1 MB 到5 GB。
|
||||||
|
|||||||
Reference in New Issue
Block a user