forked from TrueCloudLab/frostfs-s3-gw
[#488] Renamed api/errors, layer/frostfs and layer/tree package names
Signed-off-by: Nikita Zinkevich <n.zinkevich@yadro.com>
This commit is contained in:
parent
827ea1a41e
commit
9fadfbbc2f
37 changed files with 359 additions and 358 deletions
|
@ -14,7 +14,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
v4 "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/auth/signer/v4"
|
v4 "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/auth/signer/v4"
|
||||||
apiErrors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/tokens"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/tokens"
|
||||||
|
@ -94,12 +94,12 @@ func New(creds tokens.Credentials, prefixes []string) *Center {
|
||||||
func (c *Center) parseAuthHeader(header string) (*AuthHeader, error) {
|
func (c *Center) parseAuthHeader(header string) (*AuthHeader, error) {
|
||||||
submatches := c.reg.GetSubmatches(header)
|
submatches := c.reg.GetSubmatches(header)
|
||||||
if len(submatches) != authHeaderPartsNum {
|
if len(submatches) != authHeaderPartsNum {
|
||||||
return nil, fmt.Errorf("%w: %s", apiErrors.GetAPIError(apiErrors.ErrAuthorizationHeaderMalformed), header)
|
return nil, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrAuthorizationHeaderMalformed), header)
|
||||||
}
|
}
|
||||||
|
|
||||||
accessKey := strings.Split(submatches["access_key_id"], "0")
|
accessKey := strings.Split(submatches["access_key_id"], "0")
|
||||||
if len(accessKey) != accessKeyPartsNum {
|
if len(accessKey) != accessKeyPartsNum {
|
||||||
return nil, fmt.Errorf("%w: %s", apiErrors.GetAPIError(apiErrors.ErrInvalidAccessKeyID), accessKey)
|
return nil, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrInvalidAccessKeyID), accessKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
signedFields := strings.Split(submatches["signed_header_fields"], ";")
|
signedFields := strings.Split(submatches["signed_header_fields"], ";")
|
||||||
|
@ -117,7 +117,7 @@ func (c *Center) parseAuthHeader(header string) (*AuthHeader, error) {
|
||||||
func getAddress(accessKeyID string) (oid.Address, error) {
|
func getAddress(accessKeyID string) (oid.Address, error) {
|
||||||
var addr oid.Address
|
var addr oid.Address
|
||||||
if err := addr.DecodeString(strings.ReplaceAll(accessKeyID, "0", "/")); err != nil {
|
if err := addr.DecodeString(strings.ReplaceAll(accessKeyID, "0", "/")); err != nil {
|
||||||
return addr, fmt.Errorf("%w: %s", apiErrors.GetAPIError(apiErrors.ErrInvalidAccessKeyID), accessKeyID)
|
return addr, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrInvalidAccessKeyID), accessKeyID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return addr, nil
|
return addr, nil
|
||||||
|
@ -220,11 +220,11 @@ func checkFormatHashContentSHA256(hash string) error {
|
||||||
if !IsStandardContentSHA256(hash) {
|
if !IsStandardContentSHA256(hash) {
|
||||||
hashBinary, err := hex.DecodeString(hash)
|
hashBinary, err := hex.DecodeString(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: decode hash: %s: %s", apiErrors.GetAPIError(apiErrors.ErrContentSHA256Mismatch),
|
return fmt.Errorf("%w: decode hash: %s: %s", apierr.GetAPIError(apierr.ErrContentSHA256Mismatch),
|
||||||
hash, err.Error())
|
hash, err.Error())
|
||||||
}
|
}
|
||||||
if len(hashBinary) != sha256.Size && len(hash) != 0 {
|
if len(hashBinary) != sha256.Size && len(hash) != 0 {
|
||||||
return fmt.Errorf("%w: invalid hash size %d", apiErrors.GetAPIError(apiErrors.ErrContentSHA256Mismatch), len(hashBinary))
|
return fmt.Errorf("%w: invalid hash size %d", apierr.GetAPIError(apierr.ErrContentSHA256Mismatch), len(hashBinary))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,12 +242,12 @@ func (c Center) checkAccessKeyID(accessKeyID string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("%w: accesskeyID prefix isn't allowed", apiErrors.GetAPIError(apiErrors.ErrAccessDenied))
|
return fmt.Errorf("%w: accesskeyID prefix isn't allowed", apierr.GetAPIError(apierr.ErrAccessDenied))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Center) checkFormData(r *http.Request) (*middleware.Box, error) {
|
func (c *Center) checkFormData(r *http.Request) (*middleware.Box, error) {
|
||||||
if err := r.ParseMultipartForm(maxFormSizeMemory); err != nil {
|
if err := r.ParseMultipartForm(maxFormSizeMemory); err != nil {
|
||||||
return nil, fmt.Errorf("%w: parse multipart form with max size %d", apiErrors.GetAPIError(apiErrors.ErrInvalidArgument), maxFormSizeMemory)
|
return nil, fmt.Errorf("%w: parse multipart form with max size %d", apierr.GetAPIError(apierr.ErrInvalidArgument), maxFormSizeMemory)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := prepareForm(r.MultipartForm); err != nil {
|
if err := prepareForm(r.MultipartForm); err != nil {
|
||||||
|
@ -262,7 +262,7 @@ func (c *Center) checkFormData(r *http.Request) (*middleware.Box, error) {
|
||||||
creds := MultipartFormValue(r, "x-amz-credential")
|
creds := MultipartFormValue(r, "x-amz-credential")
|
||||||
submatches := c.postReg.GetSubmatches(creds)
|
submatches := c.postReg.GetSubmatches(creds)
|
||||||
if len(submatches) != 4 {
|
if len(submatches) != 4 {
|
||||||
return nil, fmt.Errorf("%w: %s", apiErrors.GetAPIError(apiErrors.ErrAuthorizationHeaderMalformed), creds)
|
return nil, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrAuthorizationHeaderMalformed), creds)
|
||||||
}
|
}
|
||||||
|
|
||||||
signatureDateTime, err := time.Parse("20060102T150405Z", MultipartFormValue(r, "x-amz-date"))
|
signatureDateTime, err := time.Parse("20060102T150405Z", MultipartFormValue(r, "x-amz-date"))
|
||||||
|
@ -288,7 +288,7 @@ func (c *Center) checkFormData(r *http.Request) (*middleware.Box, error) {
|
||||||
signature := SignStr(secret, service, region, signatureDateTime, policy)
|
signature := SignStr(secret, service, region, signatureDateTime, policy)
|
||||||
reqSignature := MultipartFormValue(r, "x-amz-signature")
|
reqSignature := MultipartFormValue(r, "x-amz-signature")
|
||||||
if signature != reqSignature {
|
if signature != reqSignature {
|
||||||
return nil, fmt.Errorf("%w: %s != %s", apiErrors.GetAPIError(apiErrors.ErrSignatureDoesNotMatch),
|
return nil, fmt.Errorf("%w: %s != %s", apierr.GetAPIError(apierr.ErrSignatureDoesNotMatch),
|
||||||
reqSignature, signature)
|
reqSignature, signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,11 +333,11 @@ func (c *Center) checkSign(authHeader *AuthHeader, box *accessbox.Box, request *
|
||||||
if authHeader.IsPresigned {
|
if authHeader.IsPresigned {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
if signatureDateTime.Add(authHeader.Expiration).Before(now) {
|
if signatureDateTime.Add(authHeader.Expiration).Before(now) {
|
||||||
return fmt.Errorf("%w: expired: now %s, signature %s", apiErrors.GetAPIError(apiErrors.ErrExpiredPresignRequest),
|
return fmt.Errorf("%w: expired: now %s, signature %s", apierr.GetAPIError(apierr.ErrExpiredPresignRequest),
|
||||||
now.Format(time.RFC3339), signatureDateTime.Format(time.RFC3339))
|
now.Format(time.RFC3339), signatureDateTime.Format(time.RFC3339))
|
||||||
}
|
}
|
||||||
if now.Before(signatureDateTime) {
|
if now.Before(signatureDateTime) {
|
||||||
return fmt.Errorf("%w: signature time from the future: now %s, signature %s", apiErrors.GetAPIError(apiErrors.ErrBadRequest),
|
return fmt.Errorf("%w: signature time from the future: now %s, signature %s", apierr.GetAPIError(apierr.ErrBadRequest),
|
||||||
now.Format(time.RFC3339), signatureDateTime.Format(time.RFC3339))
|
now.Format(time.RFC3339), signatureDateTime.Format(time.RFC3339))
|
||||||
}
|
}
|
||||||
if _, err := signer.Presign(request, nil, authHeader.Service, authHeader.Region, authHeader.Expiration, signatureDateTime); err != nil {
|
if _, err := signer.Presign(request, nil, authHeader.Service, authHeader.Region, authHeader.Expiration, signatureDateTime); err != nil {
|
||||||
|
@ -352,7 +352,7 @@ func (c *Center) checkSign(authHeader *AuthHeader, box *accessbox.Box, request *
|
||||||
}
|
}
|
||||||
|
|
||||||
if authHeader.SignatureV4 != signature {
|
if authHeader.SignatureV4 != signature {
|
||||||
return fmt.Errorf("%w: %s != %s: headers %v", apiErrors.GetAPIError(apiErrors.ErrSignatureDoesNotMatch),
|
return fmt.Errorf("%w: %s != %s: headers %v", apierr.GetAPIError(apierr.ErrSignatureDoesNotMatch),
|
||||||
authHeader.SignatureV4, signature, authHeader.SignedFields)
|
authHeader.SignatureV4, signature, authHeader.SignedFields)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/tokens"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/tokens"
|
||||||
frostfsErrors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/errors"
|
frosterr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||||
|
@ -419,7 +419,7 @@ func TestAuthenticate(t *testing.T) {
|
||||||
if tc.err {
|
if tc.err {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
if tc.errCode > 0 {
|
if tc.errCode > 0 {
|
||||||
err = frostfsErrors.UnwrapErr(err)
|
err = frosterr.UnwrapErr(err)
|
||||||
require.Equal(t, errors.GetAPIError(tc.errCode), err)
|
require.Equal(t, errors.GetAPIError(tc.errCode), err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -596,7 +596,7 @@ func TestHTTPPostAuthenticate(t *testing.T) {
|
||||||
if tc.err {
|
if tc.err {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
if tc.errCode > 0 {
|
if tc.errCode > 0 {
|
||||||
err = frostfsErrors.UnwrapErr(err)
|
err = frosterr.UnwrapErr(err)
|
||||||
require.Equal(t, errors.GetAPIError(tc.errCode), err)
|
require.Equal(t, errors.GetAPIError(tc.errCode), err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
s3errors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||||
|
@ -28,12 +28,12 @@ func TestPutObjectACLErrorAPE(t *testing.T) {
|
||||||
|
|
||||||
info := createBucket(hc, bktName)
|
info := createBucket(hc, bktName)
|
||||||
|
|
||||||
putObjectWithHeadersAssertS3Error(hc, bktName, objName, map[string]string{api.AmzACL: basicACLPublic}, s3errors.ErrAccessControlListNotSupported)
|
putObjectWithHeadersAssertS3Error(hc, bktName, objName, map[string]string{api.AmzACL: basicACLPublic}, apierr.ErrAccessControlListNotSupported)
|
||||||
putObjectWithHeaders(hc, bktName, objName, map[string]string{api.AmzACL: basicACLPrivate}) // only `private` canned acl is allowed, that is actually ignored
|
putObjectWithHeaders(hc, bktName, objName, map[string]string{api.AmzACL: basicACLPrivate}) // only `private` canned acl is allowed, that is actually ignored
|
||||||
putObjectWithHeaders(hc, bktName, objName, nil)
|
putObjectWithHeaders(hc, bktName, objName, nil)
|
||||||
|
|
||||||
aclBody := &AccessControlPolicy{}
|
aclBody := &AccessControlPolicy{}
|
||||||
putObjectACLAssertS3Error(hc, bktName, objName, info.Box, nil, aclBody, s3errors.ErrAccessControlListNotSupported)
|
putObjectACLAssertS3Error(hc, bktName, objName, info.Box, nil, aclBody, apierr.ErrAccessControlListNotSupported)
|
||||||
|
|
||||||
aclRes := getObjectACL(hc, bktName, objName)
|
aclRes := getObjectACL(hc, bktName, objName)
|
||||||
checkPrivateACL(t, aclRes, info.Key.PublicKey())
|
checkPrivateACL(t, aclRes, info.Key.PublicKey())
|
||||||
|
@ -49,7 +49,7 @@ func TestCreateObjectACLErrorAPE(t *testing.T) {
|
||||||
copyObject(hc, bktName, objName, objNameCopy, CopyMeta{Headers: map[string]string{api.AmzACL: basicACLPublic}}, http.StatusBadRequest)
|
copyObject(hc, bktName, objName, objNameCopy, CopyMeta{Headers: map[string]string{api.AmzACL: basicACLPublic}}, http.StatusBadRequest)
|
||||||
copyObject(hc, bktName, objName, objNameCopy, CopyMeta{Headers: map[string]string{api.AmzACL: basicACLPrivate}}, http.StatusOK)
|
copyObject(hc, bktName, objName, objNameCopy, CopyMeta{Headers: map[string]string{api.AmzACL: basicACLPrivate}}, http.StatusOK)
|
||||||
|
|
||||||
createMultipartUploadAssertS3Error(hc, bktName, objName, map[string]string{api.AmzACL: basicACLPublic}, s3errors.ErrAccessControlListNotSupported)
|
createMultipartUploadAssertS3Error(hc, bktName, objName, map[string]string{api.AmzACL: basicACLPublic}, apierr.ErrAccessControlListNotSupported)
|
||||||
createMultipartUpload(hc, bktName, objName, map[string]string{api.AmzACL: basicACLPrivate})
|
createMultipartUpload(hc, bktName, objName, map[string]string{api.AmzACL: basicACLPrivate})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ func TestBucketACLAPE(t *testing.T) {
|
||||||
info := createBucket(hc, bktName)
|
info := createBucket(hc, bktName)
|
||||||
|
|
||||||
aclBody := &AccessControlPolicy{}
|
aclBody := &AccessControlPolicy{}
|
||||||
putBucketACLAssertS3Error(hc, bktName, info.Box, nil, aclBody, s3errors.ErrAccessControlListNotSupported)
|
putBucketACLAssertS3Error(hc, bktName, info.Box, nil, aclBody, apierr.ErrAccessControlListNotSupported)
|
||||||
|
|
||||||
aclRes := getBucketACL(hc, bktName)
|
aclRes := getBucketACL(hc, bktName)
|
||||||
checkPrivateACL(t, aclRes, info.Key.PublicKey())
|
checkPrivateACL(t, aclRes, info.Key.PublicKey())
|
||||||
|
@ -113,7 +113,7 @@ func TestBucketPolicy(t *testing.T) {
|
||||||
|
|
||||||
createTestBucket(hc, bktName)
|
createTestBucket(hc, bktName)
|
||||||
|
|
||||||
getBucketPolicy(hc, bktName, s3errors.ErrNoSuchBucketPolicy)
|
getBucketPolicy(hc, bktName, apierr.ErrNoSuchBucketPolicy)
|
||||||
|
|
||||||
newPolicy := engineiam.Policy{
|
newPolicy := engineiam.Policy{
|
||||||
Version: "2012-10-17",
|
Version: "2012-10-17",
|
||||||
|
@ -125,7 +125,7 @@ func TestBucketPolicy(t *testing.T) {
|
||||||
}},
|
}},
|
||||||
}
|
}
|
||||||
|
|
||||||
putBucketPolicy(hc, bktName, newPolicy, s3errors.ErrMalformedPolicy)
|
putBucketPolicy(hc, bktName, newPolicy, apierr.ErrMalformedPolicy)
|
||||||
|
|
||||||
newPolicy.Statement[0].Resource[0] = arnAwsPrefix + bktName + "/*"
|
newPolicy.Statement[0].Resource[0] = arnAwsPrefix + bktName + "/*"
|
||||||
putBucketPolicy(hc, bktName, newPolicy)
|
putBucketPolicy(hc, bktName, newPolicy)
|
||||||
|
@ -140,7 +140,7 @@ func TestBucketPolicyStatus(t *testing.T) {
|
||||||
|
|
||||||
createTestBucket(hc, bktName)
|
createTestBucket(hc, bktName)
|
||||||
|
|
||||||
getBucketPolicy(hc, bktName, s3errors.ErrNoSuchBucketPolicy)
|
getBucketPolicy(hc, bktName, apierr.ErrNoSuchBucketPolicy)
|
||||||
|
|
||||||
newPolicy := engineiam.Policy{
|
newPolicy := engineiam.Policy{
|
||||||
Version: "2012-10-17",
|
Version: "2012-10-17",
|
||||||
|
@ -152,7 +152,7 @@ func TestBucketPolicyStatus(t *testing.T) {
|
||||||
}},
|
}},
|
||||||
}
|
}
|
||||||
|
|
||||||
putBucketPolicy(hc, bktName, newPolicy, s3errors.ErrMalformedPolicyNotPrincipal)
|
putBucketPolicy(hc, bktName, newPolicy, apierr.ErrMalformedPolicyNotPrincipal)
|
||||||
|
|
||||||
newPolicy.Statement[0].NotPrincipal = nil
|
newPolicy.Statement[0].NotPrincipal = nil
|
||||||
newPolicy.Statement[0].Principal = map[engineiam.PrincipalType][]string{engineiam.Wildcard: {}}
|
newPolicy.Statement[0].Principal = map[engineiam.PrincipalType][]string{engineiam.Wildcard: {}}
|
||||||
|
@ -221,7 +221,7 @@ func TestPutBucketPolicy(t *testing.T) {
|
||||||
assertStatus(hc.t, w, http.StatusOK)
|
assertStatus(hc.t, w, http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBucketPolicy(hc *handlerContext, bktName string, errCode ...s3errors.ErrorCode) engineiam.Policy {
|
func getBucketPolicy(hc *handlerContext, bktName string, errCode ...apierr.ErrorCode) engineiam.Policy {
|
||||||
w, r := prepareTestRequest(hc, bktName, "", nil)
|
w, r := prepareTestRequest(hc, bktName, "", nil)
|
||||||
hc.Handler().GetBucketPolicyHandler(w, r)
|
hc.Handler().GetBucketPolicyHandler(w, r)
|
||||||
|
|
||||||
|
@ -231,13 +231,13 @@ func getBucketPolicy(hc *handlerContext, bktName string, errCode ...s3errors.Err
|
||||||
err := json.NewDecoder(w.Result().Body).Decode(&policy)
|
err := json.NewDecoder(w.Result().Body).Decode(&policy)
|
||||||
require.NoError(hc.t, err)
|
require.NoError(hc.t, err)
|
||||||
} else {
|
} else {
|
||||||
assertS3Error(hc.t, w, s3errors.GetAPIError(errCode[0]))
|
assertS3Error(hc.t, w, apierr.GetAPIError(errCode[0]))
|
||||||
}
|
}
|
||||||
|
|
||||||
return policy
|
return policy
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBucketPolicyStatus(hc *handlerContext, bktName string, errCode ...s3errors.ErrorCode) PolicyStatus {
|
func getBucketPolicyStatus(hc *handlerContext, bktName string, errCode ...apierr.ErrorCode) PolicyStatus {
|
||||||
w, r := prepareTestRequest(hc, bktName, "", nil)
|
w, r := prepareTestRequest(hc, bktName, "", nil)
|
||||||
hc.Handler().GetBucketPolicyStatusHandler(w, r)
|
hc.Handler().GetBucketPolicyStatusHandler(w, r)
|
||||||
|
|
||||||
|
@ -247,13 +247,13 @@ func getBucketPolicyStatus(hc *handlerContext, bktName string, errCode ...s3erro
|
||||||
err := xml.NewDecoder(w.Result().Body).Decode(&policyStatus)
|
err := xml.NewDecoder(w.Result().Body).Decode(&policyStatus)
|
||||||
require.NoError(hc.t, err)
|
require.NoError(hc.t, err)
|
||||||
} else {
|
} else {
|
||||||
assertS3Error(hc.t, w, s3errors.GetAPIError(errCode[0]))
|
assertS3Error(hc.t, w, apierr.GetAPIError(errCode[0]))
|
||||||
}
|
}
|
||||||
|
|
||||||
return policyStatus
|
return policyStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
func putBucketPolicy(hc *handlerContext, bktName string, bktPolicy engineiam.Policy, errCode ...s3errors.ErrorCode) {
|
func putBucketPolicy(hc *handlerContext, bktName string, bktPolicy engineiam.Policy, errCode ...apierr.ErrorCode) {
|
||||||
body, err := json.Marshal(bktPolicy)
|
body, err := json.Marshal(bktPolicy)
|
||||||
require.NoError(hc.t, err)
|
require.NoError(hc.t, err)
|
||||||
|
|
||||||
|
@ -263,7 +263,7 @@ func putBucketPolicy(hc *handlerContext, bktName string, bktPolicy engineiam.Pol
|
||||||
if len(errCode) == 0 {
|
if len(errCode) == 0 {
|
||||||
assertStatus(hc.t, w, http.StatusOK)
|
assertStatus(hc.t, w, http.StatusOK)
|
||||||
} else {
|
} else {
|
||||||
assertS3Error(hc.t, w, s3errors.GetAPIError(errCode[0]))
|
assertS3Error(hc.t, w, apierr.GetAPIError(errCode[0]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,9 +312,9 @@ func createBucket(hc *handlerContext, bktName string) *createBucketInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createBucketAssertS3Error(hc *handlerContext, bktName string, box *accessbox.Box, code s3errors.ErrorCode) {
|
func createBucketAssertS3Error(hc *handlerContext, bktName string, box *accessbox.Box, code apierr.ErrorCode) {
|
||||||
w := createBucketBase(hc, bktName, box)
|
w := createBucketBase(hc, bktName, box)
|
||||||
assertS3Error(hc.t, w, s3errors.GetAPIError(code))
|
assertS3Error(hc.t, w, apierr.GetAPIError(code))
|
||||||
}
|
}
|
||||||
|
|
||||||
func createBucketBase(hc *handlerContext, bktName string, box *accessbox.Box) *httptest.ResponseRecorder {
|
func createBucketBase(hc *handlerContext, bktName string, box *accessbox.Box) *httptest.ResponseRecorder {
|
||||||
|
@ -330,9 +330,9 @@ func putBucketACL(hc *handlerContext, bktName string, box *accessbox.Box, header
|
||||||
assertStatus(hc.t, w, http.StatusOK)
|
assertStatus(hc.t, w, http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
func putBucketACLAssertS3Error(hc *handlerContext, bktName string, box *accessbox.Box, header map[string]string, body *AccessControlPolicy, code s3errors.ErrorCode) {
|
func putBucketACLAssertS3Error(hc *handlerContext, bktName string, box *accessbox.Box, header map[string]string, body *AccessControlPolicy, code apierr.ErrorCode) {
|
||||||
w := putBucketACLBase(hc, bktName, box, header, body)
|
w := putBucketACLBase(hc, bktName, box, header, body)
|
||||||
assertS3Error(hc.t, w, s3errors.GetAPIError(code))
|
assertS3Error(hc.t, w, apierr.GetAPIError(code))
|
||||||
}
|
}
|
||||||
|
|
||||||
func putBucketACLBase(hc *handlerContext, bktName string, box *accessbox.Box, header map[string]string, body *AccessControlPolicy) *httptest.ResponseRecorder {
|
func putBucketACLBase(hc *handlerContext, bktName string, box *accessbox.Box, header map[string]string, body *AccessControlPolicy) *httptest.ResponseRecorder {
|
||||||
|
@ -360,9 +360,9 @@ func getBucketACLBase(hc *handlerContext, bktName string) *httptest.ResponseReco
|
||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
func putObjectACLAssertS3Error(hc *handlerContext, bktName, objName string, box *accessbox.Box, header map[string]string, body *AccessControlPolicy, code s3errors.ErrorCode) {
|
func putObjectACLAssertS3Error(hc *handlerContext, bktName, objName string, box *accessbox.Box, header map[string]string, body *AccessControlPolicy, code apierr.ErrorCode) {
|
||||||
w := putObjectACLBase(hc, bktName, objName, box, header, body)
|
w := putObjectACLBase(hc, bktName, objName, box, header, body)
|
||||||
assertS3Error(hc.t, w, s3errors.GetAPIError(code))
|
assertS3Error(hc.t, w, apierr.GetAPIError(code))
|
||||||
}
|
}
|
||||||
|
|
||||||
func putObjectACLBase(hc *handlerContext, bktName, objName string, box *accessbox.Box, header map[string]string, body *AccessControlPolicy) *httptest.ResponseRecorder {
|
func putObjectACLBase(hc *handlerContext, bktName, objName string, box *accessbox.Box, header map[string]string, body *AccessControlPolicy) *httptest.ResponseRecorder {
|
||||||
|
@ -396,9 +396,9 @@ func putObjectWithHeaders(hc *handlerContext, bktName, objName string, headers m
|
||||||
return w.Header()
|
return w.Header()
|
||||||
}
|
}
|
||||||
|
|
||||||
func putObjectWithHeadersAssertS3Error(hc *handlerContext, bktName, objName string, headers map[string]string, code s3errors.ErrorCode) {
|
func putObjectWithHeadersAssertS3Error(hc *handlerContext, bktName, objName string, headers map[string]string, code apierr.ErrorCode) {
|
||||||
w := putObjectWithHeadersBase(hc, bktName, objName, headers, nil, nil)
|
w := putObjectWithHeadersBase(hc, bktName, objName, headers, nil, nil)
|
||||||
assertS3Error(hc.t, w, s3errors.GetAPIError(code))
|
assertS3Error(hc.t, w, apierr.GetAPIError(code))
|
||||||
}
|
}
|
||||||
|
|
||||||
func putObjectWithHeadersBase(hc *handlerContext, bktName, objName string, headers map[string]string, box *accessbox.Box, data []byte) *httptest.ResponseRecorder {
|
func putObjectWithHeadersBase(hc *handlerContext, bktName, objName string, headers map[string]string, box *accessbox.Box, data []byte) *httptest.ResponseRecorder {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
apiErrors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/encryption"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/encryption"
|
||||||
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
||||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||||
|
@ -131,7 +131,7 @@ func TestDeleteObjectsError(t *testing.T) {
|
||||||
addr.SetContainer(bktInfo.CID)
|
addr.SetContainer(bktInfo.CID)
|
||||||
addr.SetObject(nodeVersion.OID)
|
addr.SetObject(nodeVersion.OID)
|
||||||
|
|
||||||
expectedError := apiErrors.GetAPIError(apiErrors.ErrAccessDenied)
|
expectedError := apierr.GetAPIError(apierr.ErrAccessDenied)
|
||||||
hc.tp.SetObjectError(addr, expectedError)
|
hc.tp.SetObjectError(addr, expectedError)
|
||||||
|
|
||||||
w := deleteObjectsBase(hc, bktName, [][2]string{{objName, nodeVersion.OID.EncodeToString()}})
|
w := deleteObjectsBase(hc, bktName, [][2]string{{objName, nodeVersion.OID.EncodeToString()}})
|
||||||
|
@ -553,9 +553,9 @@ func checkNotFound(t *testing.T, hc *handlerContext, bktName, objName, version s
|
||||||
assertStatus(t, w, http.StatusNotFound)
|
assertStatus(t, w, http.StatusNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
func headObjectAssertS3Error(hc *handlerContext, bktName, objName, version string, code apiErrors.ErrorCode) {
|
func headObjectAssertS3Error(hc *handlerContext, bktName, objName, version string, code apierr.ErrorCode) {
|
||||||
w := headObjectBase(hc, bktName, objName, version)
|
w := headObjectBase(hc, bktName, objName, version)
|
||||||
assertS3Error(hc.t, w, apiErrors.GetAPIError(code))
|
assertS3Error(hc.t, w, apierr.GetAPIError(code))
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkFound(t *testing.T, hc *handlerContext, bktName, objName, version string) {
|
func checkFound(t *testing.T, hc *handlerContext, bktName, objName, version string) {
|
||||||
|
|
|
@ -2,7 +2,7 @@ package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
stderrors "errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -13,7 +13,7 @@ import (
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
||||||
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -89,7 +89,7 @@ func TestPreconditions(t *testing.T) {
|
||||||
name: "IfMatch false",
|
name: "IfMatch false",
|
||||||
info: newInfo(etag, today),
|
info: newInfo(etag, today),
|
||||||
args: &conditionalArgs{IfMatch: etag2},
|
args: &conditionalArgs{IfMatch: etag2},
|
||||||
expected: errors.GetAPIError(errors.ErrPreconditionFailed)},
|
expected: apierr.GetAPIError(apierr.ErrPreconditionFailed)},
|
||||||
{
|
{
|
||||||
name: "IfNoneMatch true",
|
name: "IfNoneMatch true",
|
||||||
info: newInfo(etag, today),
|
info: newInfo(etag, today),
|
||||||
|
@ -99,7 +99,7 @@ func TestPreconditions(t *testing.T) {
|
||||||
name: "IfNoneMatch false",
|
name: "IfNoneMatch false",
|
||||||
info: newInfo(etag, today),
|
info: newInfo(etag, today),
|
||||||
args: &conditionalArgs{IfNoneMatch: etag},
|
args: &conditionalArgs{IfNoneMatch: etag},
|
||||||
expected: errors.GetAPIError(errors.ErrNotModified)},
|
expected: apierr.GetAPIError(apierr.ErrNotModified)},
|
||||||
{
|
{
|
||||||
name: "IfModifiedSince true",
|
name: "IfModifiedSince true",
|
||||||
info: newInfo(etag, today),
|
info: newInfo(etag, today),
|
||||||
|
@ -109,7 +109,7 @@ func TestPreconditions(t *testing.T) {
|
||||||
name: "IfModifiedSince false",
|
name: "IfModifiedSince false",
|
||||||
info: newInfo(etag, yesterday),
|
info: newInfo(etag, yesterday),
|
||||||
args: &conditionalArgs{IfModifiedSince: &today},
|
args: &conditionalArgs{IfModifiedSince: &today},
|
||||||
expected: errors.GetAPIError(errors.ErrNotModified)},
|
expected: apierr.GetAPIError(apierr.ErrNotModified)},
|
||||||
{
|
{
|
||||||
name: "IfUnmodifiedSince true",
|
name: "IfUnmodifiedSince true",
|
||||||
info: newInfo(etag, yesterday),
|
info: newInfo(etag, yesterday),
|
||||||
|
@ -119,7 +119,7 @@ func TestPreconditions(t *testing.T) {
|
||||||
name: "IfUnmodifiedSince false",
|
name: "IfUnmodifiedSince false",
|
||||||
info: newInfo(etag, today),
|
info: newInfo(etag, today),
|
||||||
args: &conditionalArgs{IfUnmodifiedSince: &yesterday},
|
args: &conditionalArgs{IfUnmodifiedSince: &yesterday},
|
||||||
expected: errors.GetAPIError(errors.ErrPreconditionFailed)},
|
expected: apierr.GetAPIError(apierr.ErrPreconditionFailed)},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "IfMatch true, IfUnmodifiedSince false",
|
name: "IfMatch true, IfUnmodifiedSince false",
|
||||||
|
@ -131,19 +131,19 @@ func TestPreconditions(t *testing.T) {
|
||||||
name: "IfMatch false, IfUnmodifiedSince true",
|
name: "IfMatch false, IfUnmodifiedSince true",
|
||||||
info: newInfo(etag, yesterday),
|
info: newInfo(etag, yesterday),
|
||||||
args: &conditionalArgs{IfMatch: etag2, IfUnmodifiedSince: &today},
|
args: &conditionalArgs{IfMatch: etag2, IfUnmodifiedSince: &today},
|
||||||
expected: errors.GetAPIError(errors.ErrPreconditionFailed),
|
expected: apierr.GetAPIError(apierr.ErrPreconditionFailed),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "IfNoneMatch false, IfModifiedSince true",
|
name: "IfNoneMatch false, IfModifiedSince true",
|
||||||
info: newInfo(etag, today),
|
info: newInfo(etag, today),
|
||||||
args: &conditionalArgs{IfNoneMatch: etag, IfModifiedSince: &yesterday},
|
args: &conditionalArgs{IfNoneMatch: etag, IfModifiedSince: &yesterday},
|
||||||
expected: errors.GetAPIError(errors.ErrNotModified),
|
expected: apierr.GetAPIError(apierr.ErrNotModified),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "IfNoneMatch true, IfModifiedSince false",
|
name: "IfNoneMatch true, IfModifiedSince false",
|
||||||
info: newInfo(etag, yesterday),
|
info: newInfo(etag, yesterday),
|
||||||
args: &conditionalArgs{IfNoneMatch: etag2, IfModifiedSince: &today},
|
args: &conditionalArgs{IfNoneMatch: etag2, IfModifiedSince: &today},
|
||||||
expected: errors.GetAPIError(errors.ErrNotModified),
|
expected: apierr.GetAPIError(apierr.ErrNotModified),
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
@ -151,7 +151,7 @@ func TestPreconditions(t *testing.T) {
|
||||||
if tc.expected == nil {
|
if tc.expected == nil {
|
||||||
require.NoError(t, actual)
|
require.NoError(t, actual)
|
||||||
} else {
|
} else {
|
||||||
require.True(t, stderrors.Is(actual, tc.expected), tc.expected, actual)
|
require.True(t, errors.Is(actual, tc.expected), tc.expected, actual)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -193,8 +193,8 @@ func TestGetObject(t *testing.T) {
|
||||||
hc.tp.SetObjectError(addr, &apistatus.ObjectNotFound{})
|
hc.tp.SetObjectError(addr, &apistatus.ObjectNotFound{})
|
||||||
hc.tp.SetObjectError(objInfo.Address(), &apistatus.ObjectNotFound{})
|
hc.tp.SetObjectError(objInfo.Address(), &apistatus.ObjectNotFound{})
|
||||||
|
|
||||||
getObjectAssertS3Error(hc, bktName, objName, objInfo.VersionID(), errors.ErrNoSuchVersion)
|
getObjectAssertS3Error(hc, bktName, objName, objInfo.VersionID(), apierr.ErrNoSuchVersion)
|
||||||
getObjectAssertS3Error(hc, bktName, objName, emptyVersion, errors.ErrNoSuchKey)
|
getObjectAssertS3Error(hc, bktName, objName, emptyVersion, apierr.ErrNoSuchKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetObjectEnabledMD5(t *testing.T) {
|
func TestGetObjectEnabledMD5(t *testing.T) {
|
||||||
|
@ -236,9 +236,9 @@ func getObjectVersion(tc *handlerContext, bktName, objName, version string) []by
|
||||||
return content
|
return content
|
||||||
}
|
}
|
||||||
|
|
||||||
func getObjectAssertS3Error(hc *handlerContext, bktName, objName, version string, code errors.ErrorCode) {
|
func getObjectAssertS3Error(hc *handlerContext, bktName, objName, version string, code apierr.ErrorCode) {
|
||||||
w := getObjectBaseResponse(hc, bktName, objName, version)
|
w := getObjectBaseResponse(hc, bktName, objName, version)
|
||||||
assertS3Error(hc.t, w, errors.GetAPIError(code))
|
assertS3Error(hc.t, w, apierr.GetAPIError(code))
|
||||||
}
|
}
|
||||||
|
|
||||||
func getObjectBaseResponse(hc *handlerContext, bktName, objName, version string) *httptest.ResponseRecorder {
|
func getObjectBaseResponse(hc *handlerContext, bktName, objName, version string) *httptest.ResponseRecorder {
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||||
s3errors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||||
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
||||||
|
@ -95,8 +95,8 @@ func TestHeadObject(t *testing.T) {
|
||||||
hc.tp.SetObjectError(addr, &apistatus.ObjectNotFound{})
|
hc.tp.SetObjectError(addr, &apistatus.ObjectNotFound{})
|
||||||
hc.tp.SetObjectError(objInfo.Address(), &apistatus.ObjectNotFound{})
|
hc.tp.SetObjectError(objInfo.Address(), &apistatus.ObjectNotFound{})
|
||||||
|
|
||||||
headObjectAssertS3Error(hc, bktName, objName, objInfo.VersionID(), s3errors.ErrNoSuchVersion)
|
headObjectAssertS3Error(hc, bktName, objName, objInfo.VersionID(), apierr.ErrNoSuchVersion)
|
||||||
headObjectAssertS3Error(hc, bktName, objName, emptyVersion, s3errors.ErrNoSuchKey)
|
headObjectAssertS3Error(hc, bktName, objName, emptyVersion, apierr.ErrNoSuchKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIsAvailableToResolve(t *testing.T) {
|
func TestIsAvailableToResolve(t *testing.T) {
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
apiErr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
)
|
)
|
||||||
|
@ -52,7 +52,7 @@ func (h *handler) PutBucketLifecycleHandler(w http.ResponseWriter, r *http.Reque
|
||||||
// Content-Md5 is required and should be set
|
// Content-Md5 is required and should be set
|
||||||
// https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycleConfiguration.html
|
// https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycleConfiguration.html
|
||||||
if _, ok := r.Header[api.ContentMD5]; !ok {
|
if _, ok := r.Header[api.ContentMD5]; !ok {
|
||||||
h.logAndSendError(w, "missing Content-MD5", reqInfo, apiErr.GetAPIError(apiErr.ErrMissingContentMD5))
|
h.logAndSendError(w, "missing Content-MD5", reqInfo, apierr.GetAPIError(apierr.ErrMissingContentMD5))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,12 +64,12 @@ func (h *handler) PutBucketLifecycleHandler(w http.ResponseWriter, r *http.Reque
|
||||||
|
|
||||||
cfg := new(data.LifecycleConfiguration)
|
cfg := new(data.LifecycleConfiguration)
|
||||||
if err = h.cfg.NewXMLDecoder(tee).Decode(cfg); err != nil {
|
if err = h.cfg.NewXMLDecoder(tee).Decode(cfg); err != nil {
|
||||||
h.logAndSendError(w, "could not decode body", reqInfo, fmt.Errorf("%w: %s", apiErr.GetAPIError(apiErr.ErrMalformedXML), err.Error()))
|
h.logAndSendError(w, "could not decode body", reqInfo, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrMalformedXML), err.Error()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = checkLifecycleConfiguration(cfg); err != nil {
|
if err = checkLifecycleConfiguration(cfg); err != nil {
|
||||||
h.logAndSendError(w, "invalid lifecycle configuration", reqInfo, fmt.Errorf("%w: %s", apiErr.GetAPIError(apiErr.ErrMalformedXML), err.Error()))
|
h.logAndSendError(w, "invalid lifecycle configuration", reqInfo, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrMalformedXML), err.Error()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
apiErrors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"github.com/mr-tron/base58"
|
"github.com/mr-tron/base58"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -340,7 +340,7 @@ func TestPutBucketLifecycleConfiguration(t *testing.T) {
|
||||||
} {
|
} {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
if tc.error {
|
if tc.error {
|
||||||
putBucketLifecycleConfigurationErr(hc, bktName, tc.body, apiErrors.GetAPIError(apiErrors.ErrMalformedXML))
|
putBucketLifecycleConfigurationErr(hc, bktName, tc.body, apierr.GetAPIError(apierr.ErrMalformedXML))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,7 +350,7 @@ func TestPutBucketLifecycleConfiguration(t *testing.T) {
|
||||||
require.Equal(t, *tc.body, *cfg)
|
require.Equal(t, *tc.body, *cfg)
|
||||||
|
|
||||||
deleteBucketLifecycleConfiguration(hc, bktName)
|
deleteBucketLifecycleConfiguration(hc, bktName)
|
||||||
getBucketLifecycleConfigurationErr(hc, bktName, apiErrors.GetAPIError(apiErrors.ErrNoSuchLifecycleConfiguration))
|
getBucketLifecycleConfigurationErr(hc, bktName, apierr.GetAPIError(apierr.ErrNoSuchLifecycleConfiguration))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -374,17 +374,17 @@ func TestPutBucketLifecycleInvalidMD5(t *testing.T) {
|
||||||
|
|
||||||
w, r := prepareTestRequest(hc, bktName, "", lifecycle)
|
w, r := prepareTestRequest(hc, bktName, "", lifecycle)
|
||||||
hc.Handler().PutBucketLifecycleHandler(w, r)
|
hc.Handler().PutBucketLifecycleHandler(w, r)
|
||||||
assertS3Error(hc.t, w, apiErrors.GetAPIError(apiErrors.ErrMissingContentMD5))
|
assertS3Error(hc.t, w, apierr.GetAPIError(apierr.ErrMissingContentMD5))
|
||||||
|
|
||||||
w, r = prepareTestRequest(hc, bktName, "", lifecycle)
|
w, r = prepareTestRequest(hc, bktName, "", lifecycle)
|
||||||
r.Header.Set(api.ContentMD5, "")
|
r.Header.Set(api.ContentMD5, "")
|
||||||
hc.Handler().PutBucketLifecycleHandler(w, r)
|
hc.Handler().PutBucketLifecycleHandler(w, r)
|
||||||
assertS3Error(hc.t, w, apiErrors.GetAPIError(apiErrors.ErrInvalidDigest))
|
assertS3Error(hc.t, w, apierr.GetAPIError(apierr.ErrInvalidDigest))
|
||||||
|
|
||||||
w, r = prepareTestRequest(hc, bktName, "", lifecycle)
|
w, r = prepareTestRequest(hc, bktName, "", lifecycle)
|
||||||
r.Header.Set(api.ContentMD5, "some-hash")
|
r.Header.Set(api.ContentMD5, "some-hash")
|
||||||
hc.Handler().PutBucketLifecycleHandler(w, r)
|
hc.Handler().PutBucketLifecycleHandler(w, r)
|
||||||
assertS3Error(hc.t, w, apiErrors.GetAPIError(apiErrors.ErrInvalidDigest))
|
assertS3Error(hc.t, w, apierr.GetAPIError(apierr.ErrInvalidDigest))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPutBucketLifecycleInvalidXML(t *testing.T) {
|
func TestPutBucketLifecycleInvalidXML(t *testing.T) {
|
||||||
|
@ -396,7 +396,7 @@ func TestPutBucketLifecycleInvalidXML(t *testing.T) {
|
||||||
w, r := prepareTestRequest(hc, bktName, "", &data.CORSConfiguration{})
|
w, r := prepareTestRequest(hc, bktName, "", &data.CORSConfiguration{})
|
||||||
r.Header.Set(api.ContentMD5, "")
|
r.Header.Set(api.ContentMD5, "")
|
||||||
hc.Handler().PutBucketLifecycleHandler(w, r)
|
hc.Handler().PutBucketLifecycleHandler(w, r)
|
||||||
assertS3Error(hc.t, w, apiErrors.GetAPIError(apiErrors.ErrMalformedXML))
|
assertS3Error(hc.t, w, apierr.GetAPIError(apierr.ErrMalformedXML))
|
||||||
}
|
}
|
||||||
|
|
||||||
func putBucketLifecycleConfiguration(hc *handlerContext, bktName string, cfg *data.LifecycleConfiguration) {
|
func putBucketLifecycleConfiguration(hc *handlerContext, bktName string, cfg *data.LifecycleConfiguration) {
|
||||||
|
@ -404,7 +404,7 @@ func putBucketLifecycleConfiguration(hc *handlerContext, bktName string, cfg *da
|
||||||
assertStatus(hc.t, w, http.StatusOK)
|
assertStatus(hc.t, w, http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
func putBucketLifecycleConfigurationErr(hc *handlerContext, bktName string, cfg *data.LifecycleConfiguration, err apiErrors.Error) {
|
func putBucketLifecycleConfigurationErr(hc *handlerContext, bktName string, cfg *data.LifecycleConfiguration, err apierr.Error) {
|
||||||
w := putBucketLifecycleConfigurationBase(hc, bktName, cfg)
|
w := putBucketLifecycleConfigurationBase(hc, bktName, cfg)
|
||||||
assertS3Error(hc.t, w, err)
|
assertS3Error(hc.t, w, err)
|
||||||
}
|
}
|
||||||
|
@ -430,7 +430,7 @@ func getBucketLifecycleConfiguration(hc *handlerContext, bktName string) *data.L
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBucketLifecycleConfigurationErr(hc *handlerContext, bktName string, err apiErrors.Error) {
|
func getBucketLifecycleConfigurationErr(hc *handlerContext, bktName string, err apierr.Error) {
|
||||||
w := getBucketLifecycleConfigurationBase(hc, bktName)
|
w := getBucketLifecycleConfigurationBase(hc, bktName)
|
||||||
assertS3Error(hc.t, w, err)
|
assertS3Error(hc.t, w, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
apiErrors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
)
|
)
|
||||||
|
@ -36,7 +36,7 @@ func (h *handler) PutBucketObjectLockConfigHandler(w http.ResponseWriter, r *htt
|
||||||
|
|
||||||
if !bktInfo.ObjectLockEnabled {
|
if !bktInfo.ObjectLockEnabled {
|
||||||
h.logAndSendError(w, "couldn't put object locking configuration", reqInfo,
|
h.logAndSendError(w, "couldn't put object locking configuration", reqInfo,
|
||||||
apiErrors.GetAPIError(apiErrors.ErrObjectLockConfigurationNotAllowed))
|
apierr.GetAPIError(apierr.ErrObjectLockConfigurationNotAllowed))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ func (h *handler) GetBucketObjectLockConfigHandler(w http.ResponseWriter, r *htt
|
||||||
|
|
||||||
if !bktInfo.ObjectLockEnabled {
|
if !bktInfo.ObjectLockEnabled {
|
||||||
h.logAndSendError(w, "object lock disabled", reqInfo,
|
h.logAndSendError(w, "object lock disabled", reqInfo,
|
||||||
apiErrors.GetAPIError(apiErrors.ErrObjectLockConfigurationNotFound))
|
apierr.GetAPIError(apierr.ErrObjectLockConfigurationNotFound))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ func (h *handler) PutObjectLegalHoldHandler(w http.ResponseWriter, r *http.Reque
|
||||||
|
|
||||||
if !bktInfo.ObjectLockEnabled {
|
if !bktInfo.ObjectLockEnabled {
|
||||||
h.logAndSendError(w, "object lock disabled", reqInfo,
|
h.logAndSendError(w, "object lock disabled", reqInfo,
|
||||||
apiErrors.GetAPIError(apiErrors.ErrObjectLockConfigurationNotFound))
|
apierr.GetAPIError(apierr.ErrObjectLockConfigurationNotFound))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +168,7 @@ func (h *handler) GetObjectLegalHoldHandler(w http.ResponseWriter, r *http.Reque
|
||||||
|
|
||||||
if !bktInfo.ObjectLockEnabled {
|
if !bktInfo.ObjectLockEnabled {
|
||||||
h.logAndSendError(w, "object lock disabled", reqInfo,
|
h.logAndSendError(w, "object lock disabled", reqInfo,
|
||||||
apiErrors.GetAPIError(apiErrors.ErrObjectLockConfigurationNotFound))
|
apierr.GetAPIError(apierr.ErrObjectLockConfigurationNotFound))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,7 +204,7 @@ func (h *handler) PutObjectRetentionHandler(w http.ResponseWriter, r *http.Reque
|
||||||
}
|
}
|
||||||
if !bktInfo.ObjectLockEnabled {
|
if !bktInfo.ObjectLockEnabled {
|
||||||
h.logAndSendError(w, "object lock disabled", reqInfo,
|
h.logAndSendError(w, "object lock disabled", reqInfo,
|
||||||
apiErrors.GetAPIError(apiErrors.ErrObjectLockConfigurationNotFound))
|
apierr.GetAPIError(apierr.ErrObjectLockConfigurationNotFound))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,7 +252,7 @@ func (h *handler) GetObjectRetentionHandler(w http.ResponseWriter, r *http.Reque
|
||||||
|
|
||||||
if !bktInfo.ObjectLockEnabled {
|
if !bktInfo.ObjectLockEnabled {
|
||||||
h.logAndSendError(w, "object lock disabled", reqInfo,
|
h.logAndSendError(w, "object lock disabled", reqInfo,
|
||||||
apiErrors.GetAPIError(apiErrors.ErrObjectLockConfigurationNotFound))
|
apierr.GetAPIError(apierr.ErrObjectLockConfigurationNotFound))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,7 +269,7 @@ func (h *handler) GetObjectRetentionHandler(w http.ResponseWriter, r *http.Reque
|
||||||
}
|
}
|
||||||
|
|
||||||
if !lockInfo.IsRetentionSet() {
|
if !lockInfo.IsRetentionSet() {
|
||||||
h.logAndSendError(w, "retention lock isn't set", reqInfo, apiErrors.GetAPIError(apiErrors.ErrNoSuchKey))
|
h.logAndSendError(w, "retention lock isn't set", reqInfo, apierr.GetAPIError(apierr.ErrNoSuchKey))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,7 +314,7 @@ func checkLockConfiguration(conf *data.ObjectLockConfiguration) error {
|
||||||
func formObjectLock(ctx context.Context, bktInfo *data.BucketInfo, defaultConfig *data.ObjectLockConfiguration, header http.Header) (*data.ObjectLock, error) {
|
func formObjectLock(ctx context.Context, bktInfo *data.BucketInfo, defaultConfig *data.ObjectLockConfiguration, header http.Header) (*data.ObjectLock, error) {
|
||||||
if !bktInfo.ObjectLockEnabled {
|
if !bktInfo.ObjectLockEnabled {
|
||||||
if existLockHeaders(header) {
|
if existLockHeaders(header) {
|
||||||
return nil, apiErrors.GetAPIError(apiErrors.ErrObjectLockConfigurationNotFound)
|
return nil, apierr.GetAPIError(apierr.ErrObjectLockConfigurationNotFound)
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -346,7 +346,7 @@ func formObjectLock(ctx context.Context, bktInfo *data.BucketInfo, defaultConfig
|
||||||
until := header.Get(api.AmzObjectLockRetainUntilDate)
|
until := header.Get(api.AmzObjectLockRetainUntilDate)
|
||||||
|
|
||||||
if mode != "" && until == "" || mode == "" && until != "" {
|
if mode != "" && until == "" || mode == "" && until != "" {
|
||||||
return nil, apiErrors.GetAPIError(apiErrors.ErrObjectLockInvalidHeaders)
|
return nil, apierr.GetAPIError(apierr.ErrObjectLockInvalidHeaders)
|
||||||
}
|
}
|
||||||
|
|
||||||
if mode != "" {
|
if mode != "" {
|
||||||
|
@ -355,7 +355,7 @@ func formObjectLock(ctx context.Context, bktInfo *data.BucketInfo, defaultConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
if mode != complianceMode && mode != governanceMode {
|
if mode != complianceMode && mode != governanceMode {
|
||||||
return nil, apiErrors.GetAPIError(apiErrors.ErrUnknownWORMModeDirective)
|
return nil, apierr.GetAPIError(apierr.ErrUnknownWORMModeDirective)
|
||||||
}
|
}
|
||||||
|
|
||||||
objectLock.Retention.IsCompliance = mode == complianceMode
|
objectLock.Retention.IsCompliance = mode == complianceMode
|
||||||
|
@ -364,7 +364,7 @@ func formObjectLock(ctx context.Context, bktInfo *data.BucketInfo, defaultConfig
|
||||||
if until != "" {
|
if until != "" {
|
||||||
retentionDate, err := time.Parse(time.RFC3339, until)
|
retentionDate, err := time.Parse(time.RFC3339, until)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, apiErrors.GetAPIError(apiErrors.ErrInvalidRetentionDate)
|
return nil, apierr.GetAPIError(apierr.ErrInvalidRetentionDate)
|
||||||
}
|
}
|
||||||
if objectLock.Retention == nil {
|
if objectLock.Retention == nil {
|
||||||
objectLock.Retention = &data.RetentionLock{}
|
objectLock.Retention = &data.RetentionLock{}
|
||||||
|
@ -382,7 +382,7 @@ func formObjectLock(ctx context.Context, bktInfo *data.BucketInfo, defaultConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
if objectLock.Retention.Until.Before(layer.TimeNow(ctx)) {
|
if objectLock.Retention.Until.Before(layer.TimeNow(ctx)) {
|
||||||
return nil, apiErrors.GetAPIError(apiErrors.ErrPastObjectLockRetainDate)
|
return nil, apierr.GetAPIError(apierr.ErrPastObjectLockRetainDate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,16 +397,16 @@ func existLockHeaders(header http.Header) bool {
|
||||||
|
|
||||||
func formObjectLockFromRetention(ctx context.Context, retention *data.Retention, header http.Header) (*data.ObjectLock, error) {
|
func formObjectLockFromRetention(ctx context.Context, retention *data.Retention, header http.Header) (*data.ObjectLock, error) {
|
||||||
if retention.Mode != governanceMode && retention.Mode != complianceMode {
|
if retention.Mode != governanceMode && retention.Mode != complianceMode {
|
||||||
return nil, apiErrors.GetAPIError(apiErrors.ErrMalformedXML)
|
return nil, apierr.GetAPIError(apierr.ErrMalformedXML)
|
||||||
}
|
}
|
||||||
|
|
||||||
retentionDate, err := time.Parse(time.RFC3339, retention.RetainUntilDate)
|
retentionDate, err := time.Parse(time.RFC3339, retention.RetainUntilDate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, apiErrors.GetAPIError(apiErrors.ErrMalformedXML)
|
return nil, apierr.GetAPIError(apierr.ErrMalformedXML)
|
||||||
}
|
}
|
||||||
|
|
||||||
if retentionDate.Before(layer.TimeNow(ctx)) {
|
if retentionDate.Before(layer.TimeNow(ctx)) {
|
||||||
return nil, apiErrors.GetAPIError(apiErrors.ErrPastObjectLockRetainDate)
|
return nil, apierr.GetAPIError(apierr.ErrPastObjectLockRetainDate)
|
||||||
}
|
}
|
||||||
|
|
||||||
var bypass bool
|
var bypass bool
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
apiErrors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/encryption"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/encryption"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -270,23 +270,23 @@ func TestPutBucketLockConfigurationHandler(t *testing.T) {
|
||||||
for _, tc := range []struct {
|
for _, tc := range []struct {
|
||||||
name string
|
name string
|
||||||
bucket string
|
bucket string
|
||||||
expectedError apiErrors.Error
|
expectedError apierr.Error
|
||||||
noError bool
|
noError bool
|
||||||
configuration *data.ObjectLockConfiguration
|
configuration *data.ObjectLockConfiguration
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "bkt not found",
|
name: "bkt not found",
|
||||||
expectedError: apiErrors.GetAPIError(apiErrors.ErrNoSuchBucket),
|
expectedError: apierr.GetAPIError(apierr.ErrNoSuchBucket),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "bkt lock disabled",
|
name: "bkt lock disabled",
|
||||||
bucket: bktLockDisabled,
|
bucket: bktLockDisabled,
|
||||||
expectedError: apiErrors.GetAPIError(apiErrors.ErrObjectLockConfigurationNotAllowed),
|
expectedError: apierr.GetAPIError(apierr.ErrObjectLockConfigurationNotAllowed),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "invalid configuration",
|
name: "invalid configuration",
|
||||||
bucket: bktLockEnabled,
|
bucket: bktLockEnabled,
|
||||||
expectedError: apiErrors.GetAPIError(apiErrors.ErrInternalError),
|
expectedError: apierr.GetAPIError(apierr.ErrInternalError),
|
||||||
configuration: &data.ObjectLockConfiguration{ObjectLockEnabled: "dummy"},
|
configuration: &data.ObjectLockConfiguration{ObjectLockEnabled: "dummy"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -359,18 +359,18 @@ func TestGetBucketLockConfigurationHandler(t *testing.T) {
|
||||||
for _, tc := range []struct {
|
for _, tc := range []struct {
|
||||||
name string
|
name string
|
||||||
bucket string
|
bucket string
|
||||||
expectedError apiErrors.Error
|
expectedError apierr.Error
|
||||||
noError bool
|
noError bool
|
||||||
expectedConf *data.ObjectLockConfiguration
|
expectedConf *data.ObjectLockConfiguration
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "bkt not found",
|
name: "bkt not found",
|
||||||
expectedError: apiErrors.GetAPIError(apiErrors.ErrNoSuchBucket),
|
expectedError: apierr.GetAPIError(apierr.ErrNoSuchBucket),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "bkt lock disabled",
|
name: "bkt lock disabled",
|
||||||
bucket: bktLockDisabled,
|
bucket: bktLockDisabled,
|
||||||
expectedError: apiErrors.GetAPIError(apiErrors.ErrObjectLockConfigurationNotFound),
|
expectedError: apierr.GetAPIError(apierr.ErrObjectLockConfigurationNotFound),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "bkt lock enabled empty default",
|
name: "bkt lock enabled empty default",
|
||||||
|
@ -407,7 +407,7 @@ func TestGetBucketLockConfigurationHandler(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertS3Error(t *testing.T, w *httptest.ResponseRecorder, expectedError apiErrors.Error) {
|
func assertS3Error(t *testing.T, w *httptest.ResponseRecorder, expectedError apierr.Error) {
|
||||||
actualErrorResponse := &middleware.ErrorResponse{}
|
actualErrorResponse := &middleware.ErrorResponse{}
|
||||||
err := xml.NewDecoder(w.Result().Body).Decode(actualErrorResponse)
|
err := xml.NewDecoder(w.Result().Body).Decode(actualErrorResponse)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -415,7 +415,7 @@ func assertS3Error(t *testing.T, w *httptest.ResponseRecorder, expectedError api
|
||||||
require.Equal(t, expectedError.HTTPStatusCode, w.Code)
|
require.Equal(t, expectedError.HTTPStatusCode, w.Code)
|
||||||
require.Equal(t, expectedError.Code, actualErrorResponse.Code)
|
require.Equal(t, expectedError.Code, actualErrorResponse.Code)
|
||||||
|
|
||||||
if expectedError.ErrCode != apiErrors.ErrInternalError {
|
if expectedError.ErrCode != apierr.ErrInternalError {
|
||||||
require.Equal(t, expectedError.Description, actualErrorResponse.Message)
|
require.Equal(t, expectedError.Description, actualErrorResponse.Message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -473,33 +473,33 @@ func TestObjectRetention(t *testing.T) {
|
||||||
objName := "obj-for-retention"
|
objName := "obj-for-retention"
|
||||||
createTestObject(hc, bktInfo, objName, encryption.Params{})
|
createTestObject(hc, bktInfo, objName, encryption.Params{})
|
||||||
|
|
||||||
getObjectRetention(hc, bktName, objName, nil, apiErrors.ErrNoSuchKey)
|
getObjectRetention(hc, bktName, objName, nil, apierr.ErrNoSuchKey)
|
||||||
|
|
||||||
retention := &data.Retention{Mode: governanceMode, RetainUntilDate: time.Now().Add(time.Minute).UTC().Format(time.RFC3339)}
|
retention := &data.Retention{Mode: governanceMode, RetainUntilDate: time.Now().Add(time.Minute).UTC().Format(time.RFC3339)}
|
||||||
putObjectRetention(hc, bktName, objName, retention, false, 0)
|
putObjectRetention(hc, bktName, objName, retention, false, 0)
|
||||||
getObjectRetention(hc, bktName, objName, retention, 0)
|
getObjectRetention(hc, bktName, objName, retention, 0)
|
||||||
|
|
||||||
retention = &data.Retention{Mode: governanceMode, RetainUntilDate: time.Now().UTC().Add(time.Minute).Format(time.RFC3339)}
|
retention = &data.Retention{Mode: governanceMode, RetainUntilDate: time.Now().UTC().Add(time.Minute).Format(time.RFC3339)}
|
||||||
putObjectRetention(hc, bktName, objName, retention, false, apiErrors.ErrInternalError)
|
putObjectRetention(hc, bktName, objName, retention, false, apierr.ErrInternalError)
|
||||||
|
|
||||||
retention = &data.Retention{Mode: complianceMode, RetainUntilDate: time.Now().Add(time.Minute).UTC().Format(time.RFC3339)}
|
retention = &data.Retention{Mode: complianceMode, RetainUntilDate: time.Now().Add(time.Minute).UTC().Format(time.RFC3339)}
|
||||||
putObjectRetention(hc, bktName, objName, retention, true, 0)
|
putObjectRetention(hc, bktName, objName, retention, true, 0)
|
||||||
getObjectRetention(hc, bktName, objName, retention, 0)
|
getObjectRetention(hc, bktName, objName, retention, 0)
|
||||||
|
|
||||||
putObjectRetention(hc, bktName, objName, retention, true, apiErrors.ErrInternalError)
|
putObjectRetention(hc, bktName, objName, retention, true, apierr.ErrInternalError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getObjectRetention(hc *handlerContext, bktName, objName string, retention *data.Retention, errCode apiErrors.ErrorCode) {
|
func getObjectRetention(hc *handlerContext, bktName, objName string, retention *data.Retention, errCode apierr.ErrorCode) {
|
||||||
w, r := prepareTestRequest(hc, bktName, objName, nil)
|
w, r := prepareTestRequest(hc, bktName, objName, nil)
|
||||||
hc.Handler().GetObjectRetentionHandler(w, r)
|
hc.Handler().GetObjectRetentionHandler(w, r)
|
||||||
if errCode == 0 {
|
if errCode == 0 {
|
||||||
assertRetention(hc.t, w, retention)
|
assertRetention(hc.t, w, retention)
|
||||||
} else {
|
} else {
|
||||||
assertS3Error(hc.t, w, apiErrors.GetAPIError(errCode))
|
assertS3Error(hc.t, w, apierr.GetAPIError(errCode))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func putObjectRetention(hc *handlerContext, bktName, objName string, retention *data.Retention, byPass bool, errCode apiErrors.ErrorCode) {
|
func putObjectRetention(hc *handlerContext, bktName, objName string, retention *data.Retention, byPass bool, errCode apierr.ErrorCode) {
|
||||||
w, r := prepareTestRequest(hc, bktName, objName, retention)
|
w, r := prepareTestRequest(hc, bktName, objName, retention)
|
||||||
if byPass {
|
if byPass {
|
||||||
r.Header.Set(api.AmzBypassGovernanceRetention, strconv.FormatBool(true))
|
r.Header.Set(api.AmzBypassGovernanceRetention, strconv.FormatBool(true))
|
||||||
|
@ -508,7 +508,7 @@ func putObjectRetention(hc *handlerContext, bktName, objName string, retention *
|
||||||
if errCode == 0 {
|
if errCode == 0 {
|
||||||
assertStatus(hc.t, w, http.StatusOK)
|
assertStatus(hc.t, w, http.StatusOK)
|
||||||
} else {
|
} else {
|
||||||
assertS3Error(hc.t, w, apiErrors.GetAPIError(errCode))
|
assertS3Error(hc.t, w, apierr.GetAPIError(errCode))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -572,37 +572,37 @@ func TestPutLockErrors(t *testing.T) {
|
||||||
createTestBucketWithLock(hc, bktName, nil)
|
createTestBucketWithLock(hc, bktName, nil)
|
||||||
|
|
||||||
headers := map[string]string{api.AmzObjectLockMode: complianceMode}
|
headers := map[string]string{api.AmzObjectLockMode: complianceMode}
|
||||||
putObjectWithLockFailed(t, hc, bktName, objName, headers, apiErrors.ErrObjectLockInvalidHeaders)
|
putObjectWithLockFailed(t, hc, bktName, objName, headers, apierr.ErrObjectLockInvalidHeaders)
|
||||||
|
|
||||||
delete(headers, api.AmzObjectLockMode)
|
delete(headers, api.AmzObjectLockMode)
|
||||||
headers[api.AmzObjectLockRetainUntilDate] = time.Now().Add(time.Minute).Format(time.RFC3339)
|
headers[api.AmzObjectLockRetainUntilDate] = time.Now().Add(time.Minute).Format(time.RFC3339)
|
||||||
putObjectWithLockFailed(t, hc, bktName, objName, headers, apiErrors.ErrObjectLockInvalidHeaders)
|
putObjectWithLockFailed(t, hc, bktName, objName, headers, apierr.ErrObjectLockInvalidHeaders)
|
||||||
|
|
||||||
headers[api.AmzObjectLockMode] = "dummy"
|
headers[api.AmzObjectLockMode] = "dummy"
|
||||||
putObjectWithLockFailed(t, hc, bktName, objName, headers, apiErrors.ErrUnknownWORMModeDirective)
|
putObjectWithLockFailed(t, hc, bktName, objName, headers, apierr.ErrUnknownWORMModeDirective)
|
||||||
|
|
||||||
headers[api.AmzObjectLockMode] = complianceMode
|
headers[api.AmzObjectLockMode] = complianceMode
|
||||||
headers[api.AmzObjectLockRetainUntilDate] = time.Now().Format(time.RFC3339)
|
headers[api.AmzObjectLockRetainUntilDate] = time.Now().Format(time.RFC3339)
|
||||||
putObjectWithLockFailed(t, hc, bktName, objName, headers, apiErrors.ErrPastObjectLockRetainDate)
|
putObjectWithLockFailed(t, hc, bktName, objName, headers, apierr.ErrPastObjectLockRetainDate)
|
||||||
|
|
||||||
headers[api.AmzObjectLockRetainUntilDate] = "dummy"
|
headers[api.AmzObjectLockRetainUntilDate] = "dummy"
|
||||||
putObjectWithLockFailed(t, hc, bktName, objName, headers, apiErrors.ErrInvalidRetentionDate)
|
putObjectWithLockFailed(t, hc, bktName, objName, headers, apierr.ErrInvalidRetentionDate)
|
||||||
|
|
||||||
putObject(hc, bktName, objName)
|
putObject(hc, bktName, objName)
|
||||||
|
|
||||||
retention := &data.Retention{Mode: governanceMode}
|
retention := &data.Retention{Mode: governanceMode}
|
||||||
putObjectRetentionFailed(t, hc, bktName, objName, retention, apiErrors.ErrMalformedXML)
|
putObjectRetentionFailed(t, hc, bktName, objName, retention, apierr.ErrMalformedXML)
|
||||||
|
|
||||||
retention.Mode = "dummy"
|
retention.Mode = "dummy"
|
||||||
retention.RetainUntilDate = time.Now().Add(time.Minute).UTC().Format(time.RFC3339)
|
retention.RetainUntilDate = time.Now().Add(time.Minute).UTC().Format(time.RFC3339)
|
||||||
putObjectRetentionFailed(t, hc, bktName, objName, retention, apiErrors.ErrMalformedXML)
|
putObjectRetentionFailed(t, hc, bktName, objName, retention, apierr.ErrMalformedXML)
|
||||||
|
|
||||||
retention.Mode = governanceMode
|
retention.Mode = governanceMode
|
||||||
retention.RetainUntilDate = time.Now().UTC().Format(time.RFC3339)
|
retention.RetainUntilDate = time.Now().UTC().Format(time.RFC3339)
|
||||||
putObjectRetentionFailed(t, hc, bktName, objName, retention, apiErrors.ErrPastObjectLockRetainDate)
|
putObjectRetentionFailed(t, hc, bktName, objName, retention, apierr.ErrPastObjectLockRetainDate)
|
||||||
}
|
}
|
||||||
|
|
||||||
func putObjectWithLockFailed(t *testing.T, hc *handlerContext, bktName, objName string, headers map[string]string, errCode apiErrors.ErrorCode) {
|
func putObjectWithLockFailed(t *testing.T, hc *handlerContext, bktName, objName string, headers map[string]string, errCode apierr.ErrorCode) {
|
||||||
w, r := prepareTestRequest(hc, bktName, objName, nil)
|
w, r := prepareTestRequest(hc, bktName, objName, nil)
|
||||||
|
|
||||||
for key, val := range headers {
|
for key, val := range headers {
|
||||||
|
@ -610,13 +610,13 @@ func putObjectWithLockFailed(t *testing.T, hc *handlerContext, bktName, objName
|
||||||
}
|
}
|
||||||
|
|
||||||
hc.Handler().PutObjectHandler(w, r)
|
hc.Handler().PutObjectHandler(w, r)
|
||||||
assertS3Error(t, w, apiErrors.GetAPIError(errCode))
|
assertS3Error(t, w, apierr.GetAPIError(errCode))
|
||||||
}
|
}
|
||||||
|
|
||||||
func putObjectRetentionFailed(t *testing.T, hc *handlerContext, bktName, objName string, retention *data.Retention, errCode apiErrors.ErrorCode) {
|
func putObjectRetentionFailed(t *testing.T, hc *handlerContext, bktName, objName string, retention *data.Retention, errCode apierr.ErrorCode) {
|
||||||
w, r := prepareTestRequest(hc, bktName, objName, retention)
|
w, r := prepareTestRequest(hc, bktName, objName, retention)
|
||||||
hc.Handler().PutObjectRetentionHandler(w, r)
|
hc.Handler().PutObjectRetentionHandler(w, r)
|
||||||
assertS3Error(t, w, apiErrors.GetAPIError(errCode))
|
assertS3Error(t, w, apierr.GetAPIError(errCode))
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertRetentionApproximate(t *testing.T, w *httptest.ResponseRecorder, retention *data.Retention, delta float64) {
|
func assertRetentionApproximate(t *testing.T, w *httptest.ResponseRecorder, retention *data.Retention, delta float64) {
|
||||||
|
|
|
@ -15,7 +15,7 @@ import (
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
s3Errors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/encryption"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/encryption"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||||
|
@ -40,7 +40,7 @@ func TestMultipartUploadInvalidPart(t *testing.T) {
|
||||||
etag1, _ := uploadPart(hc, bktName, objName, multipartUpload.UploadID, 1, partSize)
|
etag1, _ := uploadPart(hc, bktName, objName, multipartUpload.UploadID, 1, partSize)
|
||||||
etag2, _ := uploadPart(hc, bktName, objName, multipartUpload.UploadID, 2, partSize)
|
etag2, _ := uploadPart(hc, bktName, objName, multipartUpload.UploadID, 2, partSize)
|
||||||
w := completeMultipartUploadBase(hc, bktName, objName, multipartUpload.UploadID, []string{etag1, etag2})
|
w := completeMultipartUploadBase(hc, bktName, objName, multipartUpload.UploadID, []string{etag1, etag2})
|
||||||
assertS3Error(hc.t, w, s3Errors.GetAPIError(s3Errors.ErrEntityTooSmall))
|
assertS3Error(hc.t, w, apierr.GetAPIError(apierr.ErrEntityTooSmall))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeleteMultipartAllParts(t *testing.T) {
|
func TestDeleteMultipartAllParts(t *testing.T) {
|
||||||
|
@ -104,7 +104,7 @@ func TestMultipartReUploadPart(t *testing.T) {
|
||||||
require.Equal(t, etag2, list.Parts[1].ETag)
|
require.Equal(t, etag2, list.Parts[1].ETag)
|
||||||
|
|
||||||
w := completeMultipartUploadBase(hc, bktName, objName, uploadInfo.UploadID, []string{etag1, etag2})
|
w := completeMultipartUploadBase(hc, bktName, objName, uploadInfo.UploadID, []string{etag1, etag2})
|
||||||
assertS3Error(hc.t, w, s3Errors.GetAPIError(s3Errors.ErrEntityTooSmall))
|
assertS3Error(hc.t, w, apierr.GetAPIError(apierr.ErrEntityTooSmall))
|
||||||
|
|
||||||
etag1, data1 := uploadPart(hc, bktName, objName, uploadInfo.UploadID, 1, partSizeFirst)
|
etag1, data1 := uploadPart(hc, bktName, objName, uploadInfo.UploadID, 1, partSizeFirst)
|
||||||
etag2, data2 := uploadPart(hc, bktName, objName, uploadInfo.UploadID, 2, partSizeLast)
|
etag2, data2 := uploadPart(hc, bktName, objName, uploadInfo.UploadID, 2, partSizeLast)
|
||||||
|
@ -521,7 +521,7 @@ func TestUploadPartCheckContentSHA256(t *testing.T) {
|
||||||
r.Header.Set(api.AmzContentSha256, tc.hash)
|
r.Header.Set(api.AmzContentSha256, tc.hash)
|
||||||
hc.Handler().UploadPartHandler(w, r)
|
hc.Handler().UploadPartHandler(w, r)
|
||||||
if tc.error {
|
if tc.error {
|
||||||
assertS3Error(t, w, s3Errors.GetAPIError(s3Errors.ErrContentSHA256Mismatch))
|
assertS3Error(t, w, apierr.GetAPIError(apierr.ErrContentSHA256Mismatch))
|
||||||
|
|
||||||
list := listParts(hc, bktName, objName, multipartUpload.UploadID, "0", http.StatusOK)
|
list := listParts(hc, bktName, objName, multipartUpload.UploadID, "0", http.StatusOK)
|
||||||
require.Len(t, list.Parts, 1)
|
require.Len(t, list.Parts, 1)
|
||||||
|
|
|
@ -18,7 +18,7 @@ import (
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
s3errors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -50,7 +50,7 @@ func TestPatch(t *testing.T) {
|
||||||
name string
|
name string
|
||||||
rng string
|
rng string
|
||||||
headers map[string]string
|
headers map[string]string
|
||||||
code s3errors.ErrorCode
|
code apierr.ErrorCode
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "success",
|
name: "success",
|
||||||
|
@ -63,22 +63,22 @@ func TestPatch(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "invalid range syntax",
|
name: "invalid range syntax",
|
||||||
rng: "bytes 0-2",
|
rng: "bytes 0-2",
|
||||||
code: s3errors.ErrInvalidRange,
|
code: apierr.ErrInvalidRange,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "invalid range length",
|
name: "invalid range length",
|
||||||
rng: "bytes 0-5/*",
|
rng: "bytes 0-5/*",
|
||||||
code: s3errors.ErrInvalidRangeLength,
|
code: apierr.ErrInvalidRangeLength,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "invalid range start",
|
name: "invalid range start",
|
||||||
rng: "bytes 20-22/*",
|
rng: "bytes 20-22/*",
|
||||||
code: s3errors.ErrRangeOutOfBounds,
|
code: apierr.ErrRangeOutOfBounds,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "range is too long",
|
name: "range is too long",
|
||||||
rng: "bytes 0-5368709120/*",
|
rng: "bytes 0-5368709120/*",
|
||||||
code: s3errors.ErrInvalidRange,
|
code: apierr.ErrInvalidRange,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "If-Unmodified-Since precondition are not satisfied",
|
name: "If-Unmodified-Since precondition are not satisfied",
|
||||||
|
@ -86,7 +86,7 @@ func TestPatch(t *testing.T) {
|
||||||
headers: map[string]string{
|
headers: map[string]string{
|
||||||
api.IfUnmodifiedSince: created.Add(-24 * time.Hour).Format(http.TimeFormat),
|
api.IfUnmodifiedSince: created.Add(-24 * time.Hour).Format(http.TimeFormat),
|
||||||
},
|
},
|
||||||
code: s3errors.ErrPreconditionFailed,
|
code: apierr.ErrPreconditionFailed,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "If-Match precondition are not satisfied",
|
name: "If-Match precondition are not satisfied",
|
||||||
|
@ -94,7 +94,7 @@ func TestPatch(t *testing.T) {
|
||||||
headers: map[string]string{
|
headers: map[string]string{
|
||||||
api.IfMatch: "etag",
|
api.IfMatch: "etag",
|
||||||
},
|
},
|
||||||
code: s3errors.ErrPreconditionFailed,
|
code: apierr.ErrPreconditionFailed,
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
@ -377,7 +377,7 @@ func TestPatchEncryptedObject(t *testing.T) {
|
||||||
tc.Handler().PutObjectHandler(w, r)
|
tc.Handler().PutObjectHandler(w, r)
|
||||||
assertStatus(t, w, http.StatusOK)
|
assertStatus(t, w, http.StatusOK)
|
||||||
|
|
||||||
patchObjectErr(t, tc, bktName, objName, "bytes 2-4/*", []byte("new"), nil, s3errors.ErrInternalError)
|
patchObjectErr(t, tc, bktName, objName, "bytes 2-4/*", []byte("new"), nil, apierr.ErrInternalError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPatchMissingHeaders(t *testing.T) {
|
func TestPatchMissingHeaders(t *testing.T) {
|
||||||
|
@ -393,13 +393,13 @@ func TestPatchMissingHeaders(t *testing.T) {
|
||||||
w = httptest.NewRecorder()
|
w = httptest.NewRecorder()
|
||||||
r = httptest.NewRequest(http.MethodPatch, defaultURL, strings.NewReader("new"))
|
r = httptest.NewRequest(http.MethodPatch, defaultURL, strings.NewReader("new"))
|
||||||
tc.Handler().PatchObjectHandler(w, r)
|
tc.Handler().PatchObjectHandler(w, r)
|
||||||
assertS3Error(t, w, s3errors.GetAPIError(s3errors.ErrMissingContentRange))
|
assertS3Error(t, w, apierr.GetAPIError(apierr.ErrMissingContentRange))
|
||||||
|
|
||||||
w = httptest.NewRecorder()
|
w = httptest.NewRecorder()
|
||||||
r = httptest.NewRequest(http.MethodPatch, defaultURL, strings.NewReader("new"))
|
r = httptest.NewRequest(http.MethodPatch, defaultURL, strings.NewReader("new"))
|
||||||
r.Header.Set(api.ContentRange, "bytes 0-2/*")
|
r.Header.Set(api.ContentRange, "bytes 0-2/*")
|
||||||
tc.Handler().PatchObjectHandler(w, r)
|
tc.Handler().PatchObjectHandler(w, r)
|
||||||
assertS3Error(t, w, s3errors.GetAPIError(s3errors.ErrMissingContentLength))
|
assertS3Error(t, w, apierr.GetAPIError(apierr.ErrMissingContentLength))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParsePatchByteRange(t *testing.T) {
|
func TestParsePatchByteRange(t *testing.T) {
|
||||||
|
@ -501,9 +501,9 @@ func patchObjectVersion(t *testing.T, tc *handlerContext, bktName, objName, vers
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func patchObjectErr(t *testing.T, tc *handlerContext, bktName, objName, rng string, payload []byte, headers map[string]string, code s3errors.ErrorCode) {
|
func patchObjectErr(t *testing.T, tc *handlerContext, bktName, objName, rng string, payload []byte, headers map[string]string, code apierr.ErrorCode) {
|
||||||
w := patchObjectBase(tc, bktName, objName, "", rng, payload, headers)
|
w := patchObjectBase(tc, bktName, objName, "", rng, payload, headers)
|
||||||
assertS3Error(t, w, s3errors.GetAPIError(code))
|
assertS3Error(t, w, apierr.GetAPIError(code))
|
||||||
}
|
}
|
||||||
|
|
||||||
func patchObjectBase(tc *handlerContext, bktName, objName, version, rng string, payload []byte, headers map[string]string) *httptest.ResponseRecorder {
|
func patchObjectBase(tc *handlerContext, bktName, objName, version, rng string, payload []byte, headers map[string]string) *httptest.ResponseRecorder {
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
stderrors "errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
|
@ -21,7 +21,7 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/auth"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/auth"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/encryption"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/encryption"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
|
@ -92,11 +92,11 @@ func (p *postPolicy) CheckField(key string, value string) error {
|
||||||
}
|
}
|
||||||
cond := p.condition(key)
|
cond := p.condition(key)
|
||||||
if cond == nil {
|
if cond == nil {
|
||||||
return errors.GetAPIError(errors.ErrPostPolicyConditionInvalidFormat)
|
return apierr.GetAPIError(apierr.ErrPostPolicyConditionInvalidFormat)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !cond.match(value) {
|
if !cond.match(value) {
|
||||||
return errors.GetAPIError(errors.ErrPostPolicyConditionInvalidFormat)
|
return apierr.GetAPIError(apierr.ErrPostPolicyConditionInvalidFormat)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -204,7 +204,7 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if cannedACLStatus == aclStatusYes {
|
if cannedACLStatus == aclStatusYes {
|
||||||
h.logAndSendError(w, "acl not supported for this bucket", reqInfo, errors.GetAPIError(errors.ErrAccessControlListNotSupported))
|
h.logAndSendError(w, "acl not supported for this bucket", reqInfo, apierr.GetAPIError(apierr.ErrAccessControlListNotSupported))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,16 +333,16 @@ func (h *handler) getBodyReader(r *http.Request) (io.ReadCloser, error) {
|
||||||
|
|
||||||
if !chunkedEncoding && !h.cfg.BypassContentEncodingInChunks() {
|
if !chunkedEncoding && !h.cfg.BypassContentEncodingInChunks() {
|
||||||
return nil, fmt.Errorf("%w: request is not chunk encoded, encodings '%s'",
|
return nil, fmt.Errorf("%w: request is not chunk encoded, encodings '%s'",
|
||||||
errors.GetAPIError(errors.ErrInvalidEncodingMethod), strings.Join(encodings, ","))
|
apierr.GetAPIError(apierr.ErrInvalidEncodingMethod), strings.Join(encodings, ","))
|
||||||
}
|
}
|
||||||
|
|
||||||
decodeContentSize := r.Header.Get(api.AmzDecodedContentLength)
|
decodeContentSize := r.Header.Get(api.AmzDecodedContentLength)
|
||||||
if len(decodeContentSize) == 0 {
|
if len(decodeContentSize) == 0 {
|
||||||
return nil, errors.GetAPIError(errors.ErrMissingContentLength)
|
return nil, apierr.GetAPIError(apierr.ErrMissingContentLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := strconv.Atoi(decodeContentSize); err != nil {
|
if _, err := strconv.Atoi(decodeContentSize); err != nil {
|
||||||
return nil, fmt.Errorf("%w: parse decoded content length: %s", errors.GetAPIError(errors.ErrMissingContentLength), err.Error())
|
return nil, fmt.Errorf("%w: parse decoded content length: %s", apierr.GetAPIError(apierr.ErrMissingContentLength), err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
chunkReader, err := newSignV4ChunkedReader(r)
|
chunkReader, err := newSignV4ChunkedReader(r)
|
||||||
|
@ -378,43 +378,43 @@ func formEncryptionParamsBase(r *http.Request, isCopySource bool) (enc encryptio
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.TLS == nil {
|
if r.TLS == nil {
|
||||||
return enc, errors.GetAPIError(errors.ErrInsecureSSECustomerRequest)
|
return enc, apierr.GetAPIError(apierr.ErrInsecureSSECustomerRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(sseCustomerKey) > 0 && len(sseCustomerAlgorithm) == 0 {
|
if len(sseCustomerKey) > 0 && len(sseCustomerAlgorithm) == 0 {
|
||||||
return enc, errors.GetAPIError(errors.ErrMissingSSECustomerAlgorithm)
|
return enc, apierr.GetAPIError(apierr.ErrMissingSSECustomerAlgorithm)
|
||||||
}
|
}
|
||||||
if len(sseCustomerAlgorithm) > 0 && len(sseCustomerKey) == 0 {
|
if len(sseCustomerAlgorithm) > 0 && len(sseCustomerKey) == 0 {
|
||||||
return enc, errors.GetAPIError(errors.ErrMissingSSECustomerKey)
|
return enc, apierr.GetAPIError(apierr.ErrMissingSSECustomerKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
if sseCustomerAlgorithm != layer.AESEncryptionAlgorithm {
|
if sseCustomerAlgorithm != layer.AESEncryptionAlgorithm {
|
||||||
return enc, errors.GetAPIError(errors.ErrInvalidEncryptionAlgorithm)
|
return enc, apierr.GetAPIError(apierr.ErrInvalidEncryptionAlgorithm)
|
||||||
}
|
}
|
||||||
|
|
||||||
key, err := base64.StdEncoding.DecodeString(sseCustomerKey)
|
key, err := base64.StdEncoding.DecodeString(sseCustomerKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isCopySource {
|
if isCopySource {
|
||||||
return enc, errors.GetAPIError(errors.ErrInvalidSSECustomerParameters)
|
return enc, apierr.GetAPIError(apierr.ErrInvalidSSECustomerParameters)
|
||||||
}
|
}
|
||||||
return enc, errors.GetAPIError(errors.ErrInvalidSSECustomerKey)
|
return enc, apierr.GetAPIError(apierr.ErrInvalidSSECustomerKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(key) != layer.AESKeySize {
|
if len(key) != layer.AESKeySize {
|
||||||
if isCopySource {
|
if isCopySource {
|
||||||
return enc, errors.GetAPIError(errors.ErrInvalidSSECustomerParameters)
|
return enc, apierr.GetAPIError(apierr.ErrInvalidSSECustomerParameters)
|
||||||
}
|
}
|
||||||
return enc, errors.GetAPIError(errors.ErrInvalidSSECustomerKey)
|
return enc, apierr.GetAPIError(apierr.ErrInvalidSSECustomerKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
keyMD5, err := base64.StdEncoding.DecodeString(sseCustomerKeyMD5)
|
keyMD5, err := base64.StdEncoding.DecodeString(sseCustomerKeyMD5)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return enc, errors.GetAPIError(errors.ErrSSECustomerKeyMD5Mismatch)
|
return enc, apierr.GetAPIError(apierr.ErrSSECustomerKeyMD5Mismatch)
|
||||||
}
|
}
|
||||||
|
|
||||||
md5Sum := md5.Sum(key)
|
md5Sum := md5.Sum(key)
|
||||||
if !bytes.Equal(md5Sum[:], keyMD5) {
|
if !bytes.Equal(md5Sum[:], keyMD5) {
|
||||||
return enc, errors.GetAPIError(errors.ErrSSECustomerKeyMD5Mismatch)
|
return enc, apierr.GetAPIError(apierr.ErrSSECustomerKeyMD5Mismatch)
|
||||||
}
|
}
|
||||||
|
|
||||||
params, err := encryption.NewParams(key)
|
params, err := encryption.NewParams(key)
|
||||||
|
@ -444,7 +444,7 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) {
|
||||||
tags := new(data.Tagging)
|
tags := new(data.Tagging)
|
||||||
if err = h.cfg.NewXMLDecoder(buffer).Decode(tags); err != nil {
|
if err = h.cfg.NewXMLDecoder(buffer).Decode(tags); err != nil {
|
||||||
h.logAndSendError(w, "could not decode tag set", reqInfo,
|
h.logAndSendError(w, "could not decode tag set", reqInfo,
|
||||||
fmt.Errorf("%w: %s", errors.GetAPIError(errors.ErrMalformedXML), err.Error()))
|
fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrMalformedXML), err.Error()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tagSet, err = h.readTagSet(tags)
|
tagSet, err = h.readTagSet(tags)
|
||||||
|
@ -467,7 +467,7 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if acl := auth.MultipartFormValue(r, "acl"); acl != "" && acl != basicACLPrivate {
|
if acl := auth.MultipartFormValue(r, "acl"); acl != "" && acl != basicACLPrivate {
|
||||||
h.logAndSendError(w, "acl not supported for this bucket", reqInfo, errors.GetAPIError(errors.ErrAccessControlListNotSupported))
|
h.logAndSendError(w, "acl not supported for this bucket", reqInfo, apierr.GetAPIError(apierr.ErrAccessControlListNotSupported))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,12 +508,12 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if reqInfo.ObjectName == "" {
|
if reqInfo.ObjectName == "" {
|
||||||
h.logAndSendError(w, "missing object name", reqInfo, errors.GetAPIError(errors.ErrInvalidArgument))
|
h.logAndSendError(w, "missing object name", reqInfo, apierr.GetAPIError(apierr.ErrInvalidArgument))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !policy.CheckContentLength(size) {
|
if !policy.CheckContentLength(size) {
|
||||||
h.logAndSendError(w, "invalid content-length", reqInfo, errors.GetAPIError(errors.ErrInvalidArgument))
|
h.logAndSendError(w, "invalid content-length", reqInfo, apierr.GetAPIError(apierr.ErrInvalidArgument))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -595,13 +595,13 @@ func checkPostPolicy(r *http.Request, reqInfo *middleware.ReqInfo, metadata map[
|
||||||
return nil, fmt.Errorf("could not unmarshal policy: %w", err)
|
return nil, fmt.Errorf("could not unmarshal policy: %w", err)
|
||||||
}
|
}
|
||||||
if policy.Expiration.Before(time.Now()) {
|
if policy.Expiration.Before(time.Now()) {
|
||||||
return nil, fmt.Errorf("policy is expired: %w", errors.GetAPIError(errors.ErrInvalidArgument))
|
return nil, fmt.Errorf("policy is expired: %w", apierr.GetAPIError(apierr.ErrInvalidArgument))
|
||||||
}
|
}
|
||||||
policy.empty = false
|
policy.empty = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.MultipartForm == nil {
|
if r.MultipartForm == nil {
|
||||||
return nil, stderrors.New("empty multipart form")
|
return nil, errors.New("empty multipart form")
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, v := range r.MultipartForm.Value {
|
for key, v := range r.MultipartForm.Value {
|
||||||
|
@ -632,7 +632,7 @@ func checkPostPolicy(r *http.Request, reqInfo *middleware.ReqInfo, metadata map[
|
||||||
for _, cond := range policy.Conditions {
|
for _, cond := range policy.Conditions {
|
||||||
if cond.Key == "bucket" {
|
if cond.Key == "bucket" {
|
||||||
if !cond.match(reqInfo.BucketName) {
|
if !cond.match(reqInfo.BucketName) {
|
||||||
return nil, errors.GetAPIError(errors.ErrPostPolicyConditionInvalidFormat)
|
return nil, apierr.GetAPIError(apierr.ErrPostPolicyConditionInvalidFormat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -674,10 +674,10 @@ func parseTaggingHeader(header http.Header) (map[string]string, error) {
|
||||||
if tagging := header.Get(api.AmzTagging); len(tagging) > 0 {
|
if tagging := header.Get(api.AmzTagging); len(tagging) > 0 {
|
||||||
queries, err := url.ParseQuery(tagging)
|
queries, err := url.ParseQuery(tagging)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.GetAPIError(errors.ErrInvalidArgument)
|
return nil, apierr.GetAPIError(apierr.ErrInvalidArgument)
|
||||||
}
|
}
|
||||||
if len(queries) > maxTags {
|
if len(queries) > maxTags {
|
||||||
return nil, errors.GetAPIError(errors.ErrInvalidTagsSizeExceed)
|
return nil, apierr.GetAPIError(apierr.ErrInvalidTagsSizeExceed)
|
||||||
}
|
}
|
||||||
tagSet = make(map[string]string, len(queries))
|
tagSet = make(map[string]string, len(queries))
|
||||||
for k, v := range queries {
|
for k, v := range queries {
|
||||||
|
@ -727,7 +727,7 @@ func (h *handler) parseCommonCreateBucketParams(reqInfo *middleware.ReqInfo, box
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.SessionContainerCreation == nil {
|
if p.SessionContainerCreation == nil {
|
||||||
return nil, nil, fmt.Errorf("%w: couldn't find session token for put", errors.GetAPIError(errors.ErrAccessDenied))
|
return nil, nil, fmt.Errorf("%w: couldn't find session token for put", apierr.GetAPIError(apierr.ErrAccessDenied))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := checkBucketName(reqInfo.BucketName); err != nil {
|
if err := checkBucketName(reqInfo.BucketName); err != nil {
|
||||||
|
@ -853,7 +853,7 @@ func (h *handler) putBucketSettingsRetryer() aws.RetryerV2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
options.Retryables = []retry.IsErrorRetryable{retry.IsErrorRetryableFunc(func(err error) aws.Ternary {
|
options.Retryables = []retry.IsErrorRetryable{retry.IsErrorRetryableFunc(func(err error) aws.Ternary {
|
||||||
if stderrors.Is(err, tree.ErrNodeAccessDenied) {
|
if errors.Is(err, tree.ErrNodeAccessDenied) {
|
||||||
return aws.TrueTernary
|
return aws.TrueTernary
|
||||||
}
|
}
|
||||||
return aws.FalseTernary
|
return aws.FalseTernary
|
||||||
|
@ -982,7 +982,7 @@ func (h handler) setPlacementPolicy(prm *layer.CreateBucketParams, namespace, lo
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors.GetAPIError(errors.ErrInvalidLocationConstraint)
|
return apierr.GetAPIError(apierr.ErrInvalidLocationConstraint)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isLockEnabled(log *zap.Logger, header http.Header) bool {
|
func isLockEnabled(log *zap.Logger, header http.Header) bool {
|
||||||
|
@ -1001,27 +1001,27 @@ func isLockEnabled(log *zap.Logger, header http.Header) bool {
|
||||||
|
|
||||||
func checkBucketName(bucketName string) error {
|
func checkBucketName(bucketName string) error {
|
||||||
if len(bucketName) < 3 || len(bucketName) > 63 {
|
if len(bucketName) < 3 || len(bucketName) > 63 {
|
||||||
return errors.GetAPIError(errors.ErrInvalidBucketName)
|
return apierr.GetAPIError(apierr.ErrInvalidBucketName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(bucketName, "xn--") || strings.HasSuffix(bucketName, "-s3alias") {
|
if strings.HasPrefix(bucketName, "xn--") || strings.HasSuffix(bucketName, "-s3alias") {
|
||||||
return errors.GetAPIError(errors.ErrInvalidBucketName)
|
return apierr.GetAPIError(apierr.ErrInvalidBucketName)
|
||||||
}
|
}
|
||||||
if net.ParseIP(bucketName) != nil {
|
if net.ParseIP(bucketName) != nil {
|
||||||
return errors.GetAPIError(errors.ErrInvalidBucketName)
|
return apierr.GetAPIError(apierr.ErrInvalidBucketName)
|
||||||
}
|
}
|
||||||
|
|
||||||
labels := strings.Split(bucketName, ".")
|
labels := strings.Split(bucketName, ".")
|
||||||
for _, label := range labels {
|
for _, label := range labels {
|
||||||
if len(label) == 0 {
|
if len(label) == 0 {
|
||||||
return errors.GetAPIError(errors.ErrInvalidBucketName)
|
return apierr.GetAPIError(apierr.ErrInvalidBucketName)
|
||||||
}
|
}
|
||||||
for i, r := range label {
|
for i, r := range label {
|
||||||
if !isAlphaNum(r) && r != '-' {
|
if !isAlphaNum(r) && r != '-' {
|
||||||
return errors.GetAPIError(errors.ErrInvalidBucketName)
|
return apierr.GetAPIError(apierr.ErrInvalidBucketName)
|
||||||
}
|
}
|
||||||
if (i == 0 || i == len(label)-1) && r == '-' {
|
if (i == 0 || i == len(label)-1) && r == '-' {
|
||||||
return errors.GetAPIError(errors.ErrInvalidBucketName)
|
return apierr.GetAPIError(apierr.ErrInvalidBucketName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1040,7 +1040,7 @@ func (h *handler) parseLocationConstraint(r *http.Request) (*createBucketParams,
|
||||||
|
|
||||||
params := new(createBucketParams)
|
params := new(createBucketParams)
|
||||||
if err := h.cfg.NewXMLDecoder(r.Body).Decode(params); err != nil {
|
if err := h.cfg.NewXMLDecoder(r.Body).Decode(params); err != nil {
|
||||||
return nil, fmt.Errorf("%w: %s", errors.GetAPIError(errors.ErrMalformedXML), err.Error())
|
return nil, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrMalformedXML), err.Error())
|
||||||
}
|
}
|
||||||
return params, nil
|
return params, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/auth"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/auth"
|
||||||
v4 "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/auth/signer/v4"
|
v4 "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/auth/signer/v4"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
s3errors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
||||||
|
@ -205,7 +205,7 @@ func TestPostObject(t *testing.T) {
|
||||||
t.Run(tc.key+";"+tc.filename, func(t *testing.T) {
|
t.Run(tc.key+";"+tc.filename, func(t *testing.T) {
|
||||||
w := postObjectBase(hc, ns, bktName, tc.key, tc.filename, tc.content)
|
w := postObjectBase(hc, ns, bktName, tc.key, tc.filename, tc.content)
|
||||||
if tc.err {
|
if tc.err {
|
||||||
assertS3Error(hc.t, w, s3errors.GetAPIError(s3errors.ErrInternalError))
|
assertS3Error(hc.t, w, apierr.GetAPIError(apierr.ErrInternalError))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
assertStatus(hc.t, w, http.StatusNoContent)
|
assertStatus(hc.t, w, http.StatusNoContent)
|
||||||
|
@ -268,7 +268,7 @@ func TestPutObjectWithStreamBodyError(t *testing.T) {
|
||||||
r.Header.Set(api.AmzContentSha256, api.StreamingContentSHA256)
|
r.Header.Set(api.AmzContentSha256, api.StreamingContentSHA256)
|
||||||
r.Header.Set(api.ContentEncoding, api.AwsChunked)
|
r.Header.Set(api.ContentEncoding, api.AwsChunked)
|
||||||
tc.Handler().PutObjectHandler(w, r)
|
tc.Handler().PutObjectHandler(w, r)
|
||||||
assertS3Error(t, w, s3errors.GetAPIError(s3errors.ErrMissingContentLength))
|
assertS3Error(t, w, apierr.GetAPIError(apierr.ErrMissingContentLength))
|
||||||
|
|
||||||
checkNotFound(t, tc, bktName, objName, emptyVersion)
|
checkNotFound(t, tc, bktName, objName, emptyVersion)
|
||||||
}
|
}
|
||||||
|
@ -284,7 +284,7 @@ func TestPutObjectWithInvalidContentMD5(t *testing.T) {
|
||||||
w, r := prepareTestPayloadRequest(tc, bktName, objName, bytes.NewReader(content))
|
w, r := prepareTestPayloadRequest(tc, bktName, objName, bytes.NewReader(content))
|
||||||
r.Header.Set(api.ContentMD5, base64.StdEncoding.EncodeToString([]byte("invalid")))
|
r.Header.Set(api.ContentMD5, base64.StdEncoding.EncodeToString([]byte("invalid")))
|
||||||
tc.Handler().PutObjectHandler(w, r)
|
tc.Handler().PutObjectHandler(w, r)
|
||||||
assertS3Error(t, w, s3errors.GetAPIError(s3errors.ErrInvalidDigest))
|
assertS3Error(t, w, apierr.GetAPIError(apierr.ErrInvalidDigest))
|
||||||
|
|
||||||
checkNotFound(t, tc, bktName, objName, emptyVersion)
|
checkNotFound(t, tc, bktName, objName, emptyVersion)
|
||||||
}
|
}
|
||||||
|
@ -347,7 +347,7 @@ func TestPutObjectCheckContentSHA256(t *testing.T) {
|
||||||
hc.Handler().PutObjectHandler(w, r)
|
hc.Handler().PutObjectHandler(w, r)
|
||||||
|
|
||||||
if tc.error {
|
if tc.error {
|
||||||
assertS3Error(t, w, s3errors.GetAPIError(s3errors.ErrContentSHA256Mismatch))
|
assertS3Error(t, w, apierr.GetAPIError(apierr.ErrContentSHA256Mismatch))
|
||||||
|
|
||||||
w, r := prepareTestRequest(hc, bktName, objName, nil)
|
w, r := prepareTestRequest(hc, bktName, objName, nil)
|
||||||
hc.Handler().GetObjectHandler(w, r)
|
hc.Handler().GetObjectHandler(w, r)
|
||||||
|
@ -400,7 +400,7 @@ func TestPutChunkedTestContentEncoding(t *testing.T) {
|
||||||
w, req, _ = getChunkedRequest(hc.context, t, bktName, objName)
|
w, req, _ = getChunkedRequest(hc.context, t, bktName, objName)
|
||||||
req.Header.Set(api.ContentEncoding, "gzip")
|
req.Header.Set(api.ContentEncoding, "gzip")
|
||||||
hc.Handler().PutObjectHandler(w, req)
|
hc.Handler().PutObjectHandler(w, req)
|
||||||
assertS3Error(t, w, s3errors.GetAPIError(s3errors.ErrInvalidEncodingMethod))
|
assertS3Error(t, w, apierr.GetAPIError(apierr.ErrInvalidEncodingMethod))
|
||||||
|
|
||||||
hc.config.bypassContentEncodingInChunks = true
|
hc.config.bypassContentEncodingInChunks = true
|
||||||
w, req, _ = getChunkedRequest(hc.context, t, bktName, objName)
|
w, req, _ = getChunkedRequest(hc.context, t, bktName, objName)
|
||||||
|
@ -479,10 +479,10 @@ func TestCreateBucket(t *testing.T) {
|
||||||
bktName := "bkt-name"
|
bktName := "bkt-name"
|
||||||
|
|
||||||
info := createBucket(hc, bktName)
|
info := createBucket(hc, bktName)
|
||||||
createBucketAssertS3Error(hc, bktName, info.Box, s3errors.ErrBucketAlreadyOwnedByYou)
|
createBucketAssertS3Error(hc, bktName, info.Box, apierr.ErrBucketAlreadyOwnedByYou)
|
||||||
|
|
||||||
box2, _ := createAccessBox(t)
|
box2, _ := createAccessBox(t)
|
||||||
createBucketAssertS3Error(hc, bktName, box2, s3errors.ErrBucketAlreadyExists)
|
createBucketAssertS3Error(hc, bktName, box2, apierr.ErrBucketAlreadyExists)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateBucketWithoutPermissions(t *testing.T) {
|
func TestCreateBucketWithoutPermissions(t *testing.T) {
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
apiErrors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -98,7 +98,7 @@ func TestPutObjectTaggingCheckUniqueness(t *testing.T) {
|
||||||
middleware.GetReqInfo(r.Context()).Tagging = tc.body
|
middleware.GetReqInfo(r.Context()).Tagging = tc.body
|
||||||
hc.Handler().PutObjectTaggingHandler(w, r)
|
hc.Handler().PutObjectTaggingHandler(w, r)
|
||||||
if tc.error {
|
if tc.error {
|
||||||
assertS3Error(t, w, apiErrors.GetAPIError(apiErrors.ErrInvalidTagKeyUniqueness))
|
assertS3Error(t, w, apierr.GetAPIError(apierr.ErrInvalidTagKeyUniqueness))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
assertStatus(t, w, http.StatusOK)
|
assertStatus(t, w, http.StatusOK)
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
s3errors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/tree"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/tree"
|
||||||
|
@ -59,25 +59,25 @@ func handleDeleteMarker(w http.ResponseWriter, err error) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set(api.AmzDeleteMarker, "true")
|
w.Header().Set(api.AmzDeleteMarker, "true")
|
||||||
return fmt.Errorf("%w: %s", s3errors.GetAPIError(target.ErrorCode), err)
|
return fmt.Errorf("%w: %s", apierr.GetAPIError(target.ErrorCode), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func transformToS3Error(err error) error {
|
func transformToS3Error(err error) error {
|
||||||
err = frosterrors.UnwrapErr(err) // this wouldn't work with errors.Join
|
err = frosterrors.UnwrapErr(err) // this wouldn't work with errors.Join
|
||||||
if _, ok := err.(s3errors.Error); ok {
|
if _, ok := err.(apierr.Error); ok {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if errors.Is(err, frostfs.ErrAccessDenied) ||
|
if errors.Is(err, frostfs.ErrAccessDenied) ||
|
||||||
errors.Is(err, tree.ErrNodeAccessDenied) {
|
errors.Is(err, tree.ErrNodeAccessDenied) {
|
||||||
return s3errors.GetAPIError(s3errors.ErrAccessDenied)
|
return apierr.GetAPIError(apierr.ErrAccessDenied)
|
||||||
}
|
}
|
||||||
|
|
||||||
if errors.Is(err, frostfs.ErrGatewayTimeout) {
|
if errors.Is(err, frostfs.ErrGatewayTimeout) {
|
||||||
return s3errors.GetAPIError(s3errors.ErrGatewayTimeout)
|
return apierr.GetAPIError(apierr.ErrGatewayTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
return s3errors.GetAPIError(s3errors.ErrInternalError)
|
return apierr.GetAPIError(apierr.ErrInternalError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handler) ResolveBucket(ctx context.Context, bucket string) (*data.BucketInfo, error) {
|
func (h *handler) ResolveBucket(ctx context.Context, bucket string) (*data.BucketInfo, error) {
|
||||||
|
@ -133,26 +133,26 @@ func parseRange(s string) (*layer.RangeParams, error) {
|
||||||
prefix := "bytes="
|
prefix := "bytes="
|
||||||
|
|
||||||
if !strings.HasPrefix(s, prefix) {
|
if !strings.HasPrefix(s, prefix) {
|
||||||
return nil, s3errors.GetAPIError(s3errors.ErrInvalidRange)
|
return nil, apierr.GetAPIError(apierr.ErrInvalidRange)
|
||||||
}
|
}
|
||||||
|
|
||||||
s = strings.TrimPrefix(s, prefix)
|
s = strings.TrimPrefix(s, prefix)
|
||||||
|
|
||||||
valuesStr := strings.Split(s, "-")
|
valuesStr := strings.Split(s, "-")
|
||||||
if len(valuesStr) != 2 {
|
if len(valuesStr) != 2 {
|
||||||
return nil, s3errors.GetAPIError(s3errors.ErrInvalidRange)
|
return nil, apierr.GetAPIError(apierr.ErrInvalidRange)
|
||||||
}
|
}
|
||||||
|
|
||||||
values := make([]uint64, 0, len(valuesStr))
|
values := make([]uint64, 0, len(valuesStr))
|
||||||
for _, v := range valuesStr {
|
for _, v := range valuesStr {
|
||||||
num, err := strconv.ParseUint(v, 10, 64)
|
num, err := strconv.ParseUint(v, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, s3errors.GetAPIError(s3errors.ErrInvalidRange)
|
return nil, apierr.GetAPIError(apierr.ErrInvalidRange)
|
||||||
}
|
}
|
||||||
values = append(values, num)
|
values = append(values, num)
|
||||||
}
|
}
|
||||||
if values[0] > values[1] {
|
if values[0] > values[1] {
|
||||||
return nil, s3errors.GetAPIError(s3errors.ErrInvalidRange)
|
return nil, apierr.GetAPIError(apierr.ErrInvalidRange)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &layer.RangeParams{
|
return &layer.RangeParams{
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
s3errors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/tree"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/tree"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ func (n *Layer) GetObjectTaggingAndLock(ctx context.Context, objVersion *data.Ob
|
||||||
tags, lockInfo, err = n.treeService.GetObjectTaggingAndLock(ctx, objVersion.BktInfo, nodeVersion)
|
tags, lockInfo, err = n.treeService.GetObjectTaggingAndLock(ctx, objVersion.BktInfo, nodeVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, tree.ErrNodeNotFound) {
|
if errors.Is(err, tree.ErrNodeNotFound) {
|
||||||
return nil, data.LockInfo{}, fmt.Errorf("%w: %s", s3errors.GetAPIError(s3errors.ErrNoSuchKey), err.Error())
|
return nil, data.LockInfo{}, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrNoSuchKey), err.Error())
|
||||||
}
|
}
|
||||||
return nil, data.LockInfo{}, err
|
return nil, data.LockInfo{}, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
s3errors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
|
@ -38,7 +38,7 @@ func (n *Layer) containerInfo(ctx context.Context, prm frostfs.PrmContainer) (*d
|
||||||
res, err = n.frostFS.Container(ctx, prm)
|
res, err = n.frostFS.Container(ctx, prm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if client.IsErrContainerNotFound(err) {
|
if client.IsErrContainerNotFound(err) {
|
||||||
return nil, fmt.Errorf("%w: %s", s3errors.GetAPIError(s3errors.ErrNoSuchBucket), err.Error())
|
return nil, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrNoSuchBucket), err.Error())
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("get frostfs container: %w", err)
|
return nil, fmt.Errorf("get frostfs container: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,12 @@ package layer
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
errorsStd "errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/tree"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/tree"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
|
@ -33,7 +33,7 @@ func (n *Layer) PutBucketCORS(ctx context.Context, p *PutCORSParams) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if cors.CORSRules == nil {
|
if cors.CORSRules == nil {
|
||||||
return errors.GetAPIError(errors.ErrMalformedXML)
|
return apierr.GetAPIError(apierr.ErrMalformedXML)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := checkCORS(cors); err != nil {
|
if err := checkCORS(cors); err != nil {
|
||||||
|
@ -63,7 +63,7 @@ func (n *Layer) PutBucketCORS(ctx context.Context, p *PutCORSParams) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
objsToDelete, err := n.treeService.PutBucketCORS(ctx, p.BktInfo, newAddress(corsBkt.CID, createdObj.ID))
|
objsToDelete, err := n.treeService.PutBucketCORS(ctx, p.BktInfo, newAddress(corsBkt.CID, createdObj.ID))
|
||||||
objToDeleteNotFound := errorsStd.Is(err, tree.ErrNoNodeToRemove)
|
objToDeleteNotFound := errors.Is(err, tree.ErrNoNodeToRemove)
|
||||||
if err != nil && !objToDeleteNotFound {
|
if err != nil && !objToDeleteNotFound {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,7 @@ func (n *Layer) GetBucketCORS(ctx context.Context, bktInfo *data.BucketInfo) (*d
|
||||||
|
|
||||||
func (n *Layer) DeleteBucketCORS(ctx context.Context, bktInfo *data.BucketInfo) error {
|
func (n *Layer) DeleteBucketCORS(ctx context.Context, bktInfo *data.BucketInfo) error {
|
||||||
objs, err := n.treeService.DeleteBucketCORS(ctx, bktInfo)
|
objs, err := n.treeService.DeleteBucketCORS(ctx, bktInfo)
|
||||||
objNotFound := errorsStd.Is(err, tree.ErrNoNodeToRemove)
|
objNotFound := errors.Is(err, tree.ErrNoNodeToRemove)
|
||||||
if err != nil && !objNotFound {
|
if err != nil && !objNotFound {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -126,12 +126,12 @@ func checkCORS(cors *data.CORSConfiguration) error {
|
||||||
for _, r := range cors.CORSRules {
|
for _, r := range cors.CORSRules {
|
||||||
for _, m := range r.AllowedMethods {
|
for _, m := range r.AllowedMethods {
|
||||||
if _, ok := supportedMethods[m]; !ok {
|
if _, ok := supportedMethods[m]; !ok {
|
||||||
return errors.GetAPIErrorWithError(errors.ErrCORSUnsupportedMethod, fmt.Errorf("unsupported method is %s", m))
|
return apierr.GetAPIErrorWithError(apierr.ErrCORSUnsupportedMethod, fmt.Errorf("unsupported method is %s", m))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, h := range r.ExposeHeaders {
|
for _, h := range r.ExposeHeaders {
|
||||||
if h == wildcard {
|
if h == wildcard {
|
||||||
return errors.GetAPIError(errors.ErrCORSWildcardExposeHeaders)
|
return apierr.GetAPIError(apierr.ErrCORSWildcardExposeHeaders)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
stderrors "errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -17,8 +17,7 @@ import (
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
s3errors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/encryption"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/encryption"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/tree"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/tree"
|
||||||
|
@ -333,7 +332,7 @@ func (n *Layer) GetBucketInfo(ctx context.Context, name string) (*data.BucketInf
|
||||||
containerID, err := n.ResolveBucket(ctx, zone, name)
|
containerID, err := n.ResolveBucket(ctx, zone, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "not found") {
|
if strings.Contains(err.Error(), "not found") {
|
||||||
return nil, fmt.Errorf("%w: %s", errors.GetAPIError(errors.ErrNoSuchBucket), err.Error())
|
return nil, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrNoSuchBucket), err.Error())
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -399,9 +398,9 @@ func (n *Layer) GetObject(ctx context.Context, p *GetObjectParams) (*ObjectPaylo
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if client.IsErrObjectNotFound(err) {
|
if client.IsErrObjectNotFound(err) {
|
||||||
if p.Versioned {
|
if p.Versioned {
|
||||||
err = fmt.Errorf("%w: %s", errors.GetAPIError(errors.ErrNoSuchVersion), err.Error())
|
err = fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrNoSuchVersion), err.Error())
|
||||||
} else {
|
} else {
|
||||||
err = fmt.Errorf("%w: %s", errors.GetAPIError(errors.ErrNoSuchKey), err.Error())
|
err = fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrNoSuchKey), err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -657,22 +656,22 @@ func (n *Layer) handleNotFoundError(bkt *data.BucketInfo, obj *VersionedObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isNotFoundError(err error) bool {
|
func isNotFoundError(err error) bool {
|
||||||
return errors.IsS3Error(err, errors.ErrNoSuchKey) ||
|
return apierr.IsS3Error(err, apierr.ErrNoSuchKey) ||
|
||||||
errors.IsS3Error(err, errors.ErrNoSuchVersion)
|
apierr.IsS3Error(err, apierr.ErrNoSuchVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Layer) getNodeVersionsToDelete(ctx context.Context, bkt *data.BucketInfo, obj *VersionedObject) ([]*data.NodeVersion, error) {
|
func (n *Layer) getNodeVersionsToDelete(ctx context.Context, bkt *data.BucketInfo, obj *VersionedObject) ([]*data.NodeVersion, error) {
|
||||||
var versionsToDelete []*data.NodeVersion
|
var versionsToDelete []*data.NodeVersion
|
||||||
versions, err := n.treeService.GetVersions(ctx, bkt, obj.Name)
|
versions, err := n.treeService.GetVersions(ctx, bkt, obj.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if stderrors.Is(err, tree.ErrNodeNotFound) {
|
if errors.Is(err, tree.ErrNodeNotFound) {
|
||||||
return nil, fmt.Errorf("%w: %s", s3errors.GetAPIError(s3errors.ErrNoSuchKey), err.Error())
|
return nil, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrNoSuchKey), err.Error())
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(versions) == 0 {
|
if len(versions) == 0 {
|
||||||
return nil, fmt.Errorf("%w: there isn't tree node with requested version id", s3errors.GetAPIError(s3errors.ErrNoSuchVersion))
|
return nil, fmt.Errorf("%w: there isn't tree node with requested version id", apierr.GetAPIError(apierr.ErrNoSuchVersion))
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(versions, func(i, j int) bool {
|
sort.Slice(versions, func(i, j int) bool {
|
||||||
|
@ -714,7 +713,7 @@ func (n *Layer) getNodeVersionsToDelete(ctx context.Context, bkt *data.BucketInf
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(versionsToDelete) == 0 {
|
if len(versionsToDelete) == 0 {
|
||||||
return nil, fmt.Errorf("%w: there isn't tree node with requested version id", s3errors.GetAPIError(s3errors.ErrNoSuchVersion))
|
return nil, fmt.Errorf("%w: there isn't tree node with requested version id", apierr.GetAPIError(apierr.ErrNoSuchVersion))
|
||||||
}
|
}
|
||||||
|
|
||||||
n.reqLogger(ctx).Debug(logs.GetTreeNodeToDelete, zap.Stringer("cid", bkt.CID), zap.Strings("oids", oids))
|
n.reqLogger(ctx).Debug(logs.GetTreeNodeToDelete, zap.Stringer("cid", bkt.CID), zap.Strings("oids", oids))
|
||||||
|
@ -787,17 +786,17 @@ func (n *Layer) DeleteObjects(ctx context.Context, p *DeleteObjectParams) []*Ver
|
||||||
func (n *Layer) CreateBucket(ctx context.Context, p *CreateBucketParams) (*data.BucketInfo, error) {
|
func (n *Layer) CreateBucket(ctx context.Context, p *CreateBucketParams) (*data.BucketInfo, error) {
|
||||||
bktInfo, err := n.GetBucketInfo(ctx, p.Name)
|
bktInfo, err := n.GetBucketInfo(ctx, p.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.IsS3Error(err, errors.ErrNoSuchBucket) {
|
if apierr.IsS3Error(err, apierr.ErrNoSuchBucket) {
|
||||||
return n.createContainer(ctx, p)
|
return n.createContainer(ctx, p)
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.SessionContainerCreation != nil && session.IssuedBy(*p.SessionContainerCreation, bktInfo.Owner) {
|
if p.SessionContainerCreation != nil && session.IssuedBy(*p.SessionContainerCreation, bktInfo.Owner) {
|
||||||
return nil, errors.GetAPIError(errors.ErrBucketAlreadyOwnedByYou)
|
return nil, apierr.GetAPIError(apierr.ErrBucketAlreadyOwnedByYou)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.GetAPIError(errors.ErrBucketAlreadyExists)
|
return nil, apierr.GetAPIError(apierr.ErrBucketAlreadyExists)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Layer) ResolveBucket(ctx context.Context, zone, name string) (cid.ID, error) {
|
func (n *Layer) ResolveBucket(ctx context.Context, zone, name string) (cid.ID, error) {
|
||||||
|
@ -824,7 +823,7 @@ func (n *Layer) DeleteBucket(ctx context.Context, p *DeleteBucketParams) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(res) != 0 {
|
if len(res) != 0 {
|
||||||
return errors.GetAPIError(errors.ErrBucketNotEmpty)
|
return apierr.GetAPIError(apierr.ErrBucketNotEmpty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
apiErr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/tree"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/tree"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
|
@ -51,13 +51,13 @@ func (n *Layer) PutBucketLifecycleConfiguration(ctx context.Context, p *PutBucke
|
||||||
|
|
||||||
hashBytes, err := base64.StdEncoding.DecodeString(p.MD5Hash)
|
hashBytes, err := base64.StdEncoding.DecodeString(p.MD5Hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apiErr.GetAPIError(apiErr.ErrInvalidDigest)
|
return apierr.GetAPIError(apierr.ErrInvalidDigest)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !bytes.Equal(hashBytes, createdObj.MD5Sum) {
|
if !bytes.Equal(hashBytes, createdObj.MD5Sum) {
|
||||||
n.deleteLifecycleObject(ctx, p.BktInfo, newAddress(lifecycleBkt.CID, createdObj.ID))
|
n.deleteLifecycleObject(ctx, p.BktInfo, newAddress(lifecycleBkt.CID, createdObj.ID))
|
||||||
|
|
||||||
return apiErr.GetAPIError(apiErr.ErrInvalidDigest)
|
return apierr.GetAPIError(apierr.ErrInvalidDigest)
|
||||||
}
|
}
|
||||||
|
|
||||||
objsToDelete, err := n.treeService.PutBucketLifecycleConfiguration(ctx, p.BktInfo, newAddress(lifecycleBkt.CID, createdObj.ID))
|
objsToDelete, err := n.treeService.PutBucketLifecycleConfiguration(ctx, p.BktInfo, newAddress(lifecycleBkt.CID, createdObj.ID))
|
||||||
|
@ -106,7 +106,7 @@ func (n *Layer) GetBucketLifecycleConfiguration(ctx context.Context, bktInfo *da
|
||||||
}
|
}
|
||||||
|
|
||||||
if objNotFound {
|
if objNotFound {
|
||||||
return nil, fmt.Errorf("%w: %s", apiErr.GetAPIError(apiErr.ErrNoSuchLifecycleConfiguration), err.Error())
|
return nil, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrNoSuchLifecycleConfiguration), err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
var prmAuth frostfs.PrmAuth
|
var prmAuth frostfs.PrmAuth
|
||||||
|
|
|
@ -8,8 +8,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
apiErr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
frostfsErrors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/errors"
|
frosterr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/errors"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ func TestBucketLifecycle(t *testing.T) {
|
||||||
hash.Write(lifecycleBytes)
|
hash.Write(lifecycleBytes)
|
||||||
|
|
||||||
_, err = tc.layer.GetBucketLifecycleConfiguration(tc.ctx, tc.bktInfo)
|
_, err = tc.layer.GetBucketLifecycleConfiguration(tc.ctx, tc.bktInfo)
|
||||||
require.Equal(t, apiErr.GetAPIError(apiErr.ErrNoSuchLifecycleConfiguration), frostfsErrors.UnwrapErr(err))
|
require.Equal(t, apierr.GetAPIError(apierr.ErrNoSuchLifecycleConfiguration), frosterr.UnwrapErr(err))
|
||||||
|
|
||||||
err = tc.layer.DeleteBucketLifecycleConfiguration(tc.ctx, tc.bktInfo)
|
err = tc.layer.DeleteBucketLifecycleConfiguration(tc.ctx, tc.bktInfo)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -57,7 +57,7 @@ func TestBucketLifecycle(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
_, err = tc.layer.GetBucketLifecycleConfiguration(tc.ctx, tc.bktInfo)
|
_, err = tc.layer.GetBucketLifecycleConfiguration(tc.ctx, tc.bktInfo)
|
||||||
require.Equal(t, apiErr.GetAPIError(apiErr.ErrNoSuchLifecycleConfiguration), frostfsErrors.UnwrapErr(err))
|
require.Equal(t, apierr.GetAPIError(apierr.ErrNoSuchLifecycleConfiguration), frosterr.UnwrapErr(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
func ptr[T any](t T) *T {
|
func ptr[T any](t T) *T {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/cache"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/cache"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
s3errors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
"github.com/panjf2000/ants/v2"
|
"github.com/panjf2000/ants/v2"
|
||||||
|
@ -691,10 +691,10 @@ func filterVersionsByMarker(objects []*data.ExtendedNodeVersion, p *ListObjectVe
|
||||||
return objects[j+1:], nil
|
return objects[j+1:], nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, s3errors.GetAPIError(s3errors.ErrInvalidVersion)
|
return nil, apierr.GetAPIError(apierr.ErrInvalidVersion)
|
||||||
} else if obj.NodeVersion.FilePath > p.KeyMarker {
|
} else if obj.NodeVersion.FilePath > p.KeyMarker {
|
||||||
if p.VersionIDMarker != "" {
|
if p.VersionIDMarker != "" {
|
||||||
return nil, s3errors.GetAPIError(s3errors.ErrInvalidVersion)
|
return nil, apierr.GetAPIError(apierr.ErrInvalidVersion)
|
||||||
}
|
}
|
||||||
return objects[i:], nil
|
return objects[i:], nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ import (
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/auth"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/auth"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
s3errors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/encryption"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/encryption"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/tree"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/tree"
|
||||||
|
@ -190,13 +190,13 @@ func (n *Layer) UploadPart(ctx context.Context, p *UploadPartParams) (string, er
|
||||||
multipartInfo, err := n.treeService.GetMultipartUpload(ctx, p.Info.Bkt, p.Info.Key, p.Info.UploadID)
|
multipartInfo, err := n.treeService.GetMultipartUpload(ctx, p.Info.Bkt, p.Info.Key, p.Info.UploadID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, tree.ErrNodeNotFound) {
|
if errors.Is(err, tree.ErrNodeNotFound) {
|
||||||
return "", fmt.Errorf("%w: %s", s3errors.GetAPIError(s3errors.ErrNoSuchUpload), err.Error())
|
return "", fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrNoSuchUpload), err.Error())
|
||||||
}
|
}
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.Size > UploadMaxSize {
|
if p.Size > UploadMaxSize {
|
||||||
return "", fmt.Errorf("%w: %d/%d", s3errors.GetAPIError(s3errors.ErrEntityTooLarge), p.Size, UploadMaxSize)
|
return "", fmt.Errorf("%w: %d/%d", apierr.GetAPIError(apierr.ErrEntityTooLarge), p.Size, UploadMaxSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
objInfo, err := n.uploadPart(ctx, multipartInfo, p)
|
objInfo, err := n.uploadPart(ctx, multipartInfo, p)
|
||||||
|
@ -211,7 +211,7 @@ func (n *Layer) uploadPart(ctx context.Context, multipartInfo *data.MultipartInf
|
||||||
encInfo := FormEncryptionInfo(multipartInfo.Meta)
|
encInfo := FormEncryptionInfo(multipartInfo.Meta)
|
||||||
if err := p.Info.Encryption.MatchObjectEncryption(encInfo); err != nil {
|
if err := p.Info.Encryption.MatchObjectEncryption(encInfo); err != nil {
|
||||||
n.reqLogger(ctx).Warn(logs.MismatchedObjEncryptionInfo, zap.Error(err))
|
n.reqLogger(ctx).Warn(logs.MismatchedObjEncryptionInfo, zap.Error(err))
|
||||||
return nil, s3errors.GetAPIError(s3errors.ErrInvalidEncryptionParameters)
|
return nil, apierr.GetAPIError(apierr.ErrInvalidEncryptionParameters)
|
||||||
}
|
}
|
||||||
|
|
||||||
bktInfo := p.Info.Bkt
|
bktInfo := p.Info.Bkt
|
||||||
|
@ -244,7 +244,7 @@ func (n *Layer) uploadPart(ctx context.Context, multipartInfo *data.MultipartInf
|
||||||
if len(p.ContentMD5) > 0 {
|
if len(p.ContentMD5) > 0 {
|
||||||
hashBytes, err := base64.StdEncoding.DecodeString(p.ContentMD5)
|
hashBytes, err := base64.StdEncoding.DecodeString(p.ContentMD5)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, s3errors.GetAPIError(s3errors.ErrInvalidDigest)
|
return nil, apierr.GetAPIError(apierr.ErrInvalidDigest)
|
||||||
}
|
}
|
||||||
if hex.EncodeToString(hashBytes) != hex.EncodeToString(createdObj.MD5Sum) {
|
if hex.EncodeToString(hashBytes) != hex.EncodeToString(createdObj.MD5Sum) {
|
||||||
prm := frostfs.PrmObjectDelete{
|
prm := frostfs.PrmObjectDelete{
|
||||||
|
@ -256,7 +256,7 @@ func (n *Layer) uploadPart(ctx context.Context, multipartInfo *data.MultipartInf
|
||||||
if err != nil {
|
if err != nil {
|
||||||
n.reqLogger(ctx).Debug(logs.FailedToDeleteObject, zap.Stringer("cid", bktInfo.CID), zap.Stringer("oid", createdObj.ID))
|
n.reqLogger(ctx).Debug(logs.FailedToDeleteObject, zap.Stringer("cid", bktInfo.CID), zap.Stringer("oid", createdObj.ID))
|
||||||
}
|
}
|
||||||
return nil, s3errors.GetAPIError(s3errors.ErrInvalidDigest)
|
return nil, apierr.GetAPIError(apierr.ErrInvalidDigest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if p.Info.Encryption.Enabled() {
|
if p.Info.Encryption.Enabled() {
|
||||||
|
@ -266,14 +266,14 @@ func (n *Layer) uploadPart(ctx context.Context, multipartInfo *data.MultipartInf
|
||||||
if !p.Info.Encryption.Enabled() && len(p.ContentSHA256Hash) > 0 && !auth.IsStandardContentSHA256(p.ContentSHA256Hash) {
|
if !p.Info.Encryption.Enabled() && len(p.ContentSHA256Hash) > 0 && !auth.IsStandardContentSHA256(p.ContentSHA256Hash) {
|
||||||
contentHashBytes, err := hex.DecodeString(p.ContentSHA256Hash)
|
contentHashBytes, err := hex.DecodeString(p.ContentSHA256Hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, s3errors.GetAPIError(s3errors.ErrContentSHA256Mismatch)
|
return nil, apierr.GetAPIError(apierr.ErrContentSHA256Mismatch)
|
||||||
}
|
}
|
||||||
if !bytes.Equal(contentHashBytes, createdObj.HashSum) {
|
if !bytes.Equal(contentHashBytes, createdObj.HashSum) {
|
||||||
err = n.objectDelete(ctx, bktInfo, createdObj.ID)
|
err = n.objectDelete(ctx, bktInfo, createdObj.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
n.reqLogger(ctx).Debug(logs.FailedToDeleteObject, zap.Stringer("cid", bktInfo.CID), zap.Stringer("oid", createdObj.ID))
|
n.reqLogger(ctx).Debug(logs.FailedToDeleteObject, zap.Stringer("cid", bktInfo.CID), zap.Stringer("oid", createdObj.ID))
|
||||||
}
|
}
|
||||||
return nil, s3errors.GetAPIError(s3errors.ErrContentSHA256Mismatch)
|
return nil, apierr.GetAPIError(apierr.ErrContentSHA256Mismatch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,7 +326,7 @@ func (n *Layer) UploadPartCopy(ctx context.Context, p *UploadCopyParams) (*data.
|
||||||
multipartInfo, err := n.treeService.GetMultipartUpload(ctx, p.Info.Bkt, p.Info.Key, p.Info.UploadID)
|
multipartInfo, err := n.treeService.GetMultipartUpload(ctx, p.Info.Bkt, p.Info.Key, p.Info.UploadID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, tree.ErrNodeNotFound) {
|
if errors.Is(err, tree.ErrNodeNotFound) {
|
||||||
return nil, fmt.Errorf("%w: %s", s3errors.GetAPIError(s3errors.ErrNoSuchUpload), err.Error())
|
return nil, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrNoSuchUpload), err.Error())
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -342,11 +342,11 @@ func (n *Layer) UploadPartCopy(ctx context.Context, p *UploadCopyParams) (*data.
|
||||||
if p.Range != nil {
|
if p.Range != nil {
|
||||||
size = p.Range.End - p.Range.Start + 1
|
size = p.Range.End - p.Range.Start + 1
|
||||||
if p.Range.End > srcObjectSize {
|
if p.Range.End > srcObjectSize {
|
||||||
return nil, fmt.Errorf("%w: %d-%d/%d", s3errors.GetAPIError(s3errors.ErrInvalidCopyPartRangeSource), p.Range.Start, p.Range.End, srcObjectSize)
|
return nil, fmt.Errorf("%w: %d-%d/%d", apierr.GetAPIError(apierr.ErrInvalidCopyPartRangeSource), p.Range.Start, p.Range.End, srcObjectSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if size > UploadMaxSize {
|
if size > UploadMaxSize {
|
||||||
return nil, fmt.Errorf("%w: %d/%d", s3errors.GetAPIError(s3errors.ErrEntityTooLarge), size, UploadMaxSize)
|
return nil, fmt.Errorf("%w: %d/%d", apierr.GetAPIError(apierr.ErrEntityTooLarge), size, UploadMaxSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
objPayload, err := n.GetObject(ctx, &GetObjectParams{
|
objPayload, err := n.GetObject(ctx, &GetObjectParams{
|
||||||
|
@ -373,7 +373,7 @@ func (n *Layer) UploadPartCopy(ctx context.Context, p *UploadCopyParams) (*data.
|
||||||
func (n *Layer) CompleteMultipartUpload(ctx context.Context, p *CompleteMultipartParams) (*UploadData, *data.ExtendedObjectInfo, error) {
|
func (n *Layer) CompleteMultipartUpload(ctx context.Context, p *CompleteMultipartParams) (*UploadData, *data.ExtendedObjectInfo, error) {
|
||||||
for i := 1; i < len(p.Parts); i++ {
|
for i := 1; i < len(p.Parts); i++ {
|
||||||
if p.Parts[i].PartNumber <= p.Parts[i-1].PartNumber {
|
if p.Parts[i].PartNumber <= p.Parts[i-1].PartNumber {
|
||||||
return nil, nil, s3errors.GetAPIError(s3errors.ErrInvalidPartOrder)
|
return nil, nil, apierr.GetAPIError(apierr.ErrInvalidPartOrder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,7 +384,7 @@ func (n *Layer) CompleteMultipartUpload(ctx context.Context, p *CompleteMultipar
|
||||||
encInfo := FormEncryptionInfo(multipartInfo.Meta)
|
encInfo := FormEncryptionInfo(multipartInfo.Meta)
|
||||||
|
|
||||||
if len(partsInfo) < len(p.Parts) {
|
if len(partsInfo) < len(p.Parts) {
|
||||||
return nil, nil, fmt.Errorf("%w: found %d parts, need %d", s3errors.GetAPIError(s3errors.ErrInvalidPart), len(partsInfo), len(p.Parts))
|
return nil, nil, fmt.Errorf("%w: found %d parts, need %d", apierr.GetAPIError(apierr.ErrInvalidPart), len(partsInfo), len(p.Parts))
|
||||||
}
|
}
|
||||||
|
|
||||||
var multipartObjetSize uint64
|
var multipartObjetSize uint64
|
||||||
|
@ -396,12 +396,12 @@ func (n *Layer) CompleteMultipartUpload(ctx context.Context, p *CompleteMultipar
|
||||||
for i, part := range p.Parts {
|
for i, part := range p.Parts {
|
||||||
partInfo := partsInfo.Extract(part.PartNumber, data.UnQuote(part.ETag), n.features.MD5Enabled())
|
partInfo := partsInfo.Extract(part.PartNumber, data.UnQuote(part.ETag), n.features.MD5Enabled())
|
||||||
if partInfo == nil {
|
if partInfo == nil {
|
||||||
return nil, nil, fmt.Errorf("%w: unknown part %d or etag mismatched", s3errors.GetAPIError(s3errors.ErrInvalidPart), part.PartNumber)
|
return nil, nil, fmt.Errorf("%w: unknown part %d or etag mismatched", apierr.GetAPIError(apierr.ErrInvalidPart), part.PartNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
// for the last part we have no minimum size limit
|
// for the last part we have no minimum size limit
|
||||||
if i != len(p.Parts)-1 && partInfo.Size < UploadMinSize {
|
if i != len(p.Parts)-1 && partInfo.Size < UploadMinSize {
|
||||||
return nil, nil, fmt.Errorf("%w: %d/%d", s3errors.GetAPIError(s3errors.ErrEntityTooSmall), partInfo.Size, UploadMinSize)
|
return nil, nil, fmt.Errorf("%w: %d/%d", apierr.GetAPIError(apierr.ErrEntityTooSmall), partInfo.Size, UploadMinSize)
|
||||||
}
|
}
|
||||||
parts = append(parts, partInfo)
|
parts = append(parts, partInfo)
|
||||||
multipartObjetSize += partInfo.Size // even if encryption is enabled size is actual (decrypted)
|
multipartObjetSize += partInfo.Size // even if encryption is enabled size is actual (decrypted)
|
||||||
|
@ -473,7 +473,7 @@ func (n *Layer) CompleteMultipartUpload(ctx context.Context, p *CompleteMultipar
|
||||||
zap.String("uploadKey", p.Info.Key),
|
zap.String("uploadKey", p.Info.Key),
|
||||||
zap.Error(err))
|
zap.Error(err))
|
||||||
|
|
||||||
return nil, nil, s3errors.GetAPIError(s3errors.ErrInternalError)
|
return nil, nil, apierr.GetAPIError(apierr.ErrInternalError)
|
||||||
}
|
}
|
||||||
|
|
||||||
var addr oid.Address
|
var addr oid.Address
|
||||||
|
@ -581,7 +581,7 @@ func (n *Layer) ListParts(ctx context.Context, p *ListPartsParams) (*ListPartsIn
|
||||||
encInfo := FormEncryptionInfo(multipartInfo.Meta)
|
encInfo := FormEncryptionInfo(multipartInfo.Meta)
|
||||||
if err = p.Info.Encryption.MatchObjectEncryption(encInfo); err != nil {
|
if err = p.Info.Encryption.MatchObjectEncryption(encInfo); err != nil {
|
||||||
n.reqLogger(ctx).Warn(logs.MismatchedObjEncryptionInfo, zap.Error(err))
|
n.reqLogger(ctx).Warn(logs.MismatchedObjEncryptionInfo, zap.Error(err))
|
||||||
return nil, s3errors.GetAPIError(s3errors.ErrInvalidEncryptionParameters)
|
return nil, apierr.GetAPIError(apierr.ErrInvalidEncryptionParameters)
|
||||||
}
|
}
|
||||||
|
|
||||||
res.Owner = multipartInfo.Owner
|
res.Owner = multipartInfo.Owner
|
||||||
|
@ -649,7 +649,7 @@ func (n *Layer) getUploadParts(ctx context.Context, p *UploadInfoParams) (*data.
|
||||||
multipartInfo, err := n.treeService.GetMultipartUpload(ctx, p.Bkt, p.Key, p.UploadID)
|
multipartInfo, err := n.treeService.GetMultipartUpload(ctx, p.Bkt, p.Key, p.UploadID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, tree.ErrNodeNotFound) {
|
if errors.Is(err, tree.ErrNodeNotFound) {
|
||||||
return nil, nil, fmt.Errorf("%w: %s", s3errors.GetAPIError(s3errors.ErrNoSuchUpload), err.Error())
|
return nil, nil, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrNoSuchUpload), err.Error())
|
||||||
}
|
}
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/auth"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/auth"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
apiErrors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/tree"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/tree"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
|
@ -51,7 +51,7 @@ type (
|
||||||
}
|
}
|
||||||
|
|
||||||
DeleteMarkerError struct {
|
DeleteMarkerError struct {
|
||||||
ErrorCode apiErrors.ErrorCode
|
ErrorCode apierr.ErrorCode
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -289,28 +289,28 @@ func (n *Layer) PutObject(ctx context.Context, p *PutObjectParams) (*data.Extend
|
||||||
if !p.Encryption.Enabled() && len(p.ContentMD5) > 0 {
|
if !p.Encryption.Enabled() && len(p.ContentMD5) > 0 {
|
||||||
headerMd5Hash, err := base64.StdEncoding.DecodeString(p.ContentMD5)
|
headerMd5Hash, err := base64.StdEncoding.DecodeString(p.ContentMD5)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, apiErrors.GetAPIError(apiErrors.ErrInvalidDigest)
|
return nil, apierr.GetAPIError(apierr.ErrInvalidDigest)
|
||||||
}
|
}
|
||||||
if !bytes.Equal(headerMd5Hash, createdObj.MD5Sum) {
|
if !bytes.Equal(headerMd5Hash, createdObj.MD5Sum) {
|
||||||
err = n.objectDelete(ctx, p.BktInfo, createdObj.ID)
|
err = n.objectDelete(ctx, p.BktInfo, createdObj.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
n.reqLogger(ctx).Debug(logs.FailedToDeleteObject, zap.Stringer("cid", p.BktInfo.CID), zap.Stringer("oid", createdObj.ID))
|
n.reqLogger(ctx).Debug(logs.FailedToDeleteObject, zap.Stringer("cid", p.BktInfo.CID), zap.Stringer("oid", createdObj.ID))
|
||||||
}
|
}
|
||||||
return nil, apiErrors.GetAPIError(apiErrors.ErrInvalidDigest)
|
return nil, apierr.GetAPIError(apierr.ErrInvalidDigest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !p.Encryption.Enabled() && len(p.ContentSHA256Hash) > 0 && !auth.IsStandardContentSHA256(p.ContentSHA256Hash) {
|
if !p.Encryption.Enabled() && len(p.ContentSHA256Hash) > 0 && !auth.IsStandardContentSHA256(p.ContentSHA256Hash) {
|
||||||
contentHashBytes, err := hex.DecodeString(p.ContentSHA256Hash)
|
contentHashBytes, err := hex.DecodeString(p.ContentSHA256Hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, apiErrors.GetAPIError(apiErrors.ErrContentSHA256Mismatch)
|
return nil, apierr.GetAPIError(apierr.ErrContentSHA256Mismatch)
|
||||||
}
|
}
|
||||||
if !bytes.Equal(contentHashBytes, createdObj.HashSum) {
|
if !bytes.Equal(contentHashBytes, createdObj.HashSum) {
|
||||||
err = n.objectDelete(ctx, p.BktInfo, createdObj.ID)
|
err = n.objectDelete(ctx, p.BktInfo, createdObj.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
n.reqLogger(ctx).Debug(logs.FailedToDeleteObject, zap.Stringer("cid", p.BktInfo.CID), zap.Stringer("oid", createdObj.ID))
|
n.reqLogger(ctx).Debug(logs.FailedToDeleteObject, zap.Stringer("cid", p.BktInfo.CID), zap.Stringer("oid", createdObj.ID))
|
||||||
}
|
}
|
||||||
return nil, apiErrors.GetAPIError(apiErrors.ErrContentSHA256Mismatch)
|
return nil, apierr.GetAPIError(apierr.ErrContentSHA256Mismatch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -398,19 +398,19 @@ func (n *Layer) headLastVersionIfNotDeleted(ctx context.Context, bkt *data.Bucke
|
||||||
node, err := n.treeService.GetLatestVersion(ctx, bkt, objectName)
|
node, err := n.treeService.GetLatestVersion(ctx, bkt, objectName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, tree.ErrNodeNotFound) {
|
if errors.Is(err, tree.ErrNodeNotFound) {
|
||||||
return nil, fmt.Errorf("%w: %s", apiErrors.GetAPIError(apiErrors.ErrNoSuchKey), err.Error())
|
return nil, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrNoSuchKey), err.Error())
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if node.IsDeleteMarker {
|
if node.IsDeleteMarker {
|
||||||
return nil, DeleteMarkerError{ErrorCode: apiErrors.ErrNoSuchKey}
|
return nil, DeleteMarkerError{ErrorCode: apierr.ErrNoSuchKey}
|
||||||
}
|
}
|
||||||
|
|
||||||
meta, err := n.objectHead(ctx, bkt, node.OID)
|
meta, err := n.objectHead(ctx, bkt, node.OID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if client.IsErrObjectNotFound(err) {
|
if client.IsErrObjectNotFound(err) {
|
||||||
return nil, fmt.Errorf("%w: %s; %s", apiErrors.GetAPIError(apiErrors.ErrNoSuchKey), err.Error(), node.OID.EncodeToString())
|
return nil, fmt.Errorf("%w: %s; %s", apierr.GetAPIError(apierr.ErrNoSuchKey), err.Error(), node.OID.EncodeToString())
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -434,7 +434,7 @@ func (n *Layer) headVersion(ctx context.Context, bkt *data.BucketInfo, p *HeadOb
|
||||||
foundVersion, err = n.treeService.GetUnversioned(ctx, bkt, p.Object)
|
foundVersion, err = n.treeService.GetUnversioned(ctx, bkt, p.Object)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, tree.ErrNodeNotFound) {
|
if errors.Is(err, tree.ErrNodeNotFound) {
|
||||||
return nil, fmt.Errorf("%w: %s", apiErrors.GetAPIError(apiErrors.ErrNoSuchVersion), err.Error())
|
return nil, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrNoSuchVersion), err.Error())
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -451,7 +451,7 @@ func (n *Layer) headVersion(ctx context.Context, bkt *data.BucketInfo, p *HeadOb
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if foundVersion == nil {
|
if foundVersion == nil {
|
||||||
return nil, fmt.Errorf("%w: there isn't tree node with requested version id", apiErrors.GetAPIError(apiErrors.ErrNoSuchVersion))
|
return nil, fmt.Errorf("%w: there isn't tree node with requested version id", apierr.GetAPIError(apierr.ErrNoSuchVersion))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -461,13 +461,13 @@ func (n *Layer) headVersion(ctx context.Context, bkt *data.BucketInfo, p *HeadOb
|
||||||
}
|
}
|
||||||
|
|
||||||
if foundVersion.IsDeleteMarker {
|
if foundVersion.IsDeleteMarker {
|
||||||
return nil, DeleteMarkerError{ErrorCode: apiErrors.ErrMethodNotAllowed}
|
return nil, DeleteMarkerError{ErrorCode: apierr.ErrMethodNotAllowed}
|
||||||
}
|
}
|
||||||
|
|
||||||
meta, err := n.objectHead(ctx, bkt, foundVersion.OID)
|
meta, err := n.objectHead(ctx, bkt, foundVersion.OID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if client.IsErrObjectNotFound(err) {
|
if client.IsErrObjectNotFound(err) {
|
||||||
return nil, fmt.Errorf("%w: %s", apiErrors.GetAPIError(apiErrors.ErrNoSuchVersion), err.Error())
|
return nil, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrNoSuchVersion), err.Error())
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ package layer
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
errorsStd "errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -11,7 +11,7 @@ import (
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
|
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/tree"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/tree"
|
||||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
|
@ -42,7 +42,7 @@ func (n *Layer) PutLockInfo(ctx context.Context, p *PutLockInfoParams) (err erro
|
||||||
}
|
}
|
||||||
|
|
||||||
lockInfo, err := n.treeService.GetLock(ctx, p.ObjVersion.BktInfo, versionNode.ID)
|
lockInfo, err := n.treeService.GetLock(ctx, p.ObjVersion.BktInfo, versionNode.ID)
|
||||||
if err != nil && !errorsStd.Is(err, tree.ErrNodeNotFound) {
|
if err != nil && !errors.Is(err, tree.ErrNodeNotFound) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ func (n *Layer) GetLockInfo(ctx context.Context, objVersion *data.ObjectVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
lockInfo, err := n.treeService.GetLock(ctx, objVersion.BktInfo, versionNode.ID)
|
lockInfo, err := n.treeService.GetLock(ctx, objVersion.BktInfo, versionNode.ID)
|
||||||
if err != nil && !errorsStd.Is(err, tree.ErrNodeNotFound) {
|
if err != nil && !errors.Is(err, tree.ErrNodeNotFound) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if lockInfo == nil {
|
if lockInfo == nil {
|
||||||
|
@ -167,13 +167,13 @@ func (n *Layer) getCORS(ctx context.Context, bkt *data.BucketInfo) (*data.CORSCo
|
||||||
}
|
}
|
||||||
|
|
||||||
addr, err := n.treeService.GetBucketCORS(ctx, bkt)
|
addr, err := n.treeService.GetBucketCORS(ctx, bkt)
|
||||||
objNotFound := errorsStd.Is(err, tree.ErrNodeNotFound)
|
objNotFound := errors.Is(err, tree.ErrNodeNotFound)
|
||||||
if err != nil && !objNotFound {
|
if err != nil && !objNotFound {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if objNotFound {
|
if objNotFound {
|
||||||
return nil, fmt.Errorf("%w: %s", errors.GetAPIError(errors.ErrNoSuchCORSConfiguration), err.Error())
|
return nil, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrNoSuchCORSConfiguration), err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
var prmAuth frostfs.PrmAuth
|
var prmAuth frostfs.PrmAuth
|
||||||
|
@ -211,7 +211,7 @@ func (n *Layer) GetBucketSettings(ctx context.Context, bktInfo *data.BucketInfo)
|
||||||
|
|
||||||
settings, err := n.treeService.GetSettingsNode(ctx, bktInfo)
|
settings, err := n.treeService.GetSettingsNode(ctx, bktInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errorsStd.Is(err, tree.ErrNodeNotFound) {
|
if !errors.Is(err, tree.ErrNodeNotFound) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
settings = &data.BucketSettings{Versioning: data.VersioningUnversioned}
|
settings = &data.BucketSettings{Versioning: data.VersioningUnversioned}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
s3errors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/tree"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/tree"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
|
@ -41,7 +41,7 @@ func (n *Layer) GetObjectTagging(ctx context.Context, p *data.GetObjectTaggingPa
|
||||||
tags, err := n.treeService.GetObjectTagging(ctx, p.ObjectVersion.BktInfo, nodeVersion)
|
tags, err := n.treeService.GetObjectTagging(ctx, p.ObjectVersion.BktInfo, nodeVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, tree.ErrNodeNotFound) {
|
if errors.Is(err, tree.ErrNodeNotFound) {
|
||||||
return "", nil, fmt.Errorf("%w: %s", s3errors.GetAPIError(s3errors.ErrNoSuchKey), err.Error())
|
return "", nil, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrNoSuchKey), err.Error())
|
||||||
}
|
}
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ func (n *Layer) PutObjectTagging(ctx context.Context, p *data.PutObjectTaggingPa
|
||||||
err = n.treeService.PutObjectTagging(ctx, p.ObjectVersion.BktInfo, nodeVersion, p.TagSet)
|
err = n.treeService.PutObjectTagging(ctx, p.ObjectVersion.BktInfo, nodeVersion, p.TagSet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, tree.ErrNodeNotFound) {
|
if errors.Is(err, tree.ErrNodeNotFound) {
|
||||||
return fmt.Errorf("%w: %s", s3errors.GetAPIError(s3errors.ErrNoSuchKey), err.Error())
|
return fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrNoSuchKey), err.Error())
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ func (n *Layer) DeleteObjectTagging(ctx context.Context, p *data.ObjectVersion)
|
||||||
err = n.treeService.DeleteObjectTagging(ctx, p.BktInfo, version)
|
err = n.treeService.DeleteObjectTagging(ctx, p.BktInfo, version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, tree.ErrNodeNotFound) {
|
if errors.Is(err, tree.ErrNodeNotFound) {
|
||||||
return fmt.Errorf("%w: %s", s3errors.GetAPIError(s3errors.ErrNoSuchKey), err.Error())
|
return fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrNoSuchKey), err.Error())
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -156,14 +156,14 @@ func (n *Layer) getNodeVersion(ctx context.Context, objVersion *data.ObjectVersi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if version == nil {
|
if version == nil {
|
||||||
err = fmt.Errorf("%w: there isn't tree node with requested version id", s3errors.GetAPIError(s3errors.ErrNoSuchVersion))
|
err = fmt.Errorf("%w: there isn't tree node with requested version id", apierr.GetAPIError(apierr.ErrNoSuchVersion))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil && version.IsDeleteMarker && !objVersion.NoErrorOnDeleteMarker {
|
if err == nil && version.IsDeleteMarker && !objVersion.NoErrorOnDeleteMarker {
|
||||||
return nil, fmt.Errorf("%w: found version is delete marker", s3errors.GetAPIError(s3errors.ErrNoSuchKey))
|
return nil, fmt.Errorf("%w: found version is delete marker", apierr.GetAPIError(apierr.ErrNoSuchKey))
|
||||||
} else if errors.Is(err, tree.ErrNodeNotFound) {
|
} else if errors.Is(err, tree.ErrNodeNotFound) {
|
||||||
return nil, fmt.Errorf("%w: %s", s3errors.GetAPIError(s3errors.ErrNoSuchKey), err.Error())
|
return nil, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrNoSuchKey), err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil && version != nil && !version.IsDeleteMarker {
|
if err == nil && version != nil && !version.IsDeleteMarker {
|
||||||
|
|
|
@ -8,9 +8,9 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
|
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
|
||||||
apiErrors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
||||||
frostfsErrors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/errors"
|
frosterr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||||
|
@ -57,9 +57,10 @@ func Auth(center Center, log *zap.Logger) Func {
|
||||||
reqLogOrDefault(ctx, log).Debug(logs.CouldntReceiveAccessBoxForGateKeyRandomKeyWillBeUsed, zap.Error(err))
|
reqLogOrDefault(ctx, log).Debug(logs.CouldntReceiveAccessBoxForGateKeyRandomKeyWillBeUsed, zap.Error(err))
|
||||||
} else {
|
} else {
|
||||||
reqLogOrDefault(ctx, log).Error(logs.FailedToPassAuthentication, zap.Error(err))
|
reqLogOrDefault(ctx, log).Error(logs.FailedToPassAuthentication, zap.Error(err))
|
||||||
err = frostfsErrors.UnwrapErr(err)
|
err = frosterr.UnwrapErr(err)
|
||||||
if _, ok := err.(apiErrors.Error); !ok {
|
log.Info("error", zap.Error(err), zap.String("code", err.(apierr.Error).Code), zap.String("description", err.(apierr.Error).Description))
|
||||||
err = apiErrors.GetAPIError(apiErrors.ErrAccessDenied)
|
if _, ok := err.(apierr.Error); !ok {
|
||||||
|
err = apierr.GetAPIError(apierr.ErrAccessDenied)
|
||||||
}
|
}
|
||||||
if _, wrErr := WriteErrorResponse(w, GetReqInfo(r.Context()), err); wrErr != nil {
|
if _, wrErr := WriteErrorResponse(w, GetReqInfo(r.Context()), err); wrErr != nil {
|
||||||
reqLogOrDefault(ctx, log).Error(logs.FailedToWriteResponse, zap.Error(wrErr))
|
reqLogOrDefault(ctx, log).Error(logs.FailedToWriteResponse, zap.Error(wrErr))
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
apiErr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
frostfsErrors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/errors"
|
frostfsErrors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
|
@ -145,11 +145,11 @@ func policyCheck(r *http.Request, cfg PolicyConfig) error {
|
||||||
case st == chain.Allow:
|
case st == chain.Allow:
|
||||||
return nil
|
return nil
|
||||||
case st != chain.NoRuleFound:
|
case st != chain.NoRuleFound:
|
||||||
return apiErr.GetAPIErrorWithError(apiErr.ErrAccessDenied, fmt.Errorf("policy check: %s", st.String()))
|
return apierr.GetAPIErrorWithError(apierr.ErrAccessDenied, fmt.Errorf("policy check: %s", st.String()))
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Settings.PolicyDenyByDefault() {
|
if cfg.Settings.PolicyDenyByDefault() {
|
||||||
return apiErr.GetAPIErrorWithError(apiErr.ErrAccessDenied, fmt.Errorf("policy check: %s", st.String()))
|
return apierr.GetAPIErrorWithError(apierr.ErrAccessDenied, fmt.Errorf("policy check: %s", st.String()))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -461,7 +461,7 @@ func determineRequestTags(r *http.Request, decoder XMLDecoder, op string) (map[s
|
||||||
if strings.HasSuffix(op, PutObjectTaggingOperation) || strings.HasSuffix(op, PutBucketTaggingOperation) {
|
if strings.HasSuffix(op, PutObjectTaggingOperation) || strings.HasSuffix(op, PutBucketTaggingOperation) {
|
||||||
tagging := new(data.Tagging)
|
tagging := new(data.Tagging)
|
||||||
if err := decoder.NewXMLDecoder(r.Body).Decode(tagging); err != nil {
|
if err := decoder.NewXMLDecoder(r.Body).Decode(tagging); err != nil {
|
||||||
return nil, fmt.Errorf("%w: %s", apiErr.GetAPIError(apiErr.ErrMalformedXML), err.Error())
|
return nil, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrMalformedXML), err.Error())
|
||||||
}
|
}
|
||||||
GetReqInfo(r.Context()).Tagging = tagging
|
GetReqInfo(r.Context()).Tagging = tagging
|
||||||
|
|
||||||
|
@ -473,7 +473,7 @@ func determineRequestTags(r *http.Request, decoder XMLDecoder, op string) (map[s
|
||||||
if tagging := r.Header.Get(amzTagging); len(tagging) > 0 {
|
if tagging := r.Header.Get(amzTagging); len(tagging) > 0 {
|
||||||
queries, err := url.ParseQuery(tagging)
|
queries, err := url.ParseQuery(tagging)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, apiErr.GetAPIError(apiErr.ErrInvalidArgument)
|
return nil, apierr.GetAPIError(apierr.ErrInvalidArgument)
|
||||||
}
|
}
|
||||||
for key := range queries {
|
for key := range queries {
|
||||||
tags[fmt.Sprintf(s3.PropertyKeyFormatRequestTag, key)] = queries.Get(key)
|
tags[fmt.Sprintf(s3.PropertyKeyFormatRequestTag, key)] = queries.Get(key)
|
||||||
|
|
|
@ -62,7 +62,7 @@ const (
|
||||||
hdrSSE = "X-Amz-Server-Side-Encryption"
|
hdrSSE = "X-Amz-Server-Side-Encryption"
|
||||||
|
|
||||||
// hdrSSECustomerKey is the HTTP header key referencing the
|
// hdrSSECustomerKey is the HTTP header key referencing the
|
||||||
// SSE-C client-provided key..
|
// SSE-C client-provided key.
|
||||||
hdrSSECustomerKey = hdrSSE + "-Customer-Key"
|
hdrSSECustomerKey = hdrSSE + "-Customer-Key"
|
||||||
|
|
||||||
// hdrSSECopyKey is the HTTP header key referencing the SSE-C
|
// hdrSSECopyKey is the HTTP header key referencing the SSE-C
|
||||||
|
@ -74,7 +74,7 @@ var (
|
||||||
xmlHeader = []byte(xml.Header)
|
xmlHeader = []byte(xml.Header)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Non exhaustive list of AWS S3 standard error responses -
|
// Non-exhaustive list of AWS S3 standard error responses -
|
||||||
// http://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html
|
// http://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html
|
||||||
var s3ErrorResponseMap = map[string]string{
|
var s3ErrorResponseMap = map[string]string{
|
||||||
"AccessDenied": "Access Denied.",
|
"AccessDenied": "Access Denied.",
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
apiErrors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||||
|
@ -159,14 +159,14 @@ type resourceTaggingMock struct {
|
||||||
|
|
||||||
func (m *resourceTaggingMock) GetBucketTagging(context.Context, *data.BucketInfo) (map[string]string, error) {
|
func (m *resourceTaggingMock) GetBucketTagging(context.Context, *data.BucketInfo) (map[string]string, error) {
|
||||||
if m.noSuchBucketKey {
|
if m.noSuchBucketKey {
|
||||||
return nil, apiErrors.GetAPIError(apiErrors.ErrNoSuchKey)
|
return nil, apierr.GetAPIError(apierr.ErrNoSuchKey)
|
||||||
}
|
}
|
||||||
return m.bucketTags, nil
|
return m.bucketTags, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *resourceTaggingMock) GetObjectTagging(context.Context, *data.GetObjectTaggingParams) (string, map[string]string, error) {
|
func (m *resourceTaggingMock) GetObjectTagging(context.Context, *data.GetObjectTaggingParams) (string, map[string]string, error) {
|
||||||
if m.noSuchObjectKey {
|
if m.noSuchObjectKey {
|
||||||
return "", nil, apiErrors.GetAPIError(apiErrors.ErrNoSuchKey)
|
return "", nil, apierr.GetAPIError(apierr.ErrNoSuchKey)
|
||||||
}
|
}
|
||||||
return "", m.objectTags, nil
|
return "", m.objectTags, nil
|
||||||
}
|
}
|
||||||
|
@ -573,7 +573,7 @@ func (h *handlerMock) ResolveBucket(ctx context.Context, name string) (*data.Buc
|
||||||
reqInfo := middleware.GetReqInfo(ctx)
|
reqInfo := middleware.GetReqInfo(ctx)
|
||||||
bktInfo, ok := h.buckets[reqInfo.Namespace+name]
|
bktInfo, ok := h.buckets[reqInfo.Namespace+name]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, apiErrors.GetAPIError(apiErrors.ErrNoSuchBucket)
|
return nil, apierr.GetAPIError(apierr.ErrNoSuchBucket)
|
||||||
}
|
}
|
||||||
return bktInfo, nil
|
return bktInfo, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
apiErrors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
s3middleware "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
s3middleware "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/metrics"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/metrics"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||||
|
@ -214,18 +214,18 @@ func TestPolicyChecker(t *testing.T) {
|
||||||
deleteObject(chiRouter, ns2, bktName2, objName2, nil)
|
deleteObject(chiRouter, ns2, bktName2, objName2, nil)
|
||||||
|
|
||||||
// check we cannot access 'bucket' in custom namespace
|
// check we cannot access 'bucket' in custom namespace
|
||||||
putObjectErr(chiRouter, ns2, bktName1, objName2, nil, apiErrors.ErrAccessDenied)
|
putObjectErr(chiRouter, ns2, bktName1, objName2, nil, apierr.ErrAccessDenied)
|
||||||
deleteObjectErr(chiRouter, ns2, bktName1, objName2, nil, apiErrors.ErrAccessDenied)
|
deleteObjectErr(chiRouter, ns2, bktName1, objName2, nil, apierr.ErrAccessDenied)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPolicyCheckerError(t *testing.T) {
|
func TestPolicyCheckerError(t *testing.T) {
|
||||||
chiRouter := prepareRouter(t)
|
chiRouter := prepareRouter(t)
|
||||||
ns1, bktName1, objName1 := "", "bucket", "object"
|
ns1, bktName1, objName1 := "", "bucket", "object"
|
||||||
putObjectErr(chiRouter, ns1, bktName1, objName1, nil, apiErrors.ErrNoSuchBucket)
|
putObjectErr(chiRouter, ns1, bktName1, objName1, nil, apierr.ErrNoSuchBucket)
|
||||||
|
|
||||||
chiRouter = prepareRouter(t)
|
chiRouter = prepareRouter(t)
|
||||||
chiRouter.cfg.FrostfsID.(*frostFSIDMock).userGroupsError = true
|
chiRouter.cfg.FrostfsID.(*frostFSIDMock).userGroupsError = true
|
||||||
putObjectErr(chiRouter, ns1, bktName1, objName1, nil, apiErrors.ErrInternalError)
|
putObjectErr(chiRouter, ns1, bktName1, objName1, nil, apierr.ErrInternalError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPolicyCheckerReqTypeDetermination(t *testing.T) {
|
func TestPolicyCheckerReqTypeDetermination(t *testing.T) {
|
||||||
|
@ -283,7 +283,7 @@ func TestDefaultBehaviorPolicyChecker(t *testing.T) {
|
||||||
|
|
||||||
// check we cannot access if rules not found when settings is enabled
|
// check we cannot access if rules not found when settings is enabled
|
||||||
chiRouter.middlewareSettings.denyByDefault = true
|
chiRouter.middlewareSettings.denyByDefault = true
|
||||||
createBucketErr(chiRouter, ns, bktName, nil, apiErrors.ErrAccessDenied)
|
createBucketErr(chiRouter, ns, bktName, nil, apierr.ErrAccessDenied)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDefaultPolicyCheckerWithUserTags(t *testing.T) {
|
func TestDefaultPolicyCheckerWithUserTags(t *testing.T) {
|
||||||
|
@ -294,7 +294,7 @@ func TestDefaultPolicyCheckerWithUserTags(t *testing.T) {
|
||||||
allowOperations(router, ns, []string{"s3:CreateBucket"}, engineiam.Conditions{
|
allowOperations(router, ns, []string{"s3:CreateBucket"}, engineiam.Conditions{
|
||||||
engineiam.CondStringEquals: engineiam.Condition{fmt.Sprintf(common.PropertyKeyFormatFrostFSIDUserClaim, "tag-test"): []string{"test"}},
|
engineiam.CondStringEquals: engineiam.Condition{fmt.Sprintf(common.PropertyKeyFormatFrostFSIDUserClaim, "tag-test"): []string{"test"}},
|
||||||
})
|
})
|
||||||
createBucketErr(router, ns, bktName, nil, apiErrors.ErrAccessDenied)
|
createBucketErr(router, ns, bktName, nil, apierr.ErrAccessDenied)
|
||||||
|
|
||||||
tags := make(map[string]string)
|
tags := make(map[string]string)
|
||||||
tags["tag-test"] = "test"
|
tags["tag-test"] = "test"
|
||||||
|
@ -321,8 +321,8 @@ func TestRequestParametersCheck(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
listObjectsV1(router, ns, bktName, prefix, "", "")
|
listObjectsV1(router, ns, bktName, prefix, "", "")
|
||||||
listObjectsV1Err(router, ns, bktName, "", "", "", apiErrors.ErrAccessDenied)
|
listObjectsV1Err(router, ns, bktName, "", "", "", apierr.ErrAccessDenied)
|
||||||
listObjectsV1Err(router, ns, bktName, "invalid", "", "", apiErrors.ErrAccessDenied)
|
listObjectsV1Err(router, ns, bktName, "invalid", "", "", apierr.ErrAccessDenied)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("delimiter parameter, prohibit specific value", func(t *testing.T) {
|
t.Run("delimiter parameter, prohibit specific value", func(t *testing.T) {
|
||||||
|
@ -344,7 +344,7 @@ func TestRequestParametersCheck(t *testing.T) {
|
||||||
|
|
||||||
listObjectsV1(router, ns, bktName, "", "", "")
|
listObjectsV1(router, ns, bktName, "", "", "")
|
||||||
listObjectsV1(router, ns, bktName, "", "some-delimiter", "")
|
listObjectsV1(router, ns, bktName, "", "some-delimiter", "")
|
||||||
listObjectsV1Err(router, ns, bktName, "", delimiter, "", apiErrors.ErrAccessDenied)
|
listObjectsV1Err(router, ns, bktName, "", delimiter, "", apierr.ErrAccessDenied)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("max-keys parameter, allow specific value", func(t *testing.T) {
|
t.Run("max-keys parameter, allow specific value", func(t *testing.T) {
|
||||||
|
@ -365,9 +365,9 @@ func TestRequestParametersCheck(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
listObjectsV1(router, ns, bktName, "", "", strconv.Itoa(maxKeys))
|
listObjectsV1(router, ns, bktName, "", "", strconv.Itoa(maxKeys))
|
||||||
listObjectsV1Err(router, ns, bktName, "", "", "", apiErrors.ErrAccessDenied)
|
listObjectsV1Err(router, ns, bktName, "", "", "", apierr.ErrAccessDenied)
|
||||||
listObjectsV1Err(router, ns, bktName, "", "", strconv.Itoa(maxKeys-1), apiErrors.ErrAccessDenied)
|
listObjectsV1Err(router, ns, bktName, "", "", strconv.Itoa(maxKeys-1), apierr.ErrAccessDenied)
|
||||||
listObjectsV1Err(router, ns, bktName, "", "", "invalid", apiErrors.ErrAccessDenied)
|
listObjectsV1Err(router, ns, bktName, "", "", "invalid", apierr.ErrAccessDenied)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("max-keys parameter, allow range of values", func(t *testing.T) {
|
t.Run("max-keys parameter, allow range of values", func(t *testing.T) {
|
||||||
|
@ -389,7 +389,7 @@ func TestRequestParametersCheck(t *testing.T) {
|
||||||
|
|
||||||
listObjectsV1(router, ns, bktName, "", "", strconv.Itoa(maxKeys))
|
listObjectsV1(router, ns, bktName, "", "", strconv.Itoa(maxKeys))
|
||||||
listObjectsV1(router, ns, bktName, "", "", strconv.Itoa(maxKeys-1))
|
listObjectsV1(router, ns, bktName, "", "", strconv.Itoa(maxKeys-1))
|
||||||
listObjectsV1Err(router, ns, bktName, "", "", strconv.Itoa(maxKeys+1), apiErrors.ErrAccessDenied)
|
listObjectsV1Err(router, ns, bktName, "", "", strconv.Itoa(maxKeys+1), apierr.ErrAccessDenied)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("max-keys parameter, prohibit specific value", func(t *testing.T) {
|
t.Run("max-keys parameter, prohibit specific value", func(t *testing.T) {
|
||||||
|
@ -411,7 +411,7 @@ func TestRequestParametersCheck(t *testing.T) {
|
||||||
|
|
||||||
listObjectsV1(router, ns, bktName, "", "", "")
|
listObjectsV1(router, ns, bktName, "", "", "")
|
||||||
listObjectsV1(router, ns, bktName, "", "", strconv.Itoa(maxKeys-1))
|
listObjectsV1(router, ns, bktName, "", "", strconv.Itoa(maxKeys-1))
|
||||||
listObjectsV1Err(router, ns, bktName, "", "", strconv.Itoa(maxKeys), apiErrors.ErrAccessDenied)
|
listObjectsV1Err(router, ns, bktName, "", "", strconv.Itoa(maxKeys), apierr.ErrAccessDenied)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,10 +439,10 @@ func TestRequestTagsCheck(t *testing.T) {
|
||||||
|
|
||||||
tagging, err = xml.Marshal(data.Tagging{TagSet: []data.Tag{{Key: "key", Value: tagValue}}})
|
tagging, err = xml.Marshal(data.Tagging{TagSet: []data.Tag{{Key: "key", Value: tagValue}}})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
putBucketTaggingErr(router, ns, bktName, tagging, apiErrors.ErrAccessDenied)
|
putBucketTaggingErr(router, ns, bktName, tagging, apierr.ErrAccessDenied)
|
||||||
|
|
||||||
tagging = nil
|
tagging = nil
|
||||||
putBucketTaggingErr(router, ns, bktName, tagging, apiErrors.ErrMalformedXML)
|
putBucketTaggingErr(router, ns, bktName, tagging, apierr.ErrMalformedXML)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("put object with tag", func(t *testing.T) {
|
t.Run("put object with tag", func(t *testing.T) {
|
||||||
|
@ -464,7 +464,7 @@ func TestRequestTagsCheck(t *testing.T) {
|
||||||
|
|
||||||
putObject(router, ns, bktName, objName, &data.Tag{Key: tagKey, Value: tagValue})
|
putObject(router, ns, bktName, objName, &data.Tag{Key: tagKey, Value: tagValue})
|
||||||
|
|
||||||
putObjectErr(router, ns, bktName, objName, &data.Tag{Key: "key", Value: tagValue}, apiErrors.ErrAccessDenied)
|
putObjectErr(router, ns, bktName, objName, &data.Tag{Key: "key", Value: tagValue}, apierr.ErrAccessDenied)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -490,7 +490,7 @@ func TestResourceTagsCheck(t *testing.T) {
|
||||||
listObjectsV1(router, ns, bktName, "", "", "")
|
listObjectsV1(router, ns, bktName, "", "", "")
|
||||||
|
|
||||||
router.cfg.Tagging.(*resourceTaggingMock).bucketTags = map[string]string{}
|
router.cfg.Tagging.(*resourceTaggingMock).bucketTags = map[string]string{}
|
||||||
listObjectsV1Err(router, ns, bktName, "", "", "", apiErrors.ErrAccessDenied)
|
listObjectsV1Err(router, ns, bktName, "", "", "", apierr.ErrAccessDenied)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("object tagging", func(t *testing.T) {
|
t.Run("object tagging", func(t *testing.T) {
|
||||||
|
@ -515,22 +515,22 @@ func TestResourceTagsCheck(t *testing.T) {
|
||||||
getObject(router, ns, bktName, objName)
|
getObject(router, ns, bktName, objName)
|
||||||
|
|
||||||
router.cfg.Tagging.(*resourceTaggingMock).objectTags = map[string]string{}
|
router.cfg.Tagging.(*resourceTaggingMock).objectTags = map[string]string{}
|
||||||
getObjectErr(router, ns, bktName, objName, apiErrors.ErrAccessDenied)
|
getObjectErr(router, ns, bktName, objName, apierr.ErrAccessDenied)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("non-existent resources", func(t *testing.T) {
|
t.Run("non-existent resources", func(t *testing.T) {
|
||||||
router := prepareRouter(t)
|
router := prepareRouter(t)
|
||||||
ns, bktName, objName := "", "bucket", "object"
|
ns, bktName, objName := "", "bucket", "object"
|
||||||
|
|
||||||
listObjectsV1Err(router, ns, bktName, "", "", "", apiErrors.ErrNoSuchBucket)
|
listObjectsV1Err(router, ns, bktName, "", "", "", apierr.ErrNoSuchBucket)
|
||||||
|
|
||||||
router.cfg.Tagging.(*resourceTaggingMock).noSuchBucketKey = true
|
router.cfg.Tagging.(*resourceTaggingMock).noSuchBucketKey = true
|
||||||
createBucket(router, ns, bktName)
|
createBucket(router, ns, bktName)
|
||||||
getBucketErr(router, ns, bktName, apiErrors.ErrNoSuchKey)
|
getBucketErr(router, ns, bktName, apierr.ErrNoSuchKey)
|
||||||
|
|
||||||
router.cfg.Tagging.(*resourceTaggingMock).noSuchObjectKey = true
|
router.cfg.Tagging.(*resourceTaggingMock).noSuchObjectKey = true
|
||||||
createBucket(router, ns, bktName)
|
createBucket(router, ns, bktName)
|
||||||
getObjectErr(router, ns, bktName, objName, apiErrors.ErrNoSuchKey)
|
getObjectErr(router, ns, bktName, objName, apierr.ErrNoSuchKey)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -548,7 +548,7 @@ func TestAccessBoxAttributesCheck(t *testing.T) {
|
||||||
engineiam.CondBool: engineiam.Condition{fmt.Sprintf(s3.PropertyKeyFormatAccessBoxAttr, attrKey): []string{attrValue}},
|
engineiam.CondBool: engineiam.Condition{fmt.Sprintf(s3.PropertyKeyFormatAccessBoxAttr, attrKey): []string{attrValue}},
|
||||||
})
|
})
|
||||||
|
|
||||||
listObjectsV1Err(router, ns, bktName, "", "", "", apiErrors.ErrAccessDenied)
|
listObjectsV1Err(router, ns, bktName, "", "", "", apierr.ErrAccessDenied)
|
||||||
|
|
||||||
var attr object.Attribute
|
var attr object.Attribute
|
||||||
attr.SetKey(attrKey)
|
attr.SetKey(attrKey)
|
||||||
|
@ -570,7 +570,7 @@ func TestSourceIPCheck(t *testing.T) {
|
||||||
|
|
||||||
router.middlewareSettings.sourceIPHeader = hdr
|
router.middlewareSettings.sourceIPHeader = hdr
|
||||||
header := map[string][]string{hdr: {"192.0.3.0"}}
|
header := map[string][]string{hdr: {"192.0.3.0"}}
|
||||||
createBucketErr(router, ns, bktName, header, apiErrors.ErrAccessDenied)
|
createBucketErr(router, ns, bktName, header, apierr.ErrAccessDenied)
|
||||||
|
|
||||||
router.middlewareSettings.sourceIPHeader = ""
|
router.middlewareSettings.sourceIPHeader = ""
|
||||||
createBucket(router, ns, bktName)
|
createBucket(router, ns, bktName)
|
||||||
|
@ -586,7 +586,7 @@ func TestMFAPolicy(t *testing.T) {
|
||||||
denyOperations(router, ns, []string{"s3:CreateBucket"}, engineiam.Conditions{
|
denyOperations(router, ns, []string{"s3:CreateBucket"}, engineiam.Conditions{
|
||||||
engineiam.CondBool: engineiam.Condition{s3.PropertyKeyAccessBoxAttrMFA: []string{"false"}},
|
engineiam.CondBool: engineiam.Condition{s3.PropertyKeyAccessBoxAttrMFA: []string{"false"}},
|
||||||
})
|
})
|
||||||
createBucketErr(router, ns, bktName, nil, apiErrors.ErrAccessDenied)
|
createBucketErr(router, ns, bktName, nil, apierr.ErrAccessDenied)
|
||||||
|
|
||||||
var attr object.Attribute
|
var attr object.Attribute
|
||||||
attr.SetKey("IAM-MFA")
|
attr.SetKey("IAM-MFA")
|
||||||
|
@ -630,7 +630,7 @@ func createBucket(router *routerMock, namespace, bktName string) {
|
||||||
require.Equal(router.t, s3middleware.CreateBucketOperation, resp.Method)
|
require.Equal(router.t, s3middleware.CreateBucketOperation, resp.Method)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createBucketErr(router *routerMock, namespace, bktName string, header http.Header, errCode apiErrors.ErrorCode) {
|
func createBucketErr(router *routerMock, namespace, bktName string, header http.Header, errCode apierr.ErrorCode) {
|
||||||
w := createBucketBase(router, namespace, bktName, header)
|
w := createBucketBase(router, namespace, bktName, header)
|
||||||
assertAPIError(router.t, w, errCode)
|
assertAPIError(router.t, w, errCode)
|
||||||
}
|
}
|
||||||
|
@ -646,7 +646,7 @@ func createBucketBase(router *routerMock, namespace, bktName string, header http
|
||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBucketErr(router *routerMock, namespace, bktName string, errCode apiErrors.ErrorCode) {
|
func getBucketErr(router *routerMock, namespace, bktName string, errCode apierr.ErrorCode) {
|
||||||
w := getBucketBase(router, namespace, bktName)
|
w := getBucketBase(router, namespace, bktName)
|
||||||
assertAPIError(router.t, w, errCode)
|
assertAPIError(router.t, w, errCode)
|
||||||
}
|
}
|
||||||
|
@ -665,7 +665,7 @@ func putObject(router *routerMock, namespace, bktName, objName string, tag *data
|
||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
|
|
||||||
func putObjectErr(router *routerMock, namespace, bktName, objName string, tag *data.Tag, errCode apiErrors.ErrorCode) {
|
func putObjectErr(router *routerMock, namespace, bktName, objName string, tag *data.Tag, errCode apierr.ErrorCode) {
|
||||||
w := putObjectBase(router, namespace, bktName, objName, tag)
|
w := putObjectBase(router, namespace, bktName, objName, tag)
|
||||||
assertAPIError(router.t, w, errCode)
|
assertAPIError(router.t, w, errCode)
|
||||||
}
|
}
|
||||||
|
@ -690,7 +690,7 @@ func deleteObject(router *routerMock, namespace, bktName, objName string, tag *d
|
||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteObjectErr(router *routerMock, namespace, bktName, objName string, tag *data.Tag, errCode apiErrors.ErrorCode) {
|
func deleteObjectErr(router *routerMock, namespace, bktName, objName string, tag *data.Tag, errCode apierr.ErrorCode) {
|
||||||
w := deleteObjectBase(router, namespace, bktName, objName, tag)
|
w := deleteObjectBase(router, namespace, bktName, objName, tag)
|
||||||
assertAPIError(router.t, w, errCode)
|
assertAPIError(router.t, w, errCode)
|
||||||
}
|
}
|
||||||
|
@ -715,7 +715,7 @@ func putBucketTagging(router *routerMock, namespace, bktName string, tagging []b
|
||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
|
|
||||||
func putBucketTaggingErr(router *routerMock, namespace, bktName string, tagging []byte, errCode apiErrors.ErrorCode) {
|
func putBucketTaggingErr(router *routerMock, namespace, bktName string, tagging []byte, errCode apierr.ErrorCode) {
|
||||||
w := putBucketTaggingBase(router, namespace, bktName, tagging)
|
w := putBucketTaggingBase(router, namespace, bktName, tagging)
|
||||||
assertAPIError(router.t, w, errCode)
|
assertAPIError(router.t, w, errCode)
|
||||||
}
|
}
|
||||||
|
@ -738,7 +738,7 @@ func getObject(router *routerMock, namespace, bktName, objName string) handlerRe
|
||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
|
|
||||||
func getObjectErr(router *routerMock, namespace, bktName, objName string, errCode apiErrors.ErrorCode) {
|
func getObjectErr(router *routerMock, namespace, bktName, objName string, errCode apierr.ErrorCode) {
|
||||||
w := getObjectBase(router, namespace, bktName, objName)
|
w := getObjectBase(router, namespace, bktName, objName)
|
||||||
assertAPIError(router.t, w, errCode)
|
assertAPIError(router.t, w, errCode)
|
||||||
}
|
}
|
||||||
|
@ -757,7 +757,7 @@ func listObjectsV1(router *routerMock, namespace, bktName, prefix, delimiter, ma
|
||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
|
|
||||||
func listObjectsV1Err(router *routerMock, namespace, bktName, prefix, delimiter, maxKeys string, errCode apiErrors.ErrorCode) {
|
func listObjectsV1Err(router *routerMock, namespace, bktName, prefix, delimiter, maxKeys string, errCode apierr.ErrorCode) {
|
||||||
w := listObjectsV1Base(router, namespace, bktName, prefix, delimiter, maxKeys)
|
w := listObjectsV1Base(router, namespace, bktName, prefix, delimiter, maxKeys)
|
||||||
assertAPIError(router.t, w, errCode)
|
assertAPIError(router.t, w, errCode)
|
||||||
}
|
}
|
||||||
|
@ -827,7 +827,7 @@ func TestAuthenticate(t *testing.T) {
|
||||||
|
|
||||||
chiRouter = prepareRouter(t)
|
chiRouter = prepareRouter(t)
|
||||||
chiRouter.cfg.Center.(*centerMock).isError = true
|
chiRouter.cfg.Center.(*centerMock).isError = true
|
||||||
createBucketErr(chiRouter, "", "bkt-3", nil, apiErrors.ErrAccessDenied)
|
createBucketErr(chiRouter, "", "bkt-3", nil, apierr.ErrAccessDenied)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFrostFSIDValidation(t *testing.T) {
|
func TestFrostFSIDValidation(t *testing.T) {
|
||||||
|
@ -843,7 +843,7 @@ func TestFrostFSIDValidation(t *testing.T) {
|
||||||
// frostFSID validation failed
|
// frostFSID validation failed
|
||||||
chiRouter = prepareRouter(t, frostFSIDValidation(true))
|
chiRouter = prepareRouter(t, frostFSIDValidation(true))
|
||||||
chiRouter.cfg.FrostfsID.(*frostFSIDMock).validateError = true
|
chiRouter.cfg.FrostfsID.(*frostFSIDMock).validateError = true
|
||||||
createBucketErr(chiRouter, "", "bkt-3", nil, apiErrors.ErrInternalError)
|
createBucketErr(chiRouter, "", "bkt-3", nil, apierr.ErrInternalError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRouterListObjectsV2Domains(t *testing.T) {
|
func TestRouterListObjectsV2Domains(t *testing.T) {
|
||||||
|
@ -882,17 +882,17 @@ func readResponse(t *testing.T, w *httptest.ResponseRecorder) handlerResult {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertAPIError(t *testing.T, w *httptest.ResponseRecorder, expectedErrorCode apiErrors.ErrorCode) {
|
func assertAPIError(t *testing.T, w *httptest.ResponseRecorder, expectedErrorCode apierr.ErrorCode) {
|
||||||
actualErrorResponse := &s3middleware.ErrorResponse{}
|
actualErrorResponse := &s3middleware.ErrorResponse{}
|
||||||
err := xml.NewDecoder(w.Result().Body).Decode(actualErrorResponse)
|
err := xml.NewDecoder(w.Result().Body).Decode(actualErrorResponse)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
expectedError := apiErrors.GetAPIError(expectedErrorCode)
|
expectedError := apierr.GetAPIError(expectedErrorCode)
|
||||||
|
|
||||||
require.Equal(t, expectedError.HTTPStatusCode, w.Code)
|
require.Equal(t, expectedError.HTTPStatusCode, w.Code)
|
||||||
require.Equal(t, expectedError.Code, actualErrorResponse.Code)
|
require.Equal(t, expectedError.Code, actualErrorResponse.Code)
|
||||||
|
|
||||||
if expectedError.ErrCode != apiErrors.ErrInternalError {
|
if expectedError.ErrCode != apierr.ErrInternalError {
|
||||||
require.Contains(t, actualErrorResponse.Message, expectedError.Description)
|
require.Contains(t, actualErrorResponse.Message, expectedError.Description)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
|
|
||||||
objectv2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
|
objectv2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
|
||||||
errorsFrost "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/errors"
|
frosterr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
||||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
|
@ -466,11 +466,11 @@ func handleObjectError(msg string, err error) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if reason, ok := errorsFrost.IsErrObjectAccessDenied(err); ok {
|
if reason, ok := frosterr.IsErrObjectAccessDenied(err); ok {
|
||||||
return fmt.Errorf("%s: %w: %s", msg, frostfs.ErrAccessDenied, reason)
|
return fmt.Errorf("%s: %w: %s", msg, frostfs.ErrAccessDenied, reason)
|
||||||
}
|
}
|
||||||
|
|
||||||
if errorsFrost.IsTimeoutError(err) {
|
if frosterr.IsTimeoutError(err) {
|
||||||
return fmt.Errorf("%s: %w: %s", msg, frostfs.ErrGatewayTimeout, err.Error())
|
return fmt.Errorf("%s: %w: %s", msg, frostfs.ErrGatewayTimeout, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
|
||||||
errorsFrost "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/errors"
|
frosterr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/errors"
|
||||||
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
|
@ -22,7 +22,7 @@ func TestErrorChecking(t *testing.T) {
|
||||||
|
|
||||||
var wrappedError error
|
var wrappedError error
|
||||||
|
|
||||||
if fetchedReason, ok := errorsFrost.IsErrObjectAccessDenied(err); ok {
|
if fetchedReason, ok := frosterr.IsErrObjectAccessDenied(err); ok {
|
||||||
wrappedError = fmt.Errorf("%w: %s", frostfs.ErrAccessDenied, fetchedReason)
|
wrappedError = fmt.Errorf("%w: %s", frostfs.ErrAccessDenied, fetchedReason)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ func TestErrorChecking(t *testing.T) {
|
||||||
|
|
||||||
func TestErrorTimeoutChecking(t *testing.T) {
|
func TestErrorTimeoutChecking(t *testing.T) {
|
||||||
t.Run("simple timeout", func(t *testing.T) {
|
t.Run("simple timeout", func(t *testing.T) {
|
||||||
require.True(t, errorsFrost.IsTimeoutError(errors.New("timeout")))
|
require.True(t, frosterr.IsTimeoutError(errors.New("timeout")))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("deadline exceeded", func(t *testing.T) {
|
t.Run("deadline exceeded", func(t *testing.T) {
|
||||||
|
@ -40,11 +40,11 @@ func TestErrorTimeoutChecking(t *testing.T) {
|
||||||
defer cancel()
|
defer cancel()
|
||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
|
|
||||||
require.True(t, errorsFrost.IsTimeoutError(ctx.Err()))
|
require.True(t, frosterr.IsTimeoutError(ctx.Err()))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("grpc deadline exceeded", func(t *testing.T) {
|
t.Run("grpc deadline exceeded", func(t *testing.T) {
|
||||||
err := fmt.Errorf("wrap grpc error: %w", status.Error(codes.DeadlineExceeded, "error"))
|
err := fmt.Errorf("wrap grpc error: %w", status.Error(codes.DeadlineExceeded, "error"))
|
||||||
require.True(t, errorsFrost.IsTimeoutError(err))
|
require.True(t, frosterr.IsTimeoutError(err))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,15 +8,15 @@ import (
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
errorsFrost "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/errors"
|
frosterr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/tree"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/tree"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||||
treepool "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool/tree"
|
treepool "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool/tree"
|
||||||
grpcService "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool/tree/service"
|
grpcservice "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool/tree/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GetNodeByPathResponseInfoWrapper struct {
|
type GetNodeByPathResponseInfoWrapper struct {
|
||||||
response *grpcService.GetNodeByPathResponse_Info
|
response *grpcservice.GetNodeByPathResponse_Info
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n GetNodeByPathResponseInfoWrapper) GetNodeID() []uint64 {
|
func (n GetNodeByPathResponseInfoWrapper) GetNodeID() []uint64 {
|
||||||
|
@ -40,7 +40,7 @@ func (n GetNodeByPathResponseInfoWrapper) GetMeta() []tree.Meta {
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetSubTreeResponseBodyWrapper struct {
|
type GetSubTreeResponseBodyWrapper struct {
|
||||||
response *grpcService.GetSubTreeResponse_Body
|
response *grpcservice.GetSubTreeResponse_Body
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n GetSubTreeResponseBodyWrapper) GetNodeID() []uint64 {
|
func (n GetSubTreeResponseBodyWrapper) GetNodeID() []uint64 {
|
||||||
|
@ -144,7 +144,7 @@ func (w *PoolWrapper) GetSubTree(ctx context.Context, bktInfo *data.BucketInfo,
|
||||||
|
|
||||||
type SubTreeStreamImpl struct {
|
type SubTreeStreamImpl struct {
|
||||||
r *treepool.SubTreeReader
|
r *treepool.SubTreeReader
|
||||||
buffer []*grpcService.GetSubTreeResponse_Body
|
buffer []*grpcservice.GetSubTreeResponse_Body
|
||||||
eof bool
|
eof bool
|
||||||
index int
|
index int
|
||||||
ln int
|
ln int
|
||||||
|
@ -204,7 +204,7 @@ func (w *PoolWrapper) GetSubTreeStream(ctx context.Context, bktInfo *data.Bucket
|
||||||
|
|
||||||
return &SubTreeStreamImpl{
|
return &SubTreeStreamImpl{
|
||||||
r: subTreeReader,
|
r: subTreeReader,
|
||||||
buffer: make([]*grpcService.GetSubTreeResponse_Body, bufSize),
|
buffer: make([]*grpcservice.GetSubTreeResponse_Body, bufSize),
|
||||||
index: -1,
|
index: -1,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -273,7 +273,7 @@ func handleError(err error) error {
|
||||||
if errors.Is(err, treepool.ErrNodeAccessDenied) {
|
if errors.Is(err, treepool.ErrNodeAccessDenied) {
|
||||||
return fmt.Errorf("%w: %s", tree.ErrNodeAccessDenied, err.Error())
|
return fmt.Errorf("%w: %s", tree.ErrNodeAccessDenied, err.Error())
|
||||||
}
|
}
|
||||||
if errorsFrost.IsTimeoutError(err) {
|
if frosterr.IsTimeoutError(err) {
|
||||||
return fmt.Errorf("%w: %s", tree.ErrGatewayTimeout, err.Error())
|
return fmt.Errorf("%w: %s", tree.ErrGatewayTimeout, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -978,7 +978,7 @@ func (s *VersionsByPrefixStreamImpl) getNodeFromMainStream() (NodeResponse, erro
|
||||||
for {
|
for {
|
||||||
node, err := s.mainStream.Next()
|
node, err := s.mainStream.Next()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, ErrNodeNotFound) {
|
if errors.Is(err, tree.ErrNodeNotFound) {
|
||||||
return nil, io.EOF
|
return nil, io.EOF
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("main stream next: %w", err)
|
return nil, fmt.Errorf("main stream next: %w", err)
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/tree"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -242,7 +243,7 @@ func (c *ServiceClientMemory) GetSubTree(_ context.Context, bktInfo *data.Bucket
|
||||||
|
|
||||||
tr, ok := cnr.trees[treeID]
|
tr, ok := cnr.trees[treeID]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, ErrNodeNotFound
|
return nil, tree.ErrNodeNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(rootID) != 1 {
|
if len(rootID) != 1 {
|
||||||
|
@ -251,7 +252,7 @@ func (c *ServiceClientMemory) GetSubTree(_ context.Context, bktInfo *data.Bucket
|
||||||
|
|
||||||
node := tr.treeData.getNode(rootID[0])
|
node := tr.treeData.getNode(rootID[0])
|
||||||
if node == nil {
|
if node == nil {
|
||||||
return nil, ErrNodeNotFound
|
return nil, tree.ErrNodeNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
if sort {
|
if sort {
|
||||||
|
@ -282,12 +283,12 @@ func (s *SubTreeStreamMemoryImpl) Next() (NodeResponse, error) {
|
||||||
func (c *ServiceClientMemory) GetSubTreeStream(_ context.Context, bktInfo *data.BucketInfo, treeID string, rootID []uint64, depth uint32) (SubTreeStream, error) {
|
func (c *ServiceClientMemory) GetSubTreeStream(_ context.Context, bktInfo *data.BucketInfo, treeID string, rootID []uint64, depth uint32) (SubTreeStream, error) {
|
||||||
cnr, ok := c.containers[bktInfo.CID.EncodeToString()]
|
cnr, ok := c.containers[bktInfo.CID.EncodeToString()]
|
||||||
if !ok {
|
if !ok {
|
||||||
return &SubTreeStreamMemoryImpl{err: ErrNodeNotFound}, nil
|
return &SubTreeStreamMemoryImpl{err: tree.ErrNodeNotFound}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
tr, ok := cnr.trees[treeID]
|
tr, ok := cnr.trees[treeID]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, ErrNodeNotFound
|
return nil, tree.ErrNodeNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(rootID) != 1 {
|
if len(rootID) != 1 {
|
||||||
|
@ -296,7 +297,7 @@ func (c *ServiceClientMemory) GetSubTreeStream(_ context.Context, bktInfo *data.
|
||||||
|
|
||||||
node := tr.treeData.getNode(rootID[0])
|
node := tr.treeData.getNode(rootID[0])
|
||||||
if node == nil {
|
if node == nil {
|
||||||
return nil, ErrNodeNotFound
|
return nil, tree.ErrNodeNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
sortNode(tr.treeData)
|
sortNode(tr.treeData)
|
||||||
|
@ -353,7 +354,7 @@ func (c *ServiceClientMemory) AddNodeBase(_ context.Context, bktInfo *data.Bucke
|
||||||
|
|
||||||
parentNode := tr.treeData.getNode(parent)
|
parentNode := tr.treeData.getNode(parent)
|
||||||
if parentNode == nil {
|
if parentNode == nil {
|
||||||
return 0, ErrNodeNotFound
|
return 0, tree.ErrNodeNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
newID := tr.idCounter
|
newID := tr.idCounter
|
||||||
|
@ -418,22 +419,22 @@ func (c *ServiceClientMemory) AddNodeByPath(_ context.Context, bktInfo *data.Buc
|
||||||
func (c *ServiceClientMemory) MoveNode(_ context.Context, bktInfo *data.BucketInfo, treeID string, nodeID, parentID uint64, meta map[string]string) error {
|
func (c *ServiceClientMemory) MoveNode(_ context.Context, bktInfo *data.BucketInfo, treeID string, nodeID, parentID uint64, meta map[string]string) error {
|
||||||
cnr, ok := c.containers[bktInfo.CID.EncodeToString()]
|
cnr, ok := c.containers[bktInfo.CID.EncodeToString()]
|
||||||
if !ok {
|
if !ok {
|
||||||
return ErrNodeNotFound
|
return tree.ErrNodeNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
tr, ok := cnr.trees[treeID]
|
tr, ok := cnr.trees[treeID]
|
||||||
if !ok {
|
if !ok {
|
||||||
return ErrNodeNotFound
|
return tree.ErrNodeNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
node := tr.treeData.getNode(nodeID)
|
node := tr.treeData.getNode(nodeID)
|
||||||
if node == nil {
|
if node == nil {
|
||||||
return ErrNodeNotFound
|
return tree.ErrNodeNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
newParent := tr.treeData.getNode(parentID)
|
newParent := tr.treeData.getNode(parentID)
|
||||||
if newParent == nil {
|
if newParent == nil {
|
||||||
return ErrNodeNotFound
|
return tree.ErrNodeNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
node.data.meta = metaToNodeMeta(meta)
|
node.data.meta = metaToNodeMeta(meta)
|
||||||
|
@ -466,17 +467,17 @@ func sortNodes(list []*treeNodeMemory) {
|
||||||
func (c *ServiceClientMemory) RemoveNode(_ context.Context, bktInfo *data.BucketInfo, treeID string, nodeID uint64) error {
|
func (c *ServiceClientMemory) RemoveNode(_ context.Context, bktInfo *data.BucketInfo, treeID string, nodeID uint64) error {
|
||||||
cnr, ok := c.containers[bktInfo.CID.EncodeToString()]
|
cnr, ok := c.containers[bktInfo.CID.EncodeToString()]
|
||||||
if !ok {
|
if !ok {
|
||||||
return ErrNodeNotFound
|
return tree.ErrNodeNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
tr, ok := cnr.trees[treeID]
|
tr, ok := cnr.trees[treeID]
|
||||||
if !ok {
|
if !ok {
|
||||||
return ErrNodeNotFound
|
return tree.ErrNodeNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
node := tr.treeData.getNode(nodeID)
|
node := tr.treeData.getNode(nodeID)
|
||||||
if node == nil {
|
if node == nil {
|
||||||
return ErrNodeNotFound
|
return tree.ErrNodeNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
node.parent.removeChild(nodeID)
|
node.parent.removeChild(nodeID)
|
||||||
|
|
Loading…
Reference in a new issue