You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
326 lines
9.0 KiB
326 lines
9.0 KiB
7 years ago
|
/*
|
||
|
* Minio Cloud Storage, (C) 2017 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 cmd
|
||
|
|
||
|
import (
|
||
|
"net/http"
|
||
|
|
||
|
"github.com/minio/minio/pkg/errors"
|
||
|
"github.com/minio/minio/pkg/hash"
|
||
|
|
||
|
minio "github.com/minio/minio-go"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
// CanonicalizeETag provides canonicalizeETag function alias.
|
||
|
CanonicalizeETag = canonicalizeETag
|
||
|
|
||
|
// MustGetUUID function alias.
|
||
|
MustGetUUID = mustGetUUID
|
||
|
|
||
|
// ErrorIf provides errorIf function alias.
|
||
|
ErrorIf = errorIf
|
||
|
|
||
|
// FatalIf provides fatalIf function alias.
|
||
|
FatalIf = fatalIf
|
||
|
)
|
||
|
|
||
|
// AnonErrToObjectErr - converts standard http codes into meaningful object layer errors.
|
||
|
func AnonErrToObjectErr(statusCode int, params ...string) error {
|
||
|
bucket := ""
|
||
|
object := ""
|
||
|
if len(params) >= 1 {
|
||
|
bucket = params[0]
|
||
|
}
|
||
|
if len(params) == 2 {
|
||
|
object = params[1]
|
||
|
}
|
||
|
|
||
|
switch statusCode {
|
||
|
case http.StatusNotFound:
|
||
|
if object != "" {
|
||
|
return ObjectNotFound{bucket, object}
|
||
|
}
|
||
|
return BucketNotFound{Bucket: bucket}
|
||
|
case http.StatusBadRequest:
|
||
|
if object != "" {
|
||
|
return ObjectNameInvalid{bucket, object}
|
||
|
}
|
||
|
return BucketNameInvalid{Bucket: bucket}
|
||
|
case http.StatusForbidden:
|
||
|
fallthrough
|
||
|
case http.StatusUnauthorized:
|
||
|
return AllAccessDisabled{bucket, object}
|
||
|
}
|
||
|
|
||
|
return errUnexpected
|
||
|
}
|
||
|
|
||
|
// FromMinioClientMetadata converts minio metadata to map[string]string
|
||
|
func FromMinioClientMetadata(metadata map[string][]string) map[string]string {
|
||
|
mm := map[string]string{}
|
||
|
for k, v := range metadata {
|
||
|
mm[http.CanonicalHeaderKey(k)] = v[0]
|
||
|
}
|
||
|
return mm
|
||
|
}
|
||
|
|
||
|
// FromMinioClientObjectPart converts minio ObjectPart to PartInfo
|
||
|
func FromMinioClientObjectPart(op minio.ObjectPart) PartInfo {
|
||
|
return PartInfo{
|
||
|
Size: op.Size,
|
||
|
ETag: canonicalizeETag(op.ETag),
|
||
|
LastModified: op.LastModified,
|
||
|
PartNumber: op.PartNumber,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// FromMinioClientListPartsInfo converts minio ListObjectPartsResult to ListPartsInfo
|
||
|
func FromMinioClientListPartsInfo(lopr minio.ListObjectPartsResult) ListPartsInfo {
|
||
|
// Convert minio ObjectPart to PartInfo
|
||
|
fromMinioClientObjectParts := func(parts []minio.ObjectPart) []PartInfo {
|
||
|
toParts := make([]PartInfo, len(parts))
|
||
|
for i, part := range parts {
|
||
|
toParts[i] = FromMinioClientObjectPart(part)
|
||
|
}
|
||
|
return toParts
|
||
|
}
|
||
|
|
||
|
return ListPartsInfo{
|
||
|
UploadID: lopr.UploadID,
|
||
|
Bucket: lopr.Bucket,
|
||
|
Object: lopr.Key,
|
||
|
StorageClass: "",
|
||
|
PartNumberMarker: lopr.PartNumberMarker,
|
||
|
NextPartNumberMarker: lopr.NextPartNumberMarker,
|
||
|
MaxParts: lopr.MaxParts,
|
||
|
IsTruncated: lopr.IsTruncated,
|
||
|
EncodingType: lopr.EncodingType,
|
||
|
Parts: fromMinioClientObjectParts(lopr.ObjectParts),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// FromMinioClientListMultipartsInfo converts minio ListMultipartUploadsResult to ListMultipartsInfo
|
||
|
func FromMinioClientListMultipartsInfo(lmur minio.ListMultipartUploadsResult) ListMultipartsInfo {
|
||
|
uploads := make([]MultipartInfo, len(lmur.Uploads))
|
||
|
|
||
|
for i, um := range lmur.Uploads {
|
||
|
uploads[i] = MultipartInfo{
|
||
|
Object: um.Key,
|
||
|
UploadID: um.UploadID,
|
||
|
Initiated: um.Initiated,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
commonPrefixes := make([]string, len(lmur.CommonPrefixes))
|
||
|
for i, cp := range lmur.CommonPrefixes {
|
||
|
commonPrefixes[i] = cp.Prefix
|
||
|
}
|
||
|
|
||
|
return ListMultipartsInfo{
|
||
|
KeyMarker: lmur.KeyMarker,
|
||
|
UploadIDMarker: lmur.UploadIDMarker,
|
||
|
NextKeyMarker: lmur.NextKeyMarker,
|
||
|
NextUploadIDMarker: lmur.NextUploadIDMarker,
|
||
|
MaxUploads: int(lmur.MaxUploads),
|
||
|
IsTruncated: lmur.IsTruncated,
|
||
|
Uploads: uploads,
|
||
|
Prefix: lmur.Prefix,
|
||
|
Delimiter: lmur.Delimiter,
|
||
|
CommonPrefixes: commonPrefixes,
|
||
|
EncodingType: lmur.EncodingType,
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// FromMinioClientObjectInfo converts minio ObjectInfo to gateway ObjectInfo
|
||
|
func FromMinioClientObjectInfo(bucket string, oi minio.ObjectInfo) ObjectInfo {
|
||
|
userDefined := FromMinioClientMetadata(oi.Metadata)
|
||
|
userDefined["Content-Type"] = oi.ContentType
|
||
|
|
||
|
return ObjectInfo{
|
||
|
Bucket: bucket,
|
||
|
Name: oi.Key,
|
||
|
ModTime: oi.LastModified,
|
||
|
Size: oi.Size,
|
||
|
ETag: canonicalizeETag(oi.ETag),
|
||
|
UserDefined: userDefined,
|
||
|
ContentType: oi.ContentType,
|
||
|
ContentEncoding: oi.Metadata.Get("Content-Encoding"),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// FromMinioClientListBucketV2Result converts minio ListBucketResult to ListObjectsInfo
|
||
|
func FromMinioClientListBucketV2Result(bucket string, result minio.ListBucketV2Result) ListObjectsV2Info {
|
||
|
objects := make([]ObjectInfo, len(result.Contents))
|
||
|
|
||
|
for i, oi := range result.Contents {
|
||
|
objects[i] = FromMinioClientObjectInfo(bucket, oi)
|
||
|
}
|
||
|
|
||
|
prefixes := make([]string, len(result.CommonPrefixes))
|
||
|
for i, p := range result.CommonPrefixes {
|
||
|
prefixes[i] = p.Prefix
|
||
|
}
|
||
|
|
||
|
return ListObjectsV2Info{
|
||
|
IsTruncated: result.IsTruncated,
|
||
|
Prefixes: prefixes,
|
||
|
Objects: objects,
|
||
|
|
||
|
ContinuationToken: result.ContinuationToken,
|
||
|
NextContinuationToken: result.NextContinuationToken,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// FromMinioClientListBucketResult converts minio ListBucketResult to ListObjectsInfo
|
||
|
func FromMinioClientListBucketResult(bucket string, result minio.ListBucketResult) ListObjectsInfo {
|
||
|
objects := make([]ObjectInfo, len(result.Contents))
|
||
|
|
||
|
for i, oi := range result.Contents {
|
||
|
objects[i] = FromMinioClientObjectInfo(bucket, oi)
|
||
|
}
|
||
|
|
||
|
prefixes := make([]string, len(result.CommonPrefixes))
|
||
|
for i, p := range result.CommonPrefixes {
|
||
|
prefixes[i] = p.Prefix
|
||
|
}
|
||
|
|
||
|
return ListObjectsInfo{
|
||
|
IsTruncated: result.IsTruncated,
|
||
|
NextMarker: result.NextMarker,
|
||
|
Prefixes: prefixes,
|
||
|
Objects: objects,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// FromMinioClientListBucketResultToV2Info converts minio ListBucketResult to ListObjectsV2Info
|
||
|
func FromMinioClientListBucketResultToV2Info(bucket string, result minio.ListBucketResult) ListObjectsV2Info {
|
||
|
objects := make([]ObjectInfo, len(result.Contents))
|
||
|
|
||
|
for i, oi := range result.Contents {
|
||
|
objects[i] = FromMinioClientObjectInfo(bucket, oi)
|
||
|
}
|
||
|
|
||
|
prefixes := make([]string, len(result.CommonPrefixes))
|
||
|
for i, p := range result.CommonPrefixes {
|
||
|
prefixes[i] = p.Prefix
|
||
|
}
|
||
|
|
||
|
return ListObjectsV2Info{
|
||
|
IsTruncated: result.IsTruncated,
|
||
|
Prefixes: prefixes,
|
||
|
Objects: objects,
|
||
|
ContinuationToken: result.Marker,
|
||
|
NextContinuationToken: result.NextMarker,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ToMinioClientMetadata converts metadata to map[string][]string
|
||
|
func ToMinioClientMetadata(metadata map[string]string) map[string]string {
|
||
|
mm := make(map[string]string)
|
||
|
for k, v := range metadata {
|
||
|
mm[http.CanonicalHeaderKey(k)] = v
|
||
|
}
|
||
|
return mm
|
||
|
}
|
||
|
|
||
|
// ToMinioClientCompletePart converts CompletePart to minio CompletePart
|
||
|
func ToMinioClientCompletePart(part CompletePart) minio.CompletePart {
|
||
|
return minio.CompletePart{
|
||
|
ETag: part.ETag,
|
||
|
PartNumber: part.PartNumber,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ToMinioClientCompleteParts converts []CompletePart to minio []CompletePart
|
||
|
func ToMinioClientCompleteParts(parts []CompletePart) []minio.CompletePart {
|
||
|
mparts := make([]minio.CompletePart, len(parts))
|
||
|
for i, part := range parts {
|
||
|
mparts[i] = ToMinioClientCompletePart(part)
|
||
|
}
|
||
|
return mparts
|
||
|
}
|
||
|
|
||
|
// ErrorRespToObjectError converts Minio errors to minio object layer errors.
|
||
|
func ErrorRespToObjectError(err error, params ...string) error {
|
||
|
if err == nil {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
e, ok := err.(*errors.Error)
|
||
|
if !ok {
|
||
|
// Code should be fixed if this function is called without doing traceError()
|
||
|
// Else handling different situations in this function makes this function complicated.
|
||
|
errorIf(err, "Expected type *Error")
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
err = e.Cause
|
||
|
|
||
|
bucket := ""
|
||
|
object := ""
|
||
|
if len(params) >= 1 {
|
||
|
bucket = params[0]
|
||
|
}
|
||
|
if len(params) == 2 {
|
||
|
object = params[1]
|
||
|
}
|
||
|
|
||
|
minioErr, ok := err.(minio.ErrorResponse)
|
||
|
if !ok {
|
||
|
// We don't interpret non Minio errors. As minio errors will
|
||
|
// have StatusCode to help to convert to object errors.
|
||
|
return e
|
||
|
}
|
||
|
|
||
|
switch minioErr.Code {
|
||
|
case "BucketAlreadyOwnedByYou":
|
||
|
err = BucketAlreadyOwnedByYou{}
|
||
|
case "BucketNotEmpty":
|
||
|
err = BucketNotEmpty{}
|
||
|
case "NoSuchBucketPolicy":
|
||
|
err = PolicyNotFound{}
|
||
|
case "InvalidBucketName":
|
||
|
err = BucketNameInvalid{Bucket: bucket}
|
||
|
case "NoSuchBucket":
|
||
|
err = BucketNotFound{Bucket: bucket}
|
||
|
case "NoSuchKey":
|
||
|
if object != "" {
|
||
|
err = ObjectNotFound{Bucket: bucket, Object: object}
|
||
|
} else {
|
||
|
err = BucketNotFound{Bucket: bucket}
|
||
|
}
|
||
|
case "XMinioInvalidObjectName":
|
||
|
err = ObjectNameInvalid{}
|
||
|
case "AccessDenied":
|
||
|
err = PrefixAccessDenied{
|
||
|
Bucket: bucket,
|
||
|
Object: object,
|
||
|
}
|
||
|
case "XAmzContentSHA256Mismatch":
|
||
|
err = hash.SHA256Mismatch{}
|
||
|
case "NoSuchUpload":
|
||
|
err = InvalidUploadID{}
|
||
|
case "EntityTooSmall":
|
||
|
err = PartTooSmall{}
|
||
|
}
|
||
|
|
||
|
e.Cause = err
|
||
|
return e
|
||
|
}
|