1package oss 2 3import ( 4 "fmt" 5 "net/http" 6 "strconv" 7 "strings" 8 "time" 9) 10 11type optionType string 12 13const ( 14 optionParam optionType = "HTTPParameter" // URL parameter 15 optionHTTP optionType = "HTTPHeader" // HTTP header 16 optionArg optionType = "FuncArgument" // Function argument 17) 18 19const ( 20 deleteObjectsQuiet = "delete-objects-quiet" 21 routineNum = "x-routine-num" 22 checkpointConfig = "x-cp-config" 23 initCRC64 = "init-crc64" 24 progressListener = "x-progress-listener" 25 storageClass = "storage-class" 26) 27 28type ( 29 optionValue struct { 30 Value interface{} 31 Type optionType 32 } 33 34 // Option HTTP option 35 Option func(map[string]optionValue) error 36) 37 38// ACL is an option to set X-Oss-Acl header 39func ACL(acl ACLType) Option { 40 return setHeader(HTTPHeaderOssACL, string(acl)) 41} 42 43// ContentType is an option to set Content-Type header 44func ContentType(value string) Option { 45 return setHeader(HTTPHeaderContentType, value) 46} 47 48// ContentLength is an option to set Content-Length header 49func ContentLength(length int64) Option { 50 return setHeader(HTTPHeaderContentLength, strconv.FormatInt(length, 10)) 51} 52 53// CacheControl is an option to set Cache-Control header 54func CacheControl(value string) Option { 55 return setHeader(HTTPHeaderCacheControl, value) 56} 57 58// ContentDisposition is an option to set Content-Disposition header 59func ContentDisposition(value string) Option { 60 return setHeader(HTTPHeaderContentDisposition, value) 61} 62 63// ContentEncoding is an option to set Content-Encoding header 64func ContentEncoding(value string) Option { 65 return setHeader(HTTPHeaderContentEncoding, value) 66} 67 68// ContentLanguage is an option to set Content-Language header 69func ContentLanguage(value string) Option { 70 return setHeader(HTTPHeaderContentLanguage, value) 71} 72 73// ContentMD5 is an option to set Content-MD5 header 74func ContentMD5(value string) Option { 75 return setHeader(HTTPHeaderContentMD5, value) 76} 77 78// Expires is an option to set Expires header 79func Expires(t time.Time) Option { 80 return setHeader(HTTPHeaderExpires, t.Format(http.TimeFormat)) 81} 82 83// Meta is an option to set Meta header 84func Meta(key, value string) Option { 85 return setHeader(HTTPHeaderOssMetaPrefix+key, value) 86} 87 88// Range is an option to set Range header, [start, end] 89func Range(start, end int64) Option { 90 return setHeader(HTTPHeaderRange, fmt.Sprintf("bytes=%d-%d", start, end)) 91} 92 93// NormalizedRange is an option to set Range header, such as 1024-2048 or 1024- or -2048 94func NormalizedRange(nr string) Option { 95 return setHeader(HTTPHeaderRange, fmt.Sprintf("bytes=%s", strings.TrimSpace(nr))) 96} 97 98// AcceptEncoding is an option to set Accept-Encoding header 99func AcceptEncoding(value string) Option { 100 return setHeader(HTTPHeaderAcceptEncoding, value) 101} 102 103// IfModifiedSince is an option to set If-Modified-Since header 104func IfModifiedSince(t time.Time) Option { 105 return setHeader(HTTPHeaderIfModifiedSince, t.Format(http.TimeFormat)) 106} 107 108// IfUnmodifiedSince is an option to set If-Unmodified-Since header 109func IfUnmodifiedSince(t time.Time) Option { 110 return setHeader(HTTPHeaderIfUnmodifiedSince, t.Format(http.TimeFormat)) 111} 112 113// IfMatch is an option to set If-Match header 114func IfMatch(value string) Option { 115 return setHeader(HTTPHeaderIfMatch, value) 116} 117 118// IfNoneMatch is an option to set IfNoneMatch header 119func IfNoneMatch(value string) Option { 120 return setHeader(HTTPHeaderIfNoneMatch, value) 121} 122 123// CopySource is an option to set X-Oss-Copy-Source header 124func CopySource(sourceBucket, sourceObject string) Option { 125 return setHeader(HTTPHeaderOssCopySource, "/"+sourceBucket+"/"+sourceObject) 126} 127 128// CopySourceRange is an option to set X-Oss-Copy-Source header 129func CopySourceRange(startPosition, partSize int64) Option { 130 val := "bytes=" + strconv.FormatInt(startPosition, 10) + "-" + 131 strconv.FormatInt((startPosition+partSize-1), 10) 132 return setHeader(HTTPHeaderOssCopySourceRange, val) 133} 134 135// CopySourceIfMatch is an option to set X-Oss-Copy-Source-If-Match header 136func CopySourceIfMatch(value string) Option { 137 return setHeader(HTTPHeaderOssCopySourceIfMatch, value) 138} 139 140// CopySourceIfNoneMatch is an option to set X-Oss-Copy-Source-If-None-Match header 141func CopySourceIfNoneMatch(value string) Option { 142 return setHeader(HTTPHeaderOssCopySourceIfNoneMatch, value) 143} 144 145// CopySourceIfModifiedSince is an option to set X-Oss-CopySource-If-Modified-Since header 146func CopySourceIfModifiedSince(t time.Time) Option { 147 return setHeader(HTTPHeaderOssCopySourceIfModifiedSince, t.Format(http.TimeFormat)) 148} 149 150// CopySourceIfUnmodifiedSince is an option to set X-Oss-Copy-Source-If-Unmodified-Since header 151func CopySourceIfUnmodifiedSince(t time.Time) Option { 152 return setHeader(HTTPHeaderOssCopySourceIfUnmodifiedSince, t.Format(http.TimeFormat)) 153} 154 155// MetadataDirective is an option to set X-Oss-Metadata-Directive header 156func MetadataDirective(directive MetadataDirectiveType) Option { 157 return setHeader(HTTPHeaderOssMetadataDirective, string(directive)) 158} 159 160// ServerSideEncryption is an option to set X-Oss-Server-Side-Encryption header 161func ServerSideEncryption(value string) Option { 162 return setHeader(HTTPHeaderOssServerSideEncryption, value) 163} 164 165// ServerSideEncryptionKeyID is an option to set X-Oss-Server-Side-Encryption-Key-Id header 166func ServerSideEncryptionKeyID(value string) Option { 167 return setHeader(HTTPHeaderOssServerSideEncryptionKeyID, value) 168} 169 170// ObjectACL is an option to set X-Oss-Object-Acl header 171func ObjectACL(acl ACLType) Option { 172 return setHeader(HTTPHeaderOssObjectACL, string(acl)) 173} 174 175// symlinkTarget is an option to set X-Oss-Symlink-Target 176func symlinkTarget(targetObjectKey string) Option { 177 return setHeader(HTTPHeaderOssSymlinkTarget, targetObjectKey) 178} 179 180// Origin is an option to set Origin header 181func Origin(value string) Option { 182 return setHeader(HTTPHeaderOrigin, value) 183} 184 185// ObjectStorageClass is an option to set the storage class of object 186func ObjectStorageClass(storageClass StorageClassType) Option { 187 return setHeader(HTTPHeaderOssStorageClass, string(storageClass)) 188} 189 190// Callback is an option to set callback values 191func Callback(callback string) Option { 192 return setHeader(HTTPHeaderOssCallback, callback) 193} 194 195// CallbackVar is an option to set callback user defined values 196func CallbackVar(callbackVar string) Option { 197 return setHeader(HTTPHeaderOssCallbackVar, callbackVar) 198} 199 200// RequestPayer is an option to set payer who pay for the request 201func RequestPayer(payerType PayerType) Option { 202 return setHeader(HTTPHeaderOSSRequester, string(payerType)) 203} 204 205// Delimiter is an option to set delimiler parameter 206func Delimiter(value string) Option { 207 return addParam("delimiter", value) 208} 209 210// Marker is an option to set marker parameter 211func Marker(value string) Option { 212 return addParam("marker", value) 213} 214 215// MaxKeys is an option to set maxkeys parameter 216func MaxKeys(value int) Option { 217 return addParam("max-keys", strconv.Itoa(value)) 218} 219 220// Prefix is an option to set prefix parameter 221func Prefix(value string) Option { 222 return addParam("prefix", value) 223} 224 225// EncodingType is an option to set encoding-type parameter 226func EncodingType(value string) Option { 227 return addParam("encoding-type", value) 228} 229 230// MaxUploads is an option to set max-uploads parameter 231func MaxUploads(value int) Option { 232 return addParam("max-uploads", strconv.Itoa(value)) 233} 234 235// KeyMarker is an option to set key-marker parameter 236func KeyMarker(value string) Option { 237 return addParam("key-marker", value) 238} 239 240// UploadIDMarker is an option to set upload-id-marker parameter 241func UploadIDMarker(value string) Option { 242 return addParam("upload-id-marker", value) 243} 244 245// MaxParts is an option to set max-parts parameter 246func MaxParts(value int) Option { 247 return addParam("max-parts", strconv.Itoa(value)) 248} 249 250// PartNumberMarker is an option to set part-number-marker parameter 251func PartNumberMarker(value int) Option { 252 return addParam("part-number-marker", strconv.Itoa(value)) 253} 254 255// DeleteObjectsQuiet false:DeleteObjects in verbose mode; true:DeleteObjects in quite mode. Default is false. 256func DeleteObjectsQuiet(isQuiet bool) Option { 257 return addArg(deleteObjectsQuiet, isQuiet) 258} 259 260// StorageClass bucket storage class 261func StorageClass(value StorageClassType) Option { 262 return addArg(storageClass, value) 263} 264 265// Checkpoint configuration 266type cpConfig struct { 267 IsEnable bool 268 FilePath string 269 DirPath string 270} 271 272// Checkpoint sets the isEnable flag and checkpoint file path for DownloadFile/UploadFile. 273func Checkpoint(isEnable bool, filePath string) Option { 274 return addArg(checkpointConfig, &cpConfig{IsEnable: isEnable, FilePath: filePath}) 275} 276 277// CheckpointDir sets the isEnable flag and checkpoint dir path for DownloadFile/UploadFile. 278func CheckpointDir(isEnable bool, dirPath string) Option { 279 return addArg(checkpointConfig, &cpConfig{IsEnable: isEnable, DirPath: dirPath}) 280} 281 282// Routines DownloadFile/UploadFile routine count 283func Routines(n int) Option { 284 return addArg(routineNum, n) 285} 286 287// InitCRC Init AppendObject CRC 288func InitCRC(initCRC uint64) Option { 289 return addArg(initCRC64, initCRC) 290} 291 292// Progress set progress listener 293func Progress(listener ProgressListener) Option { 294 return addArg(progressListener, listener) 295} 296 297// ResponseContentType is an option to set response-content-type param 298func ResponseContentType(value string) Option { 299 return addParam("response-content-type", value) 300} 301 302// ResponseContentLanguage is an option to set response-content-language param 303func ResponseContentLanguage(value string) Option { 304 return addParam("response-content-language", value) 305} 306 307// ResponseExpires is an option to set response-expires param 308func ResponseExpires(value string) Option { 309 return addParam("response-expires", value) 310} 311 312// ResponseCacheControl is an option to set response-cache-control param 313func ResponseCacheControl(value string) Option { 314 return addParam("response-cache-control", value) 315} 316 317// ResponseContentDisposition is an option to set response-content-disposition param 318func ResponseContentDisposition(value string) Option { 319 return addParam("response-content-disposition", value) 320} 321 322// ResponseContentEncoding is an option to set response-content-encoding param 323func ResponseContentEncoding(value string) Option { 324 return addParam("response-content-encoding", value) 325} 326 327// Process is an option to set x-oss-process param 328func Process(value string) Option { 329 return addParam("x-oss-process", value) 330} 331 332func setHeader(key string, value interface{}) Option { 333 return func(params map[string]optionValue) error { 334 if value == nil { 335 return nil 336 } 337 params[key] = optionValue{value, optionHTTP} 338 return nil 339 } 340} 341 342func addParam(key string, value interface{}) Option { 343 return func(params map[string]optionValue) error { 344 if value == nil { 345 return nil 346 } 347 params[key] = optionValue{value, optionParam} 348 return nil 349 } 350} 351 352func addArg(key string, value interface{}) Option { 353 return func(params map[string]optionValue) error { 354 if value == nil { 355 return nil 356 } 357 params[key] = optionValue{value, optionArg} 358 return nil 359 } 360} 361 362func handleOptions(headers map[string]string, options []Option) error { 363 params := map[string]optionValue{} 364 for _, option := range options { 365 if option != nil { 366 if err := option(params); err != nil { 367 return err 368 } 369 } 370 } 371 372 for k, v := range params { 373 if v.Type == optionHTTP { 374 headers[k] = v.Value.(string) 375 } 376 } 377 return nil 378} 379 380func getRawParams(options []Option) (map[string]interface{}, error) { 381 // Option 382 params := map[string]optionValue{} 383 for _, option := range options { 384 if option != nil { 385 if err := option(params); err != nil { 386 return nil, err 387 } 388 } 389 } 390 391 paramsm := map[string]interface{}{} 392 // Serialize 393 for k, v := range params { 394 if v.Type == optionParam { 395 vs := params[k] 396 paramsm[k] = vs.Value.(string) 397 } 398 } 399 400 return paramsm, nil 401} 402 403func findOption(options []Option, param string, defaultVal interface{}) (interface{}, error) { 404 params := map[string]optionValue{} 405 for _, option := range options { 406 if option != nil { 407 if err := option(params); err != nil { 408 return nil, err 409 } 410 } 411 } 412 413 if val, ok := params[param]; ok { 414 return val.Value, nil 415 } 416 return defaultVal, nil 417} 418 419func isOptionSet(options []Option, option string) (bool, interface{}, error) { 420 params := map[string]optionValue{} 421 for _, option := range options { 422 if option != nil { 423 if err := option(params); err != nil { 424 return false, nil, err 425 } 426 } 427 } 428 429 if val, ok := params[option]; ok { 430 return true, val.Value, nil 431 } 432 return false, nil, nil 433} 434