From 4c41b8be3bd6453d3075081b3b1a7545a9c9e3b2 Mon Sep 17 00:00:00 2001 From: niksis02 Date: Thu, 28 Aug 2025 01:43:11 +0400 Subject: [PATCH] feat: changes cors implementation in s3 to store/retreive in meta bucket The CORS actions were directly proxied in s3 proxy backend. The new implementation stores/retreives/deletes bucket cors configuration in `meta` bucket. --- backend/s3proxy/s3.go | 153 +++++++++--------------------------------- 1 file changed, 30 insertions(+), 123 deletions(-) diff --git a/backend/s3proxy/s3.go b/backend/s3proxy/s3.go index 150b4a8e..f420104f 100644 --- a/backend/s3proxy/s3.go +++ b/backend/s3proxy/s3.go @@ -17,7 +17,6 @@ package s3proxy import ( "bytes" "context" - "encoding/xml" "errors" "fmt" "io" @@ -40,6 +39,7 @@ type metaPrefix string const ( metaPrefixAcl metaPrefix = "vgw-meta-acl-" metaPrefixPolicy metaPrefix = "vgw-meta-policy-" + metaPrefixCors metaPrefix = "vgw-meta-cors-" ) type S3Proxy struct { @@ -1498,29 +1498,11 @@ func (s *S3Proxy) DeleteObjectTagging(ctx context.Context, bucket, object string } func (s *S3Proxy) PutBucketCors(ctx context.Context, bucket string, cors []byte) error { - cfg, err := auth.ParseCORSOutput(cors) - if err != nil { - return handleError(err) - } - - _, err = s.client.PutBucketCors(ctx, &s3.PutBucketCorsInput{ - Bucket: &bucket, - CORSConfiguration: parseGatewayCORSToSDKConfig(cfg), - }) - - return handleError(err) + return handleError(s.putMetaBucketObj(ctx, bucket, cors, metaPrefixCors)) } func (s *S3Proxy) GetBucketCors(ctx context.Context, bucket string) ([]byte, error) { - resp, err := s.client.GetBucketCors(ctx, &s3.GetBucketCorsInput{ - Bucket: &bucket, - }) - if err != nil { - return nil, handleError(err) - } - - config := parseSdkCORSToGatewayConfig(resp.CORSRules) - data, err := xml.Marshal(config) + data, err := s.getMetaBucketObjData(ctx, bucket, metaPrefixCors, false) if err != nil { return nil, handleError(err) } @@ -1529,11 +1511,16 @@ func (s *S3Proxy) GetBucketCors(ctx context.Context, bucket string) ([]byte, err } func (s *S3Proxy) DeleteBucketCors(ctx context.Context, bucket string) error { - _, err := s.client.DeleteBucketCors(ctx, &s3.DeleteBucketCorsInput{ - Bucket: &bucket, + key := getMetaKey(bucket, metaPrefixCors) + _, err := s.client.DeleteObject(ctx, &s3.DeleteObjectInput{ + Bucket: &s.metaBucket, + Key: &key, }) + if err != nil && !areErrSame(err, s3err.GetAPIError(s3err.ErrNoSuchKey)) { + return handleError(err) + } - return handleError(err) + return nil } func (s *S3Proxy) PutBucketPolicy(ctx context.Context, bucket string, policy []byte) error { @@ -1654,12 +1641,7 @@ func (s *S3Proxy) putMetaBucketObj(ctx context.Context, bucket string, data []by func (s *S3Proxy) getMetaBucketObjData(ctx context.Context, bucket string, prefix metaPrefix, checkExists bool) ([]byte, error) { // return default bahviour of get bucket policy/acl, if meta bucket is not provided if s.metaBucket == "" { - switch prefix { - case metaPrefixAcl: - return []byte{}, nil - case metaPrefixPolicy: - return nil, s3err.GetAPIError(s3err.ErrNoSuchBucketPolicy) - } + return handleMetaBucketObjectNotFoundErr(prefix) } key := getMetaKey(bucket, prefix) @@ -1673,13 +1655,7 @@ func (s *S3Proxy) getMetaBucketObjData(ctx context.Context, bucket string, prefi return nil, err } - switch prefix { - case metaPrefixAcl: - // If bucket acl is not found, return default acl - return []byte{}, nil - case metaPrefixPolicy: - return nil, s3err.GetAPIError(s3err.ErrNoSuchBucketPolicy) - } + return handleMetaBucketObjectNotFoundErr(prefix) } if err != nil { return nil, err @@ -1693,6 +1669,23 @@ func (s *S3Proxy) getMetaBucketObjData(ctx context.Context, bucket string, prefi return data, nil } +// handles the case when an object with the given metprefix +// is not found in meta bucket. Aggregates the not found errors +// for each meta prefix +func handleMetaBucketObjectNotFoundErr(prefix metaPrefix) ([]byte, error) { + switch prefix { + case metaPrefixAcl: + // If bucket acl is not found, return default acl + return []byte{}, nil + case metaPrefixPolicy: + return nil, s3err.GetAPIError(s3err.ErrNoSuchBucketPolicy) + case metaPrefixCors: + return nil, s3err.GetAPIError(s3err.ErrNoSuchCORSConfiguration) + } + + return []byte{}, nil +} + // Checks if the provided err is a type of smithy.APIError // and if the error code and message match with the provided apiErr func areErrSame(err error, apiErr s3err.APIError) bool { @@ -1781,89 +1774,3 @@ func convertObjectVersions(versions []types.ObjectVersion) []s3response.ObjectVe return result } - -func parseGatewayCORSToSDKConfig(config *auth.CORSConfiguration) *types.CORSConfiguration { - if config == nil { - return nil - } - - result := &types.CORSConfiguration{ - CORSRules: make([]types.CORSRule, 0, len(config.Rules)), - } - - for _, cfg := range config.Rules { - result.CORSRules = append(result.CORSRules, types.CORSRule{ - AllowedMethods: convertCORSMethodsToString(cfg.AllowedMethods), - AllowedHeaders: convertCORSHeadersToString(cfg.AllowedHeaders), - ExposeHeaders: convertCORSHeadersToString(cfg.ExposeHeaders), - AllowedOrigins: cfg.AllowedOrigins, - ID: cfg.ID, - MaxAgeSeconds: cfg.MaxAgeSeconds, - }) - } - - return result -} - -// convertCORSHeadersToString []auth.CORSHeader to []string -func convertCORSHeadersToString(headers []auth.CORSHeader) []string { - result := make([]string, 0, len(headers)) - for _, h := range headers { - result = append(result, h.String()) - } - - return result -} - -// convertCORSMethodsToString converts []auth.CORSHTTPMethod to []string -func convertCORSMethodsToString(methods []auth.CORSHTTPMethod) []string { - result := make([]string, 0, len(methods)) - for _, m := range methods { - result = append(result, m.String()) - } - - return result -} - -// convertCORSHeaders converts []string to []auth.CORSHeader -func convertCORSHeaders(headers []string) []auth.CORSHeader { - result := make([]auth.CORSHeader, 0, len(headers)) - for _, h := range headers { - result = append(result, auth.CORSHeader(h)) - } - - return result -} - -// convertCORSMethods converts []string to []auth.CORSHTTPMethod -func convertCORSMethods(methods []string) []auth.CORSHTTPMethod { - result := make([]auth.CORSHTTPMethod, 0, len(methods)) - for _, m := range methods { - result = append(result, auth.CORSHTTPMethod(m)) - } - - return result -} - -func parseSdkCORSToGatewayConfig(rules []types.CORSRule) *auth.CORSConfiguration { - if rules == nil { - return nil - } - - result := &auth.CORSConfiguration{ - Rules: make([]auth.CORSRule, 0, len(rules)), - } - - for _, cfg := range rules { - result.Rules = append(result.Rules, auth.CORSRule{ - AllowedMethods: convertCORSMethods(cfg.AllowedMethods), - AllowedHeaders: convertCORSHeaders(cfg.AllowedHeaders), - ExposeHeaders: convertCORSHeaders(cfg.ExposeHeaders), - AllowedOrigins: cfg.AllowedOrigins, - ID: cfg.ID, - MaxAgeSeconds: cfg.MaxAgeSeconds, - }) - } - - return result -}