mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-11-01 11:42:24 -05:00
[chore] update go dependencies (#4304)
- github.com/KimMachineGun/automemlimit v0.7.2 => v0.7.3
- github.com/gin-contrib/cors v1.7.5 => v1.7.6
- github.com/minio/minio-go/v7 v7.0.92 => v7.0.94
- github.com/spf13/cast v1.8.0 => v1.9.2
- github.com/uptrace/bun{,/*} v1.2.11 => v1.2.14
- golang.org/x/image v0.27.0 => v0.28.0
- golang.org/x/net v0.40.0 => v0.41.0
- code.superseriousbusiness.org/go-swagger v0.31.0-gts-go1.23-fix => v0.32.3-gts-go1.23-fix
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4304
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
This commit is contained in:
parent
7712885038
commit
8b0ea56027
294 changed files with 139999 additions and 21873 deletions
2
vendor/github.com/minio/minio-go/v7/api-bucket-cors.go
generated
vendored
2
vendor/github.com/minio/minio-go/v7/api-bucket-cors.go
generated
vendored
|
|
@ -98,7 +98,7 @@ func (c *Client) GetBucketCors(ctx context.Context, bucketName string) (*cors.Co
|
|||
bucketCors, err := c.getBucketCors(ctx, bucketName)
|
||||
if err != nil {
|
||||
errResponse := ToErrorResponse(err)
|
||||
if errResponse.Code == "NoSuchCORSConfiguration" {
|
||||
if errResponse.Code == NoSuchCORSConfiguration {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
|
|
|
|||
2
vendor/github.com/minio/minio-go/v7/api-bucket-policy.go
generated
vendored
2
vendor/github.com/minio/minio-go/v7/api-bucket-policy.go
generated
vendored
|
|
@ -104,7 +104,7 @@ func (c *Client) GetBucketPolicy(ctx context.Context, bucketName string) (string
|
|||
bucketPolicy, err := c.getBucketPolicy(ctx, bucketName)
|
||||
if err != nil {
|
||||
errResponse := ToErrorResponse(err)
|
||||
if errResponse.Code == "NoSuchBucketPolicy" {
|
||||
if errResponse.Code == NoSuchBucketPolicy {
|
||||
return "", nil
|
||||
}
|
||||
return "", err
|
||||
|
|
|
|||
37
vendor/github.com/minio/minio-go/v7/api-error-response.go
generated
vendored
37
vendor/github.com/minio/minio-go/v7/api-error-response.go
generated
vendored
|
|
@ -136,15 +136,15 @@ func httpRespToErrorResponse(resp *http.Response, bucketName, objectName string)
|
|||
if objectName == "" {
|
||||
errResp = ErrorResponse{
|
||||
StatusCode: resp.StatusCode,
|
||||
Code: "NoSuchBucket",
|
||||
Message: "The specified bucket does not exist.",
|
||||
Code: NoSuchBucket,
|
||||
Message: s3ErrorResponseMap[NoSuchBucket],
|
||||
BucketName: bucketName,
|
||||
}
|
||||
} else {
|
||||
errResp = ErrorResponse{
|
||||
StatusCode: resp.StatusCode,
|
||||
Code: "NoSuchKey",
|
||||
Message: "The specified key does not exist.",
|
||||
Code: NoSuchKey,
|
||||
Message: s3ErrorResponseMap[NoSuchKey],
|
||||
BucketName: bucketName,
|
||||
Key: objectName,
|
||||
}
|
||||
|
|
@ -152,23 +152,23 @@ func httpRespToErrorResponse(resp *http.Response, bucketName, objectName string)
|
|||
case http.StatusForbidden:
|
||||
errResp = ErrorResponse{
|
||||
StatusCode: resp.StatusCode,
|
||||
Code: "AccessDenied",
|
||||
Message: "Access Denied.",
|
||||
Code: AccessDenied,
|
||||
Message: s3ErrorResponseMap[AccessDenied],
|
||||
BucketName: bucketName,
|
||||
Key: objectName,
|
||||
}
|
||||
case http.StatusConflict:
|
||||
errResp = ErrorResponse{
|
||||
StatusCode: resp.StatusCode,
|
||||
Code: "Conflict",
|
||||
Message: "Bucket not empty.",
|
||||
Code: Conflict,
|
||||
Message: s3ErrorResponseMap[Conflict],
|
||||
BucketName: bucketName,
|
||||
}
|
||||
case http.StatusPreconditionFailed:
|
||||
errResp = ErrorResponse{
|
||||
StatusCode: resp.StatusCode,
|
||||
Code: "PreconditionFailed",
|
||||
Message: s3ErrorResponseMap["PreconditionFailed"],
|
||||
Code: PreconditionFailed,
|
||||
Message: s3ErrorResponseMap[PreconditionFailed],
|
||||
BucketName: bucketName,
|
||||
Key: objectName,
|
||||
}
|
||||
|
|
@ -209,7 +209,7 @@ func httpRespToErrorResponse(resp *http.Response, bucketName, objectName string)
|
|||
if errResp.Region == "" {
|
||||
errResp.Region = resp.Header.Get("x-amz-bucket-region")
|
||||
}
|
||||
if errResp.Code == "InvalidRegion" && errResp.Region != "" {
|
||||
if errResp.Code == InvalidRegion && errResp.Region != "" {
|
||||
errResp.Message = fmt.Sprintf("Region does not match, expecting region ‘%s’.", errResp.Region)
|
||||
}
|
||||
|
||||
|
|
@ -218,10 +218,11 @@ func httpRespToErrorResponse(resp *http.Response, bucketName, objectName string)
|
|||
|
||||
// errTransferAccelerationBucket - bucket name is invalid to be used with transfer acceleration.
|
||||
func errTransferAccelerationBucket(bucketName string) error {
|
||||
msg := "The name of the bucket used for Transfer Acceleration must be DNS-compliant and must not contain periods ‘.’."
|
||||
return ErrorResponse{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Code: "InvalidArgument",
|
||||
Message: "The name of the bucket used for Transfer Acceleration must be DNS-compliant and must not contain periods ‘.’.",
|
||||
Code: InvalidArgument,
|
||||
Message: msg,
|
||||
BucketName: bucketName,
|
||||
}
|
||||
}
|
||||
|
|
@ -231,7 +232,7 @@ func errEntityTooLarge(totalSize, maxObjectSize int64, bucketName, objectName st
|
|||
msg := fmt.Sprintf("Your proposed upload size ‘%d’ exceeds the maximum allowed object size ‘%d’ for single PUT operation.", totalSize, maxObjectSize)
|
||||
return ErrorResponse{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Code: "EntityTooLarge",
|
||||
Code: EntityTooLarge,
|
||||
Message: msg,
|
||||
BucketName: bucketName,
|
||||
Key: objectName,
|
||||
|
|
@ -243,7 +244,7 @@ func errEntityTooSmall(totalSize int64, bucketName, objectName string) error {
|
|||
msg := fmt.Sprintf("Your proposed upload size ‘%d’ is below the minimum allowed object size ‘0B’ for single PUT operation.", totalSize)
|
||||
return ErrorResponse{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Code: "EntityTooSmall",
|
||||
Code: EntityTooSmall,
|
||||
Message: msg,
|
||||
BucketName: bucketName,
|
||||
Key: objectName,
|
||||
|
|
@ -255,7 +256,7 @@ func errUnexpectedEOF(totalRead, totalSize int64, bucketName, objectName string)
|
|||
msg := fmt.Sprintf("Data read ‘%d’ is not equal to the size ‘%d’ of the input Reader.", totalRead, totalSize)
|
||||
return ErrorResponse{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Code: "UnexpectedEOF",
|
||||
Code: UnexpectedEOF,
|
||||
Message: msg,
|
||||
BucketName: bucketName,
|
||||
Key: objectName,
|
||||
|
|
@ -266,7 +267,7 @@ func errUnexpectedEOF(totalRead, totalSize int64, bucketName, objectName string)
|
|||
func errInvalidArgument(message string) error {
|
||||
return ErrorResponse{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Code: "InvalidArgument",
|
||||
Code: InvalidArgument,
|
||||
Message: message,
|
||||
RequestID: "minio",
|
||||
}
|
||||
|
|
@ -277,7 +278,7 @@ func errInvalidArgument(message string) error {
|
|||
func errAPINotSupported(message string) error {
|
||||
return ErrorResponse{
|
||||
StatusCode: http.StatusNotImplemented,
|
||||
Code: "APINotSupported",
|
||||
Code: APINotSupported,
|
||||
Message: message,
|
||||
RequestID: "minio",
|
||||
}
|
||||
|
|
|
|||
8
vendor/github.com/minio/minio-go/v7/api-get-object.go
generated
vendored
8
vendor/github.com/minio/minio-go/v7/api-get-object.go
generated
vendored
|
|
@ -34,14 +34,14 @@ func (c *Client) GetObject(ctx context.Context, bucketName, objectName string, o
|
|||
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
|
||||
return nil, ErrorResponse{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Code: "InvalidBucketName",
|
||||
Code: InvalidBucketName,
|
||||
Message: err.Error(),
|
||||
}
|
||||
}
|
||||
if err := s3utils.CheckValidObjectName(objectName); err != nil {
|
||||
return nil, ErrorResponse{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Code: "XMinioInvalidObjectName",
|
||||
Code: XMinioInvalidObjectName,
|
||||
Message: err.Error(),
|
||||
}
|
||||
}
|
||||
|
|
@ -659,14 +659,14 @@ func (c *Client) getObject(ctx context.Context, bucketName, objectName string, o
|
|||
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
|
||||
return nil, ObjectInfo{}, nil, ErrorResponse{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Code: "InvalidBucketName",
|
||||
Code: InvalidBucketName,
|
||||
Message: err.Error(),
|
||||
}
|
||||
}
|
||||
if err := s3utils.CheckValidObjectName(objectName); err != nil {
|
||||
return nil, ObjectInfo{}, nil, ErrorResponse{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Code: "XMinioInvalidObjectName",
|
||||
Code: XMinioInvalidObjectName,
|
||||
Message: err.Error(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
49
vendor/github.com/minio/minio-go/v7/api-list.go
generated
vendored
49
vendor/github.com/minio/minio-go/v7/api-list.go
generated
vendored
|
|
@ -285,7 +285,7 @@ func (c *Client) listObjectsV2Query(ctx context.Context, bucketName, objectPrefi
|
|||
// sure proper responses are received.
|
||||
if listBucketResult.IsTruncated && listBucketResult.NextContinuationToken == "" {
|
||||
return listBucketResult, ErrorResponse{
|
||||
Code: "NotImplemented",
|
||||
Code: NotImplemented,
|
||||
Message: "Truncated response should have continuation token set",
|
||||
}
|
||||
}
|
||||
|
|
@ -419,19 +419,25 @@ func (c *Client) listObjectVersions(ctx context.Context, bucketName string, opts
|
|||
}
|
||||
for _, version := range vers {
|
||||
info := ObjectInfo{
|
||||
ETag: trimEtag(version.ETag),
|
||||
Key: version.Key,
|
||||
LastModified: version.LastModified.Truncate(time.Millisecond),
|
||||
Size: version.Size,
|
||||
Owner: version.Owner,
|
||||
StorageClass: version.StorageClass,
|
||||
IsLatest: version.IsLatest,
|
||||
VersionID: version.VersionID,
|
||||
IsDeleteMarker: version.isDeleteMarker,
|
||||
UserTags: version.UserTags,
|
||||
UserMetadata: version.UserMetadata,
|
||||
Internal: version.Internal,
|
||||
NumVersions: numVersions,
|
||||
ETag: trimEtag(version.ETag),
|
||||
Key: version.Key,
|
||||
LastModified: version.LastModified.Truncate(time.Millisecond),
|
||||
Size: version.Size,
|
||||
Owner: version.Owner,
|
||||
StorageClass: version.StorageClass,
|
||||
IsLatest: version.IsLatest,
|
||||
VersionID: version.VersionID,
|
||||
IsDeleteMarker: version.isDeleteMarker,
|
||||
UserTags: version.UserTags,
|
||||
UserMetadata: version.UserMetadata,
|
||||
Internal: version.Internal,
|
||||
NumVersions: numVersions,
|
||||
ChecksumMode: version.ChecksumType,
|
||||
ChecksumCRC32: version.ChecksumCRC32,
|
||||
ChecksumCRC32C: version.ChecksumCRC32C,
|
||||
ChecksumSHA1: version.ChecksumSHA1,
|
||||
ChecksumSHA256: version.ChecksumSHA256,
|
||||
ChecksumCRC64NVME: version.ChecksumCRC64NVME,
|
||||
}
|
||||
if !yield(info) {
|
||||
return false
|
||||
|
|
@ -753,13 +759,9 @@ func (c *Client) ListObjects(ctx context.Context, bucketName string, opts ListOb
|
|||
objectStatCh := make(chan ObjectInfo, 1)
|
||||
go func() {
|
||||
defer close(objectStatCh)
|
||||
send := func(obj ObjectInfo) bool {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return false
|
||||
case objectStatCh <- obj:
|
||||
return true
|
||||
}
|
||||
if contextCanceled(ctx) {
|
||||
objectStatCh <- ObjectInfo{Err: ctx.Err()}
|
||||
return
|
||||
}
|
||||
|
||||
var objIter iter.Seq[ObjectInfo]
|
||||
|
|
@ -777,8 +779,11 @@ func (c *Client) ListObjects(ctx context.Context, bucketName string, opts ListOb
|
|||
}
|
||||
}
|
||||
for obj := range objIter {
|
||||
if !send(obj) {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
objectStatCh <- ObjectInfo{Err: ctx.Err()}
|
||||
return
|
||||
case objectStatCh <- obj:
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
|
|
|||
4
vendor/github.com/minio/minio-go/v7/api-prompt-object.go
generated
vendored
4
vendor/github.com/minio/minio-go/v7/api-prompt-object.go
generated
vendored
|
|
@ -35,14 +35,14 @@ func (c *Client) PromptObject(ctx context.Context, bucketName, objectName, promp
|
|||
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
|
||||
return nil, ErrorResponse{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Code: "InvalidBucketName",
|
||||
Code: InvalidBucketName,
|
||||
Message: err.Error(),
|
||||
}
|
||||
}
|
||||
if err := s3utils.CheckValidObjectName(objectName); err != nil {
|
||||
return nil, ErrorResponse{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Code: "XMinioInvalidObjectName",
|
||||
Code: XMinioInvalidObjectName,
|
||||
Message: err.Error(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
vendor/github.com/minio/minio-go/v7/api-put-bucket.go
generated
vendored
2
vendor/github.com/minio/minio-go/v7/api-put-bucket.go
generated
vendored
|
|
@ -35,7 +35,7 @@ func (c *Client) makeBucket(ctx context.Context, bucketName string, opts MakeBuc
|
|||
|
||||
err = c.doMakeBucket(ctx, bucketName, opts)
|
||||
if err != nil && (opts.Region == "" || opts.Region == "us-east-1") {
|
||||
if resp, ok := err.(ErrorResponse); ok && resp.Code == "AuthorizationHeaderMalformed" && resp.Region != "" {
|
||||
if resp, ok := err.(ErrorResponse); ok && resp.Code == AuthorizationHeaderMalformed && resp.Region != "" {
|
||||
opts.Region = resp.Region
|
||||
err = c.doMakeBucket(ctx, bucketName, opts)
|
||||
}
|
||||
|
|
|
|||
17
vendor/github.com/minio/minio-go/v7/api-put-object-multipart.go
generated
vendored
17
vendor/github.com/minio/minio-go/v7/api-put-object-multipart.go
generated
vendored
|
|
@ -44,7 +44,7 @@ func (c *Client) putObjectMultipart(ctx context.Context, bucketName, objectName
|
|||
errResp := ToErrorResponse(err)
|
||||
// Verify if multipart functionality is not available, if not
|
||||
// fall back to single PutObject operation.
|
||||
if errResp.Code == "AccessDenied" && strings.Contains(errResp.Message, "Access Denied") {
|
||||
if errResp.Code == AccessDenied && strings.Contains(errResp.Message, "Access Denied") {
|
||||
// Verify if size of reader is greater than '5GiB'.
|
||||
if size > maxSinglePutObjectSize {
|
||||
return UploadInfo{}, errEntityTooLarge(size, maxSinglePutObjectSize, bucketName, objectName)
|
||||
|
|
@ -392,13 +392,14 @@ func (c *Client) completeMultipartUpload(ctx context.Context, bucketName, object
|
|||
// Instantiate all the complete multipart buffer.
|
||||
completeMultipartUploadBuffer := bytes.NewReader(completeMultipartUploadBytes)
|
||||
reqMetadata := requestMetadata{
|
||||
bucketName: bucketName,
|
||||
objectName: objectName,
|
||||
queryValues: urlValues,
|
||||
contentBody: completeMultipartUploadBuffer,
|
||||
contentLength: int64(len(completeMultipartUploadBytes)),
|
||||
contentSHA256Hex: sum256Hex(completeMultipartUploadBytes),
|
||||
customHeader: headers,
|
||||
bucketName: bucketName,
|
||||
objectName: objectName,
|
||||
queryValues: urlValues,
|
||||
contentBody: completeMultipartUploadBuffer,
|
||||
contentLength: int64(len(completeMultipartUploadBytes)),
|
||||
contentSHA256Hex: sum256Hex(completeMultipartUploadBytes),
|
||||
customHeader: headers,
|
||||
expect200OKWithError: true,
|
||||
}
|
||||
|
||||
// Execute POST to complete multipart upload for an objectName.
|
||||
|
|
|
|||
2
vendor/github.com/minio/minio-go/v7/api-put-object-streaming.go
generated
vendored
2
vendor/github.com/minio/minio-go/v7/api-put-object-streaming.go
generated
vendored
|
|
@ -56,7 +56,7 @@ func (c *Client) putObjectMultipartStream(ctx context.Context, bucketName, objec
|
|||
errResp := ToErrorResponse(err)
|
||||
// Verify if multipart functionality is not available, if not
|
||||
// fall back to single PutObject operation.
|
||||
if errResp.Code == "AccessDenied" && strings.Contains(errResp.Message, "Access Denied") {
|
||||
if errResp.Code == AccessDenied && strings.Contains(errResp.Message, "Access Denied") {
|
||||
// Verify if size of reader is greater than '5GiB'.
|
||||
if size > maxSinglePutObjectSize {
|
||||
return UploadInfo{}, errEntityTooLarge(size, maxSinglePutObjectSize, bucketName, objectName)
|
||||
|
|
|
|||
187
vendor/github.com/minio/minio-go/v7/api-remove.go
generated
vendored
187
vendor/github.com/minio/minio-go/v7/api-remove.go
generated
vendored
|
|
@ -22,6 +22,7 @@ import (
|
|||
"context"
|
||||
"encoding/xml"
|
||||
"io"
|
||||
"iter"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
|
@ -271,7 +272,7 @@ func processRemoveMultiObjectsResponse(body io.Reader, resultCh chan<- RemoveObj
|
|||
for _, obj := range rmResult.UnDeletedObjects {
|
||||
// Version does not exist is not an error ignore and continue.
|
||||
switch obj.Code {
|
||||
case "InvalidArgument", "NoSuchVersion":
|
||||
case InvalidArgument, NoSuchVersion:
|
||||
continue
|
||||
}
|
||||
resultCh <- RemoveObjectResult{
|
||||
|
|
@ -333,6 +334,33 @@ func (c *Client) RemoveObjects(ctx context.Context, bucketName string, objectsCh
|
|||
return errorCh
|
||||
}
|
||||
|
||||
// RemoveObjectsWithIter bulk deletes multiple objects from a bucket.
|
||||
// Objects (with optional versions) to be removed must be provided with
|
||||
// an iterator. Objects are removed asynchronously and results must be
|
||||
// consumed. If the returned result iterator is stopped, the context is
|
||||
// canceled, or a remote call failed, the provided iterator will no
|
||||
// longer accept more objects.
|
||||
func (c *Client) RemoveObjectsWithIter(ctx context.Context, bucketName string, objectsIter iter.Seq[ObjectInfo], opts RemoveObjectsOptions) (iter.Seq[RemoveObjectResult], error) {
|
||||
// Validate if bucket name is valid.
|
||||
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Validate objects channel to be properly allocated.
|
||||
if objectsIter == nil {
|
||||
return nil, errInvalidArgument("Objects iter can never by nil")
|
||||
}
|
||||
|
||||
return func(yield func(RemoveObjectResult) bool) {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
c.removeObjectsIter(ctx, bucketName, objectsIter, yield, opts)
|
||||
}, nil
|
||||
}
|
||||
|
||||
// RemoveObjectsWithResult removes multiple objects from a bucket while
|
||||
// it is possible to specify objects versions which are received from
|
||||
// objectsCh. Remove results, successes and failures are sent back via
|
||||
|
|
@ -381,6 +409,144 @@ func hasInvalidXMLChar(str string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// Generate and call MultiDelete S3 requests based on entries received from the iterator.
|
||||
func (c *Client) removeObjectsIter(ctx context.Context, bucketName string, objectsIter iter.Seq[ObjectInfo], yield func(RemoveObjectResult) bool, opts RemoveObjectsOptions) {
|
||||
maxEntries := 1000
|
||||
urlValues := make(url.Values)
|
||||
urlValues.Set("delete", "")
|
||||
|
||||
// Build headers.
|
||||
headers := make(http.Header)
|
||||
if opts.GovernanceBypass {
|
||||
// Set the bypass goverenance retention header
|
||||
headers.Set(amzBypassGovernance, "true")
|
||||
}
|
||||
|
||||
processRemoveMultiObjectsResponseIter := func(batch []ObjectInfo, yield func(RemoveObjectResult) bool) bool {
|
||||
if len(batch) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// Generate remove multi objects XML request
|
||||
removeBytes := generateRemoveMultiObjectsRequest(batch)
|
||||
// Execute POST on bucket to remove objects.
|
||||
resp, err := c.executeMethod(ctx, http.MethodPost, requestMetadata{
|
||||
bucketName: bucketName,
|
||||
queryValues: urlValues,
|
||||
contentBody: bytes.NewReader(removeBytes),
|
||||
contentLength: int64(len(removeBytes)),
|
||||
contentMD5Base64: sumMD5Base64(removeBytes),
|
||||
contentSHA256Hex: sum256Hex(removeBytes),
|
||||
customHeader: headers,
|
||||
})
|
||||
if resp != nil {
|
||||
defer closeResponse(resp)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
err = httpRespToErrorResponse(resp, bucketName, "")
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
for _, b := range batch {
|
||||
if !yield(RemoveObjectResult{
|
||||
ObjectName: b.Key,
|
||||
ObjectVersionID: b.VersionID,
|
||||
Err: err,
|
||||
}) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Parse multi delete XML response
|
||||
rmResult := &deleteMultiObjectsResult{}
|
||||
if err := xmlDecoder(resp.Body, rmResult); err != nil {
|
||||
yield(RemoveObjectResult{ObjectName: "", Err: err})
|
||||
return false
|
||||
}
|
||||
|
||||
// Fill deletion that returned an error.
|
||||
for _, obj := range rmResult.UnDeletedObjects {
|
||||
// Version does not exist is not an error ignore and continue.
|
||||
switch obj.Code {
|
||||
case "InvalidArgument", "NoSuchVersion":
|
||||
continue
|
||||
}
|
||||
if !yield(RemoveObjectResult{
|
||||
ObjectName: obj.Key,
|
||||
ObjectVersionID: obj.VersionID,
|
||||
Err: ErrorResponse{
|
||||
Code: obj.Code,
|
||||
Message: obj.Message,
|
||||
},
|
||||
}) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Fill deletion that returned success
|
||||
for _, obj := range rmResult.DeletedObjects {
|
||||
if !yield(RemoveObjectResult{
|
||||
ObjectName: obj.Key,
|
||||
// Only filled with versioned buckets
|
||||
ObjectVersionID: obj.VersionID,
|
||||
DeleteMarker: obj.DeleteMarker,
|
||||
DeleteMarkerVersionID: obj.DeleteMarkerVersionID,
|
||||
}) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
var batch []ObjectInfo
|
||||
|
||||
next, stop := iter.Pull(objectsIter)
|
||||
defer stop()
|
||||
|
||||
for {
|
||||
// Loop over entries by 1000 and call MultiDelete requests
|
||||
object, ok := next()
|
||||
if !ok {
|
||||
// delete the remaining batch.
|
||||
processRemoveMultiObjectsResponseIter(batch, yield)
|
||||
return
|
||||
}
|
||||
|
||||
if hasInvalidXMLChar(object.Key) {
|
||||
// Use single DELETE so the object name will be in the request URL instead of the multi-delete XML document.
|
||||
removeResult := c.removeObject(ctx, bucketName, object.Key, RemoveObjectOptions{
|
||||
VersionID: object.VersionID,
|
||||
GovernanceBypass: opts.GovernanceBypass,
|
||||
})
|
||||
if err := removeResult.Err; err != nil {
|
||||
// Version does not exist is not an error ignore and continue.
|
||||
switch ToErrorResponse(err).Code {
|
||||
case "InvalidArgument", "NoSuchVersion":
|
||||
continue
|
||||
}
|
||||
}
|
||||
if !yield(removeResult) {
|
||||
return
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
batch = append(batch, object)
|
||||
if len(batch) < maxEntries {
|
||||
continue
|
||||
}
|
||||
|
||||
if !processRemoveMultiObjectsResponseIter(batch, yield) {
|
||||
return
|
||||
}
|
||||
|
||||
batch = batch[:0]
|
||||
}
|
||||
}
|
||||
|
||||
// Generate and call MultiDelete S3 requests based on entries received from objectsCh
|
||||
func (c *Client) removeObjects(ctx context.Context, bucketName string, objectsCh <-chan ObjectInfo, resultCh chan<- RemoveObjectResult, opts RemoveObjectsOptions) {
|
||||
maxEntries := 1000
|
||||
|
|
@ -407,7 +573,7 @@ func (c *Client) removeObjects(ctx context.Context, bucketName string, objectsCh
|
|||
if err := removeResult.Err; err != nil {
|
||||
// Version does not exist is not an error ignore and continue.
|
||||
switch ToErrorResponse(err).Code {
|
||||
case "InvalidArgument", "NoSuchVersion":
|
||||
case InvalidArgument, NoSuchVersion:
|
||||
continue
|
||||
}
|
||||
resultCh <- removeResult
|
||||
|
|
@ -442,13 +608,14 @@ func (c *Client) removeObjects(ctx context.Context, bucketName string, objectsCh
|
|||
removeBytes := generateRemoveMultiObjectsRequest(batch)
|
||||
// Execute POST on bucket to remove objects.
|
||||
resp, err := c.executeMethod(ctx, http.MethodPost, requestMetadata{
|
||||
bucketName: bucketName,
|
||||
queryValues: urlValues,
|
||||
contentBody: bytes.NewReader(removeBytes),
|
||||
contentLength: int64(len(removeBytes)),
|
||||
contentMD5Base64: sumMD5Base64(removeBytes),
|
||||
contentSHA256Hex: sum256Hex(removeBytes),
|
||||
customHeader: headers,
|
||||
bucketName: bucketName,
|
||||
queryValues: urlValues,
|
||||
contentBody: bytes.NewReader(removeBytes),
|
||||
contentLength: int64(len(removeBytes)),
|
||||
contentMD5Base64: sumMD5Base64(removeBytes),
|
||||
contentSHA256Hex: sum256Hex(removeBytes),
|
||||
customHeader: headers,
|
||||
expect200OKWithError: true,
|
||||
})
|
||||
if resp != nil {
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
|
|
@ -535,7 +702,7 @@ func (c *Client) abortMultipartUpload(ctx context.Context, bucketName, objectNam
|
|||
// This is needed specifically for abort and it cannot
|
||||
// be converged into default case.
|
||||
errorResponse = ErrorResponse{
|
||||
Code: "NoSuchUpload",
|
||||
Code: NoSuchUpload,
|
||||
Message: "The specified multipart upload does not exist.",
|
||||
BucketName: bucketName,
|
||||
Key: objectName,
|
||||
|
|
|
|||
8
vendor/github.com/minio/minio-go/v7/api-s3-datatypes.go
generated
vendored
8
vendor/github.com/minio/minio-go/v7/api-s3-datatypes.go
generated
vendored
|
|
@ -107,6 +107,14 @@ type Version struct {
|
|||
M int // Parity blocks
|
||||
} `xml:"Internal"`
|
||||
|
||||
// Checksum values. Only returned by AiStor servers.
|
||||
ChecksumCRC32 string `xml:",omitempty"`
|
||||
ChecksumCRC32C string `xml:",omitempty"`
|
||||
ChecksumSHA1 string `xml:",omitempty"`
|
||||
ChecksumSHA256 string `xml:",omitempty"`
|
||||
ChecksumCRC64NVME string `xml:",omitempty"`
|
||||
ChecksumType string `xml:",omitempty"`
|
||||
|
||||
isDeleteMarker bool
|
||||
}
|
||||
|
||||
|
|
|
|||
12
vendor/github.com/minio/minio-go/v7/api-stat.go
generated
vendored
12
vendor/github.com/minio/minio-go/v7/api-stat.go
generated
vendored
|
|
@ -39,14 +39,14 @@ func (c *Client) BucketExists(ctx context.Context, bucketName string) (bool, err
|
|||
})
|
||||
defer closeResponse(resp)
|
||||
if err != nil {
|
||||
if ToErrorResponse(err).Code == "NoSuchBucket" {
|
||||
if ToErrorResponse(err).Code == NoSuchBucket {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
if resp != nil {
|
||||
resperr := httpRespToErrorResponse(resp, bucketName, "")
|
||||
if ToErrorResponse(resperr).Code == "NoSuchBucket" {
|
||||
if ToErrorResponse(resperr).Code == NoSuchBucket {
|
||||
return false, nil
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
|
|
@ -63,14 +63,14 @@ func (c *Client) StatObject(ctx context.Context, bucketName, objectName string,
|
|||
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
|
||||
return ObjectInfo{}, ErrorResponse{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Code: "InvalidBucketName",
|
||||
Code: InvalidBucketName,
|
||||
Message: err.Error(),
|
||||
}
|
||||
}
|
||||
if err := s3utils.CheckValidObjectName(objectName); err != nil {
|
||||
return ObjectInfo{}, ErrorResponse{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Code: "XMinioInvalidObjectName",
|
||||
Code: XMinioInvalidObjectName,
|
||||
Message: err.Error(),
|
||||
}
|
||||
}
|
||||
|
|
@ -102,8 +102,8 @@ func (c *Client) StatObject(ctx context.Context, bucketName, objectName string,
|
|||
if resp.StatusCode == http.StatusMethodNotAllowed && opts.VersionID != "" && deleteMarker {
|
||||
errResp := ErrorResponse{
|
||||
StatusCode: resp.StatusCode,
|
||||
Code: "MethodNotAllowed",
|
||||
Message: "The specified method is not allowed against this resource.",
|
||||
Code: MethodNotAllowed,
|
||||
Message: s3ErrorResponseMap[MethodNotAllowed],
|
||||
BucketName: bucketName,
|
||||
Key: objectName,
|
||||
}
|
||||
|
|
|
|||
65
vendor/github.com/minio/minio-go/v7/api.go
generated
vendored
65
vendor/github.com/minio/minio-go/v7/api.go
generated
vendored
|
|
@ -21,6 +21,7 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
|
@ -38,6 +39,7 @@ import (
|
|||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
md5simd "github.com/minio/md5-simd"
|
||||
"github.com/minio/minio-go/v7/pkg/credentials"
|
||||
"github.com/minio/minio-go/v7/pkg/kvcache"
|
||||
|
|
@ -45,6 +47,8 @@ import (
|
|||
"github.com/minio/minio-go/v7/pkg/signer"
|
||||
"github.com/minio/minio-go/v7/pkg/singleflight"
|
||||
"golang.org/x/net/publicsuffix"
|
||||
|
||||
internalutils "github.com/minio/minio-go/v7/pkg/utils"
|
||||
)
|
||||
|
||||
// Client implements Amazon S3 compatible methods.
|
||||
|
|
@ -159,7 +163,7 @@ type Options struct {
|
|||
// Global constants.
|
||||
const (
|
||||
libraryName = "minio-go"
|
||||
libraryVersion = "v7.0.92"
|
||||
libraryVersion = "v7.0.94"
|
||||
)
|
||||
|
||||
// User Agent should always following the below style.
|
||||
|
|
@ -455,7 +459,7 @@ func (c *Client) HealthCheck(hcDuration time.Duration) (context.CancelFunc, erro
|
|||
gcancel()
|
||||
if !IsNetworkOrHostDown(err, false) {
|
||||
switch ToErrorResponse(err).Code {
|
||||
case "NoSuchBucket", "AccessDenied", "":
|
||||
case NoSuchBucket, AccessDenied, "":
|
||||
atomic.CompareAndSwapInt32(&c.healthStatus, offline, online)
|
||||
}
|
||||
}
|
||||
|
|
@ -477,7 +481,7 @@ func (c *Client) HealthCheck(hcDuration time.Duration) (context.CancelFunc, erro
|
|||
gcancel()
|
||||
if !IsNetworkOrHostDown(err, false) {
|
||||
switch ToErrorResponse(err).Code {
|
||||
case "NoSuchBucket", "AccessDenied", "":
|
||||
case NoSuchBucket, AccessDenied, "":
|
||||
atomic.CompareAndSwapInt32(&c.healthStatus, offline, online)
|
||||
}
|
||||
}
|
||||
|
|
@ -512,6 +516,8 @@ type requestMetadata struct {
|
|||
streamSha256 bool
|
||||
addCrc *ChecksumType
|
||||
trailer http.Header // (http.Request).Trailer. Requires v4 signature.
|
||||
|
||||
expect200OKWithError bool
|
||||
}
|
||||
|
||||
// dumpHTTP - dump HTTP request and response.
|
||||
|
|
@ -615,6 +621,28 @@ func (c *Client) do(req *http.Request) (resp *http.Response, err error) {
|
|||
return resp, nil
|
||||
}
|
||||
|
||||
// Peek resp.Body looking for S3 XMl error response:
|
||||
// - Return the error XML bytes if an error is found
|
||||
// - Make sure to always restablish the whole http response stream before returning
|
||||
func tryParseErrRespFromBody(resp *http.Response) ([]byte, error) {
|
||||
peeker := internalutils.NewPeekReadCloser(resp.Body, 5*humanize.MiByte)
|
||||
defer func() {
|
||||
peeker.ReplayFromStart()
|
||||
resp.Body = peeker
|
||||
}()
|
||||
|
||||
errResp := ErrorResponse{}
|
||||
errBytes, err := xmlDecodeAndBody(peeker, &errResp)
|
||||
if err != nil {
|
||||
var unmarshalErr xml.UnmarshalError
|
||||
if errors.As(err, &unmarshalErr) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return errBytes, nil
|
||||
}
|
||||
|
||||
// List of success status.
|
||||
var successStatus = []int{
|
||||
http.StatusOK,
|
||||
|
|
@ -702,16 +730,30 @@ func (c *Client) executeMethod(ctx context.Context, method string, metadata requ
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// For any known successful http status, return quickly.
|
||||
var success bool
|
||||
var errBodyBytes []byte
|
||||
|
||||
for _, httpStatus := range successStatus {
|
||||
if httpStatus == res.StatusCode {
|
||||
return res, nil
|
||||
success = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Read the body to be saved later.
|
||||
errBodyBytes, err := io.ReadAll(res.Body)
|
||||
// res.Body should be closed
|
||||
if success {
|
||||
if !metadata.expect200OKWithError {
|
||||
return res, nil
|
||||
}
|
||||
errBodyBytes, err = tryParseErrRespFromBody(res)
|
||||
if err == nil && len(errBodyBytes) == 0 {
|
||||
// No S3 XML error is found
|
||||
return res, nil
|
||||
}
|
||||
} else {
|
||||
errBodyBytes, err = io.ReadAll(res.Body)
|
||||
}
|
||||
|
||||
// By now, res.Body should be closed
|
||||
closeResponse(res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -723,6 +765,7 @@ func (c *Client) executeMethod(ctx context.Context, method string, metadata requ
|
|||
|
||||
// For errors verify if its retryable otherwise fail quickly.
|
||||
errResponse := ToErrorResponse(httpRespToErrorResponse(res, metadata.bucketName, metadata.objectName))
|
||||
err = errResponse
|
||||
|
||||
// Save the body back again.
|
||||
errBodySeeker.Seek(0, 0) // Seek back to starting point.
|
||||
|
|
@ -736,11 +779,11 @@ func (c *Client) executeMethod(ctx context.Context, method string, metadata requ
|
|||
// region is empty.
|
||||
if c.region == "" {
|
||||
switch errResponse.Code {
|
||||
case "AuthorizationHeaderMalformed":
|
||||
case AuthorizationHeaderMalformed:
|
||||
fallthrough
|
||||
case "InvalidRegion":
|
||||
case InvalidRegion:
|
||||
fallthrough
|
||||
case "AccessDenied":
|
||||
case AccessDenied:
|
||||
if errResponse.Region == "" {
|
||||
// Region is empty we simply return the error.
|
||||
return res, err
|
||||
|
|
|
|||
8
vendor/github.com/minio/minio-go/v7/bucket-cache.go
generated
vendored
8
vendor/github.com/minio/minio-go/v7/bucket-cache.go
generated
vendored
|
|
@ -84,18 +84,18 @@ 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":
|
||||
case NotImplemented:
|
||||
switch errResp.Server {
|
||||
case "AmazonSnowball":
|
||||
return "snowball", nil
|
||||
case "cloudflare":
|
||||
return "us-east-1", nil
|
||||
}
|
||||
case "AuthorizationHeaderMalformed":
|
||||
case AuthorizationHeaderMalformed:
|
||||
fallthrough
|
||||
case "InvalidRegion":
|
||||
case InvalidRegion:
|
||||
fallthrough
|
||||
case "AccessDenied":
|
||||
case AccessDenied:
|
||||
if errResp.Region == "" {
|
||||
return "us-east-1", nil
|
||||
}
|
||||
|
|
|
|||
308
vendor/github.com/minio/minio-go/v7/functional_tests.go
generated
vendored
308
vendor/github.com/minio/minio-go/v7/functional_tests.go
generated
vendored
|
|
@ -31,6 +31,7 @@ import (
|
|||
"hash"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
"iter"
|
||||
"log/slog"
|
||||
"math/rand"
|
||||
"mime/multipart"
|
||||
|
|
@ -259,7 +260,7 @@ func cleanupVersionedBucket(bucketName string, c *minio.Client) error {
|
|||
}
|
||||
|
||||
func isErrNotImplemented(err error) bool {
|
||||
return minio.ToErrorResponse(err).Code == "NotImplemented"
|
||||
return minio.ToErrorResponse(err).Code == minio.NotImplemented
|
||||
}
|
||||
|
||||
func isRunOnFail() bool {
|
||||
|
|
@ -465,8 +466,8 @@ func testMakeBucketError() {
|
|||
return
|
||||
}
|
||||
// Verify valid error response from server.
|
||||
if minio.ToErrorResponse(err).Code != "BucketAlreadyExists" &&
|
||||
minio.ToErrorResponse(err).Code != "BucketAlreadyOwnedByYou" {
|
||||
if minio.ToErrorResponse(err).Code != minio.BucketAlreadyExists &&
|
||||
minio.ToErrorResponse(err).Code != minio.BucketAlreadyOwnedByYou {
|
||||
logError(testName, function, args, startTime, "", "Invalid error returned by server", err)
|
||||
return
|
||||
}
|
||||
|
|
@ -1073,7 +1074,7 @@ func testPutObjectWithVersioning() {
|
|||
var results []minio.ObjectInfo
|
||||
for info := range objectsInfo {
|
||||
if info.Err != nil {
|
||||
logError(testName, function, args, startTime, "", "Unexpected error during listing objects", err)
|
||||
logError(testName, function, args, startTime, "", "Unexpected error during listing objects", info.Err)
|
||||
return
|
||||
}
|
||||
results = append(results, info)
|
||||
|
|
@ -3204,7 +3205,7 @@ func testGetObjectAttributesErrorCases() {
|
|||
}
|
||||
|
||||
errorResponse := err.(minio.ErrorResponse)
|
||||
if errorResponse.Code != "NoSuchBucket" {
|
||||
if errorResponse.Code != minio.NoSuchBucket {
|
||||
logError(testName, function, args, startTime, "", "Invalid error code, expected NoSuchBucket but got "+errorResponse.Code, nil)
|
||||
return
|
||||
}
|
||||
|
|
@ -3247,8 +3248,8 @@ func testGetObjectAttributesErrorCases() {
|
|||
}
|
||||
|
||||
errorResponse = err.(minio.ErrorResponse)
|
||||
if errorResponse.Code != "NoSuchKey" {
|
||||
logError(testName, function, args, startTime, "", "Invalid error code, expected NoSuchKey but got "+errorResponse.Code, nil)
|
||||
if errorResponse.Code != minio.NoSuchKey {
|
||||
logError(testName, function, args, startTime, "", "Invalid error code, expected "+minio.NoSuchKey+" but got "+errorResponse.Code, nil)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -3272,8 +3273,8 @@ func testGetObjectAttributesErrorCases() {
|
|||
return
|
||||
}
|
||||
errorResponse = err.(minio.ErrorResponse)
|
||||
if errorResponse.Code != "NoSuchVersion" {
|
||||
logError(testName, function, args, startTime, "", "Invalid error code, expected NoSuchVersion but got "+errorResponse.Code, nil)
|
||||
if errorResponse.Code != minio.NoSuchVersion {
|
||||
logError(testName, function, args, startTime, "", "Invalid error code, expected "+minio.NoSuchVersion+" but got "+errorResponse.Code, nil)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -3928,10 +3929,10 @@ func testRemoveMultipleObjects() {
|
|||
|
||||
defer cleanupBucket(bucketName, c)
|
||||
|
||||
r := bytes.NewReader(bytes.Repeat([]byte("a"), 8))
|
||||
r := bytes.NewReader(bytes.Repeat([]byte("a"), 1))
|
||||
|
||||
// Multi remove of 1100 objects
|
||||
nrObjects := 200
|
||||
nrObjects := 1100
|
||||
|
||||
objectsCh := make(chan minio.ObjectInfo)
|
||||
|
||||
|
|
@ -3940,7 +3941,7 @@ func testRemoveMultipleObjects() {
|
|||
// Upload objects and send them to objectsCh
|
||||
for i := 0; i < nrObjects; i++ {
|
||||
objectName := "sample" + strconv.Itoa(i) + ".txt"
|
||||
info, err := c.PutObject(context.Background(), bucketName, objectName, r, 8,
|
||||
info, err := c.PutObject(context.Background(), bucketName, objectName, r, 1,
|
||||
minio.PutObjectOptions{ContentType: "application/octet-stream"})
|
||||
if err != nil {
|
||||
logError(testName, function, args, startTime, "", "PutObject failed", err)
|
||||
|
|
@ -3968,6 +3969,78 @@ func testRemoveMultipleObjects() {
|
|||
logSuccess(testName, function, args, startTime)
|
||||
}
|
||||
|
||||
// Test removing multiple objects with Remove API as iterator
|
||||
func testRemoveMultipleObjectsIter() {
|
||||
// initialize logging params
|
||||
startTime := time.Now()
|
||||
testName := getFuncName()
|
||||
function := "RemoveObjects(bucketName, objectsCh)"
|
||||
args := map[string]interface{}{
|
||||
"bucketName": "",
|
||||
}
|
||||
|
||||
c, err := NewClient(ClientConfig{})
|
||||
if err != nil {
|
||||
logError(testName, function, args, startTime, "", "MinIO client object creation failed", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Generate a new random bucket name.
|
||||
bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
|
||||
args["bucketName"] = bucketName
|
||||
|
||||
// Make a new bucket.
|
||||
err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
|
||||
if err != nil {
|
||||
logError(testName, function, args, startTime, "", "MakeBucket failed", err)
|
||||
return
|
||||
}
|
||||
|
||||
defer cleanupBucket(bucketName, c)
|
||||
|
||||
buf := []byte("a")
|
||||
|
||||
// Multi remove of 1100 objects
|
||||
nrObjects := 1100
|
||||
|
||||
objectsIter := func() iter.Seq[minio.ObjectInfo] {
|
||||
return func(yield func(minio.ObjectInfo) bool) {
|
||||
// Upload objects and send them to objectsCh
|
||||
for i := 0; i < nrObjects; i++ {
|
||||
objectName := "sample" + strconv.Itoa(i) + ".txt"
|
||||
info, err := c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), 1,
|
||||
minio.PutObjectOptions{ContentType: "application/octet-stream"})
|
||||
if err != nil {
|
||||
logError(testName, function, args, startTime, "", "PutObject failed", err)
|
||||
continue
|
||||
}
|
||||
if !yield(minio.ObjectInfo{
|
||||
Key: info.Key,
|
||||
VersionID: info.VersionID,
|
||||
}) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Call RemoveObjects API
|
||||
results, err := c.RemoveObjectsWithIter(context.Background(), bucketName, objectsIter(), minio.RemoveObjectsOptions{})
|
||||
if err != nil {
|
||||
logError(testName, function, args, startTime, "", "Unexpected error", err)
|
||||
return
|
||||
}
|
||||
|
||||
for result := range results {
|
||||
if result.Err != nil {
|
||||
logError(testName, function, args, startTime, "", "Unexpected error", result.Err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
logSuccess(testName, function, args, startTime)
|
||||
}
|
||||
|
||||
// Test removing multiple objects and check for results
|
||||
func testRemoveMultipleObjectsWithResult() {
|
||||
// initialize logging params
|
||||
|
|
@ -3997,7 +4070,7 @@ func testRemoveMultipleObjectsWithResult() {
|
|||
|
||||
defer cleanupVersionedBucket(bucketName, c)
|
||||
|
||||
r := bytes.NewReader(bytes.Repeat([]byte("a"), 8))
|
||||
buf := []byte("a")
|
||||
|
||||
nrObjects := 10
|
||||
nrLockedObjects := 5
|
||||
|
|
@ -4009,7 +4082,7 @@ func testRemoveMultipleObjectsWithResult() {
|
|||
// Upload objects and send them to objectsCh
|
||||
for i := 0; i < nrObjects; i++ {
|
||||
objectName := "sample" + strconv.Itoa(i) + ".txt"
|
||||
info, err := c.PutObject(context.Background(), bucketName, objectName, r, 8,
|
||||
info, err := c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader(buf), 1,
|
||||
minio.PutObjectOptions{ContentType: "application/octet-stream"})
|
||||
if err != nil {
|
||||
logError(testName, function, args, startTime, "", "PutObject failed", err)
|
||||
|
|
@ -7589,7 +7662,7 @@ func testGetObjectModified() {
|
|||
|
||||
// Confirm that a Stat() call in between doesn't change the Object's cached etag.
|
||||
_, err = reader.Stat()
|
||||
expectedError := "At least one of the pre-conditions you specified did not hold"
|
||||
expectedError := "At least one of the pre-conditions you specified did not hold."
|
||||
if err.Error() != expectedError {
|
||||
logError(testName, function, args, startTime, "", "Expected Stat to fail with error "+expectedError+", but received "+err.Error(), err)
|
||||
return
|
||||
|
|
@ -7751,8 +7824,8 @@ func testMakeBucketErrorV2() {
|
|||
return
|
||||
}
|
||||
// Verify valid error response from server.
|
||||
if minio.ToErrorResponse(err).Code != "BucketAlreadyExists" &&
|
||||
minio.ToErrorResponse(err).Code != "BucketAlreadyOwnedByYou" {
|
||||
if minio.ToErrorResponse(err).Code != minio.BucketAlreadyExists &&
|
||||
minio.ToErrorResponse(err).Code != minio.BucketAlreadyOwnedByYou {
|
||||
logError(testName, function, args, startTime, "", "Invalid error returned by server", err)
|
||||
return
|
||||
}
|
||||
|
|
@ -11415,6 +11488,87 @@ func testPutObject0ByteV2() {
|
|||
logSuccess(testName, function, args, startTime)
|
||||
}
|
||||
|
||||
// Test put object with 0 byte object with non-US-ASCII characters.
|
||||
func testPutObjectMetadataNonUSASCIIV2() {
|
||||
// initialize logging params
|
||||
startTime := time.Now()
|
||||
testName := getFuncName()
|
||||
function := "PutObject(bucketName, objectName, reader, size, opts)"
|
||||
args := map[string]interface{}{
|
||||
"bucketName": "",
|
||||
"objectName": "",
|
||||
"size": 0,
|
||||
"opts": "",
|
||||
}
|
||||
metadata := map[string]string{
|
||||
"test-zh": "你好",
|
||||
"test-ja": "こんにちは",
|
||||
"test-ko": "안녕하세요",
|
||||
"test-ru": "Здравствуй",
|
||||
"test-de": "Hallo",
|
||||
"test-it": "Ciao",
|
||||
"test-pt": "Olá",
|
||||
"test-ar": "مرحبا",
|
||||
"test-hi": "नमस्ते",
|
||||
"test-hu": "Helló",
|
||||
"test-ro": "Bună",
|
||||
"test-be": "Прывiтанне",
|
||||
"test-sl": "Pozdravljen",
|
||||
"test-sr": "Здраво",
|
||||
"test-bg": "Здравейте",
|
||||
"test-uk": "Привіт",
|
||||
}
|
||||
c, err := NewClient(ClientConfig{CredsV2: true})
|
||||
if err != nil {
|
||||
logError(testName, function, args, startTime, "", "MinIO v2 client object creation failed", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Generate a new random bucket name.
|
||||
bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
|
||||
args["bucketName"] = bucketName
|
||||
|
||||
// Make a new bucket.
|
||||
err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1"})
|
||||
if err != nil {
|
||||
logError(testName, function, args, startTime, "", "MakeBucket failed", err)
|
||||
return
|
||||
}
|
||||
|
||||
defer cleanupBucket(bucketName, c)
|
||||
|
||||
objectName := bucketName + "unique"
|
||||
args["objectName"] = objectName
|
||||
args["opts"] = minio.PutObjectOptions{}
|
||||
|
||||
// Upload an object.
|
||||
_, err = c.PutObject(context.Background(), bucketName, objectName, bytes.NewReader([]byte("")), 0, minio.PutObjectOptions{
|
||||
UserMetadata: metadata,
|
||||
})
|
||||
if err != nil {
|
||||
logError(testName, function, args, startTime, "", "PutObjectWithSize failed", err)
|
||||
return
|
||||
}
|
||||
st, err := c.StatObject(context.Background(), bucketName, objectName, minio.StatObjectOptions{})
|
||||
if err != nil {
|
||||
logError(testName, function, args, startTime, "", "StatObjectWithSize failed", err)
|
||||
return
|
||||
}
|
||||
if st.Size != 0 {
|
||||
logError(testName, function, args, startTime, "", "Expected upload object size 0 but got "+string(st.Size), err)
|
||||
return
|
||||
}
|
||||
|
||||
for k, v := range metadata {
|
||||
if st.Metadata.Get(http.CanonicalHeaderKey("X-Amz-Meta-"+k)) != v {
|
||||
logError(testName, function, args, startTime, "", "Expected upload object metadata "+k+": "+v+" but got "+st.Metadata.Get("X-Amz-Meta-"+k), err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
logSuccess(testName, function, args, startTime)
|
||||
}
|
||||
|
||||
// Test expected error cases
|
||||
func testComposeObjectErrorCases() {
|
||||
// initialize logging params
|
||||
|
|
@ -13557,6 +13711,115 @@ func testRemoveObjects() {
|
|||
logSuccess(testName, function, args, startTime)
|
||||
}
|
||||
|
||||
// Test deleting multiple objects with object retention set in Governance mode, via iterators
|
||||
func testRemoveObjectsIter() {
|
||||
// initialize logging params
|
||||
startTime := time.Now()
|
||||
testName := getFuncName()
|
||||
function := "RemoveObjects(bucketName, objectsCh, opts)"
|
||||
args := map[string]interface{}{
|
||||
"bucketName": "",
|
||||
"objectPrefix": "",
|
||||
"recursive": "true",
|
||||
}
|
||||
|
||||
c, err := NewClient(ClientConfig{})
|
||||
if err != nil {
|
||||
logError(testName, function, args, startTime, "", "MinIO client v4 object creation failed", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Generate a new random bucket name.
|
||||
bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
|
||||
args["bucketName"] = bucketName
|
||||
objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
|
||||
args["objectName"] = objectName
|
||||
|
||||
// Make a new bucket.
|
||||
err = c.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1", ObjectLocking: true})
|
||||
if err != nil {
|
||||
logError(testName, function, args, startTime, "", "MakeBucket failed", err)
|
||||
return
|
||||
}
|
||||
|
||||
bufSize := dataFileMap["datafile-129-MB"]
|
||||
reader := getDataReader("datafile-129-MB")
|
||||
defer reader.Close()
|
||||
|
||||
_, err = c.PutObject(context.Background(), bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{})
|
||||
if err != nil {
|
||||
logError(testName, function, args, startTime, "", "Error uploading object", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Replace with smaller...
|
||||
bufSize = dataFileMap["datafile-10-kB"]
|
||||
reader = getDataReader("datafile-10-kB")
|
||||
defer reader.Close()
|
||||
|
||||
_, err = c.PutObject(context.Background(), bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{})
|
||||
if err != nil {
|
||||
logError(testName, function, args, startTime, "", "Error uploading object", err)
|
||||
}
|
||||
|
||||
t := time.Date(2030, time.April, 25, 14, 0, 0, 0, time.UTC)
|
||||
m := minio.RetentionMode(minio.Governance)
|
||||
opts := minio.PutObjectRetentionOptions{
|
||||
GovernanceBypass: false,
|
||||
RetainUntilDate: &t,
|
||||
Mode: &m,
|
||||
}
|
||||
err = c.PutObjectRetention(context.Background(), bucketName, objectName, opts)
|
||||
if err != nil {
|
||||
logError(testName, function, args, startTime, "", "Error setting retention", err)
|
||||
return
|
||||
}
|
||||
|
||||
objectsIter := c.ListObjectsIter(context.Background(), bucketName, minio.ListObjectsOptions{
|
||||
WithVersions: true,
|
||||
Recursive: true,
|
||||
})
|
||||
results, err := c.RemoveObjectsWithIter(context.Background(), bucketName, objectsIter, minio.RemoveObjectsOptions{})
|
||||
if err != nil {
|
||||
logError(testName, function, args, startTime, "", "Error sending delete request", err)
|
||||
return
|
||||
}
|
||||
for result := range results {
|
||||
if result.Err != nil {
|
||||
// Error is expected here because Retention is set on the object
|
||||
// and RemoveObjects is called without Bypass Governance
|
||||
break
|
||||
}
|
||||
logError(testName, function, args, startTime, "", "Expected error during deletion", nil)
|
||||
return
|
||||
}
|
||||
|
||||
objectsIter = c.ListObjectsIter(context.Background(), bucketName, minio.ListObjectsOptions{UseV1: true, Recursive: true})
|
||||
results, err = c.RemoveObjectsWithIter(context.Background(), bucketName, objectsIter, minio.RemoveObjectsOptions{
|
||||
GovernanceBypass: true,
|
||||
})
|
||||
if err != nil {
|
||||
logError(testName, function, args, startTime, "", "Error sending delete request", err)
|
||||
return
|
||||
}
|
||||
for result := range results {
|
||||
if result.Err != nil {
|
||||
// Error is not expected here because Retention is set on the object
|
||||
// and RemoveObjects is called with Bypass Governance
|
||||
logError(testName, function, args, startTime, "", "Error detected during deletion", result.Err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Delete all objects and buckets
|
||||
if err = cleanupVersionedBucket(bucketName, c); err != nil {
|
||||
logError(testName, function, args, startTime, "", "CleanupBucket failed", err)
|
||||
return
|
||||
}
|
||||
|
||||
logSuccess(testName, function, args, startTime)
|
||||
}
|
||||
|
||||
// Test get bucket tags
|
||||
func testGetBucketTagging() {
|
||||
// initialize logging params
|
||||
|
|
@ -13585,7 +13848,7 @@ func testGetBucketTagging() {
|
|||
}
|
||||
|
||||
_, err = c.GetBucketTagging(context.Background(), bucketName)
|
||||
if minio.ToErrorResponse(err).Code != "NoSuchTagSet" {
|
||||
if minio.ToErrorResponse(err).Code != minio.NoSuchTagSet {
|
||||
logError(testName, function, args, startTime, "", "Invalid error from server failed", err)
|
||||
return
|
||||
}
|
||||
|
|
@ -13627,7 +13890,7 @@ func testSetBucketTagging() {
|
|||
}
|
||||
|
||||
_, err = c.GetBucketTagging(context.Background(), bucketName)
|
||||
if minio.ToErrorResponse(err).Code != "NoSuchTagSet" {
|
||||
if minio.ToErrorResponse(err).Code != minio.NoSuchTagSet {
|
||||
logError(testName, function, args, startTime, "", "Invalid error from server", err)
|
||||
return
|
||||
}
|
||||
|
|
@ -13699,7 +13962,7 @@ func testRemoveBucketTagging() {
|
|||
}
|
||||
|
||||
_, err = c.GetBucketTagging(context.Background(), bucketName)
|
||||
if minio.ToErrorResponse(err).Code != "NoSuchTagSet" {
|
||||
if minio.ToErrorResponse(err).Code != minio.NoSuchTagSet {
|
||||
logError(testName, function, args, startTime, "", "Invalid error from server", err)
|
||||
return
|
||||
}
|
||||
|
|
@ -13740,7 +14003,7 @@ func testRemoveBucketTagging() {
|
|||
}
|
||||
|
||||
_, err = c.GetBucketTagging(context.Background(), bucketName)
|
||||
if minio.ToErrorResponse(err).Code != "NoSuchTagSet" {
|
||||
if minio.ToErrorResponse(err).Code != minio.NoSuchTagSet {
|
||||
logError(testName, function, args, startTime, "", "Invalid error from server", err)
|
||||
return
|
||||
}
|
||||
|
|
@ -13809,6 +14072,7 @@ func main() {
|
|||
testPutMultipartObjectWithChecksums(false)
|
||||
testPutMultipartObjectWithChecksums(true)
|
||||
testPutObject0ByteV2()
|
||||
testPutObjectMetadataNonUSASCIIV2()
|
||||
testPutObjectNoLengthV2()
|
||||
testPutObjectsUnknownV2()
|
||||
testGetObjectContextV2()
|
||||
|
|
@ -13826,6 +14090,7 @@ func main() {
|
|||
testGetObjectS3Zip()
|
||||
testRemoveMultipleObjects()
|
||||
testRemoveMultipleObjectsWithResult()
|
||||
testRemoveMultipleObjectsIter()
|
||||
testFPutObjectMultipart()
|
||||
testFPutObject()
|
||||
testGetObjectReadSeekFunctional()
|
||||
|
|
@ -13852,6 +14117,7 @@ func main() {
|
|||
testPutObjectWithContentLanguage()
|
||||
testListObjects()
|
||||
testRemoveObjects()
|
||||
testRemoveObjectsIter()
|
||||
testListObjectVersions()
|
||||
testStatObjectWithVersioning()
|
||||
testGetObjectWithVersioning()
|
||||
|
|
|
|||
45
vendor/github.com/minio/minio-go/v7/pkg/replication/replication.go
generated
vendored
45
vendor/github.com/minio/minio-go/v7/pkg/replication/replication.go
generated
vendored
|
|
@ -730,6 +730,8 @@ type Metrics struct {
|
|||
Errors TimedErrStats `json:"failed,omitempty"`
|
||||
// Total number of entries that are queued for replication
|
||||
QStats InQueueMetric `json:"queued"`
|
||||
// Total number of entries that have replication in progress
|
||||
InProgress InProgressMetric `json:"inProgress"`
|
||||
// Deprecated fields
|
||||
// Total Pending size in bytes across targets
|
||||
PendingSize uint64 `json:"pendingReplicationSize,omitempty"`
|
||||
|
|
@ -830,6 +832,9 @@ type InQueueMetric struct {
|
|||
Max QStat `json:"peak" msg:"pq"`
|
||||
}
|
||||
|
||||
// InProgressMetric holds stats for objects with replication in progress
|
||||
type InProgressMetric InQueueMetric
|
||||
|
||||
// MetricName name of replication metric
|
||||
type MetricName string
|
||||
|
||||
|
|
@ -849,6 +854,14 @@ type WorkerStat struct {
|
|||
Max int32 `json:"max"`
|
||||
}
|
||||
|
||||
// TgtHealth holds health status of a target
|
||||
type TgtHealth struct {
|
||||
Online bool `json:"online"`
|
||||
LastOnline time.Time `json:"lastOnline"`
|
||||
TotalDowntime time.Duration `json:"totalDowntime"`
|
||||
OfflineCount int64 `json:"offlineCount"`
|
||||
}
|
||||
|
||||
// ReplMRFStats holds stats of MRF backlog saved to disk in the last 5 minutes
|
||||
// and number of entries that failed replication after 3 retries
|
||||
type ReplMRFStats struct {
|
||||
|
|
@ -863,15 +876,18 @@ type ReplMRFStats struct {
|
|||
type ReplQNodeStats struct {
|
||||
NodeName string `json:"nodeName"`
|
||||
Uptime int64 `json:"uptime"`
|
||||
Workers WorkerStat `json:"activeWorkers"`
|
||||
Workers WorkerStat `json:"workers"`
|
||||
|
||||
XferStats map[MetricName]XferStats `json:"transferSummary"`
|
||||
TgtXferStats map[string]map[MetricName]XferStats `json:"tgtTransferStats"`
|
||||
|
||||
QStats InQueueMetric `json:"queueStats"`
|
||||
MRFStats ReplMRFStats `json:"mrfStats"`
|
||||
Retries CounterSummary `json:"retries"`
|
||||
Errors CounterSummary `json:"errors"`
|
||||
QStats InQueueMetric `json:"queueStats"`
|
||||
InProgressStats InProgressMetric `json:"progressStats"`
|
||||
|
||||
MRFStats ReplMRFStats `json:"mrfStats"`
|
||||
Retries CounterSummary `json:"retries"`
|
||||
Errors CounterSummary `json:"errors"`
|
||||
TgtHealth map[string]TgtHealth `json:"tgtHealth,omitempty"`
|
||||
}
|
||||
|
||||
// CounterSummary denotes the stats counter summary
|
||||
|
|
@ -918,6 +934,19 @@ func (q ReplQueueStats) qStatSummary() InQueueMetric {
|
|||
return m
|
||||
}
|
||||
|
||||
// inProgressSummary returns cluster level stats for objects with replication in progress
|
||||
func (q ReplQueueStats) inProgressSummary() InProgressMetric {
|
||||
m := InProgressMetric{}
|
||||
for _, v := range q.Nodes {
|
||||
m.Avg.Add(v.InProgressStats.Avg)
|
||||
m.Curr.Add(v.InProgressStats.Curr)
|
||||
if m.Max.Count < v.InProgressStats.Max.Count {
|
||||
m.Max.Add(v.InProgressStats.Max)
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// ReplQStats holds stats for objects in replication queue
|
||||
type ReplQStats struct {
|
||||
Uptime int64 `json:"uptime"`
|
||||
|
|
@ -926,7 +955,9 @@ type ReplQStats struct {
|
|||
XferStats map[MetricName]XferStats `json:"xferStats"`
|
||||
TgtXferStats map[string]map[MetricName]XferStats `json:"tgtXferStats"`
|
||||
|
||||
QStats InQueueMetric `json:"qStats"`
|
||||
QStats InQueueMetric `json:"qStats"`
|
||||
InProgressStats InProgressMetric `json:"progressStats"`
|
||||
|
||||
MRFStats ReplMRFStats `json:"mrfStats"`
|
||||
Retries CounterSummary `json:"retries"`
|
||||
Errors CounterSummary `json:"errors"`
|
||||
|
|
@ -935,10 +966,10 @@ type ReplQStats struct {
|
|||
// QStats returns cluster level stats for objects in replication queue
|
||||
func (q ReplQueueStats) QStats() (r ReplQStats) {
|
||||
r.QStats = q.qStatSummary()
|
||||
r.InProgressStats = q.inProgressSummary()
|
||||
r.XferStats = make(map[MetricName]XferStats)
|
||||
r.TgtXferStats = make(map[string]map[MetricName]XferStats)
|
||||
r.Workers = q.Workers()
|
||||
|
||||
for _, node := range q.Nodes {
|
||||
for arn := range node.TgtXferStats {
|
||||
xmap, ok := node.TgtXferStats[arn]
|
||||
|
|
|
|||
73
vendor/github.com/minio/minio-go/v7/pkg/utils/peek-reader-closer.go
generated
vendored
Normal file
73
vendor/github.com/minio/minio-go/v7/pkg/utils/peek-reader-closer.go
generated
vendored
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* MinIO Go Library for Amazon S3 Compatible Cloud Storage
|
||||
* Copyright 2015-2025 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 utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
// PeekReadCloser offers a way to peek a ReadCloser stream and then
|
||||
// return the exact stream of the underlying ReadCloser
|
||||
type PeekReadCloser struct {
|
||||
io.ReadCloser
|
||||
|
||||
recordMode bool
|
||||
recordMaxBuf int
|
||||
recordBuf *bytes.Buffer
|
||||
}
|
||||
|
||||
// ReplayFromStart ensures next Read() will restart to stream the
|
||||
// underlying ReadCloser stream from the beginning
|
||||
func (prc *PeekReadCloser) ReplayFromStart() {
|
||||
prc.recordMode = false
|
||||
}
|
||||
|
||||
func (prc *PeekReadCloser) Read(p []byte) (int, error) {
|
||||
if prc.recordMode {
|
||||
if prc.recordBuf.Len() > prc.recordMaxBuf {
|
||||
return 0, errors.New("maximum peek buffer exceeded")
|
||||
}
|
||||
n, err := prc.ReadCloser.Read(p)
|
||||
prc.recordBuf.Write(p[:n])
|
||||
return n, err
|
||||
}
|
||||
// Replay mode
|
||||
if prc.recordBuf.Len() > 0 {
|
||||
pn, _ := prc.recordBuf.Read(p)
|
||||
return pn, nil
|
||||
}
|
||||
return prc.ReadCloser.Read(p)
|
||||
}
|
||||
|
||||
// Close releases the record buffer memory and close the underlying ReadCloser
|
||||
func (prc *PeekReadCloser) Close() error {
|
||||
prc.recordBuf.Reset()
|
||||
return prc.ReadCloser.Close()
|
||||
}
|
||||
|
||||
// NewPeekReadCloser returns a new peek reader
|
||||
func NewPeekReadCloser(rc io.ReadCloser, maxBufSize int) *PeekReadCloser {
|
||||
return &PeekReadCloser{
|
||||
ReadCloser: rc,
|
||||
recordMode: true, // recording mode by default
|
||||
recordBuf: bytes.NewBuffer(make([]byte, 0, 1024)),
|
||||
recordMaxBuf: maxBufSize,
|
||||
}
|
||||
}
|
||||
2
vendor/github.com/minio/minio-go/v7/post-policy.go
generated
vendored
2
vendor/github.com/minio/minio-go/v7/post-policy.go
generated
vendored
|
|
@ -161,7 +161,7 @@ func (p *PostPolicy) SetTagging(tagging string) error {
|
|||
}
|
||||
_, err := tags.ParseObjectXML(strings.NewReader(tagging))
|
||||
if err != nil {
|
||||
return errors.New("The XML you provided was not well-formed or did not validate against our published schema.") //nolint
|
||||
return errors.New(s3ErrorResponseMap[MalformedXML]) //nolint
|
||||
}
|
||||
policyCond := policyCondition{
|
||||
matchType: "eq",
|
||||
|
|
|
|||
2
vendor/github.com/minio/minio-go/v7/retry.go
generated
vendored
2
vendor/github.com/minio/minio-go/v7/retry.go
generated
vendored
|
|
@ -104,6 +104,8 @@ var retryableS3Codes = map[string]struct{}{
|
|||
"ExpiredToken": {},
|
||||
"ExpiredTokenException": {},
|
||||
"SlowDown": {},
|
||||
"SlowDownWrite": {},
|
||||
"SlowDownRead": {},
|
||||
// Add more AWS S3 codes here.
|
||||
}
|
||||
|
||||
|
|
|
|||
130
vendor/github.com/minio/minio-go/v7/s3-error.go
generated
vendored
130
vendor/github.com/minio/minio-go/v7/s3-error.go
generated
vendored
|
|
@ -17,46 +17,100 @@
|
|||
|
||||
package minio
|
||||
|
||||
// Constants for error keys
|
||||
const (
|
||||
NoSuchBucket = "NoSuchBucket"
|
||||
NoSuchKey = "NoSuchKey"
|
||||
NoSuchUpload = "NoSuchUpload"
|
||||
AccessDenied = "AccessDenied"
|
||||
Conflict = "Conflict"
|
||||
PreconditionFailed = "PreconditionFailed"
|
||||
InvalidArgument = "InvalidArgument"
|
||||
EntityTooLarge = "EntityTooLarge"
|
||||
EntityTooSmall = "EntityTooSmall"
|
||||
UnexpectedEOF = "UnexpectedEOF"
|
||||
APINotSupported = "APINotSupported"
|
||||
InvalidRegion = "InvalidRegion"
|
||||
NoSuchBucketPolicy = "NoSuchBucketPolicy"
|
||||
BadDigest = "BadDigest"
|
||||
IncompleteBody = "IncompleteBody"
|
||||
InternalError = "InternalError"
|
||||
InvalidAccessKeyID = "InvalidAccessKeyId"
|
||||
InvalidBucketName = "InvalidBucketName"
|
||||
InvalidDigest = "InvalidDigest"
|
||||
InvalidRange = "InvalidRange"
|
||||
MalformedXML = "MalformedXML"
|
||||
MissingContentLength = "MissingContentLength"
|
||||
MissingContentMD5 = "MissingContentMD5"
|
||||
MissingRequestBodyError = "MissingRequestBodyError"
|
||||
NotImplemented = "NotImplemented"
|
||||
RequestTimeTooSkewed = "RequestTimeTooSkewed"
|
||||
SignatureDoesNotMatch = "SignatureDoesNotMatch"
|
||||
MethodNotAllowed = "MethodNotAllowed"
|
||||
InvalidPart = "InvalidPart"
|
||||
InvalidPartOrder = "InvalidPartOrder"
|
||||
InvalidObjectState = "InvalidObjectState"
|
||||
AuthorizationHeaderMalformed = "AuthorizationHeaderMalformed"
|
||||
MalformedPOSTRequest = "MalformedPOSTRequest"
|
||||
BucketNotEmpty = "BucketNotEmpty"
|
||||
AllAccessDisabled = "AllAccessDisabled"
|
||||
MalformedPolicy = "MalformedPolicy"
|
||||
MissingFields = "MissingFields"
|
||||
AuthorizationQueryParametersError = "AuthorizationQueryParametersError"
|
||||
MalformedDate = "MalformedDate"
|
||||
BucketAlreadyOwnedByYou = "BucketAlreadyOwnedByYou"
|
||||
InvalidDuration = "InvalidDuration"
|
||||
XAmzContentSHA256Mismatch = "XAmzContentSHA256Mismatch"
|
||||
XMinioInvalidObjectName = "XMinioInvalidObjectName"
|
||||
NoSuchCORSConfiguration = "NoSuchCORSConfiguration"
|
||||
BucketAlreadyExists = "BucketAlreadyExists"
|
||||
NoSuchVersion = "NoSuchVersion"
|
||||
NoSuchTagSet = "NoSuchTagSet"
|
||||
Testing = "Testing"
|
||||
Success = "Success"
|
||||
)
|
||||
|
||||
// Non exhaustive list of AWS S3 standard error responses -
|
||||
// http://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html
|
||||
var s3ErrorResponseMap = map[string]string{
|
||||
"AccessDenied": "Access Denied.",
|
||||
"BadDigest": "The Content-Md5 you specified did not match what we received.",
|
||||
"EntityTooSmall": "Your proposed upload is smaller than the minimum allowed object size.",
|
||||
"EntityTooLarge": "Your proposed upload exceeds the maximum allowed object size.",
|
||||
"IncompleteBody": "You did not provide the number of bytes specified by the Content-Length HTTP header.",
|
||||
"InternalError": "We encountered an internal error, please try again.",
|
||||
"InvalidAccessKeyId": "The access key ID you provided does not exist in our records.",
|
||||
"InvalidBucketName": "The specified bucket is not valid.",
|
||||
"InvalidDigest": "The Content-Md5 you specified is not valid.",
|
||||
"InvalidRange": "The requested range is not satisfiable",
|
||||
"MalformedXML": "The XML you provided was not well-formed or did not validate against our published schema.",
|
||||
"MissingContentLength": "You must provide the Content-Length HTTP header.",
|
||||
"MissingContentMD5": "Missing required header for this request: Content-Md5.",
|
||||
"MissingRequestBodyError": "Request body is empty.",
|
||||
"NoSuchBucket": "The specified bucket does not exist.",
|
||||
"NoSuchBucketPolicy": "The bucket policy does not exist",
|
||||
"NoSuchKey": "The specified key does not exist.",
|
||||
"NoSuchUpload": "The specified multipart upload does not exist. The upload ID may be invalid, or the upload may have been aborted or completed.",
|
||||
"NotImplemented": "A header you provided implies functionality that is not implemented",
|
||||
"PreconditionFailed": "At least one of the pre-conditions you specified did not hold",
|
||||
"RequestTimeTooSkewed": "The difference between the request time and the server's time is too large.",
|
||||
"SignatureDoesNotMatch": "The request signature we calculated does not match the signature you provided. Check your key and signing method.",
|
||||
"MethodNotAllowed": "The specified method is not allowed against this resource.",
|
||||
"InvalidPart": "One or more of the specified parts could not be found.",
|
||||
"InvalidPartOrder": "The list of parts was not in ascending order. The parts list must be specified in order by part number.",
|
||||
"InvalidObjectState": "The operation is not valid for the current state of the object.",
|
||||
"AuthorizationHeaderMalformed": "The authorization header is malformed; the region is wrong.",
|
||||
"MalformedPOSTRequest": "The body of your POST request is not well-formed multipart/form-data.",
|
||||
"BucketNotEmpty": "The bucket you tried to delete is not empty",
|
||||
"AllAccessDisabled": "All access to this bucket has been disabled.",
|
||||
"MalformedPolicy": "Policy has invalid resource.",
|
||||
"MissingFields": "Missing fields in request.",
|
||||
"AuthorizationQueryParametersError": "Error parsing the X-Amz-Credential parameter; the Credential is mal-formed; expecting \"<YOUR-AKID>/YYYYMMDD/REGION/SERVICE/aws4_request\".",
|
||||
"MalformedDate": "Invalid date format header, expected to be in ISO8601, RFC1123 or RFC1123Z time format.",
|
||||
"BucketAlreadyOwnedByYou": "Your previous request to create the named bucket succeeded and you already own it.",
|
||||
"InvalidDuration": "Duration provided in the request is invalid.",
|
||||
"XAmzContentSHA256Mismatch": "The provided 'x-amz-content-sha256' header does not match what was computed.",
|
||||
"NoSuchCORSConfiguration": "The specified bucket does not have a CORS configuration.",
|
||||
AccessDenied: "Access Denied.",
|
||||
BadDigest: "The Content-Md5 you specified did not match what we received.",
|
||||
EntityTooSmall: "Your proposed upload is smaller than the minimum allowed object size.",
|
||||
EntityTooLarge: "Your proposed upload exceeds the maximum allowed object size.",
|
||||
IncompleteBody: "You did not provide the number of bytes specified by the Content-Length HTTP header.",
|
||||
InternalError: "We encountered an internal error, please try again.",
|
||||
InvalidAccessKeyID: "The access key ID you provided does not exist in our records.",
|
||||
InvalidBucketName: "The specified bucket is not valid.",
|
||||
InvalidDigest: "The Content-Md5 you specified is not valid.",
|
||||
InvalidRange: "The requested range is not satisfiable.",
|
||||
MalformedXML: "The XML you provided was not well-formed or did not validate against our published schema.",
|
||||
MissingContentLength: "You must provide the Content-Length HTTP header.",
|
||||
MissingContentMD5: "Missing required header for this request: Content-Md5.",
|
||||
MissingRequestBodyError: "Request body is empty.",
|
||||
NoSuchBucket: "The specified bucket does not exist.",
|
||||
NoSuchBucketPolicy: "The bucket policy does not exist.",
|
||||
NoSuchKey: "The specified key does not exist.",
|
||||
NoSuchUpload: "The specified multipart upload does not exist. The upload ID may be invalid, or the upload may have been aborted or completed.",
|
||||
NotImplemented: "A header you provided implies functionality that is not implemented.",
|
||||
PreconditionFailed: "At least one of the pre-conditions you specified did not hold.",
|
||||
RequestTimeTooSkewed: "The difference between the request time and the server's time is too large.",
|
||||
SignatureDoesNotMatch: "The request signature we calculated does not match the signature you provided. Check your key and signing method.",
|
||||
MethodNotAllowed: "The specified method is not allowed against this resource.",
|
||||
InvalidPart: "One or more of the specified parts could not be found.",
|
||||
InvalidPartOrder: "The list of parts was not in ascending order. The parts list must be specified in order by part number.",
|
||||
InvalidObjectState: "The operation is not valid for the current state of the object.",
|
||||
AuthorizationHeaderMalformed: "The authorization header is malformed; the region is wrong.",
|
||||
MalformedPOSTRequest: "The body of your POST request is not well-formed multipart/form-data.",
|
||||
BucketNotEmpty: "The bucket you tried to delete is not empty.",
|
||||
AllAccessDisabled: "All access to this bucket has been disabled.",
|
||||
MalformedPolicy: "Policy has invalid resource.",
|
||||
MissingFields: "Missing fields in request.",
|
||||
AuthorizationQueryParametersError: "Error parsing the X-Amz-Credential parameter; the Credential is mal-formed; expecting \"<YOUR-AKID>/YYYYMMDD/REGION/SERVICE/aws4_request\".",
|
||||
MalformedDate: "Invalid date format header, expected to be in ISO8601, RFC1123 or RFC1123Z time format.",
|
||||
BucketAlreadyOwnedByYou: "Your previous request to create the named bucket succeeded and you already own it.",
|
||||
InvalidDuration: "Duration provided in the request is invalid.",
|
||||
XAmzContentSHA256Mismatch: "The provided 'x-amz-content-sha256' header does not match what was computed.",
|
||||
NoSuchCORSConfiguration: "The specified bucket does not have a CORS configuration.",
|
||||
Conflict: "Bucket not empty.",
|
||||
// Add new API errors here.
|
||||
}
|
||||
|
|
|
|||
22
vendor/github.com/minio/minio-go/v7/utils.go
generated
vendored
22
vendor/github.com/minio/minio-go/v7/utils.go
generated
vendored
|
|
@ -30,6 +30,7 @@ import (
|
|||
"hash"
|
||||
"io"
|
||||
"math/rand"
|
||||
"mime"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
|
@ -210,6 +211,7 @@ func extractObjMetadata(header http.Header) http.Header {
|
|||
"X-Amz-Server-Side-Encryption",
|
||||
"X-Amz-Tagging-Count",
|
||||
"X-Amz-Meta-",
|
||||
"X-Minio-Meta-",
|
||||
// Add new headers to be preserved.
|
||||
// if you add new headers here, please extend
|
||||
// PutObjectOptions{} to preserve them
|
||||
|
|
@ -223,6 +225,16 @@ func extractObjMetadata(header http.Header) http.Header {
|
|||
continue
|
||||
}
|
||||
found = true
|
||||
if prefix == "X-Amz-Meta-" || prefix == "X-Minio-Meta-" {
|
||||
for index, val := range v {
|
||||
if strings.HasPrefix(val, "=?") {
|
||||
decoder := mime.WordDecoder{}
|
||||
if decoded, err := decoder.DecodeHeader(val); err == nil {
|
||||
v[index] = decoded
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
if found {
|
||||
|
|
@ -268,7 +280,7 @@ func ToObjectInfo(bucketName, objectName string, h http.Header) (ObjectInfo, err
|
|||
if err != nil {
|
||||
// Content-Length is not valid
|
||||
return ObjectInfo{}, ErrorResponse{
|
||||
Code: "InternalError",
|
||||
Code: InternalError,
|
||||
Message: fmt.Sprintf("Content-Length is not an integer, failed with %v", err),
|
||||
BucketName: bucketName,
|
||||
Key: objectName,
|
||||
|
|
@ -283,7 +295,7 @@ func ToObjectInfo(bucketName, objectName string, h http.Header) (ObjectInfo, err
|
|||
mtime, err := parseRFC7231Time(h.Get("Last-Modified"))
|
||||
if err != nil {
|
||||
return ObjectInfo{}, ErrorResponse{
|
||||
Code: "InternalError",
|
||||
Code: InternalError,
|
||||
Message: fmt.Sprintf("Last-Modified time format is invalid, failed with %v", err),
|
||||
BucketName: bucketName,
|
||||
Key: objectName,
|
||||
|
|
@ -305,7 +317,7 @@ func ToObjectInfo(bucketName, objectName string, h http.Header) (ObjectInfo, err
|
|||
expiry, err = parseRFC7231Time(expiryStr)
|
||||
if err != nil {
|
||||
return ObjectInfo{}, ErrorResponse{
|
||||
Code: "InternalError",
|
||||
Code: InternalError,
|
||||
Message: fmt.Sprintf("'Expiry' is not in supported format: %v", err),
|
||||
BucketName: bucketName,
|
||||
Key: objectName,
|
||||
|
|
@ -327,7 +339,7 @@ func ToObjectInfo(bucketName, objectName string, h http.Header) (ObjectInfo, err
|
|||
userTags, err := tags.ParseObjectTags(h.Get(amzTaggingHeader))
|
||||
if err != nil {
|
||||
return ObjectInfo{}, ErrorResponse{
|
||||
Code: "InternalError",
|
||||
Code: InternalError,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -336,7 +348,7 @@ func ToObjectInfo(bucketName, objectName string, h http.Header) (ObjectInfo, err
|
|||
tagCount, err = strconv.Atoi(count)
|
||||
if err != nil {
|
||||
return ObjectInfo{}, ErrorResponse{
|
||||
Code: "InternalError",
|
||||
Code: InternalError,
|
||||
Message: fmt.Sprintf("x-amz-tagging-count is not an integer, failed with %v", err),
|
||||
BucketName: bucketName,
|
||||
Key: objectName,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue