You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
386 lines
11 KiB
386 lines
11 KiB
package oss |
|
|
|
import ( |
|
"fmt" |
|
"net/http" |
|
"strconv" |
|
"strings" |
|
"time" |
|
) |
|
|
|
type optionType string |
|
|
|
const ( |
|
optionParam optionType = "HTTPParameter" // URL parameter |
|
optionHTTP optionType = "HTTPHeader" // HTTP header |
|
optionArg optionType = "FuncArgument" // Function argument |
|
) |
|
|
|
const ( |
|
deleteObjectsQuiet = "delete-objects-quiet" |
|
routineNum = "x-routine-num" |
|
checkpointConfig = "x-cp-config" |
|
initCRC64 = "init-crc64" |
|
progressListener = "x-progress-listener" |
|
storageClass = "storage-class" |
|
) |
|
|
|
type ( |
|
optionValue struct { |
|
Value interface{} |
|
Type optionType |
|
} |
|
|
|
// Option HTTP option |
|
Option func(map[string]optionValue) error |
|
) |
|
|
|
// ACL is an option to set X-Oss-Acl header |
|
func ACL(acl ACLType) Option { |
|
return setHeader(HTTPHeaderOssACL, string(acl)) |
|
} |
|
|
|
// ContentType is an option to set Content-Type header |
|
func ContentType(value string) Option { |
|
return setHeader(HTTPHeaderContentType, value) |
|
} |
|
|
|
// ContentLength is an option to set Content-Length header |
|
func ContentLength(length int64) Option { |
|
return setHeader(HTTPHeaderContentLength, strconv.FormatInt(length, 10)) |
|
} |
|
|
|
// CacheControl is an option to set Cache-Control header |
|
func CacheControl(value string) Option { |
|
return setHeader(HTTPHeaderCacheControl, value) |
|
} |
|
|
|
// ContentDisposition is an option to set Content-Disposition header |
|
func ContentDisposition(value string) Option { |
|
return setHeader(HTTPHeaderContentDisposition, value) |
|
} |
|
|
|
// ContentEncoding is an option to set Content-Encoding header |
|
func ContentEncoding(value string) Option { |
|
return setHeader(HTTPHeaderContentEncoding, value) |
|
} |
|
|
|
// ContentMD5 is an option to set Content-MD5 header |
|
func ContentMD5(value string) Option { |
|
return setHeader(HTTPHeaderContentMD5, value) |
|
} |
|
|
|
// Expires is an option to set Expires header |
|
func Expires(t time.Time) Option { |
|
return setHeader(HTTPHeaderExpires, t.Format(http.TimeFormat)) |
|
} |
|
|
|
// Meta is an option to set Meta header |
|
func Meta(key, value string) Option { |
|
return setHeader(HTTPHeaderOssMetaPrefix+key, value) |
|
} |
|
|
|
// Range is an option to set Range header, [start, end] |
|
func Range(start, end int64) Option { |
|
return setHeader(HTTPHeaderRange, fmt.Sprintf("bytes=%d-%d", start, end)) |
|
} |
|
|
|
// NormalizedRange is an option to set Range header, such as 1024-2048 or 1024- or -2048 |
|
func NormalizedRange(nr string) Option { |
|
return setHeader(HTTPHeaderRange, fmt.Sprintf("bytes=%s", strings.TrimSpace(nr))) |
|
} |
|
|
|
// AcceptEncoding is an option to set Accept-Encoding header |
|
func AcceptEncoding(value string) Option { |
|
return setHeader(HTTPHeaderAcceptEncoding, value) |
|
} |
|
|
|
// IfModifiedSince is an option to set If-Modified-Since header |
|
func IfModifiedSince(t time.Time) Option { |
|
return setHeader(HTTPHeaderIfModifiedSince, t.Format(http.TimeFormat)) |
|
} |
|
|
|
// IfUnmodifiedSince is an option to set If-Unmodified-Since header |
|
func IfUnmodifiedSince(t time.Time) Option { |
|
return setHeader(HTTPHeaderIfUnmodifiedSince, t.Format(http.TimeFormat)) |
|
} |
|
|
|
// IfMatch is an option to set If-Match header |
|
func IfMatch(value string) Option { |
|
return setHeader(HTTPHeaderIfMatch, value) |
|
} |
|
|
|
// IfNoneMatch is an option to set IfNoneMatch header |
|
func IfNoneMatch(value string) Option { |
|
return setHeader(HTTPHeaderIfNoneMatch, value) |
|
} |
|
|
|
// CopySource is an option to set X-Oss-Copy-Source header |
|
func CopySource(sourceBucket, sourceObject string) Option { |
|
return setHeader(HTTPHeaderOssCopySource, "/"+sourceBucket+"/"+sourceObject) |
|
} |
|
|
|
// CopySourceRange is an option to set X-Oss-Copy-Source header |
|
func CopySourceRange(startPosition, partSize int64) Option { |
|
val := "bytes=" + strconv.FormatInt(startPosition, 10) + "-" + |
|
strconv.FormatInt((startPosition+partSize-1), 10) |
|
return setHeader(HTTPHeaderOssCopySourceRange, val) |
|
} |
|
|
|
// CopySourceIfMatch is an option to set X-Oss-Copy-Source-If-Match header |
|
func CopySourceIfMatch(value string) Option { |
|
return setHeader(HTTPHeaderOssCopySourceIfMatch, value) |
|
} |
|
|
|
// CopySourceIfNoneMatch is an option to set X-Oss-Copy-Source-If-None-Match header |
|
func CopySourceIfNoneMatch(value string) Option { |
|
return setHeader(HTTPHeaderOssCopySourceIfNoneMatch, value) |
|
} |
|
|
|
// CopySourceIfModifiedSince is an option to set X-Oss-CopySource-If-Modified-Since header |
|
func CopySourceIfModifiedSince(t time.Time) Option { |
|
return setHeader(HTTPHeaderOssCopySourceIfModifiedSince, t.Format(http.TimeFormat)) |
|
} |
|
|
|
// CopySourceIfUnmodifiedSince is an option to set X-Oss-Copy-Source-If-Unmodified-Since header |
|
func CopySourceIfUnmodifiedSince(t time.Time) Option { |
|
return setHeader(HTTPHeaderOssCopySourceIfUnmodifiedSince, t.Format(http.TimeFormat)) |
|
} |
|
|
|
// MetadataDirective is an option to set X-Oss-Metadata-Directive header |
|
func MetadataDirective(directive MetadataDirectiveType) Option { |
|
return setHeader(HTTPHeaderOssMetadataDirective, string(directive)) |
|
} |
|
|
|
// ServerSideEncryption is an option to set X-Oss-Server-Side-Encryption header |
|
func ServerSideEncryption(value string) Option { |
|
return setHeader(HTTPHeaderOssServerSideEncryption, value) |
|
} |
|
|
|
// ObjectACL is an option to set X-Oss-Object-Acl header |
|
func ObjectACL(acl ACLType) Option { |
|
return setHeader(HTTPHeaderOssObjectACL, string(acl)) |
|
} |
|
|
|
// symlinkTarget is an option to set X-Oss-Symlink-Target |
|
func symlinkTarget(targetObjectKey string) Option { |
|
return setHeader(HTTPHeaderOssSymlinkTarget, targetObjectKey) |
|
} |
|
|
|
// Origin is an option to set Origin header |
|
func Origin(value string) Option { |
|
return setHeader(HTTPHeaderOrigin, value) |
|
} |
|
|
|
// Delimiter is an option to set delimiler parameter |
|
func Delimiter(value string) Option { |
|
return addParam("delimiter", value) |
|
} |
|
|
|
// Marker is an option to set marker parameter |
|
func Marker(value string) Option { |
|
return addParam("marker", value) |
|
} |
|
|
|
// MaxKeys is an option to set maxkeys parameter |
|
func MaxKeys(value int) Option { |
|
return addParam("max-keys", strconv.Itoa(value)) |
|
} |
|
|
|
// Prefix is an option to set prefix parameter |
|
func Prefix(value string) Option { |
|
return addParam("prefix", value) |
|
} |
|
|
|
// EncodingType is an option to set encoding-type parameter |
|
func EncodingType(value string) Option { |
|
return addParam("encoding-type", value) |
|
} |
|
|
|
// MaxUploads is an option to set max-uploads parameter |
|
func MaxUploads(value int) Option { |
|
return addParam("max-uploads", strconv.Itoa(value)) |
|
} |
|
|
|
// KeyMarker is an option to set key-marker parameter |
|
func KeyMarker(value string) Option { |
|
return addParam("key-marker", value) |
|
} |
|
|
|
// UploadIDMarker is an option to set upload-id-marker parameter |
|
func UploadIDMarker(value string) Option { |
|
return addParam("upload-id-marker", value) |
|
} |
|
|
|
// DeleteObjectsQuiet false:DeleteObjects in verbose mode; true:DeleteObjects in quite mode. Default is false. |
|
func DeleteObjectsQuiet(isQuiet bool) Option { |
|
return addArg(deleteObjectsQuiet, isQuiet) |
|
} |
|
|
|
// StorageClass bucket storage class |
|
func StorageClass(value StorageClassType) Option { |
|
return addArg(storageClass, value) |
|
} |
|
|
|
// Checkpoint configuration |
|
type cpConfig struct { |
|
IsEnable bool |
|
FilePath string |
|
} |
|
|
|
// Checkpoint sets the isEnable flag and checkpoint file path for DownloadFile/UploadFile. |
|
func Checkpoint(isEnable bool, filePath string) Option { |
|
return addArg(checkpointConfig, &cpConfig{isEnable, filePath}) |
|
} |
|
|
|
// Routines DownloadFile/UploadFile routine count |
|
func Routines(n int) Option { |
|
return addArg(routineNum, n) |
|
} |
|
|
|
// InitCRC Init AppendObject CRC |
|
func InitCRC(initCRC uint64) Option { |
|
return addArg(initCRC64, initCRC) |
|
} |
|
|
|
// Progress set progress listener |
|
func Progress(listener ProgressListener) Option { |
|
return addArg(progressListener, listener) |
|
} |
|
|
|
// ResponseContentType is an option to set response-content-type param |
|
func ResponseContentType(value string) Option { |
|
return addParam("response-content-type", value) |
|
} |
|
|
|
// ResponseContentLanguage is an option to set response-content-language param |
|
func ResponseContentLanguage(value string) Option { |
|
return addParam("response-content-language", value) |
|
} |
|
|
|
// ResponseExpires is an option to set response-expires param |
|
func ResponseExpires(value string) Option { |
|
return addParam("response-expires", value) |
|
} |
|
|
|
// ResponseCacheControl is an option to set response-cache-control param |
|
func ResponseCacheControl(value string) Option { |
|
return addParam("response-cache-control", value) |
|
} |
|
|
|
// ResponseContentDisposition is an option to set response-content-disposition param |
|
func ResponseContentDisposition(value string) Option { |
|
return addParam("response-content-disposition", value) |
|
} |
|
|
|
// ResponseContentEncoding is an option to set response-content-encoding param |
|
func ResponseContentEncoding(value string) Option { |
|
return addParam("response-content-encoding", value) |
|
} |
|
|
|
// Process is an option to set X-Oss-Process param |
|
func Process(value string) Option { |
|
return addParam("X-Oss-Process", value) |
|
} |
|
func setHeader(key string, value interface{}) Option { |
|
return func(params map[string]optionValue) error { |
|
if value == nil { |
|
return nil |
|
} |
|
params[key] = optionValue{value, optionHTTP} |
|
return nil |
|
} |
|
} |
|
|
|
func addParam(key string, value interface{}) Option { |
|
return func(params map[string]optionValue) error { |
|
if value == nil { |
|
return nil |
|
} |
|
params[key] = optionValue{value, optionParam} |
|
return nil |
|
} |
|
} |
|
|
|
func addArg(key string, value interface{}) Option { |
|
return func(params map[string]optionValue) error { |
|
if value == nil { |
|
return nil |
|
} |
|
params[key] = optionValue{value, optionArg} |
|
return nil |
|
} |
|
} |
|
|
|
func handleOptions(headers map[string]string, options []Option) error { |
|
params := map[string]optionValue{} |
|
for _, option := range options { |
|
if option != nil { |
|
if err := option(params); err != nil { |
|
return err |
|
} |
|
} |
|
} |
|
|
|
for k, v := range params { |
|
if v.Type == optionHTTP { |
|
headers[k] = v.Value.(string) |
|
} |
|
} |
|
return nil |
|
} |
|
|
|
func getRawParams(options []Option) (map[string]interface{}, error) { |
|
// Option |
|
params := map[string]optionValue{} |
|
for _, option := range options { |
|
if option != nil { |
|
if err := option(params); err != nil { |
|
return nil, err |
|
} |
|
} |
|
} |
|
|
|
paramsm := map[string]interface{}{} |
|
// Serialize |
|
for k, v := range params { |
|
if v.Type == optionParam { |
|
vs := params[k] |
|
paramsm[k] = vs.Value.(string) |
|
} |
|
} |
|
|
|
return paramsm, nil |
|
} |
|
|
|
func findOption(options []Option, param string, defaultVal interface{}) (interface{}, error) { |
|
params := map[string]optionValue{} |
|
for _, option := range options { |
|
if option != nil { |
|
if err := option(params); err != nil { |
|
return nil, err |
|
} |
|
} |
|
} |
|
|
|
if val, ok := params[param]; ok { |
|
return val.Value, nil |
|
} |
|
return defaultVal, nil |
|
} |
|
|
|
func isOptionSet(options []Option, option string) (bool, interface{}, error) { |
|
params := map[string]optionValue{} |
|
for _, option := range options { |
|
if option != nil { |
|
if err := option(params); err != nil { |
|
return false, nil, err |
|
} |
|
} |
|
} |
|
|
|
if val, ok := params[option]; ok { |
|
return true, val.Value, nil |
|
} |
|
return false, nil, nil |
|
}
|
|
|