Этот коммит содержится в:
George Goldberg
2020-02-03 16:19:38 +00:00
коммит произвёл GitHub
родитель 1a82e3e575
Коммит d7206d2ede
782 изменённых файлов: 114917 добавлений и 55556 удалений

5
vendor/github.com/minio/minio-go/v6/Makefile сгенерированный поставляемый
Просмотреть файл

@@ -15,3 +15,8 @@ examples:
functional-test:
@GO111MODULE=on SERVER_ENDPOINT=localhost:9000 ACCESS_KEY=minio SECRET_KEY=minio123 ENABLE_HTTPS=1 MINT_MODE=full go run functional_tests.go
clean:
@echo "Cleaning up all the generated files"
@find . -name '*.test' | xargs rm -fv
@find . -name '*~' | xargs rm -fv

102
vendor/github.com/minio/minio-go/v6/api-compose-object.go сгенерированный поставляемый
Просмотреть файл

@@ -36,18 +36,53 @@ import (
// created via server-side copy requests, using the Compose API.
type DestinationInfo struct {
bucket, object string
encryption encrypt.ServerSide
opts DestInfoOptions
}
// DestInfoOptions represents options specified by user for NewDestinationInfo call
type DestInfoOptions struct {
// `Encryption` is the key info for server-side-encryption with customer
// provided key. If it is nil, no encryption is performed.
Encryption encrypt.ServerSide
// `userMeta` is the user-metadata key-value pairs to be set on the
// destination. The keys are automatically prefixed with `x-amz-meta-`
// if needed. If nil is passed, and if only a single source (of any
// size) is provided in the ComposeObject call, then metadata from the
// source is copied to the destination.
// if no user-metadata is provided, it is copied from source
// (when there is only once source object in the compose
// request)
userMetadata map[string]string
UserMeta map[string]string
// `userTags` is the user defined object tags to be set on destination.
// This will be set only if the `replaceTags` field is set to true.
// Otherwise this field is ignored
UserTags map[string]string
ReplaceTags bool
}
// Process custom-metadata to remove a `x-amz-meta-` prefix if
// present and validate that keys are distinct (after this
// prefix removal).
func filterCustomMeta(userMeta map[string]string) (map[string]string, error) {
m := make(map[string]string)
for k, v := range userMeta {
if strings.HasPrefix(strings.ToLower(k), "x-amz-meta-") {
k = k[len("x-amz-meta-"):]
}
if _, ok := m[k]; ok {
return nil, ErrInvalidArgument(fmt.Sprintf("Cannot add both %s and x-amz-meta-%s keys as custom metadata", k, k))
}
m[k] = v
}
return m, nil
}
// NewDestinationInfo - creates a compose-object/copy-source
// destination info object.
//
// `encSSEC` is the key info for server-side-encryption with customer
// `sse` is the key info for server-side-encryption with customer
// provided key. If it is nil, no encryption is performed.
//
// `userMeta` is the user-metadata key-value pairs to be set on the
@@ -63,26 +98,41 @@ func NewDestinationInfo(bucket, object string, sse encrypt.ServerSide, userMeta
if err = s3utils.CheckValidObjectName(object); err != nil {
return d, err
}
// Process custom-metadata to remove a `x-amz-meta-` prefix if
// present and validate that keys are distinct (after this
// prefix removal).
m := make(map[string]string)
for k, v := range userMeta {
if strings.HasPrefix(strings.ToLower(k), "x-amz-meta-") {
k = k[len("x-amz-meta-"):]
}
if _, ok := m[k]; ok {
return d, ErrInvalidArgument(fmt.Sprintf("Cannot add both %s and x-amz-meta-%s keys as custom metadata", k, k))
}
m[k] = v
m, err := filterCustomMeta(userMeta)
if err != nil {
return d, err
}
opts := DestInfoOptions{
Encryption: sse,
UserMeta: m,
UserTags: nil,
ReplaceTags: false,
}
return DestinationInfo{
bucket: bucket,
object: object,
encryption: sse,
userMetadata: m,
bucket: bucket,
object: object,
opts: opts,
}, nil
}
// NewDestinationInfoWithOptions - creates a compose-object/copy-source
// destination info object.
func NewDestinationInfoWithOptions(bucket, object string, destOpts DestInfoOptions) (d DestinationInfo, err error) {
// Input validation.
if err = s3utils.CheckValidBucketName(bucket); err != nil {
return d, err
}
if err = s3utils.CheckValidObjectName(object); err != nil {
return d, err
}
destOpts.UserMeta, err = filterCustomMeta(destOpts.UserMeta)
if err != nil {
return d, err
}
return DestinationInfo{
bucket: bucket,
object: object,
opts: destOpts,
}, nil
}
@@ -93,14 +143,14 @@ func NewDestinationInfo(bucket, object string, sse encrypt.ServerSide, userMeta
// `REPLACE`, so that metadata headers from the source are not copied
// over.
func (d *DestinationInfo) getUserMetaHeadersMap(withCopyDirectiveHeader bool) map[string]string {
if len(d.userMetadata) == 0 {
if len(d.opts.UserMeta) == 0 {
return nil
}
r := make(map[string]string)
if withCopyDirectiveHeader {
r["x-amz-metadata-directive"] = "REPLACE"
}
for k, v := range d.userMetadata {
for k, v := range d.opts.UserMeta {
if isAmzHeader(k) || isStandardHeader(k) || isStorageClassHeader(k) {
r[k] = v
} else {
@@ -447,7 +497,7 @@ func (c Client) ComposeObjectWithProgress(dst DestinationInfo, srcs []SourceInfo
metaHeaders[k] = v
}
uploadID, err := c.newUploadID(ctx, dst.bucket, dst.object, PutObjectOptions{ServerSideEncryption: dst.encryption, UserMetadata: metaHeaders})
uploadID, err := c.newUploadID(ctx, dst.bucket, dst.object, PutObjectOptions{ServerSideEncryption: dst.opts.Encryption, UserMetadata: metaHeaders})
if err != nil {
return err
}
@@ -461,8 +511,8 @@ func (c Client) ComposeObjectWithProgress(dst DestinationInfo, srcs []SourceInfo
encrypt.SSECopy(src.encryption).Marshal(h)
}
// Add destination encryption headers
if dst.encryption != nil {
dst.encryption.Marshal(h)
if dst.opts.Encryption != nil {
dst.opts.Encryption.Marshal(h)
}
// calculate start/end indices of parts after

45
vendor/github.com/minio/minio-go/v6/api-datatypes.go сгенерированный поставляемый
Просмотреть файл

@@ -18,6 +18,8 @@
package minio
import (
"encoding/xml"
"io"
"net/http"
"time"
)
@@ -30,6 +32,36 @@ type BucketInfo struct {
CreationDate time.Time `json:"creationDate"`
}
// StringMap represents map with custom UnmarshalXML
type StringMap map[string]string
// UnmarshalXML unmarshals the XML into a map of string to strings,
// creating a key in the map for each tag and setting it's value to the
// tags contents.
//
// The fact this function is on the pointer of Map is important, so that
// if m is nil it can be initialized, which is often the case if m is
// nested in another xml structurel. This is also why the first thing done
// on the first line is initialize it.
func (m *StringMap) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
*m = StringMap{}
type xmlMapEntry struct {
XMLName xml.Name
Value string `xml:",chardata"`
}
for {
var e xmlMapEntry
err := d.Decode(&e)
if err == io.EOF {
break
} else if err != nil {
return err
}
(*m)[e.XMLName.Local] = e.Value
}
return nil
}
// ObjectInfo container for object metadata.
type ObjectInfo struct {
// An ETag is optionally set to md5sum of an object. In case of multipart objects,
@@ -47,12 +79,25 @@ type ObjectInfo struct {
// eg: x-amz-meta-*, content-encoding etc.
Metadata http.Header `json:"metadata" xml:"-"`
// x-amz-meta-* headers stripped "x-amz-meta-" prefix containing the first value.
UserMetadata StringMap `json:"userMetadata"`
// Owner name.
Owner struct {
DisplayName string `json:"name"`
ID string `json:"id"`
} `json:"owner"`
// ACL grant.
Grant []struct {
Grantee struct {
ID string `xml:"ID"`
DisplayName string `xml:"DisplayName"`
URI string `xml:"URI"`
} `xml:"Grantee"`
Permission string `xml:"Permission"`
} `xml:"Grant"`
// The class of storage used to store the object.
StorageClass string `json:"storageClass"`

4
vendor/github.com/minio/minio-go/v6/api-error-response.go сгенерированный поставляемый
Просмотреть файл

@@ -51,6 +51,9 @@ type ErrorResponse struct {
// only in HEAD bucket and ListObjects response.
Region string
// Captures the server string returned in response header.
Server string
// Underlying HTTP status code for the returned error
StatusCode int `xml:"-" json:"-"`
}
@@ -105,6 +108,7 @@ func httpRespToErrorResponse(resp *http.Response, bucketName, objectName string)
errResp := ErrorResponse{
StatusCode: resp.StatusCode,
Server: resp.Header.Get("Server"),
}
err := xmlDecoder(resp.Body, &errResp)

140
vendor/github.com/minio/minio-go/v6/api-get-object-acl-context.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,140 @@
/*
* MinIO Go Library for Amazon S3 Compatible Cloud Storage
* Copyright 2018 MinIO, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package minio
import (
"context"
"net/http"
"net/url"
)
type accessControlPolicy struct {
Owner struct {
ID string `xml:"ID"`
DisplayName string `xml:"DisplayName"`
} `xml:"Owner"`
AccessControlList struct {
Grant []struct {
Grantee struct {
ID string `xml:"ID"`
DisplayName string `xml:"DisplayName"`
URI string `xml:"URI"`
} `xml:"Grantee"`
Permission string `xml:"Permission"`
} `xml:"Grant"`
} `xml:"AccessControlList"`
}
//GetObjectACLWithContext get object ACLs
func (c Client) GetObjectACLWithContext(ctx context.Context, bucketName, objectName string) (*ObjectInfo, error) {
resp, err := c.executeMethod(ctx, "GET", requestMetadata{
bucketName: bucketName,
objectName: objectName,
queryValues: url.Values{
"acl": []string{""},
},
})
if err != nil {
return nil, err
}
defer closeResponse(resp)
if resp.StatusCode != http.StatusOK {
return nil, httpRespToErrorResponse(resp, bucketName, objectName)
}
res := &accessControlPolicy{}
if err := xmlDecoder(resp.Body, res); err != nil {
return nil, err
}
objInfo, err := c.statObject(ctx, bucketName, objectName, StatObjectOptions{})
if err != nil {
return nil, err
}
objInfo.Owner.DisplayName = res.Owner.DisplayName
objInfo.Owner.ID = res.Owner.ID
objInfo.Grant = append(objInfo.Grant, res.AccessControlList.Grant...)
cannedACL := getCannedACL(res)
if cannedACL != "" {
objInfo.Metadata.Add("X-Amz-Acl", cannedACL)
return &objInfo, nil
}
grantACL := getAmzGrantACL(res)
for k, v := range grantACL {
objInfo.Metadata[k] = v
}
return &objInfo, nil
}
func getCannedACL(aCPolicy *accessControlPolicy) string {
grants := aCPolicy.AccessControlList.Grant
switch {
case len(grants) == 1:
if grants[0].Grantee.URI == "" && grants[0].Permission == "FULL_CONTROL" {
return "private"
}
case len(grants) == 2:
for _, g := range grants {
if g.Grantee.URI == "http://acs.amazonaws.com/groups/global/AuthenticatedUsers" && g.Permission == "READ" {
return "authenticated-read"
}
if g.Grantee.URI == "http://acs.amazonaws.com/groups/global/AllUsers" && g.Permission == "READ" {
return "public-read"
}
if g.Permission == "READ" && g.Grantee.ID == aCPolicy.Owner.ID {
return "bucket-owner-read"
}
}
case len(grants) == 3:
for _, g := range grants {
if g.Grantee.URI == "http://acs.amazonaws.com/groups/global/AllUsers" && g.Permission == "WRITE" {
return "public-read-write"
}
}
}
return ""
}
func getAmzGrantACL(aCPolicy *accessControlPolicy) map[string][]string {
grants := aCPolicy.AccessControlList.Grant
res := map[string][]string{}
for _, g := range grants {
switch {
case g.Permission == "READ":
res["X-Amz-Grant-Read"] = append(res["X-Amz-Grant-Read"], "id="+g.Grantee.ID)
case g.Permission == "WRITE":
res["X-Amz-Grant-Write"] = append(res["X-Amz-Grant-Write"], "id="+g.Grantee.ID)
case g.Permission == "READ_ACP":
res["X-Amz-Grant-Read-Acp"] = append(res["X-Amz-Grant-Read-Acp"], "id="+g.Grantee.ID)
case g.Permission == "WRITE_ACP":
res["X-Amz-Grant-Write-Acp"] = append(res["X-Amz-Grant-Write-Acp"], "id="+g.Grantee.ID)
case g.Permission == "FULL_CONTROL":
res["X-Amz-Grant-Full-Control"] = append(res["X-Amz-Grant-Full-Control"], "id="+g.Grantee.ID)
}
}
return res
}

111
vendor/github.com/minio/minio-go/v6/api-get-object-acl.go сгенерированный поставляемый
Просмотреть файл

@@ -19,118 +19,9 @@ package minio
import (
"context"
"net/http"
"net/url"
)
type accessControlPolicy struct {
Owner struct {
ID string `xml:"ID"`
DisplayName string `xml:"DisplayName"`
} `xml:"Owner"`
AccessControlList struct {
Grant []struct {
Grantee struct {
ID string `xml:"ID"`
DisplayName string `xml:"DisplayName"`
URI string `xml:"URI"`
} `xml:"Grantee"`
Permission string `xml:"Permission"`
} `xml:"Grant"`
} `xml:"AccessControlList"`
}
//GetObjectACL get object ACLs
func (c Client) GetObjectACL(bucketName, objectName string) (*ObjectInfo, error) {
resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{
bucketName: bucketName,
objectName: objectName,
queryValues: url.Values{
"acl": []string{""},
},
})
if err != nil {
return nil, err
}
defer closeResponse(resp)
if resp.StatusCode != http.StatusOK {
return nil, httpRespToErrorResponse(resp, bucketName, objectName)
}
res := &accessControlPolicy{}
if err := xmlDecoder(resp.Body, res); err != nil {
return nil, err
}
objInfo, err := c.statObject(context.Background(), bucketName, objectName, StatObjectOptions{})
if err != nil {
return nil, err
}
cannedACL := getCannedACL(res)
if cannedACL != "" {
objInfo.Metadata.Add("X-Amz-Acl", cannedACL)
return &objInfo, nil
}
grantACL := getAmzGrantACL(res)
for k, v := range grantACL {
objInfo.Metadata[k] = v
}
return &objInfo, nil
}
func getCannedACL(aCPolicy *accessControlPolicy) string {
grants := aCPolicy.AccessControlList.Grant
switch {
case len(grants) == 1:
if grants[0].Grantee.URI == "" && grants[0].Permission == "FULL_CONTROL" {
return "private"
}
case len(grants) == 2:
for _, g := range grants {
if g.Grantee.URI == "http://acs.amazonaws.com/groups/global/AuthenticatedUsers" && g.Permission == "READ" {
return "authenticated-read"
}
if g.Grantee.URI == "http://acs.amazonaws.com/groups/global/AllUsers" && g.Permission == "READ" {
return "public-read"
}
if g.Permission == "READ" && g.Grantee.ID == aCPolicy.Owner.ID {
return "bucket-owner-read"
}
}
case len(grants) == 3:
for _, g := range grants {
if g.Grantee.URI == "http://acs.amazonaws.com/groups/global/AllUsers" && g.Permission == "WRITE" {
return "public-read-write"
}
}
}
return ""
}
func getAmzGrantACL(aCPolicy *accessControlPolicy) map[string][]string {
grants := aCPolicy.AccessControlList.Grant
res := map[string][]string{}
for _, g := range grants {
switch {
case g.Permission == "READ":
res["X-Amz-Grant-Read"] = append(res["X-Amz-Grant-Read"], "id="+g.Grantee.ID)
case g.Permission == "WRITE":
res["X-Amz-Grant-Write"] = append(res["X-Amz-Grant-Write"], "id="+g.Grantee.ID)
case g.Permission == "READ_ACP":
res["X-Amz-Grant-Read-Acp"] = append(res["X-Amz-Grant-Read-Acp"], "id="+g.Grantee.ID)
case g.Permission == "WRITE_ACP":
res["X-Amz-Grant-Write-Acp"] = append(res["X-Amz-Grant-Write-Acp"], "id="+g.Grantee.ID)
case g.Permission == "FULL_CONTROL":
res["X-Amz-Grant-Full-Control"] = append(res["X-Amz-Grant-Full-Control"], "id="+g.Grantee.ID)
}
}
return res
return c.GetObjectACLWithContext(context.Background(), bucketName, objectName)
}

21
vendor/github.com/minio/minio-go/v6/api-get-object.go сгенерированный поставляемый
Просмотреть файл

@@ -45,6 +45,14 @@ func (c Client) getObjectWithContext(ctx context.Context, bucketName, objectName
return nil, err
}
// Detect if snowball is server location we are talking to.
var snowball bool
if location, ok := c.bucketLocCache.Get(bucketName); ok {
if location == "snowball" {
snowball = true
}
}
var httpReader io.ReadCloser
var objectInfo ObjectInfo
var err error
@@ -136,7 +144,10 @@ func (c Client) getObjectWithContext(ctx context.Context, bucketName, objectName
} else if req.settingObjectInfo { // Request is just to get objectInfo.
// Remove range header if already set, for stat Operations to get original file size.
delete(opts.headers, "Range")
if etag != "" {
// Check whether this is snowball
// if yes do not use If-Match feature
// it doesn't work.
if etag != "" && !snowball {
opts.SetMatchETag(etag)
}
objectInfo, err := c.statObject(ctx, bucketName, objectName, StatObjectOptions{opts})
@@ -159,7 +170,10 @@ func (c Client) getObjectWithContext(ctx context.Context, bucketName, objectName
// new ones when they haven't been already.
// All readAt requests are new requests.
if req.DidOffsetChange || !req.beenRead {
if etag != "" {
// Check whether this is snowball
// if yes do not use If-Match feature
// it doesn't work.
if etag != "" && !snowball {
opts.SetMatchETag(etag)
}
if httpReader != nil {
@@ -622,8 +636,7 @@ func (c Client) getObject(ctx context.Context, bucketName, objectName string, op
}
// Trim off the odd double quotes from ETag in the beginning and end.
md5sum := strings.TrimPrefix(resp.Header.Get("ETag"), "\"")
md5sum = strings.TrimSuffix(md5sum, "\"")
md5sum := trimEtag(resp.Header.Get("ETag"))
// Parse the date.
date, err := time.Parse(http.TimeFormat, resp.Header.Get("Last-Modified"))

113
vendor/github.com/minio/minio-go/v6/api-list.go сгенерированный поставляемый
Просмотреть файл

@@ -19,11 +19,9 @@ package minio
import (
"context"
"errors"
"fmt"
"net/http"
"net/url"
"strings"
"github.com/minio/minio-go/v6/pkg/s3utils"
)
@@ -39,8 +37,23 @@ import (
// }
//
func (c Client) ListBuckets() ([]BucketInfo, error) {
return c.ListBucketsWithContext(context.Background())
}
// ListBucketsWithContext list all buckets owned by this authenticated user,
// accepts a context for facilitate cancellation.
//
// This call requires explicit authentication, no anonymous requests are
// allowed for listing buckets.
//
// api := client.New(....)
// for message := range api.ListBucketsWithContext(context.Background()) {
// fmt.Println(message)
// }
//
func (c Client) ListBucketsWithContext(ctx context.Context) ([]BucketInfo, error) {
// Execute GET on service.
resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{contentSHA256Hex: emptySHA256Hex})
resp, err := c.executeMethod(ctx, "GET", requestMetadata{contentSHA256Hex: emptySHA256Hex})
defer closeResponse(resp)
if err != nil {
return nil, err
@@ -60,9 +73,13 @@ func (c Client) ListBuckets() ([]BucketInfo, error) {
/// Bucket Read Operations.
// ListObjectsV2 lists all objects matching the objectPrefix from
// the specified bucket. If recursion is enabled it would list
// all subdirectories and all its contents.
// ListObjectsV2WithMetadata lists all objects matching the objectPrefix
// from the specified bucket. If recursion is enabled it would list
// all subdirectories and all its contents. This call adds
// UserMetadata information as well for each object.
//
// This is a MinIO extension, this will not work against other S3
// compatible object storage vendors.
//
// Your input parameters are just bucketName, objectPrefix, recursive
// and a done channel for pro-actively closing the internal go
@@ -76,11 +93,24 @@ func (c Client) ListBuckets() ([]BucketInfo, error) {
// defer close(doneCh)
// // Recursively list all objects in 'mytestbucket'
// recursive := true
// for message := range api.ListObjectsV2("mytestbucket", "starthere", recursive, doneCh) {
// // Add metadata
// metadata := true
// for message := range api.ListObjectsV2WithMetadata("mytestbucket", "starthere", recursive, doneCh) {
// fmt.Println(message)
// }
//
func (c Client) ListObjectsV2(bucketName, objectPrefix string, recursive bool, doneCh <-chan struct{}) <-chan ObjectInfo {
func (c Client) ListObjectsV2WithMetadata(bucketName, objectPrefix string, recursive bool,
doneCh <-chan struct{}) <-chan ObjectInfo {
// Check whether this is snowball region, if yes ListObjectsV2 doesn't work, fallback to listObjectsV1.
if location, ok := c.bucketLocCache.Get(bucketName); ok {
if location == "snowball" {
return c.ListObjects(bucketName, objectPrefix, recursive, doneCh)
}
}
return c.listObjectsV2(bucketName, objectPrefix, recursive, true, doneCh)
}
func (c Client) listObjectsV2(bucketName, objectPrefix string, recursive, metadata bool, doneCh <-chan struct{}) <-chan ObjectInfo {
// Allocate new list objects channel.
objectStatCh := make(chan ObjectInfo, 1)
// Default listing is delimited at "/"
@@ -118,7 +148,8 @@ func (c Client) ListObjectsV2(bucketName, objectPrefix string, recursive bool, d
var continuationToken string
for {
// Get list of objects a maximum of 1000 per request.
result, err := c.listObjectsV2Query(bucketName, objectPrefix, continuationToken, fetchOwner, delimiter, 1000, "")
result, err := c.listObjectsV2Query(bucketName, objectPrefix, continuationToken,
fetchOwner, metadata, delimiter, 0, "")
if err != nil {
objectStatCh <- ObjectInfo{
Err: err,
@@ -128,6 +159,7 @@ func (c Client) ListObjectsV2(bucketName, objectPrefix string, recursive bool, d
// If contents are available loop through and send over channel.
for _, object := range result.Contents {
object.ETag = trimEtag(object.ETag)
select {
// Send object content.
case objectStatCh <- object:
@@ -163,6 +195,36 @@ func (c Client) ListObjectsV2(bucketName, objectPrefix string, recursive bool, d
return objectStatCh
}
// ListObjectsV2 lists all objects matching the objectPrefix from
// the specified bucket. If recursion is enabled it would list
// all subdirectories and all its contents.
//
// Your input parameters are just bucketName, objectPrefix, recursive
// and a done channel for pro-actively closing the internal go
// routine. If you enable recursive as 'true' this function will
// return back all the objects in a given bucket name and object
// prefix.
//
// api := client.New(....)
// // Create a done channel.
// doneCh := make(chan struct{})
// defer close(doneCh)
// // Recursively list all objects in 'mytestbucket'
// recursive := true
// for message := range api.ListObjectsV2("mytestbucket", "starthere", recursive, doneCh) {
// fmt.Println(message)
// }
//
func (c Client) ListObjectsV2(bucketName, objectPrefix string, recursive bool, doneCh <-chan struct{}) <-chan ObjectInfo {
// Check whether this is snowball region, if yes ListObjectsV2 doesn't work, fallback to listObjectsV1.
if location, ok := c.bucketLocCache.Get(bucketName); ok {
if location == "snowball" {
return c.ListObjects(bucketName, objectPrefix, recursive, doneCh)
}
}
return c.listObjectsV2(bucketName, objectPrefix, recursive, false, doneCh)
}
// listObjectsV2Query - (List Objects V2) - List some or all (up to 1000) of the objects in a bucket.
//
// You can use the request parameters as selection criteria to return a subset of the objects in a bucket.
@@ -173,7 +235,8 @@ func (c Client) ListObjectsV2(bucketName, objectPrefix string, recursive bool, d
// ?prefix - Limits the response to keys that begin with the specified prefix.
// ?max-keys - Sets the maximum number of keys returned in the response body.
// ?start-after - Specifies the key to start after when listing objects in a bucket.
func (c Client) listObjectsV2Query(bucketName, objectPrefix, continuationToken string, fetchOwner bool, delimiter string, maxkeys int, startAfter string) (ListBucketV2Result, error) {
// ?metadata - Specifies if we want metadata for the objects as part of list operation.
func (c Client) listObjectsV2Query(bucketName, objectPrefix, continuationToken string, fetchOwner, metadata bool, delimiter string, maxkeys int, startAfter string) (ListBucketV2Result, error) {
// Validate bucket name.
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
return ListBucketV2Result{}, err
@@ -189,6 +252,10 @@ func (c Client) listObjectsV2Query(bucketName, objectPrefix, continuationToken s
// Always set list-type in ListObjects V2
urlValues.Set("list-type", "2")
if metadata {
urlValues.Set("metadata", "true")
}
// Always set encoding-type in ListObjects V2
urlValues.Set("encoding-type", "url")
@@ -243,7 +310,10 @@ func (c Client) listObjectsV2Query(bucketName, objectPrefix, continuationToken s
// This is an additional verification check to make
// sure proper responses are received.
if listBucketResult.IsTruncated && listBucketResult.NextContinuationToken == "" {
return listBucketResult, errors.New("Truncated response should have continuation token set")
return listBucketResult, ErrorResponse{
Code: "NotImplemented",
Message: "Truncated response should have continuation token set",
}
}
for i, obj := range listBucketResult.Contents {
@@ -319,7 +389,7 @@ func (c Client) ListObjects(bucketName, objectPrefix string, recursive bool, don
var marker string
for {
// Get list of objects a maximum of 1000 per request.
result, err := c.listObjectsQuery(bucketName, objectPrefix, marker, delimiter, 1000)
result, err := c.listObjectsQuery(bucketName, objectPrefix, marker, delimiter, 0)
if err != nil {
objectStatCh <- ObjectInfo{
Err: err,
@@ -513,7 +583,7 @@ func (c Client) listIncompleteUploads(bucketName, objectPrefix string, recursive
var uploadIDMarker string
for {
// list all multipart uploads.
result, err := c.listMultipartUploadsQuery(bucketName, objectMarker, uploadIDMarker, objectPrefix, delimiter, 1000)
result, err := c.listMultipartUploadsQuery(bucketName, objectMarker, uploadIDMarker, objectPrefix, delimiter, 0)
if err != nil {
objectMultipartStatCh <- ObjectMultipartInfo{
Err: err,
@@ -600,11 +670,10 @@ func (c Client) listMultipartUploadsQuery(bucketName, keyMarker, uploadIDMarker,
urlValues.Set("encoding-type", "url")
// maxUploads should be 1000 or less.
if maxUploads == 0 || maxUploads > 1000 {
maxUploads = 1000
if maxUploads > 0 {
// Set max-uploads.
urlValues.Set("max-uploads", fmt.Sprintf("%d", maxUploads))
}
// Set max-uploads.
urlValues.Set("max-uploads", fmt.Sprintf("%d", maxUploads))
// Execute GET on bucketName to list multipart uploads.
resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{
@@ -669,8 +738,7 @@ func (c Client) listObjectParts(bucketName, objectName, uploadID string) (partsI
// Append to parts info.
for _, part := range listObjPartsResult.ObjectParts {
// Trim off the odd double quotes from ETag in the beginning and end.
part.ETag = strings.TrimPrefix(part.ETag, "\"")
part.ETag = strings.TrimSuffix(part.ETag, "\"")
part.ETag = trimEtag(part.ETag)
partsInfo[part.PartNumber] = part
}
// Keep part number marker, for the next iteration.
@@ -740,11 +808,10 @@ func (c Client) listObjectPartsQuery(bucketName, objectName, uploadID string, pa
urlValues.Set("uploadId", uploadID)
// maxParts should be 1000 or less.
if maxParts == 0 || maxParts > 1000 {
maxParts = 1000
if maxParts > 0 {
// Set max parts.
urlValues.Set("max-parts", fmt.Sprintf("%d", maxParts))
}
// Set max parts.
urlValues.Set("max-parts", fmt.Sprintf("%d", maxParts))
// Execute GET on objectName to get list of parts.
resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{

232
vendor/github.com/minio/minio-go/v6/api-object-lock.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,232 @@
/*
* MinIO Go Library for Amazon S3 Compatible Cloud Storage
* Copyright 2019 MinIO, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package minio
import (
"bytes"
"context"
"encoding/xml"
"fmt"
"net/http"
"net/url"
"time"
"github.com/minio/minio-go/v6/pkg/s3utils"
)
// RetentionMode - object retention mode.
type RetentionMode string
const (
// Governance - goverance mode.
Governance RetentionMode = "GOVERNANCE"
// Compliance - compliance mode.
Compliance RetentionMode = "COMPLIANCE"
)
func (r RetentionMode) String() string {
return string(r)
}
// IsValid - check whether this retention mode is valid or not.
func (r RetentionMode) IsValid() bool {
return r == Governance || r == Compliance
}
// ValidityUnit - retention validity unit.
type ValidityUnit string
const (
// Days - denotes no. of days.
Days ValidityUnit = "DAYS"
// Years - denotes no. of years.
Years ValidityUnit = "YEARS"
)
func (unit ValidityUnit) String() string {
return string(unit)
}
// IsValid - check whether this validity unit is valid or not.
func (unit ValidityUnit) isValid() bool {
return unit == Days || unit == Years
}
// Retention - bucket level retention configuration.
type Retention struct {
Mode RetentionMode
Validity time.Duration
}
func (r Retention) String() string {
return fmt.Sprintf("{Mode:%v, Validity:%v}", r.Mode, r.Validity)
}
// IsEmpty - returns whether retention is empty or not.
func (r Retention) IsEmpty() bool {
return r.Mode == "" || r.Validity == 0
}
// objectLockConfig - object lock configuration specified in
// https://docs.aws.amazon.com/AmazonS3/latest/API/Type_API_ObjectLockConfiguration.html
type objectLockConfig struct {
XMLNS string `xml:"xmlns,attr,omitempty"`
XMLName xml.Name `xml:"ObjectLockConfiguration"`
ObjectLockEnabled string `xml:"ObjectLockEnabled"`
Rule *struct {
DefaultRetention struct {
Mode RetentionMode `xml:"Mode"`
Days *uint `xml:"Days"`
Years *uint `xml:"Years"`
} `xml:"DefaultRetention"`
} `xml:"Rule,omitempty"`
}
func newObjectLockConfig(mode *RetentionMode, validity *uint, unit *ValidityUnit) (*objectLockConfig, error) {
config := &objectLockConfig{
ObjectLockEnabled: "Enabled",
}
if mode != nil && validity != nil && unit != nil {
if !mode.IsValid() {
return nil, fmt.Errorf("invalid retention mode `%v`", mode)
}
if !unit.isValid() {
return nil, fmt.Errorf("invalid validity unit `%v`", unit)
}
config.Rule = &struct {
DefaultRetention struct {
Mode RetentionMode `xml:"Mode"`
Days *uint `xml:"Days"`
Years *uint `xml:"Years"`
} `xml:"DefaultRetention"`
}{}
config.Rule.DefaultRetention.Mode = *mode
if *unit == Days {
config.Rule.DefaultRetention.Days = validity
} else {
config.Rule.DefaultRetention.Years = validity
}
return config, nil
}
if mode == nil && validity == nil && unit == nil {
return config, nil
}
return nil, fmt.Errorf("all of retention mode, validity and validity unit must be passed")
}
// SetBucketObjectLockConfig sets object lock configuration in given bucket. mode, validity and unit are either all set or all nil.
func (c Client) SetBucketObjectLockConfig(bucketName string, mode *RetentionMode, validity *uint, unit *ValidityUnit) error {
// Input validation.
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
return err
}
// Get resources properly escaped and lined up before
// using them in http request.
urlValues := make(url.Values)
urlValues.Set("object-lock", "")
config, err := newObjectLockConfig(mode, validity, unit)
if err != nil {
return err
}
configData, err := xml.Marshal(config)
if err != nil {
return err
}
reqMetadata := requestMetadata{
bucketName: bucketName,
queryValues: urlValues,
contentBody: bytes.NewReader(configData),
contentLength: int64(len(configData)),
contentMD5Base64: sumMD5Base64(configData),
contentSHA256Hex: sum256Hex(configData),
}
// Execute PUT bucket object lock configuration.
resp, err := c.executeMethod(context.Background(), "PUT", reqMetadata)
defer closeResponse(resp)
if err != nil {
return err
}
if resp != nil {
if resp.StatusCode != http.StatusOK {
return httpRespToErrorResponse(resp, bucketName, "")
}
}
return nil
}
// GetBucketObjectLockConfig gets object lock configuration of given bucket.
func (c Client) GetBucketObjectLockConfig(bucketName string) (mode *RetentionMode, validity *uint, unit *ValidityUnit, err error) {
// Input validation.
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
return nil, nil, nil, err
}
urlValues := make(url.Values)
urlValues.Set("object-lock", "")
// Execute GET on bucket to list objects.
resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{
bucketName: bucketName,
queryValues: urlValues,
contentSHA256Hex: emptySHA256Hex,
})
defer closeResponse(resp)
if err != nil {
return nil, nil, nil, err
}
if resp != nil {
if resp.StatusCode != http.StatusOK {
return nil, nil, nil, httpRespToErrorResponse(resp, bucketName, "")
}
}
config := &objectLockConfig{}
if err = xml.NewDecoder(resp.Body).Decode(config); err != nil {
return nil, nil, nil, err
}
if config.Rule != nil {
mode = &config.Rule.DefaultRetention.Mode
if config.Rule.DefaultRetention.Days != nil {
validity = config.Rule.DefaultRetention.Days
days := Days
unit = &days
} else {
validity = config.Rule.DefaultRetention.Years
years := Years
unit = &years
}
return mode, validity, unit, nil
}
return nil, nil, nil, nil
}

168
vendor/github.com/minio/minio-go/v6/api-object-retention.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,168 @@
/*
* MinIO Go Library for Amazon S3 Compatible Cloud Storage
* Copyright 2019 MinIO, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package minio
import (
"bytes"
"context"
"encoding/xml"
"fmt"
"net/http"
"net/url"
"time"
"github.com/minio/minio-go/v6/pkg/s3utils"
)
// objectRetention - object retention specified in
// https://docs.aws.amazon.com/AmazonS3/latest/API/Type_API_ObjectLockConfiguration.html
type objectRetention struct {
XMLNS string `xml:"xmlns,attr,omitempty"`
XMLName xml.Name `xml:"Retention"`
Mode RetentionMode `xml:"Mode"`
RetainUntilDate time.Time `type:"timestamp" timestampFormat:"iso8601" xml:"RetainUntilDate"`
}
func newObjectRetention(mode *RetentionMode, date *time.Time) (*objectRetention, error) {
if mode == nil {
return nil, fmt.Errorf("Mode not set")
}
if date == nil {
return nil, fmt.Errorf("RetainUntilDate not set")
}
if !mode.IsValid() {
return nil, fmt.Errorf("invalid retention mode `%v`", mode)
}
objectRetention := &objectRetention{
Mode: *mode,
RetainUntilDate: *date,
}
return objectRetention, nil
}
// PutObjectRetentionOptions represents options specified by user for PutObject call
type PutObjectRetentionOptions struct {
GovernanceBypass bool
Mode *RetentionMode
RetainUntilDate *time.Time
VersionID string
}
// PutObjectRetention : sets object retention for a given object and versionID.
func (c Client) PutObjectRetention(bucketName, objectName string, opts PutObjectRetentionOptions) error {
// Input validation.
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
return err
}
if err := s3utils.CheckValidObjectName(objectName); err != nil {
return err
}
// Get resources properly escaped and lined up before
// using them in http request.
urlValues := make(url.Values)
urlValues.Set("retention", "")
if opts.VersionID != "" {
urlValues.Set("versionId", opts.VersionID)
}
retention, err := newObjectRetention(opts.Mode, opts.RetainUntilDate)
if err != nil {
return err
}
retentionData, err := xml.Marshal(retention)
if err != nil {
return err
}
// Build headers.
headers := make(http.Header)
if opts.GovernanceBypass {
// Set the bypass goverenance retention header
headers.Set("x-amz-bypass-governance-retention", "True")
}
reqMetadata := requestMetadata{
bucketName: bucketName,
objectName: objectName,
queryValues: urlValues,
contentBody: bytes.NewReader(retentionData),
contentLength: int64(len(retentionData)),
contentMD5Base64: sumMD5Base64(retentionData),
contentSHA256Hex: sum256Hex(retentionData),
customHeader: headers,
}
// Execute PUT Object Retention.
resp, err := c.executeMethod(context.Background(), "PUT", reqMetadata)
defer closeResponse(resp)
if err != nil {
return err
}
if resp != nil {
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
return httpRespToErrorResponse(resp, bucketName, objectName)
}
}
return nil
}
// GetObjectRetention gets retention of given object.
func (c Client) GetObjectRetention(bucketName, objectName, versionID string) (mode *RetentionMode, retainUntilDate *time.Time, err error) {
// Input validation.
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
return nil, nil, err
}
if err := s3utils.CheckValidObjectName(objectName); err != nil {
return nil, nil, err
}
urlValues := make(url.Values)
urlValues.Set("retention", "")
if versionID != "" {
urlValues.Set("versionId", versionID)
}
// Execute GET on bucket to list objects.
resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{
bucketName: bucketName,
objectName: objectName,
queryValues: urlValues,
contentSHA256Hex: emptySHA256Hex,
})
defer closeResponse(resp)
if err != nil {
return nil, nil, err
}
if resp != nil {
if resp.StatusCode != http.StatusOK {
return nil, nil, httpRespToErrorResponse(resp, bucketName, objectName)
}
}
retention := &objectRetention{}
if err = xml.NewDecoder(resp.Body).Decode(retention); err != nil {
return nil, nil, err
}
return &retention.Mode, &retention.RetainUntilDate, nil
}

163
vendor/github.com/minio/minio-go/v6/api-object-tagging.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,163 @@
/*
* MinIO Go Library for Amazon S3 Compatible Cloud Storage
* Copyright 2020 MinIO, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package minio
import (
"bytes"
"context"
"encoding/xml"
"io/ioutil"
"net/http"
"net/url"
"github.com/minio/minio-go/v6/pkg/s3utils"
)
// PutObjectTagging replaces or creates object tag(s)
func (c Client) PutObjectTagging(bucketName, objectName string, objectTags map[string]string) error {
return c.PutObjectTaggingWithContext(context.Background(), bucketName, objectName, objectTags)
}
// PutObjectTaggingWithContext replaces or creates object tag(s) with a context to control cancellations
// and timeouts.
func (c Client) PutObjectTaggingWithContext(ctx context.Context, bucketName, objectName string, objectTags map[string]string) error {
// Input validation.
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
return err
}
// Get resources properly escaped and lined up before
// using them in http request.
urlValues := make(url.Values)
urlValues.Set("tagging", "")
tags := make([]tag, 0)
for k, v := range objectTags {
t := tag{
Key: k,
Value: v,
}
tags = append(tags, t)
}
// Prepare Tagging struct
reqBody := tagging{
TagSet: tagSet{
Tags: tags,
},
}
reqBytes, err := xml.Marshal(reqBody)
if err != nil {
return err
}
reqMetadata := requestMetadata{
bucketName: bucketName,
objectName: objectName,
queryValues: urlValues,
contentBody: bytes.NewReader(reqBytes),
contentLength: int64(len(reqBytes)),
contentMD5Base64: sumMD5Base64(reqBytes),
}
// Execute PUT to set a object tagging.
resp, err := c.executeMethod(ctx, "PUT", reqMetadata)
defer closeResponse(resp)
if err != nil {
return err
}
if resp != nil {
if resp.StatusCode != http.StatusOK {
return httpRespToErrorResponse(resp, bucketName, objectName)
}
}
return nil
}
// GetObjectTagging fetches object tag(s)
func (c Client) GetObjectTagging(bucketName, objectName string) (string, error) {
return c.GetObjectTaggingWithContext(context.Background(), bucketName, objectName)
}
// GetObjectTaggingWithContext fetches object tag(s) with a context to control cancellations
// and timeouts.
func (c Client) GetObjectTaggingWithContext(ctx context.Context, bucketName, objectName string) (string, error) {
// Get resources properly escaped and lined up before
// using them in http request.
urlValues := make(url.Values)
urlValues.Set("tagging", "")
// Execute GET on object to get object tag(s)
resp, err := c.executeMethod(ctx, "GET", requestMetadata{
bucketName: bucketName,
objectName: objectName,
queryValues: urlValues,
})
defer closeResponse(resp)
if err != nil {
return "", err
}
if resp != nil {
if resp.StatusCode != http.StatusOK {
return "", httpRespToErrorResponse(resp, bucketName, objectName)
}
}
tagBuf, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
return string(tagBuf), err
}
// RemoveObjectTagging deletes object tag(s)
func (c Client) RemoveObjectTagging(bucketName, objectName string) error {
return c.RemoveObjectTaggingWithContext(context.Background(), bucketName, objectName)
}
// RemoveObjectTaggingWithContext removes object tag(s) with a context to control cancellations
// and timeouts.
func (c Client) RemoveObjectTaggingWithContext(ctx context.Context, bucketName, objectName string) error {
// Get resources properly escaped and lined up before
// using them in http request.
urlValues := make(url.Values)
urlValues.Set("tagging", "")
// Execute DELETE on object to remove object tag(s)
resp, err := c.executeMethod(ctx, "DELETE", requestMetadata{
bucketName: bucketName,
objectName: objectName,
queryValues: urlValues,
})
defer closeResponse(resp)
if err != nil {
return err
}
if resp != nil {
if resp.StatusCode != http.StatusOK {
return httpRespToErrorResponse(resp, bucketName, objectName)
}
}
return err
}

170
vendor/github.com/minio/minio-go/v6/api-put-bucket.go сгенерированный поставляемый
Просмотреть файл

@@ -31,14 +31,7 @@ import (
/// Bucket operations
// MakeBucket creates a new bucket with bucketName.
//
// Location is an optional argument, by default all buckets are
// created in US Standard Region.
//
// For Amazon S3 for more supported regions - http://docs.aws.amazon.com/general/latest/gr/rande.html
// For Google Cloud Storage for more supported regions - https://cloud.google.com/storage/docs/bucket-locations
func (c Client) MakeBucket(bucketName string, location string) (err error) {
func (c Client) makeBucket(ctx context.Context, bucketName string, location string, objectLockEnabled bool) (err error) {
defer func() {
// Save the location into cache on a successful makeBucket response.
if err == nil {
@@ -66,6 +59,12 @@ func (c Client) MakeBucket(bucketName string, location string) (err error) {
bucketLocation: location,
}
if objectLockEnabled {
headers := make(http.Header)
headers.Add("x-amz-bucket-object-lock-enabled", "true")
reqMetadata.customHeader = headers
}
// If location is not 'us-east-1' create bucket location config.
if location != "us-east-1" && location != "" {
createBucketConfig := createBucketConfiguration{}
@@ -82,7 +81,7 @@ func (c Client) MakeBucket(bucketName string, location string) (err error) {
}
// Execute PUT to create a new bucket.
resp, err := c.executeMethod(context.Background(), "PUT", reqMetadata)
resp, err := c.executeMethod(ctx, "PUT", reqMetadata)
defer closeResponse(resp)
if err != nil {
return err
@@ -98,8 +97,58 @@ func (c Client) MakeBucket(bucketName string, location string) (err error) {
return nil
}
// MakeBucket creates a new bucket with bucketName.
//
// Location is an optional argument, by default all buckets are
// created in US Standard Region.
//
// For Amazon S3 for more supported regions - http://docs.aws.amazon.com/general/latest/gr/rande.html
// For Google Cloud Storage for more supported regions - https://cloud.google.com/storage/docs/bucket-locations
func (c Client) MakeBucket(bucketName string, location string) (err error) {
return c.MakeBucketWithContext(context.Background(), bucketName, location)
}
// MakeBucketWithContext creates a new bucket with bucketName with a context to control cancellations and timeouts.
//
// Location is an optional argument, by default all buckets are
// created in US Standard Region.
//
// For Amazon S3 for more supported regions - http://docs.aws.amazon.com/general/latest/gr/rande.html
// For Google Cloud Storage for more supported regions - https://cloud.google.com/storage/docs/bucket-locations
func (c Client) MakeBucketWithContext(ctx context.Context, bucketName string, location string) (err error) {
return c.makeBucket(ctx, bucketName, location, false)
}
// MakeBucketWithObjectLock creates a object lock enabled new bucket with bucketName.
//
// Location is an optional argument, by default all buckets are
// created in US Standard Region.
//
// For Amazon S3 for more supported regions - http://docs.aws.amazon.com/general/latest/gr/rande.html
// For Google Cloud Storage for more supported regions - https://cloud.google.com/storage/docs/bucket-locations
func (c Client) MakeBucketWithObjectLock(bucketName string, location string) (err error) {
return c.MakeBucketWithObjectLockWithContext(context.Background(), bucketName, location)
}
// MakeBucketWithObjectLockWithContext creates a object lock enabled new bucket with bucketName with a context to
// control cancellations and timeouts.
//
// Location is an optional argument, by default all buckets are
// created in US Standard Region.
//
// For Amazon S3 for more supported regions - http://docs.aws.amazon.com/general/latest/gr/rande.html
// For Google Cloud Storage for more supported regions - https://cloud.google.com/storage/docs/bucket-locations
func (c Client) MakeBucketWithObjectLockWithContext(ctx context.Context, bucketName string, location string) (err error) {
return c.makeBucket(ctx, bucketName, location, true)
}
// SetBucketPolicy set the access permissions on an existing bucket.
func (c Client) SetBucketPolicy(bucketName, policy string) error {
return c.SetBucketPolicyWithContext(context.Background(), bucketName, policy)
}
// SetBucketPolicyWithContext set the access permissions on an existing bucket.
func (c Client) SetBucketPolicyWithContext(ctx context.Context, bucketName, policy string) error {
// Input validation.
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
return err
@@ -107,15 +156,15 @@ func (c Client) SetBucketPolicy(bucketName, policy string) error {
// If policy is empty then delete the bucket policy.
if policy == "" {
return c.removeBucketPolicy(bucketName)
return c.removeBucketPolicy(ctx, bucketName)
}
// Save the updated policies.
return c.putBucketPolicy(bucketName, policy)
return c.putBucketPolicy(ctx, bucketName, policy)
}
// Saves a new bucket policy.
func (c Client) putBucketPolicy(bucketName, policy string) error {
func (c Client) putBucketPolicy(ctx context.Context, bucketName, policy string) error {
// Input validation.
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
return err
@@ -141,7 +190,7 @@ func (c Client) putBucketPolicy(bucketName, policy string) error {
}
// Execute PUT to upload a new bucket policy.
resp, err := c.executeMethod(context.Background(), "PUT", reqMetadata)
resp, err := c.executeMethod(ctx, "PUT", reqMetadata)
defer closeResponse(resp)
if err != nil {
return err
@@ -155,7 +204,7 @@ func (c Client) putBucketPolicy(bucketName, policy string) error {
}
// Removes all policies on a bucket.
func (c Client) removeBucketPolicy(bucketName string) error {
func (c Client) removeBucketPolicy(ctx context.Context, bucketName string) error {
// Input validation.
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
return err
@@ -166,7 +215,7 @@ func (c Client) removeBucketPolicy(bucketName string) error {
urlValues.Set("policy", "")
// Execute DELETE on objectName.
resp, err := c.executeMethod(context.Background(), "DELETE", requestMetadata{
resp, err := c.executeMethod(ctx, "DELETE", requestMetadata{
bucketName: bucketName,
queryValues: urlValues,
contentSHA256Hex: emptySHA256Hex,
@@ -180,6 +229,11 @@ func (c Client) removeBucketPolicy(bucketName string) error {
// SetBucketLifecycle set the lifecycle on an existing bucket.
func (c Client) SetBucketLifecycle(bucketName, lifecycle string) error {
return c.SetBucketLifecycleWithContext(context.Background(), bucketName, lifecycle)
}
// SetBucketLifecycleWithContext set the lifecycle on an existing bucket with a context to control cancellations and timeouts.
func (c Client) SetBucketLifecycleWithContext(ctx context.Context, bucketName, lifecycle string) error {
// Input validation.
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
return err
@@ -187,15 +241,15 @@ func (c Client) SetBucketLifecycle(bucketName, lifecycle string) error {
// If lifecycle is empty then delete it.
if lifecycle == "" {
return c.removeBucketLifecycle(bucketName)
return c.removeBucketLifecycle(ctx, bucketName)
}
// Save the updated lifecycle.
return c.putBucketLifecycle(bucketName, lifecycle)
return c.putBucketLifecycle(ctx, bucketName, lifecycle)
}
// Saves a new bucket lifecycle.
func (c Client) putBucketLifecycle(bucketName, lifecycle string) error {
func (c Client) putBucketLifecycle(ctx context.Context, bucketName, lifecycle string) error {
// Input validation.
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
return err
@@ -222,7 +276,7 @@ func (c Client) putBucketLifecycle(bucketName, lifecycle string) error {
}
// Execute PUT to upload a new bucket lifecycle.
resp, err := c.executeMethod(context.Background(), "PUT", reqMetadata)
resp, err := c.executeMethod(ctx, "PUT", reqMetadata)
defer closeResponse(resp)
if err != nil {
return err
@@ -236,7 +290,7 @@ func (c Client) putBucketLifecycle(bucketName, lifecycle string) error {
}
// Remove lifecycle from a bucket.
func (c Client) removeBucketLifecycle(bucketName string) error {
func (c Client) removeBucketLifecycle(ctx context.Context, bucketName string) error {
// Input validation.
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
return err
@@ -247,7 +301,7 @@ func (c Client) removeBucketLifecycle(bucketName string) error {
urlValues.Set("lifecycle", "")
// Execute DELETE on objectName.
resp, err := c.executeMethod(context.Background(), "DELETE", requestMetadata{
resp, err := c.executeMethod(ctx, "DELETE", requestMetadata{
bucketName: bucketName,
queryValues: urlValues,
contentSHA256Hex: emptySHA256Hex,
@@ -261,6 +315,12 @@ func (c Client) removeBucketLifecycle(bucketName string) error {
// SetBucketNotification saves a new bucket notification.
func (c Client) SetBucketNotification(bucketName string, bucketNotification BucketNotification) error {
return c.SetBucketNotificationWithContext(context.Background(), bucketName, bucketNotification)
}
// SetBucketNotificationWithContext saves a new bucket notification with a context to control cancellations
// and timeouts.
func (c Client) SetBucketNotificationWithContext(ctx context.Context, bucketName string, bucketNotification BucketNotification) error {
// Input validation.
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
return err
@@ -287,7 +347,7 @@ func (c Client) SetBucketNotification(bucketName string, bucketNotification Buck
}
// Execute PUT to upload a new bucket notification.
resp, err := c.executeMethod(context.Background(), "PUT", reqMetadata)
resp, err := c.executeMethod(ctx, "PUT", reqMetadata)
defer closeResponse(resp)
if err != nil {
return err
@@ -304,3 +364,69 @@ func (c Client) SetBucketNotification(bucketName string, bucketNotification Buck
func (c Client) RemoveAllBucketNotification(bucketName string) error {
return c.SetBucketNotification(bucketName, BucketNotification{})
}
var (
versionEnableConfig = []byte("<VersioningConfiguration xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"><Status>Enabled</Status></VersioningConfiguration>")
versionEnableConfigLen = int64(len(versionEnableConfig))
versionEnableConfigMD5Sum = sumMD5Base64(versionEnableConfig)
versionEnableConfigSHA256 = sum256Hex(versionEnableConfig)
versionDisableConfig = []byte("<VersioningConfiguration xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"><Status>Suspended</Status></VersioningConfiguration>")
versionDisableConfigLen = int64(len(versionDisableConfig))
versionDisableConfigMD5Sum = sumMD5Base64(versionDisableConfig)
versionDisableConfigSHA256 = sum256Hex(versionDisableConfig)
)
func (c Client) setVersioning(ctx context.Context, bucketName string, config []byte, length int64, md5sum, sha256sum string) error {
// Input validation.
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
return err
}
// Get resources properly escaped and lined up before
// using them in http request.
urlValues := make(url.Values)
urlValues.Set("versioning", "")
reqMetadata := requestMetadata{
bucketName: bucketName,
queryValues: urlValues,
contentBody: bytes.NewReader(config),
contentLength: length,
contentMD5Base64: md5sum,
contentSHA256Hex: sha256sum,
}
// Execute PUT to set a bucket versioning.
resp, err := c.executeMethod(ctx, "PUT", reqMetadata)
defer closeResponse(resp)
if err != nil {
return err
}
if resp != nil {
if resp.StatusCode != http.StatusOK {
return httpRespToErrorResponse(resp, bucketName, "")
}
}
return nil
}
// EnableVersioning - Enable object versioning in given bucket.
func (c Client) EnableVersioning(bucketName string) error {
return c.EnableVersioningWithContext(context.Background(), bucketName)
}
// EnableVersioningWithContext - Enable object versioning in given bucket with a context to control cancellations and timeouts.
func (c Client) EnableVersioningWithContext(ctx context.Context, bucketName string) error {
return c.setVersioning(ctx, bucketName, versionEnableConfig, versionEnableConfigLen, versionEnableConfigMD5Sum, versionEnableConfigSHA256)
}
// DisableVersioning - Disable object versioning in given bucket.
func (c Client) DisableVersioning(bucketName string) error {
return c.DisableVersioningWithContext(context.Background(), bucketName)
}
// DisableVersioningWithContext - Disable object versioning in given bucket with a context to control cancellations and timeouts.
func (c Client) DisableVersioningWithContext(ctx context.Context, bucketName string) error {
return c.setVersioning(ctx, bucketName, versionDisableConfig, versionDisableConfigLen, versionDisableConfigMD5Sum, versionDisableConfigSHA256)
}

16
vendor/github.com/minio/minio-go/v6/api-put-object-common.go сгенерированный поставляемый
Просмотреть файл

@@ -69,7 +69,9 @@ func isReadAt(reader io.Reader) (ok bool) {
//
func optimalPartInfo(objectSize int64, configuredPartSize uint64) (totalPartsCount int, partSize int64, lastPartSize int64, err error) {
// object size is '-1' set it to 5TiB.
var unknownSize bool
if objectSize == -1 {
unknownSize = true
objectSize = maxMultipartPutObjectSize
}
@@ -86,9 +88,11 @@ func optimalPartInfo(objectSize int64, configuredPartSize uint64) (totalPartsCou
return
}
if objectSize > (int64(configuredPartSize) * maxPartsCount) {
err = ErrInvalidArgument("Part size * max_parts(10000) is lesser than input objectSize.")
return
if !unknownSize {
if objectSize > (int64(configuredPartSize) * maxPartsCount) {
err = ErrInvalidArgument("Part size * max_parts(10000) is lesser than input objectSize.")
return
}
}
if configuredPartSize < absMinPartSize {
@@ -100,7 +104,13 @@ func optimalPartInfo(objectSize int64, configuredPartSize uint64) (totalPartsCou
err = ErrInvalidArgument("Input part size is bigger than allowed maximum of 5GiB.")
return
}
partSizeFlt = float64(configuredPartSize)
if unknownSize {
// If input has unknown size and part size is configured
// keep it to maximum allowed as per 10000 parts.
objectSize = int64(configuredPartSize) * maxPartsCount
}
} else {
configuredPartSize = minPartSize
// Use floats for part size for all calculations to avoid

10
vendor/github.com/minio/minio-go/v6/api-put-object-copy.go сгенерированный поставляемый
Просмотреть файл

@@ -24,6 +24,7 @@ import (
"net/http"
"github.com/minio/minio-go/v6/pkg/encrypt"
"github.com/minio/minio-go/v6/pkg/s3utils"
)
// CopyObject - copy a source object into a new object
@@ -39,6 +40,11 @@ func (c Client) CopyObjectWithProgress(dst DestinationInfo, src SourceInfo, prog
header[k] = v
}
if dst.opts.ReplaceTags && len(dst.opts.UserTags) != 0 {
header.Set(amzTaggingHeaderDirective, "REPLACE")
header.Set(amzTaggingHeader, s3utils.TagEncode(dst.opts.UserTags))
}
var err error
var size int64
// If progress bar is specified, size should be requested as well initiate a StatObject request.
@@ -53,8 +59,8 @@ func (c Client) CopyObjectWithProgress(dst DestinationInfo, src SourceInfo, prog
encrypt.SSECopy(src.encryption).Marshal(header)
}
if dst.encryption != nil {
dst.encryption.Marshal(header)
if dst.opts.Encryption != nil {
dst.opts.Encryption.Marshal(header)
}
for k, v := range dst.getUserMetaHeadersMap(true) {
header.Set(k, v)

10
vendor/github.com/minio/minio-go/v6/api-put-object-multipart.go сгенерированный поставляемый
Просмотреть файл

@@ -137,11 +137,10 @@ func (c Client) putObjectMultipartNoStream(ctx context.Context, bucketName, obje
}
// Proceed to upload the part.
var objPart ObjectPart
objPart, err = c.uploadPart(ctx, bucketName, objectName, uploadID, rd, partNumber,
objPart, uerr := c.uploadPart(ctx, bucketName, objectName, uploadID, rd, partNumber,
md5Base64, sha256Hex, int64(length), opts.ServerSideEncryption)
if err != nil {
return totalUploadedSize, err
if uerr != nil {
return totalUploadedSize, uerr
}
// Save successfully uploaded part metadata.
@@ -294,8 +293,7 @@ func (c Client) uploadPart(ctx context.Context, bucketName, objectName, uploadID
objPart.Size = size
objPart.PartNumber = partNumber
// Trim off the odd double quotes from ETag in the beginning and end.
objPart.ETag = strings.TrimPrefix(resp.Header.Get("ETag"), "\"")
objPart.ETag = strings.TrimSuffix(objPart.ETag, "\"")
objPart.ETag = trimEtag(resp.Header.Get("ETag"))
return objPart, nil
}

35
vendor/github.com/minio/minio-go/v6/api-put-object-streaming.go сгенерированный поставляемый
Просмотреть файл

@@ -67,12 +67,12 @@ type uploadedPartRes struct {
Error error // Any error encountered while uploading the part.
PartNum int // Number of the part uploaded.
Size int64 // Size of the part uploaded.
Part *ObjectPart
Part ObjectPart
}
type uploadPartReq struct {
PartNum int // Number of the part uploaded.
Part *ObjectPart // Size of the part uploaded.
PartNum int // Number of the part uploaded.
Part ObjectPart // Size of the part uploaded.
}
// putObjectMultipartFromReadAt - Uploads files bigger than 128MiB.
@@ -139,7 +139,7 @@ func (c Client) putObjectMultipartStreamFromReadAt(ctx context.Context, bucketNa
// Send each part number to the channel to be processed.
for p := 1; p <= totalPartsCount; p++ {
uploadPartsCh <- uploadPartReq{PartNum: p, Part: nil}
uploadPartsCh <- uploadPartReq{PartNum: p}
}
close(uploadPartsCh)
// Receive each part number from the channel allowing three parallel uploads.
@@ -164,13 +164,11 @@ func (c Client) putObjectMultipartStreamFromReadAt(ctx context.Context, bucketNa
sectionReader := newHook(io.NewSectionReader(reader, readOffset, partSize), opts.Progress)
// Proceed to upload the part.
var objPart ObjectPart
objPart, err = c.uploadPart(ctx, bucketName, objectName, uploadID,
objPart, err := c.uploadPart(ctx, bucketName, objectName, uploadID,
sectionReader, uploadReq.PartNum,
"", "", partSize, opts.ServerSideEncryption)
if err != nil {
uploadedPartsCh <- uploadedPartRes{
Size: 0,
Error: err,
}
// Exit the goroutine.
@@ -178,14 +176,13 @@ func (c Client) putObjectMultipartStreamFromReadAt(ctx context.Context, bucketNa
}
// Save successfully uploaded part metadata.
uploadReq.Part = &objPart
uploadReq.Part = objPart
// Send successful part info through the channel.
uploadedPartsCh <- uploadedPartRes{
Size: objPart.Size,
PartNum: uploadReq.PartNum,
Part: uploadReq.Part,
Error: nil,
}
}
}(partSize)
@@ -198,18 +195,12 @@ func (c Client) putObjectMultipartStreamFromReadAt(ctx context.Context, bucketNa
if uploadRes.Error != nil {
return totalUploadedSize, uploadRes.Error
}
// Retrieve each uploaded part and store it to be completed.
// part, ok := partsInfo[uploadRes.PartNum]
part := uploadRes.Part
if part == nil {
return 0, ErrInvalidArgument(fmt.Sprintf("Missing part number %d", uploadRes.PartNum))
}
// Update the totalUploadedSize.
totalUploadedSize += uploadRes.Size
// Store the parts to be completed in order.
complMultipartUpload.Parts = append(complMultipartUpload.Parts, CompletePart{
ETag: part.ETag,
PartNumber: part.PartNumber,
ETag: uploadRes.Part.ETag,
PartNumber: uploadRes.Part.PartNumber,
})
}
@@ -277,12 +268,11 @@ func (c Client) putObjectMultipartStreamNoChecksum(ctx context.Context, bucketNa
if partNumber == totalPartsCount {
partSize = lastPartSize
}
var objPart ObjectPart
objPart, err = c.uploadPart(ctx, bucketName, objectName, uploadID,
objPart, uerr := c.uploadPart(ctx, bucketName, objectName, uploadID,
io.LimitReader(hookReader, partSize),
partNumber, "", "", partSize, opts.ServerSideEncryption)
if err != nil {
return totalUploadedSize, err
if uerr != nil {
return totalUploadedSize, uerr
}
// Save successfully uploaded part metadata.
@@ -407,8 +397,7 @@ func (c Client) putObjectDo(ctx context.Context, bucketName, objectName string,
var objInfo ObjectInfo
// Trim off the odd double quotes from ETag in the beginning and end.
objInfo.ETag = strings.TrimPrefix(resp.Header.Get("ETag"), "\"")
objInfo.ETag = strings.TrimSuffix(objInfo.ETag, "\"")
objInfo.ETag = trimEtag(resp.Header.Get("ETag"))
// A success here means data was written to server successfully.
objInfo.Size = size

38
vendor/github.com/minio/minio-go/v6/api-put-object.go сгенерированный поставляемый
Просмотреть файл

@@ -25,6 +25,7 @@ import (
"net/http"
"runtime/debug"
"sort"
"time"
"github.com/minio/minio-go/v6/pkg/encrypt"
"github.com/minio/minio-go/v6/pkg/s3utils"
@@ -34,12 +35,15 @@ import (
// PutObjectOptions represents options specified by user for PutObject call
type PutObjectOptions struct {
UserMetadata map[string]string
UserTags map[string]string
Progress io.Reader
ContentType string
ContentEncoding string
ContentDisposition string
ContentLanguage string
CacheControl string
Mode *RetentionMode
RetainUntilDate *time.Time
ServerSideEncryption encrypt.ServerSide
NumThreads uint
StorageClass string
@@ -80,6 +84,14 @@ func (opts PutObjectOptions) Header() (header http.Header) {
if opts.CacheControl != "" {
header["Cache-Control"] = []string{opts.CacheControl}
}
if opts.Mode != nil {
header["x-amz-object-lock-mode"] = []string{opts.Mode.String()}
}
if opts.RetainUntilDate != nil {
header["x-amz-object-lock-retain-until-date"] = []string{opts.RetainUntilDate.Format(time.RFC3339)}
}
if opts.ServerSideEncryption != nil {
opts.ServerSideEncryption.Marshal(header)
}
@@ -89,6 +101,9 @@ func (opts PutObjectOptions) Header() (header http.Header) {
if opts.WebsiteRedirectLocation != "" {
header[amzWebsiteRedirectLocation] = []string{opts.WebsiteRedirectLocation}
}
if len(opts.UserTags) != 0 {
header[amzTaggingHeader] = []string{s3utils.TagEncode(opts.UserTags)}
}
for k, v := range opts.UserMetadata {
if !isAmzHeader(k) && !isStandardHeader(k) && !isStorageClassHeader(k) {
header["X-Amz-Meta-"+k] = []string{v}
@@ -109,6 +124,11 @@ func (opts PutObjectOptions) validate() (err error) {
return ErrInvalidArgument(v + " unsupported user defined metadata value")
}
}
if opts.Mode != nil {
if !opts.Mode.IsValid() {
return ErrInvalidArgument(opts.Mode.String() + " unsupported retention mode")
}
}
return nil
}
@@ -215,23 +235,23 @@ func (c Client) putObjectMultipartStreamNoLength(ctx context.Context, bucketName
defer debug.FreeOSMemory()
for partNumber <= totalPartsCount {
length, rErr := io.ReadFull(reader, buf)
if rErr == io.EOF && partNumber > 1 {
length, rerr := io.ReadFull(reader, buf)
if rerr == io.EOF && partNumber > 1 {
break
}
if rErr != nil && rErr != io.ErrUnexpectedEOF && rErr != io.EOF {
return 0, rErr
if rerr != nil && rerr != io.ErrUnexpectedEOF && rerr != io.EOF {
return 0, rerr
}
// Update progress reader appropriately to the latest offset
// as we read from the source.
rd := newHook(bytes.NewReader(buf[:length]), opts.Progress)
// Proceed to upload the part.
var objPart ObjectPart
objPart, err = c.uploadPart(ctx, bucketName, objectName, uploadID, rd, partNumber,
objPart, uerr := c.uploadPart(ctx, bucketName, objectName, uploadID, rd, partNumber,
"", "", int64(length), opts.ServerSideEncryption)
if err != nil {
return totalUploadedSize, err
if uerr != nil {
return totalUploadedSize, uerr
}
// Save successfully uploaded part metadata.
@@ -245,7 +265,7 @@ func (c Client) putObjectMultipartStreamNoLength(ctx context.Context, bucketName
// For unknown size, Read EOF we break away.
// We do not have to upload till totalPartsCount.
if rErr == io.EOF {
if rerr == io.EOF {
break
}
}

29
vendor/github.com/minio/minio-go/v6/api-remove.go сгенерированный поставляемый
Просмотреть файл

@@ -60,6 +60,17 @@ func (c Client) RemoveBucket(bucketName string) error {
// RemoveObject remove an object from a bucket.
func (c Client) RemoveObject(bucketName, objectName string) error {
return c.RemoveObjectWithOptions(bucketName, objectName, RemoveObjectOptions{})
}
// RemoveObjectOptions represents options specified by user for PutObject call
type RemoveObjectOptions struct {
GovernanceBypass bool
VersionID string
}
// RemoveObjectWithOptions removes an object from a bucket.
func (c Client) RemoveObjectWithOptions(bucketName, objectName string, opts RemoveObjectOptions) error {
// Input validation.
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
return err
@@ -67,11 +78,29 @@ func (c Client) RemoveObject(bucketName, objectName string) error {
if err := s3utils.CheckValidObjectName(objectName); err != nil {
return err
}
// Get resources properly escaped and lined up before
// using them in http request.
urlValues := make(url.Values)
if opts.VersionID != "" {
urlValues.Set("versionId", opts.VersionID)
}
// Build headers.
headers := make(http.Header)
if opts.GovernanceBypass {
// Set the bypass goverenance retention header
headers.Set("x-amz-bypass-governance-retention", "True")
}
// Execute DELETE on objectName.
resp, err := c.executeMethod(context.Background(), "DELETE", requestMetadata{
bucketName: bucketName,
objectName: objectName,
contentSHA256Hex: emptySHA256Hex,
queryValues: urlValues,
customHeader: headers,
})
defer closeResponse(resp)
if err != nil {

16
vendor/github.com/minio/minio-go/v6/api-s3-datatypes.go сгенерированный поставляемый
Просмотреть файл

@@ -243,3 +243,19 @@ type deleteMultiObjectsResult struct {
DeletedObjects []deletedObject `xml:"Deleted"`
UnDeletedObjects []nonDeletedObject `xml:"Error"`
}
type tagging struct {
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ Tagging"`
TagSet tagSet
}
type tagSet struct {
XMLName xml.Name `xml:"TagSet"`
Tags []tag
}
type tag struct {
XMLName xml.Name `xml:"Tag"`
Key string `xml:"Key"`
Value string `xml:"Value"`
}

37
vendor/github.com/minio/minio-go/v6/api-stat.go сгенерированный поставляемый
Просмотреть файл

@@ -29,13 +29,19 @@ import (
// BucketExists verify if bucket exists and you have permission to access it.
func (c Client) BucketExists(bucketName string) (bool, error) {
return c.BucketExistsWithContext(context.Background(), bucketName)
}
// BucketExistsWithContext verify if bucket exists and you have permission to access it. Allows for a Context to
// control cancellations and timeouts.
func (c Client) BucketExistsWithContext(ctx context.Context, bucketName string) (bool, error) {
// Input validation.
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
return false, err
}
// Execute HEAD on bucketName.
resp, err := c.executeMethod(context.Background(), "HEAD", requestMetadata{
resp, err := c.executeMethod(ctx, "HEAD", requestMetadata{
bucketName: bucketName,
contentSHA256Hex: emptySHA256Hex,
})
@@ -72,7 +78,7 @@ var defaultFilterKeys = []string{
"x-amz-id-2",
"Content-Security-Policy",
"X-Xss-Protection",
amzTaggingHeaderCount,
// Add new headers to be ignored.
}
@@ -85,12 +91,20 @@ func extractObjMetadata(header http.Header) http.Header {
"Last-Modified",
"Content-Type",
"Expires",
"X-Cache",
"X-Cache-Lookup",
}, defaultFilterKeys...)
return filterHeader(header, filterKeys)
}
// StatObject verifies if object exists and you have permission to access.
func (c Client) StatObject(bucketName, objectName string, opts StatObjectOptions) (ObjectInfo, error) {
return c.StatObjectWithContext(context.Background(), bucketName, objectName, opts)
}
// StatObjectWithContext verifies if object exists and you have permission to access with a context to control
// cancellations and timeouts.
func (c Client) StatObjectWithContext(ctx context.Context, bucketName, objectName string, opts StatObjectOptions) (ObjectInfo, error) {
// Input validation.
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
return ObjectInfo{}, err
@@ -98,7 +112,7 @@ func (c Client) StatObject(bucketName, objectName string, opts StatObjectOptions
if err := s3utils.CheckValidObjectName(objectName); err != nil {
return ObjectInfo{}, err
}
return c.statObject(context.Background(), bucketName, objectName, opts)
return c.statObject(ctx, bucketName, objectName, opts)
}
// Lower level API for statObject supporting pre-conditions and range headers.
@@ -129,8 +143,7 @@ func (c Client) statObject(ctx context.Context, bucketName, objectName string, o
}
// Trim off the odd double quotes from ETag in the beginning and end.
md5sum := strings.TrimPrefix(resp.Header.Get("ETag"), "\"")
md5sum = strings.TrimSuffix(md5sum, "\"")
md5sum := trimEtag(resp.Header.Get("ETag"))
// Parse content length is exists
var size int64 = -1
@@ -176,6 +189,17 @@ func (c Client) statObject(ctx context.Context, bucketName, objectName string, o
if t, err := time.Parse(http.TimeFormat, expiryStr); err == nil {
expTime = t.UTC()
}
metadata := extractObjMetadata(resp.Header)
userMetadata := map[string]string{}
const xamzmeta = "x-amz-meta-"
const xamzmetaLen = len(xamzmeta)
for k, v := range metadata {
if strings.HasPrefix(strings.ToLower(k), xamzmeta) {
userMetadata[k[xamzmetaLen:]] = v[0]
}
}
// Save object metadata info.
return ObjectInfo{
ETag: md5sum,
@@ -187,6 +211,7 @@ func (c Client) statObject(ctx context.Context, bucketName, objectName string, o
// Extract only the relevant header keys describing the object.
// following function filters out a list of standard set of keys
// which are not part of object metadata.
Metadata: extractObjMetadata(resp.Header),
Metadata: metadata,
UserMetadata: userMetadata,
}, nil
}

18
vendor/github.com/minio/minio-go/v6/api.go сгенерированный поставляемый
Просмотреть файл

@@ -104,7 +104,7 @@ type Options struct {
// Global constants.
const (
libraryName = "minio-go"
libraryVersion = "v6.0.40"
libraryVersion = "v6.0.45"
)
// User Agent should always following the below style.
@@ -560,6 +560,13 @@ func (c Client) executeMethod(ctx context.Context, method string, metadata reque
var bodySeeker io.Seeker // Extracted seeker from io.Reader.
var reqRetry = MaxRetry // Indicates how many times we can retry the request
defer func() {
if err != nil {
// close idle connections before returning, upon error.
c.httpClient.CloseIdleConnections()
}
}()
if metadata.contentBody != nil {
// Check if body is seekable then it is retryable.
bodySeeker, isRetryable = metadata.contentBody.(io.Seeker)
@@ -620,12 +627,7 @@ func (c Client) executeMethod(ctx context.Context, method string, metadata reque
// Initiate the request.
res, err = c.do(req)
if err != nil {
// For supported http requests errors verify.
if isHTTPReqErrorRetryable(err) {
continue // Retry.
}
// For other errors, return here no need to retry.
return nil, err
continue
}
// For any known successful http status, return quickly.
@@ -822,7 +824,7 @@ func (c Client) newRequest(method string, metadata requestMetadata) (req *http.R
case signerType.IsV2():
// Add signature version '2' authorization header.
req = s3signer.SignV2(*req, accessKeyID, secretAccessKey, isVirtualHost)
case metadata.objectName != "" && method == "PUT" && metadata.customHeader.Get("X-Amz-Copy-Source") == "" && !c.secure:
case metadata.objectName != "" && metadata.queryValues == nil && method == "PUT" && metadata.customHeader.Get("X-Amz-Copy-Source") == "" && !c.secure:
// Streaming signature is used by default for a PUT object request. Additionally we also
// look if the initialized client is secure, if yes then we don't need to perform
// streaming signature.

4
vendor/github.com/minio/minio-go/v6/bucket-cache.go сгенерированный поставляемый
Просмотреть файл

@@ -125,6 +125,10 @@ func processBucketLocationResponse(resp *http.Response, bucketName string) (buck
// request. Move forward and let the top level callers
// succeed if possible based on their policy.
switch errResp.Code {
case "NotImplemented":
if errResp.Server == "AmazonSnowball" {
return "snowball", nil
}
case "AuthorizationHeaderMalformed":
fallthrough
case "InvalidRegion":

5
vendor/github.com/minio/minio-go/v6/constants.go сгенерированный поставляемый
Просмотреть файл

@@ -60,3 +60,8 @@ const amzStorageClass = "X-Amz-Storage-Class"
// Website redirect location header constant
const amzWebsiteRedirectLocation = "X-Amz-Website-Redirect-Location"
// Tagging header constants
const amzTaggingHeader = "X-Amz-Tagging"
const amzTaggingHeaderDirective = "X-Amz-Tagging-Directive"
const amzTaggingHeaderCount = "X-Amz-Tagging-Count"

10
vendor/github.com/minio/minio-go/v6/core.go сгенерированный поставляемый
Просмотреть файл

@@ -53,7 +53,7 @@ func (c Core) ListObjects(bucket, prefix, marker, delimiter string, maxKeys int)
// ListObjectsV2 - Lists all the objects at a prefix, similar to ListObjects() but uses
// continuationToken instead of marker to support iteration over the results.
func (c Core) ListObjectsV2(bucketName, objectPrefix, continuationToken string, fetchOwner bool, delimiter string, maxkeys int, startAfter string) (ListBucketV2Result, error) {
return c.listObjectsV2Query(bucketName, objectPrefix, continuationToken, fetchOwner, delimiter, maxkeys, startAfter)
return c.listObjectsV2Query(bucketName, objectPrefix, continuationToken, fetchOwner, false, delimiter, maxkeys, startAfter)
}
// CopyObjectWithContext - copies an object from source object to destination object on server side.
@@ -171,7 +171,13 @@ func (c Core) GetBucketPolicy(bucket string) (string, error) {
// PutBucketPolicy - applies a new bucket access policy for a given bucket.
func (c Core) PutBucketPolicy(bucket, bucketPolicy string) error {
return c.putBucketPolicy(bucket, bucketPolicy)
return c.PutBucketPolicyWithContext(context.Background(), bucket, bucketPolicy)
}
// PutBucketPolicyWithContext - applies a new bucket access policy for a given bucket with a context to control
// cancellations and timeouts.
func (c Core) PutBucketPolicyWithContext(ctx context.Context, bucket, bucketPolicy string) error {
return c.putBucketPolicy(ctx, bucket, bucketPolicy)
}
// GetObjectWithContext is a lower level API implemented to support reading

95
vendor/github.com/minio/minio-go/v6/pkg/credentials/iam_aws.go сгенерированный поставляемый
Просмотреть файл

@@ -22,6 +22,8 @@ import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net"
"net/http"
"net/url"
"os"
@@ -53,20 +55,10 @@ type IAM struct {
const (
defaultIAMRoleEndpoint = "http://169.254.169.254"
defaultECSRoleEndpoint = "http://169.254.170.2"
defaultSTSRoleEndpoint = "https://sts.amazonaws.com"
defaultIAMSecurityCredsPath = "/latest/meta-data/iam/security-credentials/"
)
// https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-iam-roles.html
func getEndpoint(endpoint string) (string, bool) {
if endpoint != "" {
return endpoint, os.Getenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI") != ""
}
if ecsURI := os.Getenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"); ecsURI != "" {
return fmt.Sprintf("%s%s", defaultECSRoleEndpoint, ecsURI), true
}
return defaultIAMRoleEndpoint, false
}
// NewIAM returns a pointer to a new Credentials object wrapping the IAM.
func NewIAM(endpoint string) *Credentials {
p := &IAM{
@@ -82,14 +74,64 @@ func NewIAM(endpoint string) *Credentials {
// Error will be returned if the request fails, or unable to extract
// the desired
func (m *IAM) Retrieve() (Value, error) {
endpoint, isEcsTask := getEndpoint(m.endpoint)
var roleCreds ec2RoleCredRespBody
var err error
if isEcsTask {
endpoint := m.endpoint
switch {
case len(os.Getenv("AWS_WEB_IDENTITY_TOKEN_FILE")) > 0:
if len(endpoint) == 0 {
if len(os.Getenv("AWS_REGION")) > 0 {
endpoint = "sts." + os.Getenv("AWS_REGION") + ".amazonaws.com"
} else {
endpoint = defaultSTSRoleEndpoint
}
}
creds := &STSWebIdentity{
Client: m.Client,
stsEndpoint: endpoint,
roleARN: os.Getenv("AWS_ROLE_ARN"),
roleSessionName: os.Getenv("AWS_ROLE_SESSION_NAME"),
getWebIDTokenExpiry: func() (*WebIdentityToken, error) {
token, err := ioutil.ReadFile(os.Getenv("AWS_WEB_IDENTITY_TOKEN_FILE"))
if err != nil {
return nil, err
}
return &WebIdentityToken{Token: string(token)}, nil
},
}
return creds.Retrieve()
case len(os.Getenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI")) > 0:
if len(endpoint) == 0 {
endpoint = fmt.Sprintf("%s%s", defaultECSRoleEndpoint,
os.Getenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"))
}
roleCreds, err = getEcsTaskCredentials(m.Client, endpoint)
} else {
case len(os.Getenv("AWS_CONTAINER_CREDENTIALS_FULL_URI")) > 0:
if len(endpoint) == 0 {
endpoint = os.Getenv("AWS_CONTAINER_CREDENTIALS_FULL_URI")
var ok bool
if ok, err = isLoopback(endpoint); !ok {
if err == nil {
err = fmt.Errorf("uri host is not a loopback address: %s", endpoint)
}
break
}
}
roleCreds, err = getEcsTaskCredentials(m.Client, endpoint)
default:
roleCreds, err = getCredentials(m.Client, endpoint)
}
if err != nil {
return Value{}, err
}
@@ -248,3 +290,28 @@ func getCredentials(client *http.Client, endpoint string) (ec2RoleCredRespBody,
return respCreds, nil
}
// isLoopback identifies if a uri's host is on a loopback address
func isLoopback(uri string) (bool, error) {
u, err := url.Parse(uri)
if err != nil {
return false, err
}
host := u.Hostname()
if len(host) == 0 {
return false, fmt.Errorf("can't parse host from uri: %s", uri)
}
ips, err := net.LookupHost(host)
if err != nil {
return false, err
}
for _, ip := range ips {
if !net.ParseIP(ip).IsLoopback() {
return false, nil
}
}
return true, nil
}

24
vendor/github.com/minio/minio-go/v6/pkg/credentials/sts_web_identity.go сгенерированный поставляемый
Просмотреть файл

@@ -23,6 +23,7 @@ import (
"fmt"
"net/http"
"net/url"
"strconv"
"time"
)
@@ -75,6 +76,13 @@ type STSWebIdentity struct {
// this token.
// This is a customer provided function and is mandatory.
getWebIDTokenExpiry func() (*WebIdentityToken, error)
// roleARN is the Amazon Resource Name (ARN) of the role that the caller is
// assuming.
roleARN string
// roleSessionName is the identifier for the assumed role session.
roleSessionName string
}
// NewSTSWebIdentity returns a pointer to a new
@@ -95,7 +103,7 @@ func NewSTSWebIdentity(stsEndpoint string, getWebIDTokenExpiry func() (*WebIdent
}), nil
}
func getWebIdentityCredentials(clnt *http.Client, endpoint string,
func getWebIdentityCredentials(clnt *http.Client, endpoint, roleARN, roleSessionName string,
getWebIDTokenExpiry func() (*WebIdentityToken, error)) (AssumeRoleWithWebIdentityResponse, error) {
idToken, err := getWebIDTokenExpiry()
if err != nil {
@@ -104,8 +112,18 @@ func getWebIdentityCredentials(clnt *http.Client, endpoint string,
v := url.Values{}
v.Set("Action", "AssumeRoleWithWebIdentity")
if len(roleARN) > 0 {
v.Set("RoleArn", roleARN)
if len(roleSessionName) == 0 {
roleSessionName = strconv.FormatInt(time.Now().UnixNano(), 10)
}
v.Set("RoleSessionName", roleSessionName)
}
v.Set("WebIdentityToken", idToken.Token)
v.Set("DurationSeconds", fmt.Sprintf("%d", idToken.Expiry))
if idToken.Expiry > 0 {
v.Set("DurationSeconds", fmt.Sprintf("%d", idToken.Expiry))
}
v.Set("Version", "2011-06-15")
u, err := url.Parse(endpoint)
@@ -141,7 +159,7 @@ func getWebIdentityCredentials(clnt *http.Client, endpoint string,
// Retrieve retrieves credentials from the MinIO service.
// Error will be returned if the request fails.
func (m *STSWebIdentity) Retrieve() (Value, error) {
a, err := getWebIdentityCredentials(m.Client, m.stsEndpoint, m.getWebIDTokenExpiry)
a, err := getWebIdentityCredentials(m.Client, m.stsEndpoint, m.roleARN, m.roleSessionName, m.getWebIDTokenExpiry)
if err != nil {
return Value{}, err
}

4
vendor/github.com/minio/minio-go/v6/pkg/encrypt/server-side.go сгенерированный поставляемый
Просмотреть файл

@@ -188,7 +188,9 @@ func (s kms) Type() Type { return KMS }
func (s kms) Marshal(h http.Header) {
h.Set(sseGenericHeader, "aws:kms")
h.Set(sseKmsKeyID, s.key)
if s.key != "" {
h.Set(sseKmsKeyID, s.key)
}
if s.hasContext {
h.Set(sseEncryptionContext, base64.StdEncoding.EncodeToString(s.context))
}

25
vendor/github.com/minio/minio-go/v6/pkg/s3utils/utils.go сгенерированный поставляемый
Просмотреть файл

@@ -219,6 +219,31 @@ func QueryEncode(v url.Values) string {
return buf.String()
}
// TagEncode - encodes tag values in their URL encoded form. In
// addition to the percent encoding performed by urlEncodePath() used
// here, it also percent encodes '/' (forward slash)
func TagEncode(tags map[string]string) string {
if tags == nil {
return ""
}
var buf bytes.Buffer
keys := make([]string, 0, len(tags))
for k := range tags {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
v := tags[k]
prefix := percentEncodeSlash(EncodePath(k)) + "="
if buf.Len() > 0 {
buf.WriteByte('&')
}
buf.WriteString(prefix)
buf.WriteString(percentEncodeSlash(EncodePath(v)))
}
return buf.String()
}
// if object matches reserved string, no need to encode them
var reservedObjectNames = regexp.MustCompile("^[a-zA-Z0-9-_.~/]+$")

21
vendor/github.com/minio/minio-go/v6/post-policy.go сгенерированный поставляемый
Просмотреть файл

@@ -131,6 +131,27 @@ func (p *PostPolicy) SetBucket(bucketName string) error {
return nil
}
// SetCondition - Sets condition for credentials, date and algorithm
func (p *PostPolicy) SetCondition(matchType, condition, value string) error {
if strings.TrimSpace(value) == "" || value == "" {
return ErrInvalidArgument("No value specified for condition")
}
policyCond := policyCondition{
matchType: matchType,
condition: "$" + condition,
value: value,
}
if condition == "X-Amz-Credential" || condition == "X-Amz-Date" || condition == "X-Amz-Algorithm" {
if err := p.addNewPolicy(policyCond); err != nil {
return err
}
p.formData[condition] = value
return nil
}
return ErrInvalidArgument("Invalid condition in policy")
}
// SetContentType - Sets content-type of the object for this policy
// based upload.
func (p *PostPolicy) SetContentType(contentType string) error {

37
vendor/github.com/minio/minio-go/v6/retry.go сгенерированный поставляемый
Просмотреть файл

@@ -18,10 +18,7 @@
package minio
import (
"net"
"net/http"
"net/url"
"strings"
"time"
)
@@ -85,40 +82,6 @@ func (c Client) newRetryTimer(maxRetry int, unit time.Duration, cap time.Duratio
return attemptCh
}
// isHTTPReqErrorRetryable - is http requests error retryable, such
// as i/o timeout, connection broken etc..
func isHTTPReqErrorRetryable(err error) bool {
if err == nil {
return false
}
switch e := err.(type) {
case *url.Error:
switch e.Err.(type) {
case *net.DNSError, *net.OpError, net.UnknownNetworkError:
return true
}
if strings.Contains(err.Error(), "Connection closed by foreign host") {
return true
} else if strings.Contains(err.Error(), "net/http: TLS handshake timeout") {
// If error is - tlsHandshakeTimeoutError, retry.
return true
} else if strings.Contains(err.Error(), "i/o timeout") {
// If error is - tcp timeoutError, retry.
return true
} else if strings.Contains(err.Error(), "connection timed out") {
// If err is a net.Dial timeout, retry.
return true
} else if strings.Contains(err.Error(), "net/http: HTTP/1.x transport connection broken") {
// If error is transport connection broken, retry.
return true
} else if strings.Contains(err.Error(), "net/http: timeout awaiting response headers") {
// Retry errors due to server not sending the response before timeout
return true
}
}
return false
}
// List of AWS S3 error codes which are retryable.
var retryableS3Codes = map[string]struct{}{
"RequestError": {},

22
vendor/github.com/minio/minio-go/v6/transport.go сгенерированный поставляемый
Просмотреть файл

@@ -21,12 +21,9 @@ package minio
import (
"crypto/tls"
"crypto/x509"
"net"
"net/http"
"time"
"golang.org/x/net/http2"
)
// DefaultTransport - this default transport is similar to
@@ -54,29 +51,12 @@ var DefaultTransport = func(secure bool) (http.RoundTripper, error) {
}
if secure {
rootCAs, _ := x509.SystemCertPool()
if rootCAs == nil {
// In some systems (like Windows) system cert pool is
// not supported or no certificates are present on the
// system - so we create a new cert pool.
rootCAs = x509.NewCertPool()
}
// Keep TLS config.
tlsConfig := &tls.Config{
RootCAs: rootCAs,
tr.TLSClientConfig = &tls.Config{
// Can't use SSLv3 because of POODLE and BEAST
// Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher
// Can't use TLSv1.1 because of RC4 cipher usage
MinVersion: tls.VersionTLS12,
}
tr.TLSClientConfig = tlsConfig
// Because we create a custom TLSClientConfig, we have to opt-in to HTTP/2.
// See https://github.com/golang/go/issues/14275
if err := http2.ConfigureTransport(tr); err != nil {
return nil, err
}
}
return tr, nil
}

7
vendor/github.com/minio/minio-go/v6/utils.go сгенерированный поставляемый
Просмотреть файл

@@ -36,6 +36,11 @@ import (
"github.com/minio/minio-go/v6/pkg/s3utils"
)
func trimEtag(etag string) string {
etag = strings.TrimPrefix(etag, "\"")
return strings.TrimSuffix(etag, "\"")
}
// xmlDecoder provide decoded value in xml.
func xmlDecoder(body io.Reader, v interface{}) error {
d := xml.NewDecoder(body)
@@ -224,6 +229,8 @@ var supportedHeaders = []string{
"content-disposition",
"content-language",
"x-amz-website-redirect-location",
"x-amz-object-lock-mode",
"x-amz-object-lock-retain-until-date",
"expires",
// Add more supported headers here.
}