Denis Kirillov
689f7ee818
All checks were successful
/ DCO (pull_request) Successful in 1m47s
/ Builds (1.21) (pull_request) Successful in 2m20s
/ Builds (1.22) (pull_request) Successful in 2m22s
/ Vulncheck (pull_request) Successful in 2m6s
/ Lint (pull_request) Successful in 4m43s
/ Tests (1.21) (pull_request) Successful in 2m30s
/ Tests (1.22) (pull_request) Successful in 2m25s
It's need to fit user expectation on deleting CORs for example. Previously after removing cors (that was uploaded in split manner) we can still get some data (from other node) because deletion worked only for latest node version. Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
118 lines
2.9 KiB
Go
118 lines
2.9 KiB
Go
package layer
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
errorsStd "errors"
|
|
"fmt"
|
|
"io"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
const wildcard = "*"
|
|
|
|
var supportedMethods = map[string]struct{}{"GET": {}, "HEAD": {}, "POST": {}, "PUT": {}, "DELETE": {}}
|
|
|
|
func (n *Layer) PutBucketCORS(ctx context.Context, p *PutCORSParams) error {
|
|
var (
|
|
buf bytes.Buffer
|
|
tee = io.TeeReader(p.Reader, &buf)
|
|
cors = &data.CORSConfiguration{}
|
|
)
|
|
|
|
if err := p.NewDecoder(tee).Decode(cors); err != nil {
|
|
return fmt.Errorf("xml decode cors: %w", err)
|
|
}
|
|
|
|
if cors.CORSRules == nil {
|
|
return errors.GetAPIError(errors.ErrMalformedXML)
|
|
}
|
|
|
|
if err := checkCORS(cors); err != nil {
|
|
return err
|
|
}
|
|
|
|
prm := PrmObjectCreate{
|
|
Container: p.BktInfo.CID,
|
|
Payload: &buf,
|
|
Filepath: p.BktInfo.CORSObjectName(),
|
|
CreationTime: TimeNow(ctx),
|
|
CopiesNumber: p.CopiesNumbers,
|
|
}
|
|
|
|
_, objID, _, _, err := n.objectPutAndHash(ctx, prm, p.BktInfo)
|
|
if err != nil {
|
|
return fmt.Errorf("put system object: %w", err)
|
|
}
|
|
|
|
objIDsToDelete, err := n.treeService.PutBucketCORS(ctx, p.BktInfo, objID)
|
|
objIDToDeleteNotFound := errorsStd.Is(err, ErrNoNodeToRemove)
|
|
if err != nil && !objIDToDeleteNotFound {
|
|
return err
|
|
}
|
|
|
|
if !objIDToDeleteNotFound {
|
|
for _, id := range objIDsToDelete {
|
|
if err = n.objectDelete(ctx, p.BktInfo, id); err != nil {
|
|
n.reqLogger(ctx).Error(logs.CouldntDeleteCorsObject, zap.Error(err),
|
|
zap.String("cnrID", p.BktInfo.CID.EncodeToString()),
|
|
zap.String("objID", id.EncodeToString()))
|
|
}
|
|
}
|
|
}
|
|
|
|
n.cache.PutCORS(n.BearerOwner(ctx), p.BktInfo, cors)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (n *Layer) GetBucketCORS(ctx context.Context, bktInfo *data.BucketInfo) (*data.CORSConfiguration, error) {
|
|
cors, err := n.getCORS(ctx, bktInfo)
|
|
if err != nil {
|
|
if errorsStd.Is(err, ErrNodeNotFound) {
|
|
return nil, fmt.Errorf("%w: %s", errors.GetAPIError(errors.ErrNoSuchCORSConfiguration), err.Error())
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
return cors, nil
|
|
}
|
|
|
|
func (n *Layer) DeleteBucketCORS(ctx context.Context, bktInfo *data.BucketInfo) error {
|
|
objIDs, err := n.treeService.DeleteBucketCORS(ctx, bktInfo)
|
|
objIDNotFound := errorsStd.Is(err, ErrNoNodeToRemove)
|
|
if err != nil && !objIDNotFound {
|
|
return err
|
|
}
|
|
if !objIDNotFound {
|
|
for _, id := range objIDs {
|
|
if err = n.objectDelete(ctx, bktInfo, id); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
n.cache.DeleteCORS(bktInfo)
|
|
|
|
return nil
|
|
}
|
|
|
|
func checkCORS(cors *data.CORSConfiguration) error {
|
|
for _, r := range cors.CORSRules {
|
|
for _, m := range r.AllowedMethods {
|
|
if _, ok := supportedMethods[m]; !ok {
|
|
return errors.GetAPIErrorWithError(errors.ErrCORSUnsupportedMethod, fmt.Errorf("unsupported method is %s", m))
|
|
}
|
|
}
|
|
for _, h := range r.ExposeHeaders {
|
|
if h == wildcard {
|
|
return errors.GetAPIError(errors.ErrCORSWildcardExposeHeaders)
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|