|
|
@@ -9,11 +9,11 @@ import (
|
|
|
"hash"
|
|
|
"hash/crc64"
|
|
|
"io"
|
|
|
- "io/ioutil"
|
|
|
"net/http"
|
|
|
"net/url"
|
|
|
"os"
|
|
|
"strconv"
|
|
|
+ "strings"
|
|
|
"time"
|
|
|
)
|
|
|
|
|
|
@@ -128,7 +128,8 @@ func (bucket Bucket) GetObject(objectKey string, options ...Option) (io.ReadClos
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
- return result.Response.Body, nil
|
|
|
+
|
|
|
+ return result.Response, nil
|
|
|
}
|
|
|
|
|
|
// GetObjectToFile downloads the data to a local file.
|
|
|
@@ -147,7 +148,7 @@ func (bucket Bucket) GetObjectToFile(objectKey, filePath string, options ...Opti
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
- defer result.Response.Body.Close()
|
|
|
+ defer result.Response.Close()
|
|
|
|
|
|
// If the local file does not exist, create a new one. If it exists, overwrite it.
|
|
|
fd, err := os.OpenFile(tempFilePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, FilePermMode)
|
|
|
@@ -164,7 +165,12 @@ func (bucket Bucket) GetObjectToFile(objectKey, filePath string, options ...Opti
|
|
|
|
|
|
// Compares the CRC value
|
|
|
hasRange, _, _ := isOptionSet(options, HTTPHeaderRange)
|
|
|
- if bucket.getConfig().IsEnableCRC && !hasRange {
|
|
|
+ encodeOpt, _ := findOption(options, HTTPHeaderAcceptEncoding, nil)
|
|
|
+ acceptEncoding := ""
|
|
|
+ if encodeOpt != nil {
|
|
|
+ acceptEncoding = encodeOpt.(string)
|
|
|
+ }
|
|
|
+ if bucket.getConfig().IsEnableCRC && !hasRange && acceptEncoding != "gzip" {
|
|
|
result.Response.ClientCRC = result.ClientCRC.Sum64()
|
|
|
err = checkCRC(result.Response, "GetObjectToFile")
|
|
|
if err != nil {
|
|
|
@@ -185,7 +191,7 @@ func (bucket Bucket) GetObjectToFile(objectKey, filePath string, options ...Opti
|
|
|
// error it's nil if no error, otherwise it's an error object.
|
|
|
//
|
|
|
func (bucket Bucket) DoGetObject(request *GetObjectRequest, options []Option) (*GetObjectResult, error) {
|
|
|
- params := map[string]interface{}{}
|
|
|
+ params, _ := getRawParams(options)
|
|
|
resp, err := bucket.do("GET", request.ObjectKey, params, options, nil, nil)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
@@ -208,7 +214,7 @@ func (bucket Bucket) DoGetObject(request *GetObjectRequest, options []Option) (*
|
|
|
listener := getProgressListener(options)
|
|
|
|
|
|
contentLen, _ := strconv.ParseInt(resp.Headers.Get(HTTPHeaderContentLength), 10, 64)
|
|
|
- resp.Body = ioutil.NopCloser(TeeReader(resp.Body, crcCalc, contentLen, listener, nil))
|
|
|
+ resp.Body = TeeReader(resp.Body, crcCalc, contentLen, listener, nil)
|
|
|
|
|
|
return result, nil
|
|
|
}
|
|
|
@@ -219,7 +225,7 @@ func (bucket Bucket) DoGetObject(request *GetObjectRequest, options []Option) (*
|
|
|
// destObjectKey the target object to copy.
|
|
|
// options options for copying an object. You can specify the conditions of copy. The valid conditions are CopySourceIfMatch,
|
|
|
// CopySourceIfNoneMatch, CopySourceIfModifiedSince, CopySourceIfUnmodifiedSince, MetadataDirective.
|
|
|
-// Also you can specify the target object's attributes, such as CacheControl, ContentDisposition, ContentEncoding, Expires,
|
|
|
+// Also you can specify the target object's attributes, such as CacheControl, ContentDisposition, ContentEncoding, Expires,
|
|
|
// ServerSideEncryption, ObjectACL, Meta. Refer to the link below for more details :
|
|
|
// https://help.aliyun.com/document_detail/oss/api-reference/object/CopyObject.html
|
|
|
//
|
|
|
@@ -303,7 +309,7 @@ func (bucket Bucket) copy(srcObjectKey, destBucketName, destObjectKey string, op
|
|
|
// reader io.Reader. The read instance for reading the data to append.
|
|
|
// appendPosition the start position to append.
|
|
|
// destObjectProperties the options for the first appending, such as CacheControl, ContentDisposition, ContentEncoding,
|
|
|
-// Expires, ServerSideEncryption, ObjectACL.
|
|
|
+// Expires, ServerSideEncryption, ObjectACL.
|
|
|
//
|
|
|
// int64 the next append position, it's valid when error is nil.
|
|
|
// error it's nil if no error, otherwise it's an error object.
|
|
|
@@ -451,7 +457,7 @@ func (bucket Bucket) IsObjectExist(objectKey string) (bool, error) {
|
|
|
|
|
|
switch err.(type) {
|
|
|
case ServiceError:
|
|
|
- if err.(ServiceError).StatusCode == 404 && err.(ServiceError).Code == "NoSuchKey" {
|
|
|
+ if err.(ServiceError).StatusCode == 404 {
|
|
|
return false, nil
|
|
|
}
|
|
|
}
|
|
|
@@ -464,7 +470,7 @@ func (bucket Bucket) IsObjectExist(objectKey string) (bool, error) {
|
|
|
// options it contains all the filters for listing objects.
|
|
|
// It could specify a prefix filter on object keys, the max keys count to return and the object key marker and the delimiter for grouping object names.
|
|
|
// The key marker means the returned objects' key must be greater than it in lexicographic order.
|
|
|
-//
|
|
|
+//
|
|
|
// For example, if the bucket has 8 objects, my-object-1, my-object-11, my-object-2, my-object-21,
|
|
|
// my-object-22, my-object-3, my-object-31, my-object-32. If the prefix is my-object-2 (no other filters), then it returns
|
|
|
// my-object-2, my-object-21, my-object-22 three objects. If the marker is my-object-22 (no other filters), then it returns
|
|
|
@@ -474,9 +480,9 @@ func (bucket Bucket) IsObjectExist(objectKey string) (bool, error) {
|
|
|
// But if the delimiter is specified with '/', then it only returns that folder's files (no subfolder's files). The direct subfolders are in the commonPrefixes properties.
|
|
|
// For example, if the bucket has three objects fun/test.jpg, fun/movie/001.avi, fun/movie/007.avi. And if the prefix is "fun/", then it returns all three objects.
|
|
|
// But if the delimiter is '/', then only "fun/test.jpg" is returned as files and fun/movie/ is returned as common prefix.
|
|
|
-//
|
|
|
+//
|
|
|
// For common usage scenario, check out sample/list_object.go.
|
|
|
-//
|
|
|
+//
|
|
|
// ListObjectsResponse the return value after operation succeeds (only valid when error is nil).
|
|
|
//
|
|
|
func (bucket Bucket) ListObjects(options ...Option) (ListObjectsResult, error) {
|
|
|
@@ -488,7 +494,7 @@ func (bucket Bucket) ListObjects(options ...Option) (ListObjectsResult, error) {
|
|
|
return out, err
|
|
|
}
|
|
|
|
|
|
- resp, err := bucket.do("GET", "", params, nil, nil, nil)
|
|
|
+ resp, err := bucket.do("GET", "", params, options, nil, nil)
|
|
|
if err != nil {
|
|
|
return out, err
|
|
|
}
|
|
|
@@ -547,11 +553,11 @@ func (bucket Bucket) GetObjectDetailedMeta(objectKey string, options ...Option)
|
|
|
// http.Header the object's metadata, valid when error is nil.
|
|
|
// error it's nil if no error, otherwise it's an error object.
|
|
|
//
|
|
|
-func (bucket Bucket) GetObjectMeta(objectKey string) (http.Header, error) {
|
|
|
+func (bucket Bucket) GetObjectMeta(objectKey string, options ...Option) (http.Header, error) {
|
|
|
params := map[string]interface{}{}
|
|
|
params["objectMeta"] = nil
|
|
|
//resp, err := bucket.do("GET", objectKey, "?objectMeta", "", nil, nil, nil)
|
|
|
- resp, err := bucket.do("GET", objectKey, params, nil, nil, nil)
|
|
|
+ resp, err := bucket.do("HEAD", objectKey, params, options, nil, nil)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
@@ -802,7 +808,7 @@ func (bucket Bucket) GetObjectWithURL(signedURL string, options ...Option) (io.R
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
- return result.Response.Body, nil
|
|
|
+ return result.Response, nil
|
|
|
}
|
|
|
|
|
|
// GetObjectToFileWithURL downloads the object into a local file with the signed URL.
|
|
|
@@ -821,7 +827,7 @@ func (bucket Bucket) GetObjectToFileWithURL(signedURL, filePath string, options
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
- defer result.Response.Body.Close()
|
|
|
+ defer result.Response.Close()
|
|
|
|
|
|
// If the file does not exist, create one. If exists, then overwrite it.
|
|
|
fd, err := os.OpenFile(tempFilePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, FilePermMode)
|
|
|
@@ -838,7 +844,13 @@ func (bucket Bucket) GetObjectToFileWithURL(signedURL, filePath string, options
|
|
|
|
|
|
// Compare the CRC value. If CRC values do not match, return error.
|
|
|
hasRange, _, _ := isOptionSet(options, HTTPHeaderRange)
|
|
|
- if bucket.getConfig().IsEnableCRC && !hasRange {
|
|
|
+ encodeOpt, _ := findOption(options, HTTPHeaderAcceptEncoding, nil)
|
|
|
+ acceptEncoding := ""
|
|
|
+ if encodeOpt != nil {
|
|
|
+ acceptEncoding = encodeOpt.(string)
|
|
|
+ }
|
|
|
+
|
|
|
+ if bucket.getConfig().IsEnableCRC && !hasRange && acceptEncoding != "gzip" {
|
|
|
result.Response.ClientCRC = result.ClientCRC.Sum64()
|
|
|
err = checkCRC(result.Response, "GetObjectToFileWithURL")
|
|
|
if err != nil {
|
|
|
@@ -859,7 +871,7 @@ func (bucket Bucket) GetObjectToFileWithURL(signedURL, filePath string, options
|
|
|
// error it's nil if no error, otherwise it's an error object.
|
|
|
//
|
|
|
func (bucket Bucket) DoGetObjectWithURL(signedURL string, options []Option) (*GetObjectResult, error) {
|
|
|
- params := map[string]interface{}{}
|
|
|
+ params, _ := getRawParams(options)
|
|
|
resp, err := bucket.doURL("GET", signedURL, params, options, nil, nil)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
@@ -882,11 +894,39 @@ func (bucket Bucket) DoGetObjectWithURL(signedURL string, options []Option) (*Ge
|
|
|
listener := getProgressListener(options)
|
|
|
|
|
|
contentLen, _ := strconv.ParseInt(resp.Headers.Get(HTTPHeaderContentLength), 10, 64)
|
|
|
- resp.Body = ioutil.NopCloser(TeeReader(resp.Body, crcCalc, contentLen, listener, nil))
|
|
|
+ resp.Body = TeeReader(resp.Body, crcCalc, contentLen, listener, nil)
|
|
|
|
|
|
return result, nil
|
|
|
}
|
|
|
|
|
|
+//
|
|
|
+// ProcessObject apply process on the specified image file.
|
|
|
+//
|
|
|
+// The supported process includes resize, rotate, crop, watermark, format,
|
|
|
+// udf, customized style, etc.
|
|
|
+//
|
|
|
+//
|
|
|
+// objectKey object key to process.
|
|
|
+// process process string, such as "image/resize,w_100|sys/saveas,o_dGVzdC5qcGc,b_dGVzdA"
|
|
|
+//
|
|
|
+// error it's nil if no error, otherwise it's an error object.
|
|
|
+//
|
|
|
+func (bucket Bucket) ProcessObject(objectKey string, process string) (ProcessObjectResult, error) {
|
|
|
+ var out ProcessObjectResult
|
|
|
+ params := map[string]interface{}{}
|
|
|
+ params["x-oss-process"] = nil
|
|
|
+ processData := fmt.Sprintf("%v=%v", "x-oss-process", process)
|
|
|
+ data := strings.NewReader(processData)
|
|
|
+ resp, err := bucket.do("POST", objectKey, params, nil, data, nil)
|
|
|
+ if err != nil {
|
|
|
+ return out, err
|
|
|
+ }
|
|
|
+ defer resp.Body.Close()
|
|
|
+
|
|
|
+ err = jsonUnmarshal(resp.Body, &out)
|
|
|
+ return out, err
|
|
|
+}
|
|
|
+
|
|
|
// Private
|
|
|
func (bucket Bucket) do(method, objectName string, params map[string]interface{}, options []Option,
|
|
|
data io.Reader, listener ProgressListener) (*Response, error) {
|